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