19#define DEBUG_TYPE "debug-info-btf-parser"
45 Err(
const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {}
47 : Buffer(), Stream(Buffer) {
49 <<
" section: " <<
C.takeError();
68 operator Error()
const {
92 Obj.getBytesInAddress());
112 return Err(
".BTF",
C);
114 return Err(
"invalid .BTF magic: ").write_hex(Magic);
117 return Err(
".BTF",
C);
120 (void)Extractor.getU8(
C);
123 return Err(
".BTF",
C);
125 return Err(
"unexpected .BTF header length: ") << HdrLen;
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);
136 return Err(
".BTF",
C);
137 if (Extractor.getData().size() < BytesExpected)
138 return Err(
"invalid .BTF section size, expecting at-least ")
139 << BytesExpected <<
" bytes";
141 StringsTable = Extractor.getData().
slice(StrStart, StrEnd);
143 if (TypeLen > 0 && Ctx.Opts.LoadTypes) {
144 StringRef RawData = Extractor.getData().
slice(TypesInfoStart, TypesInfoEnd);
145 if (
Error E = parseTypesInfo(Ctx, TypesInfoStart, RawData))
156 switch (
Type->getKind()) {
157 case BTF::BTF_KIND_INT:
160 case BTF::BTF_KIND_ARRAY:
163 case BTF::BTF_KIND_VAR:
166 case BTF::BTF_KIND_DECL_TAG:
169 case BTF::BTF_KIND_STRUCT:
170 case BTF::BTF_KIND_UNION:
173 case BTF::BTF_KIND_ENUM:
176 case BTF::BTF_KIND_ENUM64:
179 case BTF::BTF_KIND_FUNC_PROTO:
182 case BTF::BTF_KIND_DATASEC:
205Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,
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);
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();
230 if (BytesLeft <
Size)
231 return Err(
"incomplete type definition in .BTF section:")
232 <<
" offset=" <<
Offset <<
", index=" << Types.size()
233 <<
", vlen=" <<
Type->getVlen();
237 <<
" Id = " << Types.size() <<
"\n"
238 <<
" Kind = " <<
Type->getKind() <<
"\n"
240 <<
" Record Size = " <<
Size <<
"\n";
242 Types.push_back(
Type);
250 Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTFExt);
254 DataExtractor &Extractor = MaybeExtractor.
get();
255 DataExtractor::Cursor
C = DataExtractor::Cursor(0);
258 return Err(
".BTF.ext",
C);
260 return Err(
"invalid .BTF.ext magic: ").write_hex(Magic);
263 return Err(
".BTF",
C);
265 return Err(
"unsupported .BTF.ext version: ") << (unsigned)
Version;
267 uint32_t HdrLen = Extractor.
getU32(
C);
269 return Err(
".BTF.ext",
C);
271 return Err(
"unexpected .BTF.ext header length: ") << HdrLen;
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);
279 return Err(
".BTF.ext",
C);
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))
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))
299 uint64_t LineInfoStart, uint64_t LineInfoEnd) {
300 DataExtractor::Cursor
C = DataExtractor::Cursor(LineInfoStart);
301 uint32_t RecSize = Extractor.
getU32(
C);
303 return Err(
".BTF.ext",
C);
305 return Err(
"unexpected .BTF.ext line info record length: ") << RecSize;
307 while (
C &&
C.tell() < LineInfoEnd) {
308 uint32_t SecNameOff = Extractor.
getU32(
C);
309 uint32_t NumInfo = Extractor.
getU32(
C);
311 std::optional<SectionRef> Sec = Ctx.findSection(SecName);
313 return Err(
".BTF.ext",
C);
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);
325 return Err(
".BTF.ext",
C);
326 Lines.push_back({InsnOff, FileNameOff, LineOff, LineCol});
327 C.seek(RecStart + RecSize);
330 [](
const BTF::BPFLineInfo &L,
const BTF::BPFLineInfo &R) {
331 return L.InsnOffset <
R.InsnOffset;
335 return Err(
".BTF.ext",
C);
341 uint64_t RelocInfoStart,
342 uint64_t RelocInfoEnd) {
343 DataExtractor::Cursor
C = DataExtractor::Cursor(RelocInfoStart);
344 uint32_t RecSize = Extractor.
getU32(
C);
346 return Err(
".BTF.ext",
C);
348 return Err(
"unexpected .BTF.ext field reloc info record length: ")
350 while (
C &&
C.tell() < RelocInfoEnd) {
351 uint32_t SecNameOff = Extractor.
getU32(
C);
352 uint32_t NumInfo = Extractor.
getU32(
C);
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);
360 uint32_t OffsetNameOff = Extractor.
getU32(
C);
361 uint32_t RelocKind = Extractor.
getU32(
C);
363 return Err(
".BTF.ext",
C);
364 Relocs.push_back({InsnOff,
TypeID, OffsetNameOff, RelocKind});
365 C.seek(RecStart + RecSize);
368 Relocs, [](
const BTF::BPFFieldReloc &L,
const BTF::BPFFieldReloc &R) {
369 return L.InsnOffset <
R.InsnOffset;
373 return Err(
".BTF.ext",
C);
380 SectionLines.clear();
381 SectionRelocs.clear();
386 std::optional<SectionRef>
BTF;
387 std::optional<SectionRef> BTFExt;
391 return Err(
"error while reading section name: ") << MaybeName.
takeError();
392 Ctx.Sections[*MaybeName] = Sec;
399 return Err(
"can't find .BTF section");
401 return Err(
"can't find .BTF.ext section");
404 if (
Error E = parseBTFExt(Ctx, *BTFExt))
412 bool HasBTFExt =
false;
415 if (
Error E = Name.takeError()) {
421 if (HasBTF && HasBTFExt)
434 auto MaybeSecInfo = SecMap.find(Address.SectionIndex);
435 if (MaybeSecInfo == SecMap.end())
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)
459 if (Id < Types.size())
472 switch (
Reloc->RelocKind) {
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:
508 switch (
Type->getKind()) {
509 case BTF::BTF_KIND_CONST:
512 case BTF::BTF_KIND_VOLATILE:
513 Stream <<
" volatile";
515 case BTF::BTF_KIND_RESTRICT:
516 Stream <<
" restrict";
518 case BTF::BTF_KIND_TYPE_TAG:
519 Stream <<
" type_tag(\"" <<
BTF.findString(
Type->NameOff) <<
"\")";
529 while (
isMod(
Type) ||
Type->getKind() == BTF::BTF_KIND_TYPEDEF) {
540 const BTFParser &BTF;
548 Stream <<
"<anon " << S.Idx <<
">";
559 Out <<
"reloc kind #" <<
X;
568 Out <<
"field_exists";
580 Out <<
"local_type_id";
583 Out <<
"target_type_id";
586 Out <<
"type_exists";
589 Out <<
"type_matches";
595 Out <<
"enumval_exists";
598 Out <<
"enumval_value";
663 auto Fail = [&](
auto Msg) {
666 Stream <<
" [" <<
Reloc->TypeID <<
"] '" << FullSpecStr <<
"'"
667 <<
" <" << Msg <<
">";
674 while (SpecStr.
size()) {
675 unsigned long long Val;
677 return Fail(
"spec string is not a number");
681 if (SpecStr[0] !=
':')
682 return Fail(
format(
"unexpected spec string delimiter: '%c'", SpecStr[0]));
683 SpecStr = SpecStr.
substr(1);
692 return Fail(
format(
"unknown type id: %d", CurId));
694 Stream <<
" [" << CurId <<
"]";
701 return Fail(
"modifiers chain is too long");
706 return Fail(
format(
"unknown type id: %d in modifiers chain", CurId));
713 switch (
Type->getKind()) {
714 case BTF::BTF_KIND_TYPEDEF:
715 Stream <<
" typedef";
717 case BTF::BTF_KIND_STRUCT:
720 case BTF::BTF_KIND_UNION:
723 case BTF::BTF_KIND_ENUM:
726 case BTF::BTF_KIND_ENUM64:
729 case BTF::BTF_KIND_FWD:
731 Stream <<
" fwd union";
733 Stream <<
" fwd struct";
738 Stream <<
" " << StrOrAnon({*
this,
Type->NameOff, CurId});
745 if (RawSpec.
size() != 1 || RawSpec[0] != 0)
746 return Fail(
"unexpected type-based relocation spec: should be '0'");
762 if (RawSpec.
size() != 1)
763 return Fail(
"unexpected enumval relocation spec size");
769 if (
T->values().size() <= Idx)
770 return Fail(
format(
"bad value index: %d", Idx));
775 if (
T->values().size() <= Idx)
776 return Fail(
format(
"bad value index: %d", Idx));
779 Val = (
uint64_t)E.Val_Hi32 << 32u | E.Val_Lo32;
781 return Fail(
format(
"unexpected type kind for enum relocation: %d",
785 Stream << StrOrAnon({*
this, NameOff, Idx});
787 Stream <<
" = " << (int64_t)Val;
816 if (RawSpec.
size() < 1)
817 return Fail(
"field spec too short");
820 Stream <<
"[" << RawSpec[0] <<
"]";
826 if (
T->getVlen() <= Idx)
828 format(
"member index %d for spec sub-string %d is out of range",
832 if (
I != 1 || RawSpec[0] != 0)
834 Stream << StrOrAnon({*
this, Member.NameOff, Idx});
837 return Fail(
format(
"unknown member type id %d for spec sub-string %d",
840 Stream <<
"[" << Idx <<
"]";
844 format(
"unknown element type id %d for spec sub-string %d",
845 T->getArray().ElemType,
I));
847 return Fail(
format(
"unexpected type kind %d for spec sub-string %d",
848 Type->getKind(),
I));
852 Stream <<
" (" << FullSpecStr <<
")";
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[]
const char BTFExtSectionName[]
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)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
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
Base class for error info classes.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
This is a MutableArrayRef that owns its array.
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.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
constexpr bool empty() const
empty - Check if the string is empty.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
The instances of the Type class are immutable: once they are created, they are never changed.
Type(LLVMContext &C, TypeID tid)
This class is the base class for all object file types.
section_iterator_range sections() const
This is a value type class that represents a single section in the list of sections in the object fil...
Expected< StringRef > getContents() const
This class implements an extremely fast bulk output stream that can only output to a stream.
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
constexpr uint32_t FWD_UNION_FLAG
@ C
The default llvm calling convention, compatible with C.
constexpr llvm::endianness Endianness
The endianness of all multi-byte encoded values in MessagePack.
value_type byte_swap(value_type value, endianness endian)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
void stable_sort(R &&Range)
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.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
auto partition_point(R &&Range, Predicate P)
Binary search for the first iterator in a range where a predicate is false.
LLVM_ABI bool consumeUnsignedInteger(StringRef &Str, unsigned Radix, unsigned long long &Result)
FunctionAddr VTableAddr uintptr_t uintptr_t Version
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
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)
std::optional< SectionRef > findSection(StringRef Name) const
Expected< DataExtractor > makeExtractor(SectionRef Sec)
ParseContext(const ObjectFile &Obj, const ParseOptions &Opts)
DenseMap< StringRef, SectionRef > Sections
const ParseOptions & Opts
Specifying one offset relocation.
Specifying one line info.
BTF_KIND_ARRAY is followed by one "struct BTFArray".
BTF_KIND_DATASEC are followed by multiple "struct BTFDataSecVar".
BTF_KIND_ENUM64 is followed by multiple "struct BTFEnum64".
BTF_KIND_ENUM is followed by multiple "struct BTFEnum".
BTF_KIND_STRUCT and BTF_KIND_UNION are followed by multiple "struct BTFMember".
BTF_KIND_FUNC_PROTO are followed by multiple "struct BTFParam".
The BTF common type definition.