1 //===- BTFParser.cpp ------------------------------------------------------===//
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 // BTFParser reads/interprets .BTF and .BTF.ext ELF sections.
10 // Refer to BTFParser.h for API description.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/DebugInfo/BTF/BTFParser.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/Errc.h"
18 
19 #define DEBUG_TYPE "debug-info-btf-parser"
20 
21 using namespace llvm;
22 using object::ObjectFile;
23 using object::SectionedAddress;
24 using object::SectionRef;
25 
26 const char BTFSectionName[] = ".BTF";
27 const char BTFExtSectionName[] = ".BTF.ext";
28 
29 // Utility class with API similar to raw_ostream but can be cast
30 // to Error, e.g.:
31 //
32 // Error foo(...) {
33 //   ...
34 //   if (Error E = bar(...))
35 //     return Err("error while foo(): ") << E;
36 //   ...
37 // }
38 //
39 namespace {
40 class Err {
41   std::string Buffer;
42   raw_string_ostream Stream;
43 
44 public:
Err(const char * InitialMsg)45   Err(const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {}
Err(const char * SectionName,DataExtractor::Cursor & C)46   Err(const char *SectionName, DataExtractor::Cursor &C)
47       : Buffer(), Stream(Buffer) {
48     *this << "error while reading " << SectionName
49           << " section: " << C.takeError();
50   };
51 
operator <<(T Val)52   template <typename T> Err &operator<<(T Val) {
53     Stream << Val;
54     return *this;
55   }
56 
write_hex(unsigned long long Val)57   Err &write_hex(unsigned long long Val) {
58     Stream.write_hex(Val);
59     return *this;
60   }
61 
operator <<(Error Val)62   Err &operator<<(Error Val) {
63     handleAllErrors(std::move(Val),
64                     [=](ErrorInfoBase &Info) { Stream << Info.message(); });
65     return *this;
66   }
67 
operator Error() const68   operator Error() const {
69     return make_error<StringError>(Buffer, errc::invalid_argument);
70   }
71 };
72 } // anonymous namespace
73 
74 // ParseContext wraps information that is only necessary while parsing
75 // ObjectFile and can be discarded once parsing is done.
76 // Used by BTFParser::parse* auxiliary functions.
77 struct BTFParser::ParseContext {
78   const ObjectFile &Obj;
79   const ParseOptions &Opts;
80   // Map from ELF section name to SectionRef
81   DenseMap<StringRef, SectionRef> Sections;
82 
83 public:
ParseContextBTFParser::ParseContext84   ParseContext(const ObjectFile &Obj, const ParseOptions &Opts)
85       : Obj(Obj), Opts(Opts) {}
86 
makeExtractorBTFParser::ParseContext87   Expected<DataExtractor> makeExtractor(SectionRef Sec) {
88     Expected<StringRef> Contents = Sec.getContents();
89     if (!Contents)
90       return Contents.takeError();
91     return DataExtractor(Contents.get(), Obj.isLittleEndian(),
92                          Obj.getBytesInAddress());
93   }
94 
findSectionBTFParser::ParseContext95   std::optional<SectionRef> findSection(StringRef Name) const {
96     auto It = Sections.find(Name);
97     if (It != Sections.end())
98       return It->second;
99     return std::nullopt;
100   }
101 };
102 
parseBTF(ParseContext & Ctx,SectionRef BTF)103 Error BTFParser::parseBTF(ParseContext &Ctx, SectionRef BTF) {
104   Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTF);
105   if (!MaybeExtractor)
106     return MaybeExtractor.takeError();
107 
108   DataExtractor &Extractor = MaybeExtractor.get();
109   DataExtractor::Cursor C = DataExtractor::Cursor(0);
110   uint16_t Magic = Extractor.getU16(C);
111   if (!C)
112     return Err(".BTF", C);
113   if (Magic != BTF::MAGIC)
114     return Err("invalid .BTF magic: ").write_hex(Magic);
115   uint8_t Version = Extractor.getU8(C);
116   if (!C)
117     return Err(".BTF", C);
118   if (Version != 1)
119     return Err("unsupported .BTF version: ") << (unsigned)Version;
120   (void)Extractor.getU8(C); // flags
121   uint32_t HdrLen = Extractor.getU32(C);
122   if (!C)
123     return Err(".BTF", C);
124   if (HdrLen < 8)
125     return Err("unexpected .BTF header length: ") << HdrLen;
126   uint32_t TypeOff = Extractor.getU32(C);
127   uint32_t TypeLen = Extractor.getU32(C);
128   uint32_t StrOff = Extractor.getU32(C);
129   uint32_t StrLen = Extractor.getU32(C);
130   uint32_t StrStart = HdrLen + StrOff;
131   uint32_t StrEnd = StrStart + StrLen;
132   uint32_t TypesInfoStart = HdrLen + TypeOff;
133   uint32_t TypesInfoEnd = TypesInfoStart + TypeLen;
134   uint32_t BytesExpected = std::max(StrEnd, TypesInfoEnd);
135   if (!C)
136     return Err(".BTF", C);
137   if (Extractor.getData().size() < BytesExpected)
138     return Err("invalid .BTF section size, expecting at-least ")
139            << BytesExpected << " bytes";
140 
141   StringsTable = Extractor.getData().slice(StrStart, StrEnd);
142 
143   if (TypeLen > 0 && Ctx.Opts.LoadTypes) {
144     StringRef RawData = Extractor.getData().slice(TypesInfoStart, TypesInfoEnd);
145     if (Error E = parseTypesInfo(Ctx, TypesInfoStart, RawData))
146       return E;
147   }
148 
149   return Error::success();
150 }
151 
152 // Compute record size for each BTF::CommonType sub-type
153 // (including entries in the tail position).
byteSize(BTF::CommonType * Type)154 static size_t byteSize(BTF::CommonType *Type) {
155   size_t Size = sizeof(BTF::CommonType);
156   switch (Type->getKind()) {
157   case BTF::BTF_KIND_INT:
158     Size += sizeof(uint32_t);
159     break;
160   case BTF::BTF_KIND_ARRAY:
161     Size += sizeof(BTF::BTFArray);
162     break;
163   case BTF::BTF_KIND_VAR:
164     Size += sizeof(uint32_t);
165     break;
166   case BTF::BTF_KIND_DECL_TAG:
167     Size += sizeof(uint32_t);
168     break;
169   case BTF::BTF_KIND_STRUCT:
170   case BTF::BTF_KIND_UNION:
171     Size += sizeof(BTF::BTFMember) * Type->getVlen();
172     break;
173   case BTF::BTF_KIND_ENUM:
174     Size += sizeof(BTF::BTFEnum) * Type->getVlen();
175     break;
176   case BTF::BTF_KIND_ENUM64:
177     Size += sizeof(BTF::BTFEnum64) * Type->getVlen();
178     break;
179   case BTF::BTF_KIND_FUNC_PROTO:
180     Size += sizeof(BTF::BTFParam) * Type->getVlen();
181     break;
182   case BTF::BTF_KIND_DATASEC:
183     Size += sizeof(BTF::BTFDataSec) * Type->getVlen();
184     break;
185   }
186   return Size;
187 }
188 
189 // Guard value for voids, simplifies code a bit, but NameOff is not
190 // actually valid.
191 const BTF::CommonType VoidTypeInst = {0, BTF::BTF_KIND_UNKN << 24, {0}};
192 
193 // Type information "parsing" is very primitive:
194 // - The `RawData` is copied to a buffer owned by `BTFParser` instance.
195 // - The buffer is treated as an array of `uint32_t` values, each value
196 //   is swapped to use native endianness. This is possible, because
197 //   according to BTF spec all buffer elements are structures comprised
198 //   of `uint32_t` fields.
199 // - `BTFParser::Types` vector is filled with pointers to buffer
200 //   elements, using `byteSize()` function to slice the buffer at type
201 //   record boundaries.
202 // - If at some point a type definition with incorrect size (logical size
203 //   exceeding buffer boundaries) is reached it is not added to the
204 //   `BTFParser::Types` vector and the process stops.
parseTypesInfo(ParseContext & Ctx,uint64_t TypesInfoStart,StringRef RawData)205 Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,
206                                 StringRef RawData) {
207   using support::endian::byte_swap;
208 
209   TypesBuffer = OwningArrayRef<uint8_t>(arrayRefFromStringRef(RawData));
210   // Switch endianness if necessary.
211   endianness Endianness = Ctx.Obj.isLittleEndian() ? llvm::endianness::little
212                                                    : llvm::endianness::big;
213   uint32_t *TypesBuffer32 = (uint32_t *)TypesBuffer.data();
214   for (uint64_t I = 0; I < TypesBuffer.size() / 4; ++I)
215     TypesBuffer32[I] = byte_swap(TypesBuffer32[I], Endianness);
216 
217   // The type id 0 is reserved for void type.
218   Types.push_back(&VoidTypeInst);
219 
220   uint64_t Pos = 0;
221   while (Pos < RawData.size()) {
222     uint64_t BytesLeft = RawData.size() - Pos;
223     uint64_t Offset = TypesInfoStart + Pos;
224     BTF::CommonType *Type = (BTF::CommonType *)&TypesBuffer[Pos];
225     if (BytesLeft < sizeof(*Type))
226       return Err("incomplete type definition in .BTF section:")
227              << " offset " << Offset << ", index " << Types.size();
228 
229     uint64_t Size = byteSize(Type);
230     if (BytesLeft < Size)
231       return Err("incomplete type definition in .BTF section:")
232              << " offset=" << Offset << ", index=" << Types.size()
233              << ", vlen=" << Type->getVlen();
234 
235     LLVM_DEBUG({
236       llvm::dbgs() << "Adding BTF type:\n"
237                    << "  Id = " << Types.size() << "\n"
238                    << "  Kind = " << Type->getKind() << "\n"
239                    << "  Name = " << findString(Type->NameOff) << "\n"
240                    << "  Record Size = " << Size << "\n";
241     });
242     Types.push_back(Type);
243     Pos += Size;
244   }
245 
246   return Error::success();
247 }
248 
parseBTFExt(ParseContext & Ctx,SectionRef BTFExt)249 Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) {
250   Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTFExt);
251   if (!MaybeExtractor)
252     return MaybeExtractor.takeError();
253 
254   DataExtractor &Extractor = MaybeExtractor.get();
255   DataExtractor::Cursor C = DataExtractor::Cursor(0);
256   uint16_t Magic = Extractor.getU16(C);
257   if (!C)
258     return Err(".BTF.ext", C);
259   if (Magic != BTF::MAGIC)
260     return Err("invalid .BTF.ext magic: ").write_hex(Magic);
261   uint8_t Version = Extractor.getU8(C);
262   if (!C)
263     return Err(".BTF", C);
264   if (Version != 1)
265     return Err("unsupported .BTF.ext version: ") << (unsigned)Version;
266   (void)Extractor.getU8(C); // flags
267   uint32_t HdrLen = Extractor.getU32(C);
268   if (!C)
269     return Err(".BTF.ext", C);
270   if (HdrLen < 8)
271     return Err("unexpected .BTF.ext header length: ") << HdrLen;
272   (void)Extractor.getU32(C); // func_info_off
273   (void)Extractor.getU32(C); // func_info_len
274   uint32_t LineInfoOff = Extractor.getU32(C);
275   uint32_t LineInfoLen = Extractor.getU32(C);
276   uint32_t RelocInfoOff = Extractor.getU32(C);
277   uint32_t RelocInfoLen = Extractor.getU32(C);
278   if (!C)
279     return Err(".BTF.ext", C);
280 
281   if (LineInfoLen > 0 && Ctx.Opts.LoadLines) {
282     uint32_t LineInfoStart = HdrLen + LineInfoOff;
283     uint32_t LineInfoEnd = LineInfoStart + LineInfoLen;
284     if (Error E = parseLineInfo(Ctx, Extractor, LineInfoStart, LineInfoEnd))
285       return E;
286   }
287 
288   if (RelocInfoLen > 0 && Ctx.Opts.LoadRelocs) {
289     uint32_t RelocInfoStart = HdrLen + RelocInfoOff;
290     uint32_t RelocInfoEnd = RelocInfoStart + RelocInfoLen;
291     if (Error E = parseRelocInfo(Ctx, Extractor, RelocInfoStart, RelocInfoEnd))
292       return E;
293   }
294 
295   return Error::success();
296 }
297 
parseLineInfo(ParseContext & Ctx,DataExtractor & Extractor,uint64_t LineInfoStart,uint64_t LineInfoEnd)298 Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor,
299                                uint64_t LineInfoStart, uint64_t LineInfoEnd) {
300   DataExtractor::Cursor C = DataExtractor::Cursor(LineInfoStart);
301   uint32_t RecSize = Extractor.getU32(C);
302   if (!C)
303     return Err(".BTF.ext", C);
304   if (RecSize < 16)
305     return Err("unexpected .BTF.ext line info record length: ") << RecSize;
306 
307   while (C && C.tell() < LineInfoEnd) {
308     uint32_t SecNameOff = Extractor.getU32(C);
309     uint32_t NumInfo = Extractor.getU32(C);
310     StringRef SecName = findString(SecNameOff);
311     std::optional<SectionRef> Sec = Ctx.findSection(SecName);
312     if (!C)
313       return Err(".BTF.ext", C);
314     if (!Sec)
315       return Err("") << "can't find section '" << SecName
316                      << "' while parsing .BTF.ext line info";
317     BTFLinesVector &Lines = SectionLines[Sec->getIndex()];
318     for (uint32_t I = 0; C && I < NumInfo; ++I) {
319       uint64_t RecStart = C.tell();
320       uint32_t InsnOff = Extractor.getU32(C);
321       uint32_t FileNameOff = Extractor.getU32(C);
322       uint32_t LineOff = Extractor.getU32(C);
323       uint32_t LineCol = Extractor.getU32(C);
324       if (!C)
325         return Err(".BTF.ext", C);
326       Lines.push_back({InsnOff, FileNameOff, LineOff, LineCol});
327       C.seek(RecStart + RecSize);
328     }
329     llvm::stable_sort(Lines,
330                       [](const BTF::BPFLineInfo &L, const BTF::BPFLineInfo &R) {
331                         return L.InsnOffset < R.InsnOffset;
332                       });
333   }
334   if (!C)
335     return Err(".BTF.ext", C);
336 
337   return Error::success();
338 }
339 
parseRelocInfo(ParseContext & Ctx,DataExtractor & Extractor,uint64_t RelocInfoStart,uint64_t RelocInfoEnd)340 Error BTFParser::parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor,
341                                 uint64_t RelocInfoStart,
342                                 uint64_t RelocInfoEnd) {
343   DataExtractor::Cursor C = DataExtractor::Cursor(RelocInfoStart);
344   uint32_t RecSize = Extractor.getU32(C);
345   if (!C)
346     return Err(".BTF.ext", C);
347   if (RecSize < 16)
348     return Err("unexpected .BTF.ext field reloc info record length: ")
349            << RecSize;
350   while (C && C.tell() < RelocInfoEnd) {
351     uint32_t SecNameOff = Extractor.getU32(C);
352     uint32_t NumInfo = Extractor.getU32(C);
353     StringRef SecName = findString(SecNameOff);
354     std::optional<SectionRef> Sec = Ctx.findSection(SecName);
355     BTFRelocVector &Relocs = SectionRelocs[Sec->getIndex()];
356     for (uint32_t I = 0; C && I < NumInfo; ++I) {
357       uint64_t RecStart = C.tell();
358       uint32_t InsnOff = Extractor.getU32(C);
359       uint32_t TypeID = Extractor.getU32(C);
360       uint32_t OffsetNameOff = Extractor.getU32(C);
361       uint32_t RelocKind = Extractor.getU32(C);
362       if (!C)
363         return Err(".BTF.ext", C);
364       Relocs.push_back({InsnOff, TypeID, OffsetNameOff, RelocKind});
365       C.seek(RecStart + RecSize);
366     }
367     llvm::stable_sort(
368         Relocs, [](const BTF::BPFFieldReloc &L, const BTF::BPFFieldReloc &R) {
369           return L.InsnOffset < R.InsnOffset;
370         });
371   }
372   if (!C)
373     return Err(".BTF.ext", C);
374 
375   return Error::success();
376 }
377 
parse(const ObjectFile & Obj,const ParseOptions & Opts)378 Error BTFParser::parse(const ObjectFile &Obj, const ParseOptions &Opts) {
379   StringsTable = StringRef();
380   SectionLines.clear();
381   SectionRelocs.clear();
382   Types.clear();
383   TypesBuffer = OwningArrayRef<uint8_t>();
384 
385   ParseContext Ctx(Obj, Opts);
386   std::optional<SectionRef> BTF;
387   std::optional<SectionRef> BTFExt;
388   for (SectionRef Sec : Obj.sections()) {
389     Expected<StringRef> MaybeName = Sec.getName();
390     if (!MaybeName)
391       return Err("error while reading section name: ") << MaybeName.takeError();
392     Ctx.Sections[*MaybeName] = Sec;
393     if (*MaybeName == BTFSectionName)
394       BTF = Sec;
395     if (*MaybeName == BTFExtSectionName)
396       BTFExt = Sec;
397   }
398   if (!BTF)
399     return Err("can't find .BTF section");
400   if (!BTFExt)
401     return Err("can't find .BTF.ext section");
402   if (Error E = parseBTF(Ctx, *BTF))
403     return E;
404   if (Error E = parseBTFExt(Ctx, *BTFExt))
405     return E;
406 
407   return Error::success();
408 }
409 
hasBTFSections(const ObjectFile & Obj)410 bool BTFParser::hasBTFSections(const ObjectFile &Obj) {
411   bool HasBTF = false;
412   bool HasBTFExt = false;
413   for (SectionRef Sec : Obj.sections()) {
414     Expected<StringRef> Name = Sec.getName();
415     if (Error E = Name.takeError()) {
416       logAllUnhandledErrors(std::move(E), errs());
417       continue;
418     }
419     HasBTF |= *Name == BTFSectionName;
420     HasBTFExt |= *Name == BTFExtSectionName;
421     if (HasBTF && HasBTFExt)
422       return true;
423   }
424   return false;
425 }
426 
findString(uint32_t Offset) const427 StringRef BTFParser::findString(uint32_t Offset) const {
428   return StringsTable.slice(Offset, StringsTable.find(0, Offset));
429 }
430 
431 template <typename T>
findInfo(const DenseMap<uint64_t,SmallVector<T,0>> & SecMap,SectionedAddress Address)432 static const T *findInfo(const DenseMap<uint64_t, SmallVector<T, 0>> &SecMap,
433                          SectionedAddress Address) {
434   auto MaybeSecInfo = SecMap.find(Address.SectionIndex);
435   if (MaybeSecInfo == SecMap.end())
436     return nullptr;
437 
438   const SmallVector<T, 0> &SecInfo = MaybeSecInfo->second;
439   const uint64_t TargetOffset = Address.Address;
440   typename SmallVector<T, 0>::const_iterator MaybeInfo = llvm::partition_point(
441       SecInfo, [=](const T &Entry) { return Entry.InsnOffset < TargetOffset; });
442   if (MaybeInfo == SecInfo.end() || MaybeInfo->InsnOffset != Address.Address)
443     return nullptr;
444 
445   return &*MaybeInfo;
446 }
447 
448 const BTF::BPFLineInfo *
findLineInfo(SectionedAddress Address) const449 BTFParser::findLineInfo(SectionedAddress Address) const {
450   return findInfo(SectionLines, Address);
451 }
452 
453 const BTF::BPFFieldReloc *
findFieldReloc(SectionedAddress Address) const454 BTFParser::findFieldReloc(SectionedAddress Address) const {
455   return findInfo(SectionRelocs, Address);
456 }
457 
findType(uint32_t Id) const458 const BTF::CommonType *BTFParser::findType(uint32_t Id) const {
459   if (Id < Types.size())
460     return Types[Id];
461   return nullptr;
462 }
463 
464 enum RelocKindGroup {
465   RKG_FIELD,
466   RKG_TYPE,
467   RKG_ENUMVAL,
468   RKG_UNKNOWN,
469 };
470 
relocKindGroup(const BTF::BPFFieldReloc * Reloc)471 static RelocKindGroup relocKindGroup(const BTF::BPFFieldReloc *Reloc) {
472   switch (Reloc->RelocKind) {
473   case BTF::FIELD_BYTE_OFFSET:
474   case BTF::FIELD_BYTE_SIZE:
475   case BTF::FIELD_EXISTENCE:
476   case BTF::FIELD_SIGNEDNESS:
477   case BTF::FIELD_LSHIFT_U64:
478   case BTF::FIELD_RSHIFT_U64:
479     return RKG_FIELD;
480   case BTF::BTF_TYPE_ID_LOCAL:
481   case BTF::BTF_TYPE_ID_REMOTE:
482   case BTF::TYPE_EXISTENCE:
483   case BTF::TYPE_MATCH:
484   case BTF::TYPE_SIZE:
485     return RKG_TYPE;
486   case BTF::ENUM_VALUE_EXISTENCE:
487   case BTF::ENUM_VALUE:
488     return RKG_ENUMVAL;
489   default:
490     return RKG_UNKNOWN;
491   }
492 }
493 
isMod(const BTF::CommonType * Type)494 static bool isMod(const BTF::CommonType *Type) {
495   switch (Type->getKind()) {
496   case BTF::BTF_KIND_VOLATILE:
497   case BTF::BTF_KIND_CONST:
498   case BTF::BTF_KIND_RESTRICT:
499   case BTF::BTF_KIND_TYPE_TAG:
500     return true;
501   default:
502     return false;
503   }
504 }
505 
printMod(const BTFParser & BTF,const BTF::CommonType * Type,raw_ostream & Stream)506 static bool printMod(const BTFParser &BTF, const BTF::CommonType *Type,
507                      raw_ostream &Stream) {
508   switch (Type->getKind()) {
509   case BTF::BTF_KIND_CONST:
510     Stream << " const";
511     break;
512   case BTF::BTF_KIND_VOLATILE:
513     Stream << " volatile";
514     break;
515   case BTF::BTF_KIND_RESTRICT:
516     Stream << " restrict";
517     break;
518   case BTF::BTF_KIND_TYPE_TAG:
519     Stream << " type_tag(\"" << BTF.findString(Type->NameOff) << "\")";
520     break;
521   default:
522     return false;
523   }
524   return true;
525 }
526 
skipModsAndTypedefs(const BTFParser & BTF,const BTF::CommonType * Type)527 static const BTF::CommonType *skipModsAndTypedefs(const BTFParser &BTF,
528                                                   const BTF::CommonType *Type) {
529   while (isMod(Type) || Type->getKind() == BTF::BTF_KIND_TYPEDEF) {
530     auto *Base = BTF.findType(Type->Type);
531     if (!Base)
532       break;
533     Type = Base;
534   }
535   return Type;
536 }
537 
538 namespace {
539 struct StrOrAnon {
540   const BTFParser &BTF;
541   uint32_t Offset;
542   uint32_t Idx;
543 };
544 
operator <<(raw_ostream & Stream,const StrOrAnon & S)545 static raw_ostream &operator<<(raw_ostream &Stream, const StrOrAnon &S) {
546   StringRef Str = S.BTF.findString(S.Offset);
547   if (Str.empty())
548     Stream << "<anon " << S.Idx << ">";
549   else
550     Stream << Str;
551   return Stream;
552 }
553 } // anonymous namespace
554 
relocKindName(uint32_t X,raw_ostream & Out)555 static void relocKindName(uint32_t X, raw_ostream &Out) {
556   Out << "<";
557   switch (X) {
558   default:
559     Out << "reloc kind #" << X;
560     break;
561   case BTF::FIELD_BYTE_OFFSET:
562     Out << "byte_off";
563     break;
564   case BTF::FIELD_BYTE_SIZE:
565     Out << "byte_sz";
566     break;
567   case BTF::FIELD_EXISTENCE:
568     Out << "field_exists";
569     break;
570   case BTF::FIELD_SIGNEDNESS:
571     Out << "signed";
572     break;
573   case BTF::FIELD_LSHIFT_U64:
574     Out << "lshift_u64";
575     break;
576   case BTF::FIELD_RSHIFT_U64:
577     Out << "rshift_u64";
578     break;
579   case BTF::BTF_TYPE_ID_LOCAL:
580     Out << "local_type_id";
581     break;
582   case BTF::BTF_TYPE_ID_REMOTE:
583     Out << "target_type_id";
584     break;
585   case BTF::TYPE_EXISTENCE:
586     Out << "type_exists";
587     break;
588   case BTF::TYPE_MATCH:
589     Out << "type_matches";
590     break;
591   case BTF::TYPE_SIZE:
592     Out << "type_size";
593     break;
594   case BTF::ENUM_VALUE_EXISTENCE:
595     Out << "enumval_exists";
596     break;
597   case BTF::ENUM_VALUE:
598     Out << "enumval_value";
599     break;
600   }
601   Out << ">";
602 }
603 
604 // Produces a human readable description of a CO-RE relocation.
605 // Such relocations are generated by BPF backend, and processed
606 // by libbpf's BPF program loader [1].
607 //
608 // Each relocation record has the following information:
609 // - Relocation kind;
610 // - BTF type ID;
611 // - Access string offset in string table.
612 //
613 // There are different kinds of relocations, these kinds could be split
614 // in three groups:
615 // - load-time information about types (size, existence),
616 //   `BTFParser::symbolize()` output for such relocations uses the template:
617 //
618 //     <relocation-kind> [<id>] <type-name>
619 //
620 //   For example:
621 //   - "<type_exists> [7] struct foo"
622 //   - "<type_size> [7] struct foo"
623 //
624 // - load-time information about enums (literal existence, literal value),
625 //   `BTFParser::symbolize()` output for such relocations uses the template:
626 //
627 //     <relocation-kind> [<id>] <type-name>::<literal-name> = <original-value>
628 //
629 //   For example:
630 //   - "<enumval_exists> [5] enum foo::U = 1"
631 //   - "<enumval_value> [5] enum foo::V = 2"
632 //
633 // - load-time information about fields (e.g. field offset),
634 //   `BTFParser::symbolize()` output for such relocations uses the template:
635 //
636 //     <relocation-kind> [<id>] \
637 //       <type-name>::[N].<field-1-name>...<field-M-name> \
638 //       (<access string>)
639 //
640 //   For example:
641 //   - "<byte_off> [8] struct bar::[7].v (7:1)"
642 //   - "<field_exists> [8] struct bar::v (0:1)"
643 //
644 // If relocation description is not valid output follows the following pattern:
645 //
646 //     <relocation-kind> <type-id>::<unprocessedaccess-string> <<error-msg>>
647 //
648 // For example:
649 //
650 // - "<type_sz> [42] '' <unknown type id: 42>"
651 // - "<byte_off> [4] '0:' <field spec too short>"
652 //
653 // Additional examples could be found in unit tests, see
654 // llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp.
655 //
656 // [1] https://www.kernel.org/doc/html/latest/bpf/libbpf/index.html
symbolize(const BTF::BPFFieldReloc * Reloc,SmallVectorImpl<char> & Result) const657 void BTFParser::symbolize(const BTF::BPFFieldReloc *Reloc,
658                           SmallVectorImpl<char> &Result) const {
659   raw_svector_ostream Stream(Result);
660   StringRef FullSpecStr = findString(Reloc->OffsetNameOff);
661   SmallVector<uint32_t, 8> RawSpec;
662 
663   auto Fail = [&](auto Msg) {
664     Result.resize(0);
665     relocKindName(Reloc->RelocKind, Stream);
666     Stream << " [" << Reloc->TypeID << "] '" << FullSpecStr << "'"
667            << " <" << Msg << ">";
668   };
669 
670   // Relocation access string follows pattern [0-9]+(:[0-9]+)*,
671   // e.g.: 12:22:3. Code below splits `SpecStr` by ':', parses
672   // numbers, and pushes them to `RawSpec`.
673   StringRef SpecStr = FullSpecStr;
674   while (SpecStr.size()) {
675     unsigned long long Val;
676     if (consumeUnsignedInteger(SpecStr, 10, Val))
677       return Fail("spec string is not a number");
678     RawSpec.push_back(Val);
679     if (SpecStr.empty())
680       break;
681     if (SpecStr[0] != ':')
682       return Fail(format("unexpected spec string delimiter: '%c'", SpecStr[0]));
683     SpecStr = SpecStr.substr(1);
684   }
685 
686   // Print relocation kind to `Stream`.
687   relocKindName(Reloc->RelocKind, Stream);
688 
689   uint32_t CurId = Reloc->TypeID;
690   const BTF::CommonType *Type = findType(CurId);
691   if (!Type)
692     return Fail(format("unknown type id: %d", CurId));
693 
694   Stream << " [" << CurId << "]";
695 
696   // `Type` might have modifiers, e.g. for type 'const int' the `Type`
697   // would refer to BTF type of kind BTF_KIND_CONST.
698   // Print all these modifiers to `Stream`.
699   for (uint32_t ChainLen = 0; printMod(*this, Type, Stream); ++ChainLen) {
700     if (ChainLen >= 32)
701       return Fail("modifiers chain is too long");
702 
703     CurId = Type->Type;
704     const BTF::CommonType *NextType = findType(CurId);
705     if (!NextType)
706       return Fail(format("unknown type id: %d in modifiers chain", CurId));
707     Type = NextType;
708   }
709   // Print the type name to `Stream`.
710   if (CurId == 0) {
711     Stream << " void";
712   } else {
713     switch (Type->getKind()) {
714     case BTF::BTF_KIND_TYPEDEF:
715       Stream << " typedef";
716       break;
717     case BTF::BTF_KIND_STRUCT:
718       Stream << " struct";
719       break;
720     case BTF::BTF_KIND_UNION:
721       Stream << " union";
722       break;
723     case BTF::BTF_KIND_ENUM:
724       Stream << " enum";
725       break;
726     case BTF::BTF_KIND_ENUM64:
727       Stream << " enum";
728       break;
729     case BTF::BTF_KIND_FWD:
730       if (Type->Info & BTF::FWD_UNION_FLAG)
731         Stream << " fwd union";
732       else
733         Stream << " fwd struct";
734       break;
735     default:
736       break;
737     }
738     Stream << " " << StrOrAnon({*this, Type->NameOff, CurId});
739   }
740 
741   RelocKindGroup Group = relocKindGroup(Reloc);
742   // Type-based relocations don't use access string but clang backend
743   // generates '0' and libbpf checks it's value, do the same here.
744   if (Group == RKG_TYPE) {
745     if (RawSpec.size() != 1 || RawSpec[0] != 0)
746       return Fail("unexpected type-based relocation spec: should be '0'");
747     return;
748   }
749 
750   Stream << "::";
751 
752   // For enum-based relocations access string is a single number,
753   // corresponding to the enum literal sequential number.
754   // E.g. for `enum E { U, V }`, relocation requesting value of `V`
755   // would look as follows:
756   // - kind: BTF::ENUM_VALUE
757   // - BTF id: id for `E`
758   // - access string: "1"
759   if (Group == RKG_ENUMVAL) {
760     Type = skipModsAndTypedefs(*this, Type);
761 
762     if (RawSpec.size() != 1)
763       return Fail("unexpected enumval relocation spec size");
764 
765     uint32_t NameOff;
766     uint64_t Val;
767     uint32_t Idx = RawSpec[0];
768     if (auto *T = dyn_cast<BTF::EnumType>(Type)) {
769       if (T->values().size() <= Idx)
770         return Fail(format("bad value index: %d", Idx));
771       const BTF::BTFEnum &E = T->values()[Idx];
772       NameOff = E.NameOff;
773       Val = E.Val;
774     } else if (auto *T = dyn_cast<BTF::Enum64Type>(Type)) {
775       if (T->values().size() <= Idx)
776         return Fail(format("bad value index: %d", Idx));
777       const BTF::BTFEnum64 &E = T->values()[Idx];
778       NameOff = E.NameOff;
779       Val = (uint64_t)E.Val_Hi32 << 32u | E.Val_Lo32;
780     } else {
781       return Fail(format("unexpected type kind for enum relocation: %d",
782                          Type->getKind()));
783     }
784 
785     Stream << StrOrAnon({*this, NameOff, Idx});
786     if (Type->Info & BTF::ENUM_SIGNED_FLAG)
787       Stream << " = " << (int64_t)Val;
788     else
789       Stream << " = " << (uint64_t)Val;
790     return;
791   }
792 
793   // For type-based relocations access string is an array of numbers,
794   // which resemble index parameters for `getelementptr` LLVM IR instruction.
795   // E.g. for the following types:
796   //
797   //   struct foo {
798   //     int a;
799   //     int b;
800   //   };
801   //   struct bar {
802   //     int u;
803   //     struct foo v[7];
804   //   };
805   //
806   // Relocation requesting `offsetof(struct bar, v[2].b)` will have
807   // the following access string: 0:1:2:1
808   //                              ^ ^ ^ ^
809   //                              | | | |
810   //                  initial index | | field 'b' is a field #1
811   //                                | | (counting from 0)
812   //                                | array index #2
813   //           field 'v' is a field #1
814   //              (counting from 0)
815   if (Group == RKG_FIELD) {
816     if (RawSpec.size() < 1)
817       return Fail("field spec too short");
818 
819     if (RawSpec[0] != 0)
820       Stream << "[" << RawSpec[0] << "]";
821     for (uint32_t I = 1; I < RawSpec.size(); ++I) {
822       Type = skipModsAndTypedefs(*this, Type);
823       uint32_t Idx = RawSpec[I];
824 
825       if (auto *T = dyn_cast<BTF::StructType>(Type)) {
826         if (T->getVlen() <= Idx)
827           return Fail(
828               format("member index %d for spec sub-string %d is out of range",
829                      Idx, I));
830 
831         const BTF::BTFMember &Member = T->members()[Idx];
832         if (I != 1 || RawSpec[0] != 0)
833           Stream << ".";
834         Stream << StrOrAnon({*this, Member.NameOff, Idx});
835         Type = findType(Member.Type);
836         if (!Type)
837           return Fail(format("unknown member type id %d for spec sub-string %d",
838                              Member.Type, I));
839       } else if (auto *T = dyn_cast<BTF::ArrayType>(Type)) {
840         Stream << "[" << Idx << "]";
841         Type = findType(T->getArray().ElemType);
842         if (!Type)
843           return Fail(
844               format("unknown element type id %d for spec sub-string %d",
845                      T->getArray().ElemType, I));
846       } else {
847         return Fail(format("unexpected type kind %d for spec sub-string %d",
848                            Type->getKind(), I));
849       }
850     }
851 
852     Stream << " (" << FullSpecStr << ")";
853     return;
854   }
855 
856   return Fail(format("unknown relocation kind: %d", Reloc->RelocKind));
857 }
858