//===- BTFParser.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // BTFParser reads/interprets .BTF and .BTF.ext ELF sections. // Refer to BTFParser.h for API description. // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/BTF/BTFParser.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Errc.h" #define DEBUG_TYPE … usingnamespacellvm; ObjectFile; SectionedAddress; SectionRef; const char BTFSectionName[] = …; const char BTFExtSectionName[] = …; // Utility class with API similar to raw_ostream but can be cast // to Error, e.g.: // // Error foo(...) { // ... // if (Error E = bar(...)) // return Err("error while foo(): ") << E; // ... // } // namespace { class Err { … }; } // anonymous namespace // ParseContext wraps information that is only necessary while parsing // ObjectFile and can be discarded once parsing is done. // Used by BTFParser::parse* auxiliary functions. struct BTFParser::ParseContext { … }; Error BTFParser::parseBTF(ParseContext &Ctx, SectionRef BTF) { … } // Compute record size for each BTF::CommonType sub-type // (including entries in the tail position). static size_t byteSize(BTF::CommonType *Type) { … } // Guard value for voids, simplifies code a bit, but NameOff is not // actually valid. const BTF::CommonType VoidTypeInst = …; // Type information "parsing" is very primitive: // - The `RawData` is copied to a buffer owned by `BTFParser` instance. // - The buffer is treated as an array of `uint32_t` values, each value // is swapped to use native endianness. This is possible, because // according to BTF spec all buffer elements are structures comprised // of `uint32_t` fields. // - `BTFParser::Types` vector is filled with pointers to buffer // elements, using `byteSize()` function to slice the buffer at type // record boundaries. // - If at some point a type definition with incorrect size (logical size // exceeding buffer boundaries) is reached it is not added to the // `BTFParser::Types` vector and the process stops. Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart, StringRef RawData) { … } Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) { … } Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor, uint64_t LineInfoStart, uint64_t LineInfoEnd) { … } Error BTFParser::parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor, uint64_t RelocInfoStart, uint64_t RelocInfoEnd) { … } Error BTFParser::parse(const ObjectFile &Obj, const ParseOptions &Opts) { … } bool BTFParser::hasBTFSections(const ObjectFile &Obj) { … } StringRef BTFParser::findString(uint32_t Offset) const { … } template <typename T> static const T *findInfo(const DenseMap<uint64_t, SmallVector<T, 0>> &SecMap, SectionedAddress Address) { … } const BTF::BPFLineInfo * BTFParser::findLineInfo(SectionedAddress Address) const { … } const BTF::BPFFieldReloc * BTFParser::findFieldReloc(SectionedAddress Address) const { … } const BTF::CommonType *BTFParser::findType(uint32_t Id) const { … } enum RelocKindGroup { … }; static RelocKindGroup relocKindGroup(const BTF::BPFFieldReloc *Reloc) { … } static bool isMod(const BTF::CommonType *Type) { … } static bool printMod(const BTFParser &BTF, const BTF::CommonType *Type, raw_ostream &Stream) { … } static const BTF::CommonType *skipModsAndTypedefs(const BTFParser &BTF, const BTF::CommonType *Type) { … } namespace { struct StrOrAnon { … }; static raw_ostream &operator<<(raw_ostream &Stream, const StrOrAnon &S) { … } } // anonymous namespace static void relocKindName(uint32_t X, raw_ostream &Out) { … } // Produces a human readable description of a CO-RE relocation. // Such relocations are generated by BPF backend, and processed // by libbpf's BPF program loader [1]. // // Each relocation record has the following information: // - Relocation kind; // - BTF type ID; // - Access string offset in string table. // // There are different kinds of relocations, these kinds could be split // in three groups: // - load-time information about types (size, existence), // `BTFParser::symbolize()` output for such relocations uses the template: // // <relocation-kind> [<id>] <type-name> // // For example: // - "<type_exists> [7] struct foo" // - "<type_size> [7] struct foo" // // - load-time information about enums (literal existence, literal value), // `BTFParser::symbolize()` output for such relocations uses the template: // // <relocation-kind> [<id>] <type-name>::<literal-name> = <original-value> // // For example: // - "<enumval_exists> [5] enum foo::U = 1" // - "<enumval_value> [5] enum foo::V = 2" // // - load-time information about fields (e.g. field offset), // `BTFParser::symbolize()` output for such relocations uses the template: // // <relocation-kind> [<id>] \ // <type-name>::[N].<field-1-name>...<field-M-name> \ // (<access string>) // // For example: // - "<byte_off> [8] struct bar::[7].v (7:1)" // - "<field_exists> [8] struct bar::v (0:1)" // // If relocation description is not valid output follows the following pattern: // // <relocation-kind> <type-id>::<unprocessedaccess-string> <<error-msg>> // // For example: // // - "<type_sz> [42] '' <unknown type id: 42>" // - "<byte_off> [4] '0:' <field spec too short>" // // Additional examples could be found in unit tests, see // llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp. // // [1] https://www.kernel.org/doc/html/latest/bpf/libbpf/index.html void BTFParser::symbolize(const BTF::BPFFieldReloc *Reloc, SmallVectorImpl<char> &Result) const { … }