1 | //===- BTFDebug.cpp - BTF Generator ---------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains support for writing BTF debug info. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "BTFDebug.h" |
14 | #include "BPF.h" |
15 | #include "BPFCORE.h" |
16 | #include "MCTargetDesc/BPFMCTargetDesc.h" |
17 | #include "llvm/BinaryFormat/ELF.h" |
18 | #include "llvm/CodeGen/AsmPrinter.h" |
19 | #include "llvm/CodeGen/MachineModuleInfo.h" |
20 | #include "llvm/CodeGen/MachineOperand.h" |
21 | #include "llvm/IR/Module.h" |
22 | #include "llvm/MC/MCContext.h" |
23 | #include "llvm/MC/MCObjectFileInfo.h" |
24 | #include "llvm/MC/MCSectionELF.h" |
25 | #include "llvm/MC/MCStreamer.h" |
26 | #include "llvm/Support/LineIterator.h" |
27 | #include "llvm/Support/MemoryBuffer.h" |
28 | #include "llvm/Target/TargetLoweringObjectFile.h" |
29 | #include <optional> |
30 | |
31 | using namespace llvm; |
32 | |
33 | static const char *BTFKindStr[] = { |
34 | #define HANDLE_BTF_KIND(ID, NAME) "BTF_KIND_" #NAME, |
35 | #include "llvm/DebugInfo/BTF/BTF.def" |
36 | }; |
37 | |
38 | static const DIType *tryRemoveAtomicType(const DIType *Ty) { |
39 | if (!Ty) |
40 | return Ty; |
41 | auto DerivedTy = dyn_cast<DIDerivedType>(Val: Ty); |
42 | if (DerivedTy && DerivedTy->getTag() == dwarf::DW_TAG_atomic_type) |
43 | return DerivedTy->getBaseType(); |
44 | return Ty; |
45 | } |
46 | |
47 | /// Emit a BTF common type. |
48 | void BTFTypeBase::emitType(MCStreamer &OS) { |
49 | OS.AddComment(T: std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(val: Id) + |
50 | ")" ); |
51 | OS.emitInt32(Value: BTFType.NameOff); |
52 | OS.AddComment(T: "0x" + Twine::utohexstr(Val: BTFType.Info)); |
53 | OS.emitInt32(Value: BTFType.Info); |
54 | OS.emitInt32(Value: BTFType.Size); |
55 | } |
56 | |
57 | BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag, |
58 | bool NeedsFixup) |
59 | : DTy(DTy), NeedsFixup(NeedsFixup), Name(DTy->getName()) { |
60 | switch (Tag) { |
61 | case dwarf::DW_TAG_pointer_type: |
62 | Kind = BTF::BTF_KIND_PTR; |
63 | break; |
64 | case dwarf::DW_TAG_const_type: |
65 | Kind = BTF::BTF_KIND_CONST; |
66 | break; |
67 | case dwarf::DW_TAG_volatile_type: |
68 | Kind = BTF::BTF_KIND_VOLATILE; |
69 | break; |
70 | case dwarf::DW_TAG_typedef: |
71 | Kind = BTF::BTF_KIND_TYPEDEF; |
72 | break; |
73 | case dwarf::DW_TAG_restrict_type: |
74 | Kind = BTF::BTF_KIND_RESTRICT; |
75 | break; |
76 | default: |
77 | llvm_unreachable("Unknown DIDerivedType Tag" ); |
78 | } |
79 | BTFType.Info = Kind << 24; |
80 | } |
81 | |
82 | /// Used by DW_TAG_pointer_type only. |
83 | BTFTypeDerived::BTFTypeDerived(unsigned NextTypeId, unsigned Tag, |
84 | StringRef Name) |
85 | : DTy(nullptr), NeedsFixup(false), Name(Name) { |
86 | Kind = BTF::BTF_KIND_PTR; |
87 | BTFType.Info = Kind << 24; |
88 | BTFType.Type = NextTypeId; |
89 | } |
90 | |
91 | void BTFTypeDerived::completeType(BTFDebug &BDebug) { |
92 | if (IsCompleted) |
93 | return; |
94 | IsCompleted = true; |
95 | |
96 | BTFType.NameOff = BDebug.addString(S: Name); |
97 | |
98 | if (NeedsFixup || !DTy) |
99 | return; |
100 | |
101 | // The base type for PTR/CONST/VOLATILE could be void. |
102 | const DIType *ResolvedType = tryRemoveAtomicType(Ty: DTy->getBaseType()); |
103 | if (!ResolvedType) { |
104 | assert((Kind == BTF::BTF_KIND_PTR || Kind == BTF::BTF_KIND_CONST || |
105 | Kind == BTF::BTF_KIND_VOLATILE) && |
106 | "Invalid null basetype" ); |
107 | BTFType.Type = 0; |
108 | } else { |
109 | BTFType.Type = BDebug.getTypeId(Ty: ResolvedType); |
110 | } |
111 | } |
112 | |
113 | void BTFTypeDerived::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } |
114 | |
115 | void BTFTypeDerived::setPointeeType(uint32_t PointeeType) { |
116 | BTFType.Type = PointeeType; |
117 | } |
118 | |
119 | /// Represent a struct/union forward declaration. |
120 | BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) { |
121 | Kind = BTF::BTF_KIND_FWD; |
122 | BTFType.Info = IsUnion << 31 | Kind << 24; |
123 | BTFType.Type = 0; |
124 | } |
125 | |
126 | void BTFTypeFwd::completeType(BTFDebug &BDebug) { |
127 | if (IsCompleted) |
128 | return; |
129 | IsCompleted = true; |
130 | |
131 | BTFType.NameOff = BDebug.addString(S: Name); |
132 | } |
133 | |
134 | void BTFTypeFwd::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } |
135 | |
136 | BTFTypeInt::BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits, |
137 | uint32_t OffsetInBits, StringRef TypeName) |
138 | : Name(TypeName) { |
139 | // Translate IR int encoding to BTF int encoding. |
140 | uint8_t BTFEncoding; |
141 | switch (Encoding) { |
142 | case dwarf::DW_ATE_boolean: |
143 | BTFEncoding = BTF::INT_BOOL; |
144 | break; |
145 | case dwarf::DW_ATE_signed: |
146 | case dwarf::DW_ATE_signed_char: |
147 | BTFEncoding = BTF::INT_SIGNED; |
148 | break; |
149 | case dwarf::DW_ATE_unsigned: |
150 | case dwarf::DW_ATE_unsigned_char: |
151 | BTFEncoding = 0; |
152 | break; |
153 | default: |
154 | llvm_unreachable("Unknown BTFTypeInt Encoding" ); |
155 | } |
156 | |
157 | Kind = BTF::BTF_KIND_INT; |
158 | BTFType.Info = Kind << 24; |
159 | BTFType.Size = roundupToBytes(NumBits: SizeInBits); |
160 | IntVal = (BTFEncoding << 24) | OffsetInBits << 16 | SizeInBits; |
161 | } |
162 | |
163 | void BTFTypeInt::completeType(BTFDebug &BDebug) { |
164 | if (IsCompleted) |
165 | return; |
166 | IsCompleted = true; |
167 | |
168 | BTFType.NameOff = BDebug.addString(S: Name); |
169 | } |
170 | |
171 | void BTFTypeInt::emitType(MCStreamer &OS) { |
172 | BTFTypeBase::emitType(OS); |
173 | OS.AddComment(T: "0x" + Twine::utohexstr(Val: IntVal)); |
174 | OS.emitInt32(Value: IntVal); |
175 | } |
176 | |
177 | BTFTypeEnum::BTFTypeEnum(const DICompositeType *ETy, uint32_t VLen, |
178 | bool IsSigned) : ETy(ETy) { |
179 | Kind = BTF::BTF_KIND_ENUM; |
180 | BTFType.Info = IsSigned << 31 | Kind << 24 | VLen; |
181 | BTFType.Size = roundupToBytes(NumBits: ETy->getSizeInBits()); |
182 | } |
183 | |
184 | void BTFTypeEnum::completeType(BTFDebug &BDebug) { |
185 | if (IsCompleted) |
186 | return; |
187 | IsCompleted = true; |
188 | |
189 | BTFType.NameOff = BDebug.addString(S: ETy->getName()); |
190 | |
191 | DINodeArray Elements = ETy->getElements(); |
192 | for (const auto Element : Elements) { |
193 | const auto *Enum = cast<DIEnumerator>(Val: Element); |
194 | |
195 | struct BTF::BTFEnum BTFEnum; |
196 | BTFEnum.NameOff = BDebug.addString(S: Enum->getName()); |
197 | // BTF enum value is 32bit, enforce it. |
198 | uint32_t Value; |
199 | if (Enum->isUnsigned()) |
200 | Value = static_cast<uint32_t>(Enum->getValue().getZExtValue()); |
201 | else |
202 | Value = static_cast<uint32_t>(Enum->getValue().getSExtValue()); |
203 | BTFEnum.Val = Value; |
204 | EnumValues.push_back(x: BTFEnum); |
205 | } |
206 | } |
207 | |
208 | void BTFTypeEnum::emitType(MCStreamer &OS) { |
209 | BTFTypeBase::emitType(OS); |
210 | for (const auto &Enum : EnumValues) { |
211 | OS.emitInt32(Value: Enum.NameOff); |
212 | OS.emitInt32(Value: Enum.Val); |
213 | } |
214 | } |
215 | |
216 | BTFTypeEnum64::BTFTypeEnum64(const DICompositeType *ETy, uint32_t VLen, |
217 | bool IsSigned) : ETy(ETy) { |
218 | Kind = BTF::BTF_KIND_ENUM64; |
219 | BTFType.Info = IsSigned << 31 | Kind << 24 | VLen; |
220 | BTFType.Size = roundupToBytes(NumBits: ETy->getSizeInBits()); |
221 | } |
222 | |
223 | void BTFTypeEnum64::completeType(BTFDebug &BDebug) { |
224 | if (IsCompleted) |
225 | return; |
226 | IsCompleted = true; |
227 | |
228 | BTFType.NameOff = BDebug.addString(S: ETy->getName()); |
229 | |
230 | DINodeArray Elements = ETy->getElements(); |
231 | for (const auto Element : Elements) { |
232 | const auto *Enum = cast<DIEnumerator>(Val: Element); |
233 | |
234 | struct BTF::BTFEnum64 BTFEnum; |
235 | BTFEnum.NameOff = BDebug.addString(S: Enum->getName()); |
236 | uint64_t Value; |
237 | if (Enum->isUnsigned()) |
238 | Value = static_cast<uint64_t>(Enum->getValue().getZExtValue()); |
239 | else |
240 | Value = static_cast<uint64_t>(Enum->getValue().getSExtValue()); |
241 | BTFEnum.Val_Lo32 = Value; |
242 | BTFEnum.Val_Hi32 = Value >> 32; |
243 | EnumValues.push_back(x: BTFEnum); |
244 | } |
245 | } |
246 | |
247 | void BTFTypeEnum64::emitType(MCStreamer &OS) { |
248 | BTFTypeBase::emitType(OS); |
249 | for (const auto &Enum : EnumValues) { |
250 | OS.emitInt32(Value: Enum.NameOff); |
251 | OS.AddComment(T: "0x" + Twine::utohexstr(Val: Enum.Val_Lo32)); |
252 | OS.emitInt32(Value: Enum.Val_Lo32); |
253 | OS.AddComment(T: "0x" + Twine::utohexstr(Val: Enum.Val_Hi32)); |
254 | OS.emitInt32(Value: Enum.Val_Hi32); |
255 | } |
256 | } |
257 | |
258 | BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) { |
259 | Kind = BTF::BTF_KIND_ARRAY; |
260 | BTFType.NameOff = 0; |
261 | BTFType.Info = Kind << 24; |
262 | BTFType.Size = 0; |
263 | |
264 | ArrayInfo.ElemType = ElemTypeId; |
265 | ArrayInfo.Nelems = NumElems; |
266 | } |
267 | |
268 | /// Represent a BTF array. |
269 | void BTFTypeArray::completeType(BTFDebug &BDebug) { |
270 | if (IsCompleted) |
271 | return; |
272 | IsCompleted = true; |
273 | |
274 | // The IR does not really have a type for the index. |
275 | // A special type for array index should have been |
276 | // created during initial type traversal. Just |
277 | // retrieve that type id. |
278 | ArrayInfo.IndexType = BDebug.getArrayIndexTypeId(); |
279 | } |
280 | |
281 | void BTFTypeArray::emitType(MCStreamer &OS) { |
282 | BTFTypeBase::emitType(OS); |
283 | OS.emitInt32(Value: ArrayInfo.ElemType); |
284 | OS.emitInt32(Value: ArrayInfo.IndexType); |
285 | OS.emitInt32(Value: ArrayInfo.Nelems); |
286 | } |
287 | |
288 | /// Represent either a struct or a union. |
289 | BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct, |
290 | bool HasBitField, uint32_t Vlen) |
291 | : STy(STy), HasBitField(HasBitField) { |
292 | Kind = IsStruct ? BTF::BTF_KIND_STRUCT : BTF::BTF_KIND_UNION; |
293 | BTFType.Size = roundupToBytes(NumBits: STy->getSizeInBits()); |
294 | BTFType.Info = (HasBitField << 31) | (Kind << 24) | Vlen; |
295 | } |
296 | |
297 | void BTFTypeStruct::completeType(BTFDebug &BDebug) { |
298 | if (IsCompleted) |
299 | return; |
300 | IsCompleted = true; |
301 | |
302 | BTFType.NameOff = BDebug.addString(S: STy->getName()); |
303 | |
304 | // Add struct/union members. |
305 | const DINodeArray Elements = STy->getElements(); |
306 | for (const auto *Element : Elements) { |
307 | struct BTF::BTFMember BTFMember; |
308 | const auto *DDTy = cast<DIDerivedType>(Val: Element); |
309 | |
310 | BTFMember.NameOff = BDebug.addString(S: DDTy->getName()); |
311 | if (HasBitField) { |
312 | uint8_t BitFieldSize = DDTy->isBitField() ? DDTy->getSizeInBits() : 0; |
313 | BTFMember.Offset = BitFieldSize << 24 | DDTy->getOffsetInBits(); |
314 | } else { |
315 | BTFMember.Offset = DDTy->getOffsetInBits(); |
316 | } |
317 | const auto *BaseTy = tryRemoveAtomicType(Ty: DDTy->getBaseType()); |
318 | BTFMember.Type = BDebug.getTypeId(Ty: BaseTy); |
319 | Members.push_back(x: BTFMember); |
320 | } |
321 | } |
322 | |
323 | void BTFTypeStruct::emitType(MCStreamer &OS) { |
324 | BTFTypeBase::emitType(OS); |
325 | for (const auto &Member : Members) { |
326 | OS.emitInt32(Value: Member.NameOff); |
327 | OS.emitInt32(Value: Member.Type); |
328 | OS.AddComment(T: "0x" + Twine::utohexstr(Val: Member.Offset)); |
329 | OS.emitInt32(Value: Member.Offset); |
330 | } |
331 | } |
332 | |
333 | std::string BTFTypeStruct::getName() { return std::string(STy->getName()); } |
334 | |
335 | /// The Func kind represents both subprogram and pointee of function |
336 | /// pointers. If the FuncName is empty, it represents a pointee of function |
337 | /// pointer. Otherwise, it represents a subprogram. The func arg names |
338 | /// are empty for pointee of function pointer case, and are valid names |
339 | /// for subprogram. |
340 | BTFTypeFuncProto::BTFTypeFuncProto( |
341 | const DISubroutineType *STy, uint32_t VLen, |
342 | const std::unordered_map<uint32_t, StringRef> &FuncArgNames) |
343 | : STy(STy), FuncArgNames(FuncArgNames) { |
344 | Kind = BTF::BTF_KIND_FUNC_PROTO; |
345 | BTFType.Info = (Kind << 24) | VLen; |
346 | } |
347 | |
348 | void BTFTypeFuncProto::completeType(BTFDebug &BDebug) { |
349 | if (IsCompleted) |
350 | return; |
351 | IsCompleted = true; |
352 | |
353 | DITypeRefArray Elements = STy->getTypeArray(); |
354 | auto RetType = tryRemoveAtomicType(Ty: Elements[0]); |
355 | BTFType.Type = RetType ? BDebug.getTypeId(Ty: RetType) : 0; |
356 | BTFType.NameOff = 0; |
357 | |
358 | // For null parameter which is typically the last one |
359 | // to represent the vararg, encode the NameOff/Type to be 0. |
360 | for (unsigned I = 1, N = Elements.size(); I < N; ++I) { |
361 | struct BTF::BTFParam Param; |
362 | auto Element = tryRemoveAtomicType(Ty: Elements[I]); |
363 | if (Element) { |
364 | Param.NameOff = BDebug.addString(S: FuncArgNames[I]); |
365 | Param.Type = BDebug.getTypeId(Ty: Element); |
366 | } else { |
367 | Param.NameOff = 0; |
368 | Param.Type = 0; |
369 | } |
370 | Parameters.push_back(x: Param); |
371 | } |
372 | } |
373 | |
374 | void BTFTypeFuncProto::emitType(MCStreamer &OS) { |
375 | BTFTypeBase::emitType(OS); |
376 | for (const auto &Param : Parameters) { |
377 | OS.emitInt32(Value: Param.NameOff); |
378 | OS.emitInt32(Value: Param.Type); |
379 | } |
380 | } |
381 | |
382 | BTFTypeFunc::BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId, |
383 | uint32_t Scope) |
384 | : Name(FuncName) { |
385 | Kind = BTF::BTF_KIND_FUNC; |
386 | BTFType.Info = (Kind << 24) | Scope; |
387 | BTFType.Type = ProtoTypeId; |
388 | } |
389 | |
390 | void BTFTypeFunc::completeType(BTFDebug &BDebug) { |
391 | if (IsCompleted) |
392 | return; |
393 | IsCompleted = true; |
394 | |
395 | BTFType.NameOff = BDebug.addString(S: Name); |
396 | } |
397 | |
398 | void BTFTypeFunc::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } |
399 | |
400 | BTFKindVar::BTFKindVar(StringRef VarName, uint32_t TypeId, uint32_t VarInfo) |
401 | : Name(VarName) { |
402 | Kind = BTF::BTF_KIND_VAR; |
403 | BTFType.Info = Kind << 24; |
404 | BTFType.Type = TypeId; |
405 | Info = VarInfo; |
406 | } |
407 | |
408 | void BTFKindVar::completeType(BTFDebug &BDebug) { |
409 | BTFType.NameOff = BDebug.addString(S: Name); |
410 | } |
411 | |
412 | void BTFKindVar::emitType(MCStreamer &OS) { |
413 | BTFTypeBase::emitType(OS); |
414 | OS.emitInt32(Value: Info); |
415 | } |
416 | |
417 | BTFKindDataSec::BTFKindDataSec(AsmPrinter *AsmPrt, std::string SecName) |
418 | : Asm(AsmPrt), Name(SecName) { |
419 | Kind = BTF::BTF_KIND_DATASEC; |
420 | BTFType.Info = Kind << 24; |
421 | BTFType.Size = 0; |
422 | } |
423 | |
424 | void BTFKindDataSec::completeType(BTFDebug &BDebug) { |
425 | BTFType.NameOff = BDebug.addString(S: Name); |
426 | BTFType.Info |= Vars.size(); |
427 | } |
428 | |
429 | void BTFKindDataSec::emitType(MCStreamer &OS) { |
430 | BTFTypeBase::emitType(OS); |
431 | |
432 | for (const auto &V : Vars) { |
433 | OS.emitInt32(Value: std::get<0>(t: V)); |
434 | Asm->emitLabelReference(Label: std::get<1>(t: V), Size: 4); |
435 | OS.emitInt32(Value: std::get<2>(t: V)); |
436 | } |
437 | } |
438 | |
439 | BTFTypeFloat::BTFTypeFloat(uint32_t SizeInBits, StringRef TypeName) |
440 | : Name(TypeName) { |
441 | Kind = BTF::BTF_KIND_FLOAT; |
442 | BTFType.Info = Kind << 24; |
443 | BTFType.Size = roundupToBytes(NumBits: SizeInBits); |
444 | } |
445 | |
446 | void BTFTypeFloat::completeType(BTFDebug &BDebug) { |
447 | if (IsCompleted) |
448 | return; |
449 | IsCompleted = true; |
450 | |
451 | BTFType.NameOff = BDebug.addString(S: Name); |
452 | } |
453 | |
454 | BTFTypeDeclTag::BTFTypeDeclTag(uint32_t BaseTypeId, int ComponentIdx, |
455 | StringRef Tag) |
456 | : Tag(Tag) { |
457 | Kind = BTF::BTF_KIND_DECL_TAG; |
458 | BTFType.Info = Kind << 24; |
459 | BTFType.Type = BaseTypeId; |
460 | Info = ComponentIdx; |
461 | } |
462 | |
463 | void BTFTypeDeclTag::completeType(BTFDebug &BDebug) { |
464 | if (IsCompleted) |
465 | return; |
466 | IsCompleted = true; |
467 | |
468 | BTFType.NameOff = BDebug.addString(S: Tag); |
469 | } |
470 | |
471 | void BTFTypeDeclTag::emitType(MCStreamer &OS) { |
472 | BTFTypeBase::emitType(OS); |
473 | OS.emitInt32(Value: Info); |
474 | } |
475 | |
476 | BTFTypeTypeTag::BTFTypeTypeTag(uint32_t NextTypeId, StringRef Tag) |
477 | : DTy(nullptr), Tag(Tag) { |
478 | Kind = BTF::BTF_KIND_TYPE_TAG; |
479 | BTFType.Info = Kind << 24; |
480 | BTFType.Type = NextTypeId; |
481 | } |
482 | |
483 | BTFTypeTypeTag::BTFTypeTypeTag(const DIDerivedType *DTy, StringRef Tag) |
484 | : DTy(DTy), Tag(Tag) { |
485 | Kind = BTF::BTF_KIND_TYPE_TAG; |
486 | BTFType.Info = Kind << 24; |
487 | } |
488 | |
489 | void BTFTypeTypeTag::completeType(BTFDebug &BDebug) { |
490 | if (IsCompleted) |
491 | return; |
492 | IsCompleted = true; |
493 | BTFType.NameOff = BDebug.addString(S: Tag); |
494 | if (DTy) { |
495 | const DIType *ResolvedType = tryRemoveAtomicType(Ty: DTy->getBaseType()); |
496 | if (!ResolvedType) |
497 | BTFType.Type = 0; |
498 | else |
499 | BTFType.Type = BDebug.getTypeId(Ty: ResolvedType); |
500 | } |
501 | } |
502 | |
503 | uint32_t BTFStringTable::addString(StringRef S) { |
504 | // Check whether the string already exists. |
505 | for (auto &OffsetM : OffsetToIdMap) { |
506 | if (Table[OffsetM.second] == S) |
507 | return OffsetM.first; |
508 | } |
509 | // Not find, add to the string table. |
510 | uint32_t Offset = Size; |
511 | OffsetToIdMap[Offset] = Table.size(); |
512 | Table.push_back(x: std::string(S)); |
513 | Size += S.size() + 1; |
514 | return Offset; |
515 | } |
516 | |
517 | BTFDebug::BTFDebug(AsmPrinter *AP) |
518 | : DebugHandlerBase(AP), OS(*Asm->OutStreamer), SkipInstruction(false), |
519 | LineInfoGenerated(false), SecNameOff(0), ArrayIndexTypeId(0), |
520 | MapDefNotCollected(true) { |
521 | addString(S: "\0" ); |
522 | } |
523 | |
524 | uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry, |
525 | const DIType *Ty) { |
526 | TypeEntry->setId(TypeEntries.size() + 1); |
527 | uint32_t Id = TypeEntry->getId(); |
528 | DIToIdMap[Ty] = Id; |
529 | TypeEntries.push_back(x: std::move(TypeEntry)); |
530 | return Id; |
531 | } |
532 | |
533 | uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry) { |
534 | TypeEntry->setId(TypeEntries.size() + 1); |
535 | uint32_t Id = TypeEntry->getId(); |
536 | TypeEntries.push_back(x: std::move(TypeEntry)); |
537 | return Id; |
538 | } |
539 | |
540 | void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { |
541 | // Only int and binary floating point types are supported in BTF. |
542 | uint32_t Encoding = BTy->getEncoding(); |
543 | std::unique_ptr<BTFTypeBase> TypeEntry; |
544 | switch (Encoding) { |
545 | case dwarf::DW_ATE_boolean: |
546 | case dwarf::DW_ATE_signed: |
547 | case dwarf::DW_ATE_signed_char: |
548 | case dwarf::DW_ATE_unsigned: |
549 | case dwarf::DW_ATE_unsigned_char: |
550 | // Create a BTF type instance for this DIBasicType and put it into |
551 | // DIToIdMap for cross-type reference check. |
552 | TypeEntry = std::make_unique<BTFTypeInt>( |
553 | args&: Encoding, args: BTy->getSizeInBits(), args: BTy->getOffsetInBits(), args: BTy->getName()); |
554 | break; |
555 | case dwarf::DW_ATE_float: |
556 | TypeEntry = |
557 | std::make_unique<BTFTypeFloat>(args: BTy->getSizeInBits(), args: BTy->getName()); |
558 | break; |
559 | default: |
560 | return; |
561 | } |
562 | |
563 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: BTy); |
564 | } |
565 | |
566 | /// Handle subprogram or subroutine types. |
567 | void BTFDebug::visitSubroutineType( |
568 | const DISubroutineType *STy, bool ForSubprog, |
569 | const std::unordered_map<uint32_t, StringRef> &FuncArgNames, |
570 | uint32_t &TypeId) { |
571 | DITypeRefArray Elements = STy->getTypeArray(); |
572 | uint32_t VLen = Elements.size() - 1; |
573 | if (VLen > BTF::MAX_VLEN) |
574 | return; |
575 | |
576 | // Subprogram has a valid non-zero-length name, and the pointee of |
577 | // a function pointer has an empty name. The subprogram type will |
578 | // not be added to DIToIdMap as it should not be referenced by |
579 | // any other types. |
580 | auto TypeEntry = std::make_unique<BTFTypeFuncProto>(args&: STy, args&: VLen, args: FuncArgNames); |
581 | if (ForSubprog) |
582 | TypeId = addType(TypeEntry: std::move(TypeEntry)); // For subprogram |
583 | else |
584 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: STy); // For func ptr |
585 | |
586 | // Visit return type and func arg types. |
587 | for (const auto Element : Elements) { |
588 | visitTypeEntry(Ty: Element); |
589 | } |
590 | } |
591 | |
592 | void BTFDebug::processDeclAnnotations(DINodeArray Annotations, |
593 | uint32_t BaseTypeId, |
594 | int ComponentIdx) { |
595 | if (!Annotations) |
596 | return; |
597 | |
598 | for (const Metadata *Annotation : Annotations->operands()) { |
599 | const MDNode *MD = cast<MDNode>(Val: Annotation); |
600 | const MDString *Name = cast<MDString>(Val: MD->getOperand(I: 0)); |
601 | if (Name->getString() != "btf_decl_tag" ) |
602 | continue; |
603 | |
604 | const MDString *Value = cast<MDString>(Val: MD->getOperand(I: 1)); |
605 | auto TypeEntry = std::make_unique<BTFTypeDeclTag>(args&: BaseTypeId, args&: ComponentIdx, |
606 | args: Value->getString()); |
607 | addType(TypeEntry: std::move(TypeEntry)); |
608 | } |
609 | } |
610 | |
611 | uint32_t BTFDebug::processDISubprogram(const DISubprogram *SP, |
612 | uint32_t ProtoTypeId, uint8_t Scope) { |
613 | auto FuncTypeEntry = |
614 | std::make_unique<BTFTypeFunc>(args: SP->getName(), args&: ProtoTypeId, args&: Scope); |
615 | uint32_t FuncId = addType(TypeEntry: std::move(FuncTypeEntry)); |
616 | |
617 | // Process argument annotations. |
618 | for (const DINode *DN : SP->getRetainedNodes()) { |
619 | if (const auto *DV = dyn_cast<DILocalVariable>(Val: DN)) { |
620 | uint32_t Arg = DV->getArg(); |
621 | if (Arg) |
622 | processDeclAnnotations(Annotations: DV->getAnnotations(), BaseTypeId: FuncId, ComponentIdx: Arg - 1); |
623 | } |
624 | } |
625 | processDeclAnnotations(Annotations: SP->getAnnotations(), BaseTypeId: FuncId, ComponentIdx: -1); |
626 | |
627 | return FuncId; |
628 | } |
629 | |
630 | /// Generate btf_type_tag chains. |
631 | int BTFDebug::genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId) { |
632 | SmallVector<const MDString *, 4> MDStrs; |
633 | DINodeArray Annots = DTy->getAnnotations(); |
634 | if (Annots) { |
635 | // For type with "int __tag1 __tag2 *p", the MDStrs will have |
636 | // content: [__tag1, __tag2]. |
637 | for (const Metadata *Annotations : Annots->operands()) { |
638 | const MDNode *MD = cast<MDNode>(Val: Annotations); |
639 | const MDString *Name = cast<MDString>(Val: MD->getOperand(I: 0)); |
640 | if (Name->getString() != "btf_type_tag" ) |
641 | continue; |
642 | MDStrs.push_back(Elt: cast<MDString>(Val: MD->getOperand(I: 1))); |
643 | } |
644 | } |
645 | |
646 | if (MDStrs.size() == 0) |
647 | return -1; |
648 | |
649 | // With MDStrs [__tag1, __tag2], the output type chain looks like |
650 | // PTR -> __tag2 -> __tag1 -> BaseType |
651 | // In the below, we construct BTF types with the order of __tag1, __tag2 |
652 | // and PTR. |
653 | unsigned TmpTypeId; |
654 | std::unique_ptr<BTFTypeTypeTag> TypeEntry; |
655 | if (BaseTypeId >= 0) |
656 | TypeEntry = |
657 | std::make_unique<BTFTypeTypeTag>(args&: BaseTypeId, args: MDStrs[0]->getString()); |
658 | else |
659 | TypeEntry = std::make_unique<BTFTypeTypeTag>(args&: DTy, args: MDStrs[0]->getString()); |
660 | TmpTypeId = addType(TypeEntry: std::move(TypeEntry)); |
661 | |
662 | for (unsigned I = 1; I < MDStrs.size(); I++) { |
663 | const MDString *Value = MDStrs[I]; |
664 | TypeEntry = std::make_unique<BTFTypeTypeTag>(args&: TmpTypeId, args: Value->getString()); |
665 | TmpTypeId = addType(TypeEntry: std::move(TypeEntry)); |
666 | } |
667 | return TmpTypeId; |
668 | } |
669 | |
670 | /// Handle structure/union types. |
671 | void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, |
672 | uint32_t &TypeId) { |
673 | const DINodeArray Elements = CTy->getElements(); |
674 | uint32_t VLen = Elements.size(); |
675 | if (VLen > BTF::MAX_VLEN) |
676 | return; |
677 | |
678 | // Check whether we have any bitfield members or not |
679 | bool HasBitField = false; |
680 | for (const auto *Element : Elements) { |
681 | auto E = cast<DIDerivedType>(Val: Element); |
682 | if (E->isBitField()) { |
683 | HasBitField = true; |
684 | break; |
685 | } |
686 | } |
687 | |
688 | auto TypeEntry = |
689 | std::make_unique<BTFTypeStruct>(args&: CTy, args&: IsStruct, args&: HasBitField, args&: VLen); |
690 | StructTypes.push_back(x: TypeEntry.get()); |
691 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: CTy); |
692 | |
693 | // Check struct/union annotations |
694 | processDeclAnnotations(Annotations: CTy->getAnnotations(), BaseTypeId: TypeId, ComponentIdx: -1); |
695 | |
696 | // Visit all struct members. |
697 | int FieldNo = 0; |
698 | for (const auto *Element : Elements) { |
699 | const auto Elem = cast<DIDerivedType>(Val: Element); |
700 | visitTypeEntry(Ty: Elem); |
701 | processDeclAnnotations(Annotations: Elem->getAnnotations(), BaseTypeId: TypeId, ComponentIdx: FieldNo); |
702 | FieldNo++; |
703 | } |
704 | } |
705 | |
706 | void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { |
707 | // Visit array element type. |
708 | uint32_t ElemTypeId; |
709 | const DIType *ElemType = CTy->getBaseType(); |
710 | visitTypeEntry(Ty: ElemType, TypeId&: ElemTypeId, CheckPointer: false, SeenPointer: false); |
711 | |
712 | // Visit array dimensions. |
713 | DINodeArray Elements = CTy->getElements(); |
714 | for (int I = Elements.size() - 1; I >= 0; --I) { |
715 | if (auto *Element = dyn_cast_or_null<DINode>(Val: Elements[I])) |
716 | if (Element->getTag() == dwarf::DW_TAG_subrange_type) { |
717 | const DISubrange *SR = cast<DISubrange>(Val: Element); |
718 | auto *CI = dyn_cast<ConstantInt *>(Val: SR->getCount()); |
719 | int64_t Count = CI->getSExtValue(); |
720 | |
721 | // For struct s { int b; char c[]; }, the c[] will be represented |
722 | // as an array with Count = -1. |
723 | auto TypeEntry = |
724 | std::make_unique<BTFTypeArray>(args&: ElemTypeId, |
725 | args: Count >= 0 ? Count : 0); |
726 | if (I == 0) |
727 | ElemTypeId = addType(TypeEntry: std::move(TypeEntry), Ty: CTy); |
728 | else |
729 | ElemTypeId = addType(TypeEntry: std::move(TypeEntry)); |
730 | } |
731 | } |
732 | |
733 | // The array TypeId is the type id of the outermost dimension. |
734 | TypeId = ElemTypeId; |
735 | |
736 | // The IR does not have a type for array index while BTF wants one. |
737 | // So create an array index type if there is none. |
738 | if (!ArrayIndexTypeId) { |
739 | auto TypeEntry = std::make_unique<BTFTypeInt>(args: dwarf::DW_ATE_unsigned, args: 32, |
740 | args: 0, args: "__ARRAY_SIZE_TYPE__" ); |
741 | ArrayIndexTypeId = addType(TypeEntry: std::move(TypeEntry)); |
742 | } |
743 | } |
744 | |
745 | void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) { |
746 | DINodeArray Elements = CTy->getElements(); |
747 | uint32_t VLen = Elements.size(); |
748 | if (VLen > BTF::MAX_VLEN) |
749 | return; |
750 | |
751 | bool IsSigned = false; |
752 | unsigned NumBits = 32; |
753 | // No BaseType implies forward declaration in which case a |
754 | // BTFTypeEnum with Vlen = 0 is emitted. |
755 | if (CTy->getBaseType() != nullptr) { |
756 | const auto *BTy = cast<DIBasicType>(Val: CTy->getBaseType()); |
757 | IsSigned = BTy->getEncoding() == dwarf::DW_ATE_signed || |
758 | BTy->getEncoding() == dwarf::DW_ATE_signed_char; |
759 | NumBits = BTy->getSizeInBits(); |
760 | } |
761 | |
762 | if (NumBits <= 32) { |
763 | auto TypeEntry = std::make_unique<BTFTypeEnum>(args&: CTy, args&: VLen, args&: IsSigned); |
764 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: CTy); |
765 | } else { |
766 | assert(NumBits == 64); |
767 | auto TypeEntry = std::make_unique<BTFTypeEnum64>(args&: CTy, args&: VLen, args&: IsSigned); |
768 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: CTy); |
769 | } |
770 | // No need to visit base type as BTF does not encode it. |
771 | } |
772 | |
773 | /// Handle structure/union forward declarations. |
774 | void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, |
775 | uint32_t &TypeId) { |
776 | auto TypeEntry = std::make_unique<BTFTypeFwd>(args: CTy->getName(), args&: IsUnion); |
777 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: CTy); |
778 | } |
779 | |
780 | /// Handle structure, union, array and enumeration types. |
781 | void BTFDebug::visitCompositeType(const DICompositeType *CTy, |
782 | uint32_t &TypeId) { |
783 | auto Tag = CTy->getTag(); |
784 | if (Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { |
785 | // Handle forward declaration differently as it does not have members. |
786 | if (CTy->isForwardDecl()) |
787 | visitFwdDeclType(CTy, IsUnion: Tag == dwarf::DW_TAG_union_type, TypeId); |
788 | else |
789 | visitStructType(CTy, IsStruct: Tag == dwarf::DW_TAG_structure_type, TypeId); |
790 | } else if (Tag == dwarf::DW_TAG_array_type) |
791 | visitArrayType(CTy, TypeId); |
792 | else if (Tag == dwarf::DW_TAG_enumeration_type) |
793 | visitEnumType(CTy, TypeId); |
794 | } |
795 | |
796 | bool BTFDebug::IsForwardDeclCandidate(const DIType *Base) { |
797 | if (const auto *CTy = dyn_cast<DICompositeType>(Val: Base)) { |
798 | auto CTag = CTy->getTag(); |
799 | if ((CTag == dwarf::DW_TAG_structure_type || |
800 | CTag == dwarf::DW_TAG_union_type) && |
801 | !CTy->getName().empty() && !CTy->isForwardDecl()) |
802 | return true; |
803 | } |
804 | return false; |
805 | } |
806 | |
807 | /// Handle pointer, typedef, const, volatile, restrict and member types. |
808 | void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, |
809 | bool CheckPointer, bool SeenPointer) { |
810 | unsigned Tag = DTy->getTag(); |
811 | |
812 | if (Tag == dwarf::DW_TAG_atomic_type) |
813 | return visitTypeEntry(Ty: DTy->getBaseType(), TypeId, CheckPointer, |
814 | SeenPointer); |
815 | |
816 | /// Try to avoid chasing pointees, esp. structure pointees which may |
817 | /// unnecessary bring in a lot of types. |
818 | if (CheckPointer && !SeenPointer) { |
819 | SeenPointer = Tag == dwarf::DW_TAG_pointer_type && !DTy->getAnnotations(); |
820 | } |
821 | |
822 | if (CheckPointer && SeenPointer) { |
823 | const DIType *Base = DTy->getBaseType(); |
824 | if (Base) { |
825 | if (IsForwardDeclCandidate(Base)) { |
826 | /// Find a candidate, generate a fixup. Later on the struct/union |
827 | /// pointee type will be replaced with either a real type or |
828 | /// a forward declaration. |
829 | auto TypeEntry = std::make_unique<BTFTypeDerived>(args&: DTy, args&: Tag, args: true); |
830 | auto &Fixup = FixupDerivedTypes[cast<DICompositeType>(Val: Base)]; |
831 | Fixup.push_back(x: std::make_pair(x&: DTy, y: TypeEntry.get())); |
832 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: DTy); |
833 | return; |
834 | } |
835 | } |
836 | } |
837 | |
838 | if (Tag == dwarf::DW_TAG_pointer_type) { |
839 | int TmpTypeId = genBTFTypeTags(DTy, BaseTypeId: -1); |
840 | if (TmpTypeId >= 0) { |
841 | auto TypeDEntry = |
842 | std::make_unique<BTFTypeDerived>(args&: TmpTypeId, args&: Tag, args: DTy->getName()); |
843 | TypeId = addType(TypeEntry: std::move(TypeDEntry), Ty: DTy); |
844 | } else { |
845 | auto TypeEntry = std::make_unique<BTFTypeDerived>(args&: DTy, args&: Tag, args: false); |
846 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: DTy); |
847 | } |
848 | } else if (Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type || |
849 | Tag == dwarf::DW_TAG_volatile_type || |
850 | Tag == dwarf::DW_TAG_restrict_type) { |
851 | auto TypeEntry = std::make_unique<BTFTypeDerived>(args&: DTy, args&: Tag, args: false); |
852 | TypeId = addType(TypeEntry: std::move(TypeEntry), Ty: DTy); |
853 | if (Tag == dwarf::DW_TAG_typedef) |
854 | processDeclAnnotations(Annotations: DTy->getAnnotations(), BaseTypeId: TypeId, ComponentIdx: -1); |
855 | } else if (Tag != dwarf::DW_TAG_member) { |
856 | return; |
857 | } |
858 | |
859 | // Visit base type of pointer, typedef, const, volatile, restrict or |
860 | // struct/union member. |
861 | uint32_t TempTypeId = 0; |
862 | if (Tag == dwarf::DW_TAG_member) |
863 | visitTypeEntry(Ty: DTy->getBaseType(), TypeId&: TempTypeId, CheckPointer: true, SeenPointer: false); |
864 | else |
865 | visitTypeEntry(Ty: DTy->getBaseType(), TypeId&: TempTypeId, CheckPointer, SeenPointer); |
866 | } |
867 | |
868 | /// Visit a type entry. CheckPointer is true if the type has |
869 | /// one of its predecessors as one struct/union member. SeenPointer |
870 | /// is true if CheckPointer is true and one of its predecessors |
871 | /// is a pointer. The goal of CheckPointer and SeenPointer is to |
872 | /// do pruning for struct/union types so some of these types |
873 | /// will not be emitted in BTF and rather forward declarations |
874 | /// will be generated. |
875 | void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId, |
876 | bool CheckPointer, bool SeenPointer) { |
877 | if (!Ty || DIToIdMap.find(x: Ty) != DIToIdMap.end()) { |
878 | TypeId = DIToIdMap[Ty]; |
879 | |
880 | // To handle the case like the following: |
881 | // struct t; |
882 | // typedef struct t _t; |
883 | // struct s1 { _t *c; }; |
884 | // int test1(struct s1 *arg) { ... } |
885 | // |
886 | // struct t { int a; int b; }; |
887 | // struct s2 { _t c; } |
888 | // int test2(struct s2 *arg) { ... } |
889 | // |
890 | // During traversing test1() argument, "_t" is recorded |
891 | // in DIToIdMap and a forward declaration fixup is created |
892 | // for "struct t" to avoid pointee type traversal. |
893 | // |
894 | // During traversing test2() argument, even if we see "_t" is |
895 | // already defined, we should keep moving to eventually |
896 | // bring in types for "struct t". Otherwise, the "struct s2" |
897 | // definition won't be correct. |
898 | // |
899 | // In the above, we have following debuginfo: |
900 | // {ptr, struct_member} -> typedef -> struct |
901 | // and BTF type for 'typedef' is generated while 'struct' may |
902 | // be in FixUp. But let us generalize the above to handle |
903 | // {different types} -> [various derived types]+ -> another type. |
904 | // For example, |
905 | // {func_param, struct_member} -> const -> ptr -> volatile -> struct |
906 | // We will traverse const/ptr/volatile which already have corresponding |
907 | // BTF types and generate type for 'struct' which might be in Fixup |
908 | // state. |
909 | if (Ty && (!CheckPointer || !SeenPointer)) { |
910 | if (const auto *DTy = dyn_cast<DIDerivedType>(Val: Ty)) { |
911 | while (DTy) { |
912 | const DIType *BaseTy = DTy->getBaseType(); |
913 | if (!BaseTy) |
914 | break; |
915 | |
916 | if (DIToIdMap.find(x: BaseTy) != DIToIdMap.end()) { |
917 | DTy = dyn_cast<DIDerivedType>(Val: BaseTy); |
918 | } else { |
919 | if (CheckPointer && DTy->getTag() == dwarf::DW_TAG_pointer_type && |
920 | !DTy->getAnnotations()) { |
921 | SeenPointer = true; |
922 | if (IsForwardDeclCandidate(Base: BaseTy)) |
923 | break; |
924 | } |
925 | uint32_t TmpTypeId; |
926 | visitTypeEntry(Ty: BaseTy, TypeId&: TmpTypeId, CheckPointer, SeenPointer); |
927 | break; |
928 | } |
929 | } |
930 | } |
931 | } |
932 | |
933 | return; |
934 | } |
935 | |
936 | if (const auto *BTy = dyn_cast<DIBasicType>(Val: Ty)) |
937 | visitBasicType(BTy, TypeId); |
938 | else if (const auto *STy = dyn_cast<DISubroutineType>(Val: Ty)) |
939 | visitSubroutineType(STy, ForSubprog: false, FuncArgNames: std::unordered_map<uint32_t, StringRef>(), |
940 | TypeId); |
941 | else if (const auto *CTy = dyn_cast<DICompositeType>(Val: Ty)) |
942 | visitCompositeType(CTy, TypeId); |
943 | else if (const auto *DTy = dyn_cast<DIDerivedType>(Val: Ty)) |
944 | visitDerivedType(DTy, TypeId, CheckPointer, SeenPointer); |
945 | else |
946 | llvm_unreachable("Unknown DIType" ); |
947 | } |
948 | |
949 | void BTFDebug::visitTypeEntry(const DIType *Ty) { |
950 | uint32_t TypeId; |
951 | visitTypeEntry(Ty, TypeId, CheckPointer: false, SeenPointer: false); |
952 | } |
953 | |
954 | void BTFDebug::visitMapDefType(const DIType *Ty, uint32_t &TypeId) { |
955 | if (!Ty || DIToIdMap.find(x: Ty) != DIToIdMap.end()) { |
956 | TypeId = DIToIdMap[Ty]; |
957 | return; |
958 | } |
959 | |
960 | // MapDef type may be a struct type or a non-pointer derived type |
961 | const DIType *OrigTy = Ty; |
962 | while (auto *DTy = dyn_cast<DIDerivedType>(Val: Ty)) { |
963 | auto Tag = DTy->getTag(); |
964 | if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type && |
965 | Tag != dwarf::DW_TAG_volatile_type && |
966 | Tag != dwarf::DW_TAG_restrict_type) |
967 | break; |
968 | Ty = DTy->getBaseType(); |
969 | } |
970 | |
971 | const auto *CTy = dyn_cast<DICompositeType>(Val: Ty); |
972 | if (!CTy) |
973 | return; |
974 | |
975 | auto Tag = CTy->getTag(); |
976 | if (Tag != dwarf::DW_TAG_structure_type || CTy->isForwardDecl()) |
977 | return; |
978 | |
979 | // Visit all struct members to ensure their types are visited. |
980 | const DINodeArray Elements = CTy->getElements(); |
981 | for (const auto *Element : Elements) { |
982 | const auto *MemberType = cast<DIDerivedType>(Val: Element); |
983 | const DIType *MemberBaseType = MemberType->getBaseType(); |
984 | |
985 | // If the member is a composite type, that may indicate the currently |
986 | // visited composite type is a wrapper, and the member represents the |
987 | // actual map definition. |
988 | // In that case, visit the member with `visitMapDefType` instead of |
989 | // `visitTypeEntry`, treating it specifically as a map definition rather |
990 | // than as a regular composite type. |
991 | const auto *MemberCTy = dyn_cast<DICompositeType>(Val: MemberBaseType); |
992 | if (MemberCTy) { |
993 | visitMapDefType(Ty: MemberBaseType, TypeId); |
994 | } else { |
995 | visitTypeEntry(Ty: MemberBaseType); |
996 | } |
997 | } |
998 | |
999 | // Visit this type, struct or a const/typedef/volatile/restrict type |
1000 | visitTypeEntry(Ty: OrigTy, TypeId, CheckPointer: false, SeenPointer: false); |
1001 | } |
1002 | |
1003 | /// Read file contents from the actual file or from the source |
1004 | std::string BTFDebug::populateFileContent(const DIFile *File) { |
1005 | std::string FileName; |
1006 | |
1007 | if (!File->getFilename().starts_with(Prefix: "/" ) && File->getDirectory().size()) |
1008 | FileName = File->getDirectory().str() + "/" + File->getFilename().str(); |
1009 | else |
1010 | FileName = std::string(File->getFilename()); |
1011 | |
1012 | // No need to populate the contends if it has been populated! |
1013 | if (FileContent.contains(Key: FileName)) |
1014 | return FileName; |
1015 | |
1016 | std::vector<std::string> Content; |
1017 | std::string Line; |
1018 | Content.push_back(x: Line); // Line 0 for empty string |
1019 | |
1020 | std::unique_ptr<MemoryBuffer> Buf; |
1021 | auto Source = File->getSource(); |
1022 | if (Source) |
1023 | Buf = MemoryBuffer::getMemBufferCopy(InputData: *Source); |
1024 | else if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = |
1025 | MemoryBuffer::getFile(Filename: FileName)) |
1026 | Buf = std::move(*BufOrErr); |
1027 | if (Buf) |
1028 | for (line_iterator I(*Buf, false), E; I != E; ++I) |
1029 | Content.push_back(x: std::string(*I)); |
1030 | |
1031 | FileContent[FileName] = Content; |
1032 | return FileName; |
1033 | } |
1034 | |
1035 | void BTFDebug::constructLineInfo(MCSymbol *Label, const DIFile *File, |
1036 | uint32_t Line, uint32_t Column) { |
1037 | std::string FileName = populateFileContent(File); |
1038 | BTFLineInfo LineInfo; |
1039 | |
1040 | LineInfo.Label = Label; |
1041 | LineInfo.FileNameOff = addString(S: FileName); |
1042 | // If file content is not available, let LineOff = 0. |
1043 | const auto &Content = FileContent[FileName]; |
1044 | if (Line < Content.size()) |
1045 | LineInfo.LineOff = addString(S: Content[Line]); |
1046 | else |
1047 | LineInfo.LineOff = 0; |
1048 | LineInfo.LineNum = Line; |
1049 | LineInfo.ColumnNum = Column; |
1050 | LineInfoTable[SecNameOff].push_back(x: LineInfo); |
1051 | } |
1052 | |
1053 | void BTFDebug::() { |
1054 | OS.AddComment(T: "0x" + Twine::utohexstr(Val: BTF::MAGIC)); |
1055 | OS.emitIntValue(Value: BTF::MAGIC, Size: 2); |
1056 | OS.emitInt8(Value: BTF::VERSION); |
1057 | OS.emitInt8(Value: 0); |
1058 | } |
1059 | |
1060 | void BTFDebug::emitBTFSection() { |
1061 | // Do not emit section if no types and only "" string. |
1062 | if (!TypeEntries.size() && StringTable.getSize() == 1) |
1063 | return; |
1064 | |
1065 | MCContext &Ctx = OS.getContext(); |
1066 | MCSectionELF *Sec = Ctx.getELFSection(Section: ".BTF" , Type: ELF::SHT_PROGBITS, Flags: 0); |
1067 | Sec->setAlignment(Align(4)); |
1068 | OS.switchSection(Section: Sec); |
1069 | |
1070 | // Emit header. |
1071 | emitCommonHeader(); |
1072 | OS.emitInt32(Value: BTF::HeaderSize); |
1073 | |
1074 | uint32_t TypeLen = 0, StrLen; |
1075 | for (const auto &TypeEntry : TypeEntries) |
1076 | TypeLen += TypeEntry->getSize(); |
1077 | StrLen = StringTable.getSize(); |
1078 | |
1079 | OS.emitInt32(Value: 0); |
1080 | OS.emitInt32(Value: TypeLen); |
1081 | OS.emitInt32(Value: TypeLen); |
1082 | OS.emitInt32(Value: StrLen); |
1083 | |
1084 | // Emit type table. |
1085 | for (const auto &TypeEntry : TypeEntries) |
1086 | TypeEntry->emitType(OS); |
1087 | |
1088 | // Emit string table. |
1089 | uint32_t StringOffset = 0; |
1090 | for (const auto &S : StringTable.getTable()) { |
1091 | OS.AddComment(T: "string offset=" + std::to_string(val: StringOffset)); |
1092 | OS.emitBytes(Data: S); |
1093 | OS.emitBytes(Data: StringRef("\0" , 1)); |
1094 | StringOffset += S.size() + 1; |
1095 | } |
1096 | } |
1097 | |
1098 | void BTFDebug::emitBTFExtSection() { |
1099 | // Do not emit section if empty FuncInfoTable and LineInfoTable |
1100 | // and FieldRelocTable. |
1101 | if (!FuncInfoTable.size() && !LineInfoTable.size() && |
1102 | !FieldRelocTable.size()) |
1103 | return; |
1104 | |
1105 | MCContext &Ctx = OS.getContext(); |
1106 | MCSectionELF *Sec = Ctx.getELFSection(Section: ".BTF.ext" , Type: ELF::SHT_PROGBITS, Flags: 0); |
1107 | Sec->setAlignment(Align(4)); |
1108 | OS.switchSection(Section: Sec); |
1109 | |
1110 | // Emit header. |
1111 | emitCommonHeader(); |
1112 | OS.emitInt32(Value: BTF::ExtHeaderSize); |
1113 | |
1114 | // Account for FuncInfo/LineInfo record size as well. |
1115 | uint32_t FuncLen = 4, LineLen = 4; |
1116 | // Do not account for optional FieldReloc. |
1117 | uint32_t FieldRelocLen = 0; |
1118 | for (const auto &FuncSec : FuncInfoTable) { |
1119 | FuncLen += BTF::SecFuncInfoSize; |
1120 | FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize; |
1121 | } |
1122 | for (const auto &LineSec : LineInfoTable) { |
1123 | LineLen += BTF::SecLineInfoSize; |
1124 | LineLen += LineSec.second.size() * BTF::BPFLineInfoSize; |
1125 | } |
1126 | for (const auto &FieldRelocSec : FieldRelocTable) { |
1127 | FieldRelocLen += BTF::SecFieldRelocSize; |
1128 | FieldRelocLen += FieldRelocSec.second.size() * BTF::BPFFieldRelocSize; |
1129 | } |
1130 | |
1131 | if (FieldRelocLen) |
1132 | FieldRelocLen += 4; |
1133 | |
1134 | OS.emitInt32(Value: 0); |
1135 | OS.emitInt32(Value: FuncLen); |
1136 | OS.emitInt32(Value: FuncLen); |
1137 | OS.emitInt32(Value: LineLen); |
1138 | OS.emitInt32(Value: FuncLen + LineLen); |
1139 | OS.emitInt32(Value: FieldRelocLen); |
1140 | |
1141 | // Emit func_info table. |
1142 | OS.AddComment(T: "FuncInfo" ); |
1143 | OS.emitInt32(Value: BTF::BPFFuncInfoSize); |
1144 | for (const auto &FuncSec : FuncInfoTable) { |
1145 | OS.AddComment(T: "FuncInfo section string offset=" + |
1146 | std::to_string(val: FuncSec.first)); |
1147 | OS.emitInt32(Value: FuncSec.first); |
1148 | OS.emitInt32(Value: FuncSec.second.size()); |
1149 | for (const auto &FuncInfo : FuncSec.second) { |
1150 | Asm->emitLabelReference(Label: FuncInfo.Label, Size: 4); |
1151 | OS.emitInt32(Value: FuncInfo.TypeId); |
1152 | } |
1153 | } |
1154 | |
1155 | // Emit line_info table. |
1156 | OS.AddComment(T: "LineInfo" ); |
1157 | OS.emitInt32(Value: BTF::BPFLineInfoSize); |
1158 | for (const auto &LineSec : LineInfoTable) { |
1159 | OS.AddComment(T: "LineInfo section string offset=" + |
1160 | std::to_string(val: LineSec.first)); |
1161 | OS.emitInt32(Value: LineSec.first); |
1162 | OS.emitInt32(Value: LineSec.second.size()); |
1163 | for (const auto &LineInfo : LineSec.second) { |
1164 | Asm->emitLabelReference(Label: LineInfo.Label, Size: 4); |
1165 | OS.emitInt32(Value: LineInfo.FileNameOff); |
1166 | OS.emitInt32(Value: LineInfo.LineOff); |
1167 | OS.AddComment(T: "Line " + std::to_string(val: LineInfo.LineNum) + " Col " + |
1168 | std::to_string(val: LineInfo.ColumnNum)); |
1169 | OS.emitInt32(Value: LineInfo.LineNum << 10 | LineInfo.ColumnNum); |
1170 | } |
1171 | } |
1172 | |
1173 | // Emit field reloc table. |
1174 | if (FieldRelocLen) { |
1175 | OS.AddComment(T: "FieldReloc" ); |
1176 | OS.emitInt32(Value: BTF::BPFFieldRelocSize); |
1177 | for (const auto &FieldRelocSec : FieldRelocTable) { |
1178 | OS.AddComment(T: "Field reloc section string offset=" + |
1179 | std::to_string(val: FieldRelocSec.first)); |
1180 | OS.emitInt32(Value: FieldRelocSec.first); |
1181 | OS.emitInt32(Value: FieldRelocSec.second.size()); |
1182 | for (const auto &FieldRelocInfo : FieldRelocSec.second) { |
1183 | Asm->emitLabelReference(Label: FieldRelocInfo.Label, Size: 4); |
1184 | OS.emitInt32(Value: FieldRelocInfo.TypeID); |
1185 | OS.emitInt32(Value: FieldRelocInfo.OffsetNameOff); |
1186 | OS.emitInt32(Value: FieldRelocInfo.RelocKind); |
1187 | } |
1188 | } |
1189 | } |
1190 | } |
1191 | |
1192 | void BTFDebug::beginFunctionImpl(const MachineFunction *MF) { |
1193 | auto *SP = MF->getFunction().getSubprogram(); |
1194 | auto *Unit = SP->getUnit(); |
1195 | |
1196 | if (Unit->getEmissionKind() == DICompileUnit::NoDebug) { |
1197 | SkipInstruction = true; |
1198 | return; |
1199 | } |
1200 | SkipInstruction = false; |
1201 | |
1202 | // Collect MapDef types. Map definition needs to collect |
1203 | // pointee types. Do it first. Otherwise, for the following |
1204 | // case: |
1205 | // struct m { ...}; |
1206 | // struct t { |
1207 | // struct m *key; |
1208 | // }; |
1209 | // foo(struct t *arg); |
1210 | // |
1211 | // struct mapdef { |
1212 | // ... |
1213 | // struct m *key; |
1214 | // ... |
1215 | // } __attribute__((section(".maps"))) hash_map; |
1216 | // |
1217 | // If subroutine foo is traversed first, a type chain |
1218 | // "ptr->struct m(fwd)" will be created and later on |
1219 | // when traversing mapdef, since "ptr->struct m" exists, |
1220 | // the traversal of "struct m" will be omitted. |
1221 | if (MapDefNotCollected) { |
1222 | processGlobals(ProcessingMapDef: true); |
1223 | MapDefNotCollected = false; |
1224 | } |
1225 | |
1226 | // Collect all types locally referenced in this function. |
1227 | // Use RetainedNodes so we can collect all argument names |
1228 | // even if the argument is not used. |
1229 | std::unordered_map<uint32_t, StringRef> FuncArgNames; |
1230 | for (const DINode *DN : SP->getRetainedNodes()) { |
1231 | if (const auto *DV = dyn_cast<DILocalVariable>(Val: DN)) { |
1232 | // Collect function arguments for subprogram func type. |
1233 | uint32_t Arg = DV->getArg(); |
1234 | if (Arg) { |
1235 | visitTypeEntry(Ty: DV->getType()); |
1236 | FuncArgNames[Arg] = DV->getName(); |
1237 | } |
1238 | } |
1239 | } |
1240 | |
1241 | // Construct subprogram func proto type. |
1242 | uint32_t ProtoTypeId; |
1243 | visitSubroutineType(STy: SP->getType(), ForSubprog: true, FuncArgNames, TypeId&: ProtoTypeId); |
1244 | |
1245 | // Construct subprogram func type |
1246 | uint8_t Scope = SP->isLocalToUnit() ? BTF::FUNC_STATIC : BTF::FUNC_GLOBAL; |
1247 | uint32_t FuncTypeId = processDISubprogram(SP, ProtoTypeId, Scope); |
1248 | |
1249 | for (const auto &TypeEntry : TypeEntries) |
1250 | TypeEntry->completeType(BDebug&: *this); |
1251 | |
1252 | // Construct funcinfo and the first lineinfo for the function. |
1253 | MCSymbol *FuncLabel = Asm->getFunctionBegin(); |
1254 | BTFFuncInfo FuncInfo; |
1255 | FuncInfo.Label = FuncLabel; |
1256 | FuncInfo.TypeId = FuncTypeId; |
1257 | if (FuncLabel->isInSection()) { |
1258 | MCSection &Section = FuncLabel->getSection(); |
1259 | const MCSectionELF *SectionELF = dyn_cast<MCSectionELF>(Val: &Section); |
1260 | assert(SectionELF && "Null section for Function Label" ); |
1261 | SecNameOff = addString(S: SectionELF->getName()); |
1262 | } else { |
1263 | SecNameOff = addString(S: ".text" ); |
1264 | } |
1265 | FuncInfoTable[SecNameOff].push_back(x: FuncInfo); |
1266 | } |
1267 | |
1268 | void BTFDebug::endFunctionImpl(const MachineFunction *MF) { |
1269 | SkipInstruction = false; |
1270 | LineInfoGenerated = false; |
1271 | SecNameOff = 0; |
1272 | } |
1273 | |
1274 | /// On-demand populate types as requested from abstract member |
1275 | /// accessing or preserve debuginfo type. |
1276 | unsigned BTFDebug::populateType(const DIType *Ty) { |
1277 | unsigned Id; |
1278 | visitTypeEntry(Ty, TypeId&: Id, CheckPointer: false, SeenPointer: false); |
1279 | for (const auto &TypeEntry : TypeEntries) |
1280 | TypeEntry->completeType(BDebug&: *this); |
1281 | return Id; |
1282 | } |
1283 | |
1284 | /// Generate a struct member field relocation. |
1285 | void BTFDebug::generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, |
1286 | const GlobalVariable *GVar, bool IsAma) { |
1287 | BTFFieldReloc FieldReloc; |
1288 | FieldReloc.Label = ORSym; |
1289 | FieldReloc.TypeID = RootId; |
1290 | |
1291 | StringRef AccessPattern = GVar->getName(); |
1292 | size_t FirstDollar = AccessPattern.find_first_of(C: '$'); |
1293 | if (IsAma) { |
1294 | size_t FirstColon = AccessPattern.find_first_of(C: ':'); |
1295 | size_t SecondColon = AccessPattern.find_first_of(C: ':', From: FirstColon + 1); |
1296 | StringRef IndexPattern = AccessPattern.substr(Start: FirstDollar + 1); |
1297 | StringRef RelocKindStr = AccessPattern.substr(Start: FirstColon + 1, |
1298 | N: SecondColon - FirstColon); |
1299 | StringRef PatchImmStr = AccessPattern.substr(Start: SecondColon + 1, |
1300 | N: FirstDollar - SecondColon); |
1301 | |
1302 | FieldReloc.OffsetNameOff = addString(S: IndexPattern); |
1303 | FieldReloc.RelocKind = std::stoull(str: std::string(RelocKindStr)); |
1304 | PatchImms[GVar] = std::make_pair(x: std::stoll(str: std::string(PatchImmStr)), |
1305 | y&: FieldReloc.RelocKind); |
1306 | } else { |
1307 | StringRef RelocStr = AccessPattern.substr(Start: FirstDollar + 1); |
1308 | FieldReloc.OffsetNameOff = addString(S: "0" ); |
1309 | FieldReloc.RelocKind = std::stoull(str: std::string(RelocStr)); |
1310 | PatchImms[GVar] = std::make_pair(x&: RootId, y&: FieldReloc.RelocKind); |
1311 | } |
1312 | FieldRelocTable[SecNameOff].push_back(x: FieldReloc); |
1313 | } |
1314 | |
1315 | void BTFDebug::processGlobalValue(const MachineOperand &MO) { |
1316 | // check whether this is a candidate or not |
1317 | if (MO.isGlobal()) { |
1318 | const GlobalValue *GVal = MO.getGlobal(); |
1319 | auto *GVar = dyn_cast<GlobalVariable>(Val: GVal); |
1320 | if (!GVar) { |
1321 | // Not a global variable. Maybe an extern function reference. |
1322 | processFuncPrototypes(dyn_cast<Function>(Val: GVal)); |
1323 | return; |
1324 | } |
1325 | |
1326 | if (!GVar->hasAttribute(Kind: BPFCoreSharedInfo::AmaAttr) && |
1327 | !GVar->hasAttribute(Kind: BPFCoreSharedInfo::TypeIdAttr)) |
1328 | return; |
1329 | |
1330 | MCSymbol *ORSym = OS.getContext().createTempSymbol(); |
1331 | OS.emitLabel(Symbol: ORSym); |
1332 | |
1333 | MDNode *MDN = GVar->getMetadata(KindID: LLVMContext::MD_preserve_access_index); |
1334 | uint32_t RootId = populateType(Ty: dyn_cast<DIType>(Val: MDN)); |
1335 | generatePatchImmReloc(ORSym, RootId, GVar, |
1336 | IsAma: GVar->hasAttribute(Kind: BPFCoreSharedInfo::AmaAttr)); |
1337 | } |
1338 | } |
1339 | |
1340 | void BTFDebug::beginInstruction(const MachineInstr *MI) { |
1341 | DebugHandlerBase::beginInstruction(MI); |
1342 | |
1343 | if (SkipInstruction || MI->isMetaInstruction() || |
1344 | MI->getFlag(Flag: MachineInstr::FrameSetup)) |
1345 | return; |
1346 | |
1347 | if (MI->isInlineAsm()) { |
1348 | // Count the number of register definitions to find the asm string. |
1349 | unsigned NumDefs = 0; |
1350 | while (true) { |
1351 | const MachineOperand &MO = MI->getOperand(i: NumDefs); |
1352 | if (MO.isReg() && MO.isDef()) { |
1353 | ++NumDefs; |
1354 | continue; |
1355 | } |
1356 | // Skip this inline asm instruction if the asmstr is empty. |
1357 | const char *AsmStr = MO.getSymbolName(); |
1358 | if (AsmStr[0] == 0) |
1359 | return; |
1360 | break; |
1361 | } |
1362 | } |
1363 | |
1364 | if (MI->getOpcode() == BPF::LD_imm64) { |
1365 | // If the insn is "r2 = LD_imm64 @<an AmaAttr global>", |
1366 | // add this insn into the .BTF.ext FieldReloc subsection. |
1367 | // Relocation looks like: |
1368 | // . SecName: |
1369 | // . InstOffset |
1370 | // . TypeID |
1371 | // . OffSetNameOff |
1372 | // . RelocType |
1373 | // Later, the insn is replaced with "r2 = <offset>" |
1374 | // where "<offset>" equals to the offset based on current |
1375 | // type definitions. |
1376 | // |
1377 | // If the insn is "r2 = LD_imm64 @<an TypeIdAttr global>", |
1378 | // The LD_imm64 result will be replaced with a btf type id. |
1379 | processGlobalValue(MO: MI->getOperand(i: 1)); |
1380 | } else if (MI->getOpcode() == BPF::CORE_LD64 || |
1381 | MI->getOpcode() == BPF::CORE_LD32 || |
1382 | MI->getOpcode() == BPF::CORE_ST || |
1383 | MI->getOpcode() == BPF::CORE_SHIFT) { |
1384 | // relocation insn is a load, store or shift insn. |
1385 | processGlobalValue(MO: MI->getOperand(i: 3)); |
1386 | } else if (MI->getOpcode() == BPF::JAL) { |
1387 | // check extern function references |
1388 | const MachineOperand &MO = MI->getOperand(i: 0); |
1389 | if (MO.isGlobal()) { |
1390 | processFuncPrototypes(dyn_cast<Function>(Val: MO.getGlobal())); |
1391 | } |
1392 | } |
1393 | |
1394 | if (!CurMI) // no debug info |
1395 | return; |
1396 | |
1397 | // Skip this instruction if no DebugLoc, the DebugLoc |
1398 | // is the same as the previous instruction or Line is 0. |
1399 | const DebugLoc &DL = MI->getDebugLoc(); |
1400 | if (!DL || PrevInstLoc == DL || DL.getLine() == 0) { |
1401 | // This instruction will be skipped, no LineInfo has |
1402 | // been generated, construct one based on function signature. |
1403 | if (LineInfoGenerated == false) { |
1404 | auto *S = MI->getMF()->getFunction().getSubprogram(); |
1405 | if (!S) |
1406 | return; |
1407 | MCSymbol *FuncLabel = Asm->getFunctionBegin(); |
1408 | constructLineInfo(Label: FuncLabel, File: S->getFile(), Line: S->getLine(), Column: 0); |
1409 | LineInfoGenerated = true; |
1410 | } |
1411 | |
1412 | return; |
1413 | } |
1414 | |
1415 | // Create a temporary label to remember the insn for lineinfo. |
1416 | MCSymbol *LineSym = OS.getContext().createTempSymbol(); |
1417 | OS.emitLabel(Symbol: LineSym); |
1418 | |
1419 | // Construct the lineinfo. |
1420 | constructLineInfo(Label: LineSym, File: DL->getFile(), Line: DL.getLine(), Column: DL.getCol()); |
1421 | |
1422 | LineInfoGenerated = true; |
1423 | PrevInstLoc = DL; |
1424 | } |
1425 | |
1426 | void BTFDebug::processGlobals(bool ProcessingMapDef) { |
1427 | // Collect all types referenced by globals. |
1428 | const Module *M = MMI->getModule(); |
1429 | for (const GlobalVariable &Global : M->globals()) { |
1430 | // Decide the section name. |
1431 | StringRef SecName; |
1432 | std::optional<SectionKind> GVKind; |
1433 | |
1434 | if (!Global.isDeclarationForLinker()) |
1435 | GVKind = TargetLoweringObjectFile::getKindForGlobal(GO: &Global, TM: Asm->TM); |
1436 | |
1437 | if (Global.isDeclarationForLinker()) |
1438 | SecName = Global.hasSection() ? Global.getSection() : "" ; |
1439 | else if (GVKind->isCommon()) |
1440 | SecName = ".bss" ; |
1441 | else { |
1442 | TargetLoweringObjectFile *TLOF = Asm->TM.getObjFileLowering(); |
1443 | MCSection *Sec = TLOF->SectionForGlobal(GO: &Global, TM: Asm->TM); |
1444 | SecName = Sec->getName(); |
1445 | } |
1446 | |
1447 | if (ProcessingMapDef != SecName.starts_with(Prefix: ".maps" )) |
1448 | continue; |
1449 | |
1450 | // Create a .rodata datasec if the global variable is an initialized |
1451 | // constant with private linkage and if it won't be in .rodata.str<#> |
1452 | // and .rodata.cst<#> sections. |
1453 | if (SecName == ".rodata" && Global.hasPrivateLinkage() && |
1454 | DataSecEntries.find(x: SecName) == DataSecEntries.end()) { |
1455 | // skip .rodata.str<#> and .rodata.cst<#> sections |
1456 | if (!GVKind->isMergeableCString() && !GVKind->isMergeableConst()) { |
1457 | DataSecEntries[std::string(SecName)] = |
1458 | std::make_unique<BTFKindDataSec>(args&: Asm, args: std::string(SecName)); |
1459 | } |
1460 | } |
1461 | |
1462 | SmallVector<DIGlobalVariableExpression *, 1> GVs; |
1463 | Global.getDebugInfo(GVs); |
1464 | |
1465 | // No type information, mostly internal, skip it. |
1466 | if (GVs.size() == 0) |
1467 | continue; |
1468 | |
1469 | uint32_t GVTypeId = 0; |
1470 | DIGlobalVariable *DIGlobal = nullptr; |
1471 | for (auto *GVE : GVs) { |
1472 | DIGlobal = GVE->getVariable(); |
1473 | if (SecName.starts_with(Prefix: ".maps" )) |
1474 | visitMapDefType(Ty: DIGlobal->getType(), TypeId&: GVTypeId); |
1475 | else { |
1476 | const DIType *Ty = tryRemoveAtomicType(Ty: DIGlobal->getType()); |
1477 | visitTypeEntry(Ty, TypeId&: GVTypeId, CheckPointer: false, SeenPointer: false); |
1478 | } |
1479 | break; |
1480 | } |
1481 | |
1482 | // Only support the following globals: |
1483 | // . static variables |
1484 | // . non-static weak or non-weak global variables |
1485 | // . weak or non-weak extern global variables |
1486 | // Whether DataSec is readonly or not can be found from corresponding ELF |
1487 | // section flags. Whether a BTF_KIND_VAR is a weak symbol or not |
1488 | // can be found from the corresponding ELF symbol table. |
1489 | auto Linkage = Global.getLinkage(); |
1490 | if (Linkage != GlobalValue::InternalLinkage && |
1491 | Linkage != GlobalValue::ExternalLinkage && |
1492 | Linkage != GlobalValue::WeakAnyLinkage && |
1493 | Linkage != GlobalValue::WeakODRLinkage && |
1494 | Linkage != GlobalValue::ExternalWeakLinkage) |
1495 | continue; |
1496 | |
1497 | uint32_t GVarInfo; |
1498 | if (Linkage == GlobalValue::InternalLinkage) { |
1499 | GVarInfo = BTF::VAR_STATIC; |
1500 | } else if (Global.hasInitializer()) { |
1501 | GVarInfo = BTF::VAR_GLOBAL_ALLOCATED; |
1502 | } else { |
1503 | GVarInfo = BTF::VAR_GLOBAL_EXTERNAL; |
1504 | } |
1505 | |
1506 | auto VarEntry = |
1507 | std::make_unique<BTFKindVar>(args: Global.getName(), args&: GVTypeId, args&: GVarInfo); |
1508 | uint32_t VarId = addType(TypeEntry: std::move(VarEntry)); |
1509 | |
1510 | processDeclAnnotations(Annotations: DIGlobal->getAnnotations(), BaseTypeId: VarId, ComponentIdx: -1); |
1511 | |
1512 | // An empty SecName means an extern variable without section attribute. |
1513 | if (SecName.empty()) |
1514 | continue; |
1515 | |
1516 | // Find or create a DataSec |
1517 | auto [It, Inserted] = DataSecEntries.try_emplace(k: std::string(SecName)); |
1518 | if (Inserted) |
1519 | It->second = std::make_unique<BTFKindDataSec>(args&: Asm, args: std::string(SecName)); |
1520 | |
1521 | // Calculate symbol size |
1522 | const DataLayout &DL = Global.getDataLayout(); |
1523 | uint32_t Size = DL.getTypeAllocSize(Ty: Global.getValueType()); |
1524 | |
1525 | It->second->addDataSecEntry(Id: VarId, Sym: Asm->getSymbol(GV: &Global), Size); |
1526 | |
1527 | if (Global.hasInitializer()) |
1528 | processGlobalInitializer(C: Global.getInitializer()); |
1529 | } |
1530 | } |
1531 | |
1532 | /// Process global variable initializer in pursuit for function |
1533 | /// pointers. Add discovered (extern) functions to BTF. Some (extern) |
1534 | /// functions might have been missed otherwise. Every symbol needs BTF |
1535 | /// info when linking with bpftool. Primary use case: "static" |
1536 | /// initialization of BPF maps. |
1537 | /// |
1538 | /// struct { |
1539 | /// __uint(type, BPF_MAP_TYPE_PROG_ARRAY); |
1540 | /// ... |
1541 | /// } prog_map SEC(".maps") = { .values = { extern_func } }; |
1542 | /// |
1543 | void BTFDebug::processGlobalInitializer(const Constant *C) { |
1544 | if (auto *Fn = dyn_cast<Function>(Val: C)) |
1545 | processFuncPrototypes(Fn); |
1546 | if (auto *CA = dyn_cast<ConstantAggregate>(Val: C)) { |
1547 | for (unsigned I = 0, N = CA->getNumOperands(); I < N; ++I) |
1548 | processGlobalInitializer(C: CA->getOperand(i_nocapture: I)); |
1549 | } |
1550 | } |
1551 | |
1552 | /// Emit proper patchable instructions. |
1553 | bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) { |
1554 | if (MI->getOpcode() == BPF::LD_imm64) { |
1555 | const MachineOperand &MO = MI->getOperand(i: 1); |
1556 | if (MO.isGlobal()) { |
1557 | const GlobalValue *GVal = MO.getGlobal(); |
1558 | auto *GVar = dyn_cast<GlobalVariable>(Val: GVal); |
1559 | if (GVar) { |
1560 | if (!GVar->hasAttribute(Kind: BPFCoreSharedInfo::AmaAttr) && |
1561 | !GVar->hasAttribute(Kind: BPFCoreSharedInfo::TypeIdAttr)) |
1562 | return false; |
1563 | |
1564 | // Emit "mov ri, <imm>" |
1565 | auto [Imm, Reloc] = PatchImms[GVar]; |
1566 | if (Reloc == BTF::ENUM_VALUE_EXISTENCE || Reloc == BTF::ENUM_VALUE || |
1567 | Reloc == BTF::BTF_TYPE_ID_LOCAL || Reloc == BTF::BTF_TYPE_ID_REMOTE) |
1568 | OutMI.setOpcode(BPF::LD_imm64); |
1569 | else |
1570 | OutMI.setOpcode(BPF::MOV_ri); |
1571 | OutMI.addOperand(Op: MCOperand::createReg(Reg: MI->getOperand(i: 0).getReg())); |
1572 | OutMI.addOperand(Op: MCOperand::createImm(Val: Imm)); |
1573 | return true; |
1574 | } |
1575 | } |
1576 | } else if (MI->getOpcode() == BPF::CORE_LD64 || |
1577 | MI->getOpcode() == BPF::CORE_LD32 || |
1578 | MI->getOpcode() == BPF::CORE_ST || |
1579 | MI->getOpcode() == BPF::CORE_SHIFT) { |
1580 | const MachineOperand &MO = MI->getOperand(i: 3); |
1581 | if (MO.isGlobal()) { |
1582 | const GlobalValue *GVal = MO.getGlobal(); |
1583 | auto *GVar = dyn_cast<GlobalVariable>(Val: GVal); |
1584 | if (GVar && GVar->hasAttribute(Kind: BPFCoreSharedInfo::AmaAttr)) { |
1585 | uint32_t Imm = PatchImms[GVar].first; |
1586 | OutMI.setOpcode(MI->getOperand(i: 1).getImm()); |
1587 | if (MI->getOperand(i: 0).isImm()) |
1588 | OutMI.addOperand(Op: MCOperand::createImm(Val: MI->getOperand(i: 0).getImm())); |
1589 | else |
1590 | OutMI.addOperand(Op: MCOperand::createReg(Reg: MI->getOperand(i: 0).getReg())); |
1591 | OutMI.addOperand(Op: MCOperand::createReg(Reg: MI->getOperand(i: 2).getReg())); |
1592 | OutMI.addOperand(Op: MCOperand::createImm(Val: Imm)); |
1593 | return true; |
1594 | } |
1595 | } |
1596 | } |
1597 | return false; |
1598 | } |
1599 | |
1600 | void BTFDebug::processFuncPrototypes(const Function *F) { |
1601 | if (!F) |
1602 | return; |
1603 | |
1604 | const DISubprogram *SP = F->getSubprogram(); |
1605 | if (!SP || SP->isDefinition()) |
1606 | return; |
1607 | |
1608 | // Do not emit again if already emitted. |
1609 | if (!ProtoFunctions.insert(x: F).second) |
1610 | return; |
1611 | |
1612 | uint32_t ProtoTypeId; |
1613 | const std::unordered_map<uint32_t, StringRef> FuncArgNames; |
1614 | visitSubroutineType(STy: SP->getType(), ForSubprog: false, FuncArgNames, TypeId&: ProtoTypeId); |
1615 | uint32_t FuncId = processDISubprogram(SP, ProtoTypeId, Scope: BTF::FUNC_EXTERN); |
1616 | |
1617 | if (F->hasSection()) { |
1618 | StringRef SecName = F->getSection(); |
1619 | |
1620 | auto [It, Inserted] = DataSecEntries.try_emplace(k: std::string(SecName)); |
1621 | if (Inserted) |
1622 | It->second = std::make_unique<BTFKindDataSec>(args&: Asm, args: std::string(SecName)); |
1623 | |
1624 | // We really don't know func size, set it to 0. |
1625 | It->second->addDataSecEntry(Id: FuncId, Sym: Asm->getSymbol(GV: F), Size: 0); |
1626 | } |
1627 | } |
1628 | |
1629 | void BTFDebug::endModule() { |
1630 | // Collect MapDef globals if not collected yet. |
1631 | if (MapDefNotCollected) { |
1632 | processGlobals(ProcessingMapDef: true); |
1633 | MapDefNotCollected = false; |
1634 | } |
1635 | |
1636 | // Collect global types/variables except MapDef globals. |
1637 | processGlobals(ProcessingMapDef: false); |
1638 | |
1639 | // In case that BPF_TRAP usage is removed during machine-level optimization, |
1640 | // generate btf for BPF_TRAP function here. |
1641 | for (const Function &F : *MMI->getModule()) { |
1642 | if (F.getName() == BPF_TRAP) |
1643 | processFuncPrototypes(F: &F); |
1644 | } |
1645 | |
1646 | for (auto &DataSec : DataSecEntries) |
1647 | addType(TypeEntry: std::move(DataSec.second)); |
1648 | |
1649 | // Fixups |
1650 | for (auto &Fixup : FixupDerivedTypes) { |
1651 | const DICompositeType *CTy = Fixup.first; |
1652 | StringRef TypeName = CTy->getName(); |
1653 | bool IsUnion = CTy->getTag() == dwarf::DW_TAG_union_type; |
1654 | |
1655 | // Search through struct types |
1656 | uint32_t StructTypeId = 0; |
1657 | for (const auto &StructType : StructTypes) { |
1658 | if (StructType->getName() == TypeName) { |
1659 | StructTypeId = StructType->getId(); |
1660 | break; |
1661 | } |
1662 | } |
1663 | |
1664 | if (StructTypeId == 0) { |
1665 | auto FwdTypeEntry = std::make_unique<BTFTypeFwd>(args&: TypeName, args&: IsUnion); |
1666 | StructTypeId = addType(TypeEntry: std::move(FwdTypeEntry)); |
1667 | } |
1668 | |
1669 | for (auto &TypeInfo : Fixup.second) { |
1670 | const DIDerivedType *DTy = TypeInfo.first; |
1671 | BTFTypeDerived *BDType = TypeInfo.second; |
1672 | |
1673 | int TmpTypeId = genBTFTypeTags(DTy, BaseTypeId: StructTypeId); |
1674 | if (TmpTypeId >= 0) |
1675 | BDType->setPointeeType(TmpTypeId); |
1676 | else |
1677 | BDType->setPointeeType(StructTypeId); |
1678 | } |
1679 | } |
1680 | |
1681 | // Complete BTF type cross refereences. |
1682 | for (const auto &TypeEntry : TypeEntries) |
1683 | TypeEntry->completeType(BDebug&: *this); |
1684 | |
1685 | // Emit BTF sections. |
1686 | emitBTFSection(); |
1687 | emitBTFExtSection(); |
1688 | } |
1689 | |