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