LLVM 19.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"
18
19#define DEBUG_TYPE "debug-info-btf-parser"
20
21using namespace llvm;
25
26const char BTFSectionName[] = ".BTF";
27const 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//
39namespace {
40class Err {
41 std::string Buffer;
42 raw_string_ostream Stream;
43
44public:
45 Err(const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {}
46 Err(const char *SectionName, DataExtractor::Cursor &C)
47 : Buffer(), Stream(Buffer) {
48 *this << "error while reading " << SectionName
49 << " section: " << C.takeError();
50 };
51
52 template <typename T> Err &operator<<(T Val) {
53 Stream << Val;
54 return *this;
55 }
56
57 Err &write_hex(unsigned long long Val) {
58 Stream.write_hex(Val);
59 return *this;
60 }
61
62 Err &operator<<(Error Val) {
63 handleAllErrors(std::move(Val),
64 [=](ErrorInfoBase &Info) { Stream << Info.message(); });
65 return *this;
66 }
67
68 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.
80 // Map from ELF section name to SectionRef
82
83public:
85 : Obj(Obj), Opts(Opts) {}
86
88 Expected<StringRef> Contents = Sec.getContents();
89 if (!Contents)
90 return Contents.takeError();
91 return DataExtractor(Contents.get(), Obj.isLittleEndian(),
93 }
94
95 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
103Error 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();
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).
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.
191const 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.
205Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,
206 StringRef RawData) {
208
209 TypesBuffer = OwningArrayRef<uint8_t>(arrayRefFromStringRef(RawData));
210 // Switch endianness if necessary.
211 endianness Endianness = Ctx.Obj.isLittleEndian() ? llvm::endianness::little
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
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
249Error 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();
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
298Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor,
299 uint64_t LineInfoStart, uint64_t LineInfoEnd) {
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
340Error BTFParser::parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor,
341 uint64_t RelocInfoStart,
342 uint64_t RelocInfoEnd) {
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 }
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
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
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
428 return StringsTable.slice(Offset, StringsTable.find(0, Offset));
429}
430
431template <typename T>
432static const T *findInfo(const DenseMap<uint64_t, SmallVector<T, 0>> &SecMap,
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;
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
448const BTF::BPFLineInfo *
450 return findInfo(SectionLines, Address);
451}
452
453const BTF::BPFFieldReloc *
455 return findInfo(SectionRelocs, Address);
456}
457
459 if (Id < Types.size())
460 return Types[Id];
461 return nullptr;
462}
463
469};
470
472 switch (Reloc->RelocKind) {
479 return RKG_FIELD;
483 case BTF::TYPE_MATCH:
484 case BTF::TYPE_SIZE:
485 return RKG_TYPE;
487 case BTF::ENUM_VALUE:
488 return RKG_ENUMVAL;
489 default:
490 return RKG_UNKNOWN;
491 }
492}
493
494static 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
506static 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
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
538namespace {
539struct StrOrAnon {
540 const BTFParser &BTF;
543};
544
545static 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
556 Out << "<";
557 switch (X) {
558 default:
559 Out << "reloc kind #" << X;
560 break;
562 Out << "byte_off";
563 break;
565 Out << "byte_sz";
566 break;
568 Out << "field_exists";
569 break;
571 Out << "signed";
572 break;
574 Out << "lshift_u64";
575 break;
577 Out << "rshift_u64";
578 break;
580 Out << "local_type_id";
581 break;
583 Out << "target_type_id";
584 break;
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;
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
658 SmallVectorImpl<char> &Result) const {
659 raw_svector_ostream Stream(Result);
660 StringRef FullSpecStr = findString(Reloc->OffsetNameOff);
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}
#define Fail
static RelocKindGroup relocKindGroup(const BTF::BPFFieldReloc *Reloc)
Definition: BTFParser.cpp:471
static size_t byteSize(BTF::CommonType *Type)
Definition: BTFParser.cpp:154
static bool printMod(const BTFParser &BTF, const BTF::CommonType *Type, raw_ostream &Stream)
Definition: BTFParser.cpp:506
const BTF::CommonType VoidTypeInst
Definition: BTFParser.cpp:191
static bool isMod(const BTF::CommonType *Type)
Definition: BTFParser.cpp:494
const char BTFSectionName[]
Definition: BTFParser.cpp:26
const char BTFExtSectionName[]
Definition: BTFParser.cpp:27
static void relocKindName(uint32_t X, raw_ostream &Out)
Definition: BTFParser.cpp:555
static const T * findInfo(const DenseMap< uint64_t, SmallVector< T, 0 > > &SecMap, SectionedAddress Address)
Definition: BTFParser.cpp:432
static const BTF::CommonType * skipModsAndTypedefs(const BTFParser &BTF, const BTF::CommonType *Type)
Definition: BTFParser.cpp:527
RelocKindGroup
Definition: BTFParser.cpp:464
@ RKG_UNKNOWN
Definition: BTFParser.cpp:468
@ RKG_ENUMVAL
Definition: BTFParser.cpp:467
@ RKG_FIELD
Definition: BTFParser.cpp:465
@ RKG_TYPE
Definition: BTFParser.cpp:466
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
std::string Name
uint64_t Size
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
#define I(x, y, z)
Definition: MD5.cpp:58
This file contains some functions that are useful when dealing with strings.
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
StringRef findString(uint32_t Offset) const
Definition: BTFParser.cpp:427
Error parse(const ObjectFile &Obj, const ParseOptions &Opts)
Definition: BTFParser.cpp:378
const BTF::BPFLineInfo * findLineInfo(SectionedAddress Address) const
Definition: BTFParser.cpp:449
void symbolize(const BTF::BPFFieldReloc *Reloc, SmallVectorImpl< char > &Result) const
Definition: BTFParser.cpp:657
const BTF::CommonType * findType(uint32_t Id) const
Definition: BTFParser.cpp:458
static bool hasBTFSections(const ObjectFile &Obj)
Definition: BTFParser.cpp:410
const BTF::BPFFieldReloc * findFieldReloc(SectionedAddress Address) const
Definition: BTFParser.cpp:454
A class representing a position in a DataExtractor, as well as any error encountered during extractio...
Definition: DataExtractor.h:54
uint32_t getU32(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint32_t value from *offset_ptr.
uint8_t getU8(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint8_t value from *offset_ptr.
StringRef getData() const
Get the data pointed to by this extractor.
Definition: DataExtractor.h:95
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:45
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
Error takeError()
Take ownership of the stored error.
Definition: Error.h:601
reference get()
Returns a reference to the stored T value.
Definition: Error.h:571
T * data() const
Definition: ArrayRef.h:354
This is a MutableArrayRef that owns its array.
Definition: ArrayRef.h:449
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:557
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
Definition: StringRef.h:670
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:283
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
TypeID
Definitions of all of the base types for the Type system.
Definition: Type.h:54
Type(LLVMContext &C, TypeID tid)
Definition: Type.h:94
bool isLittleEndian() const
Definition: Binary.h:155
This class is the base class for all object file types.
Definition: ObjectFile.h:229
virtual uint8_t getBytesInAddress() const =0
The number of bytes used to represent an address in this object file format.
section_iterator_range sections() const
Definition: ObjectFile.h:328
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:81
Expected< StringRef > getContents() const
Definition: ObjectFile.h:532
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
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.
Definition: raw_ostream.h:660
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:690
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
const uint64_t Version
Definition: InstrProf.h:1153
const uint64_t Magic
Definition: InstrProf.h:1114
constexpr llvm::endianness Endianness
The endianness of all multi-byte encoded values in MessagePack.
Definition: MsgPack.h:24
value_type byte_swap(value_type value, endianness endian)
Definition: Endian.h:44
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition: Error.cpp:65
void stable_sort(R &&Range)
Definition: STLExtras.h:1995
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:970
auto partition_point(R &&Range, Predicate P)
Binary search for the first iterator in a range where a predicate is false.
Definition: STLExtras.h:2008
bool consumeUnsignedInteger(StringRef &Str, unsigned Radix, unsigned long long &Result)
Definition: StringRef.cpp:408
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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)
Definition: APFixedPoint.h:293
endianness
Definition: bit.h:70
std::optional< SectionRef > findSection(StringRef Name) const
Definition: BTFParser.cpp:95
Expected< DataExtractor > makeExtractor(SectionRef Sec)
Definition: BTFParser.cpp:87
ParseContext(const ObjectFile &Obj, const ParseOptions &Opts)
Definition: BTFParser.cpp:84
const ObjectFile & Obj
Definition: BTFParser.cpp:78
DenseMap< StringRef, SectionRef > Sections
Definition: BTFParser.cpp:81
const ParseOptions & Opts
Definition: BTFParser.cpp:79
Specifying one offset relocation.
Definition: BTF.h:267
uint32_t OffsetNameOff
The string to traverse types.
Definition: BTF.h:270
uint32_t RelocKind
What to patch the instruction.
Definition: BTF.h:271
uint32_t TypeID
TypeID for the relocation.
Definition: BTF.h:269
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
uint32_t NameOff
Enum name offset in the string table.
Definition: BTF.h:163
uint32_t Val_Hi32
Enum member hi32 value.
Definition: BTF.h:165
uint32_t Val_Lo32
Enum member lo32 value.
Definition: BTF.h:164
BTF_KIND_ENUM is followed by multiple "struct BTFEnum".
Definition: BTF.h:154
int32_t Val
Enum member value.
Definition: BTF.h:156
uint32_t NameOff
Enum name offset in the string table.
Definition: BTF.h:155
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