LLVM: lib/DebugInfo/BTF/BTFParser.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

18

19#define DEBUG_TYPE "debug-info-btf-parser"

20

21using namespace llvm;

25

28

29

30

31

32

33

34

35

36

37

38

39namespace {

40class Err {

41 std::string Buffer;

43

44public:

45 Err(const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {}

47 : Buffer(), Stream(Buffer) {

48 *this << "error while reading " << SectionName

49 << " section: " << C.takeError();

50 };

51

52 template Err &operator<<(T Val) {

53 Stream << Val;

54 return *this;

55 }

56

57 Err &write_hex(unsigned long long Val) {

59 return *this;

60 }

61

65 return *this;

66 }

67

68 operator Error() const {

70 }

71};

72}

73

74

75

76

80

82

83public:

86

89 if (!Contents)

92 Obj.getBytesInAddress());

93 }

94

96 auto It = Sections.find(Name);

98 return It->second;

99 return std::nullopt;

100 }

101};

102

105 if (!MaybeExtractor)

106 return MaybeExtractor.takeError();

107

110 uint16_t Magic = Extractor.getU16(C);

111 if (C)

112 return Err(".BTF", C);

114 return Err("invalid .BTF magic: ").write_hex(Magic);

116 if (C)

117 return Err(".BTF", C);

119 return Err("unsupported .BTF version: ") << (unsigned)Version;

120 (void)Extractor.getU8(C);

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

150}

151

152

153

156 switch (Type->getKind()) {

157 case BTF::BTF_KIND_INT:

159 break;

160 case BTF::BTF_KIND_ARRAY:

162 break;

163 case BTF::BTF_KIND_VAR:

165 break;

166 case BTF::BTF_KIND_DECL_TAG:

168 break;

169 case BTF::BTF_KIND_STRUCT:

170 case BTF::BTF_KIND_UNION:

172 break;

173 case BTF::BTF_KIND_ENUM:

175 break;

176 case BTF::BTF_KIND_ENUM64:

178 break;

179 case BTF::BTF_KIND_FUNC_PROTO:

181 break;

182 case BTF::BTF_KIND_DATASEC:

184 break;

185 }

187}

188

189

190

192

193

194

195

196

197

198

199

200

201

202

203

204

205Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,

208

210

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

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

237 << " Id = " << Types.size() << "\n"

238 << " Kind = " << Type->getKind() << "\n"

240 << " Record Size = " << Size << "\n";

241 });

242 Types.push_back(Type);

244 }

245

247}

248

249Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) {

250 Expected MaybeExtractor = Ctx.makeExtractor(BTFExt);

251 if (!MaybeExtractor)

252 return MaybeExtractor.takeError();

253

254 DataExtractor &Extractor = MaybeExtractor.get();

255 DataExtractor::Cursor C = DataExtractor::Cursor(0);

257 if (C)

258 return Err(".BTF.ext", C);

260 return Err("invalid .BTF.ext magic: ").write_hex(Magic);

262 if (C)

263 return Err(".BTF", C);

265 return Err("unsupported .BTF.ext version: ") << (unsigned)Version;

266 (void)Extractor.getU8(C);

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);

273 (void)Extractor.getU32(C);

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

296}

297

298Error 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 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 }

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

338}

339

340Error 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 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);

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

376}

377

380 SectionLines.clear();

381 SectionRelocs.clear();

382 Types.clear();

384

386 std::optional BTF;

387 std::optional BTFExt;

388 for (SectionRef Sec : Obj.sections()) {

390 if (!MaybeName)

391 return Err("error while reading section name: ") << MaybeName.takeError();

392 Ctx.Sections[*MaybeName] = Sec;

394 BTF = Sec;

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

408}

409

411 bool HasBTF = false;

412 bool HasBTFExt = false;

413 for (SectionRef Sec : Obj.sections()) {

415 if (Error E = Name.takeError()) {

417 continue;

418 }

421 if (HasBTF && HasBTFExt)

422 return true;

423 }

424 return false;

425}

426

430

431template

434 auto MaybeSecInfo = SecMap.find(Address.SectionIndex);

435 if (MaybeSecInfo == SecMap.end())

436 return nullptr;

437

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

452

457

459 if (Id < Types.size())

460 return Types[Id];

461 return nullptr;

462}

463

470

472 switch (Reloc->RelocKind) {

489 default:

491 }

492}

493

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

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

529 while (isMod(Type) || Type->getKind() == BTF::BTF_KIND_TYPEDEF) {

532 break;

534 }

536}

537

538namespace {

539struct StrOrAnon {

540 const BTFParser &BTF;

542 uint32_t Idx;

543};

544

547 if (Str.empty())

548 Stream << "<anon " << S.Idx << ">";

549 else

550 Stream << Str;

551 return Stream;

552}

553}

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;

589 Out << "type_matches";

590 break;

592 Out << "type_size";

593 break;

595 Out << "enumval_exists";

596 break;

598 Out << "enumval_value";

599 break;

600 }

601 Out << ">";

602}

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

662

663 auto Fail = [&](auto Msg) {

664 Result.resize(0);

666 Stream << " [" << Reloc->TypeID << "] '" << FullSpecStr << "'"

667 << " <" << Msg << ">";

668 };

669

670

671

672

674 while (SpecStr.size()) {

675 unsigned long long Val;

677 return Fail("spec string is not a number");

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

688

692 return Fail(format("unknown type id: %d", CurId));

693

694 Stream << " [" << CurId << "]";

695

696

697

698

700 if (ChainLen >= 32)

701 return Fail("modifiers chain is too long");

702

705 if (!NextType)

706 return Fail(format("unknown type id: %d in modifiers chain", CurId));

707 Type = NextType;

708 }

709

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:

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

742

743

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

753

754

755

756

757

758

761

762 if (RawSpec.size() != 1)

763 return Fail("unexpected enumval relocation spec size");

764

769 if (T->values().size() <= Idx)

770 return Fail(format("bad value index: %d", Idx));

772 NameOff = E.NameOff;

773 Val = E.Val;

775 if (T->values().size() <= Idx)

776 return Fail(format("bad value index: %d", 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});

787 Stream << " = " << (int64_t)Val;

788 else

789 Stream << " = " << (uint64_t)Val;

790 return;

791 }

792

793

794

795

796

797

798

799

800

801

802

803

804

805

806

807

808

809

810

811

812

813

814

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) {

824

826 if (T->getVlen() <= Idx)

828 format("member index %d for spec sub-string %d is out of range",

829 Idx, I));

830

832 if (I != 1 || RawSpec[0] != 0)

833 Stream << ".";

834 Stream << StrOrAnon({*this, Member.NameOff, Idx});

837 return Fail(format("unknown member type id %d for spec sub-string %d",

838 Member.Type, I));

840 Stream << "[" << Idx << "]";

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}

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

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

Definition BTFParser.cpp:427

LLVM_ABI Error parse(const ObjectFile &Obj, const ParseOptions &Opts)

Definition BTFParser.cpp:378

LLVM_ABI const BTF::BPFLineInfo * findLineInfo(SectionedAddress Address) const

Definition BTFParser.cpp:449

LLVM_ABI void symbolize(const BTF::BPFFieldReloc *Reloc, SmallVectorImpl< char > &Result) const

Definition BTFParser.cpp:657

LLVM_ABI const BTF::CommonType * findType(uint32_t Id) const

Definition BTFParser.cpp:458

static LLVM_ABI bool hasBTFSections(const ObjectFile &Obj)

Definition BTFParser.cpp:410

LLVM_ABI const BTF::BPFFieldReloc * findFieldReloc(SectionedAddress Address) const

Definition BTFParser.cpp:454

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.

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 - 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)

Definition BTFParser.cpp:77

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.

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.