xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/BTF/BTFParser.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
106c3fb27SDimitry Andric //===- BTFParser.cpp ------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // BTFParser reads/interprets .BTF and .BTF.ext ELF sections.
1006c3fb27SDimitry Andric // Refer to BTFParser.h for API description.
1106c3fb27SDimitry Andric //
1206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1306c3fb27SDimitry Andric 
1406c3fb27SDimitry Andric #include "llvm/DebugInfo/BTF/BTFParser.h"
15*5f757f3fSDimitry Andric #include "llvm/ADT/StringExtras.h"
16*5f757f3fSDimitry Andric #include "llvm/Support/Endian.h"
1706c3fb27SDimitry Andric #include "llvm/Support/Errc.h"
1806c3fb27SDimitry Andric 
1906c3fb27SDimitry Andric #define DEBUG_TYPE "debug-info-btf-parser"
2006c3fb27SDimitry Andric 
2106c3fb27SDimitry Andric using namespace llvm;
2206c3fb27SDimitry Andric using object::ObjectFile;
2306c3fb27SDimitry Andric using object::SectionedAddress;
2406c3fb27SDimitry Andric using object::SectionRef;
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric const char BTFSectionName[] = ".BTF";
2706c3fb27SDimitry Andric const char BTFExtSectionName[] = ".BTF.ext";
2806c3fb27SDimitry Andric 
2906c3fb27SDimitry Andric // Utility class with API similar to raw_ostream but can be cast
3006c3fb27SDimitry Andric // to Error, e.g.:
3106c3fb27SDimitry Andric //
3206c3fb27SDimitry Andric // Error foo(...) {
3306c3fb27SDimitry Andric //   ...
3406c3fb27SDimitry Andric //   if (Error E = bar(...))
3506c3fb27SDimitry Andric //     return Err("error while foo(): ") << E;
3606c3fb27SDimitry Andric //   ...
3706c3fb27SDimitry Andric // }
3806c3fb27SDimitry Andric //
3906c3fb27SDimitry Andric namespace {
4006c3fb27SDimitry Andric class Err {
4106c3fb27SDimitry Andric   std::string Buffer;
4206c3fb27SDimitry Andric   raw_string_ostream Stream;
4306c3fb27SDimitry Andric 
4406c3fb27SDimitry Andric public:
Err(const char * InitialMsg)4506c3fb27SDimitry Andric   Err(const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {}
Err(const char * SectionName,DataExtractor::Cursor & C)4606c3fb27SDimitry Andric   Err(const char *SectionName, DataExtractor::Cursor &C)
4706c3fb27SDimitry Andric       : Buffer(), Stream(Buffer) {
4806c3fb27SDimitry Andric     *this << "error while reading " << SectionName
4906c3fb27SDimitry Andric           << " section: " << C.takeError();
5006c3fb27SDimitry Andric   };
5106c3fb27SDimitry Andric 
operator <<(T Val)5206c3fb27SDimitry Andric   template <typename T> Err &operator<<(T Val) {
5306c3fb27SDimitry Andric     Stream << Val;
5406c3fb27SDimitry Andric     return *this;
5506c3fb27SDimitry Andric   }
5606c3fb27SDimitry Andric 
write_hex(unsigned long long Val)5706c3fb27SDimitry Andric   Err &write_hex(unsigned long long Val) {
5806c3fb27SDimitry Andric     Stream.write_hex(Val);
5906c3fb27SDimitry Andric     return *this;
6006c3fb27SDimitry Andric   }
6106c3fb27SDimitry Andric 
operator <<(Error Val)6206c3fb27SDimitry Andric   Err &operator<<(Error Val) {
6306c3fb27SDimitry Andric     handleAllErrors(std::move(Val),
6406c3fb27SDimitry Andric                     [=](ErrorInfoBase &Info) { Stream << Info.message(); });
6506c3fb27SDimitry Andric     return *this;
6606c3fb27SDimitry Andric   }
6706c3fb27SDimitry Andric 
operator Error() const6806c3fb27SDimitry Andric   operator Error() const {
6906c3fb27SDimitry Andric     return make_error<StringError>(Buffer, errc::invalid_argument);
7006c3fb27SDimitry Andric   }
7106c3fb27SDimitry Andric };
7206c3fb27SDimitry Andric } // anonymous namespace
7306c3fb27SDimitry Andric 
7406c3fb27SDimitry Andric // ParseContext wraps information that is only necessary while parsing
7506c3fb27SDimitry Andric // ObjectFile and can be discarded once parsing is done.
7606c3fb27SDimitry Andric // Used by BTFParser::parse* auxiliary functions.
7706c3fb27SDimitry Andric struct BTFParser::ParseContext {
7806c3fb27SDimitry Andric   const ObjectFile &Obj;
79*5f757f3fSDimitry Andric   const ParseOptions &Opts;
8006c3fb27SDimitry Andric   // Map from ELF section name to SectionRef
8106c3fb27SDimitry Andric   DenseMap<StringRef, SectionRef> Sections;
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric public:
ParseContextBTFParser::ParseContext84*5f757f3fSDimitry Andric   ParseContext(const ObjectFile &Obj, const ParseOptions &Opts)
85*5f757f3fSDimitry Andric       : Obj(Obj), Opts(Opts) {}
8606c3fb27SDimitry Andric 
makeExtractorBTFParser::ParseContext8706c3fb27SDimitry Andric   Expected<DataExtractor> makeExtractor(SectionRef Sec) {
8806c3fb27SDimitry Andric     Expected<StringRef> Contents = Sec.getContents();
8906c3fb27SDimitry Andric     if (!Contents)
9006c3fb27SDimitry Andric       return Contents.takeError();
9106c3fb27SDimitry Andric     return DataExtractor(Contents.get(), Obj.isLittleEndian(),
9206c3fb27SDimitry Andric                          Obj.getBytesInAddress());
9306c3fb27SDimitry Andric   }
9406c3fb27SDimitry Andric 
findSectionBTFParser::ParseContext9506c3fb27SDimitry Andric   std::optional<SectionRef> findSection(StringRef Name) const {
9606c3fb27SDimitry Andric     auto It = Sections.find(Name);
9706c3fb27SDimitry Andric     if (It != Sections.end())
9806c3fb27SDimitry Andric       return It->second;
9906c3fb27SDimitry Andric     return std::nullopt;
10006c3fb27SDimitry Andric   }
10106c3fb27SDimitry Andric };
10206c3fb27SDimitry Andric 
parseBTF(ParseContext & Ctx,SectionRef BTF)10306c3fb27SDimitry Andric Error BTFParser::parseBTF(ParseContext &Ctx, SectionRef BTF) {
10406c3fb27SDimitry Andric   Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTF);
10506c3fb27SDimitry Andric   if (!MaybeExtractor)
10606c3fb27SDimitry Andric     return MaybeExtractor.takeError();
10706c3fb27SDimitry Andric 
10806c3fb27SDimitry Andric   DataExtractor &Extractor = MaybeExtractor.get();
10906c3fb27SDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(0);
11006c3fb27SDimitry Andric   uint16_t Magic = Extractor.getU16(C);
11106c3fb27SDimitry Andric   if (!C)
11206c3fb27SDimitry Andric     return Err(".BTF", C);
11306c3fb27SDimitry Andric   if (Magic != BTF::MAGIC)
11406c3fb27SDimitry Andric     return Err("invalid .BTF magic: ").write_hex(Magic);
11506c3fb27SDimitry Andric   uint8_t Version = Extractor.getU8(C);
11606c3fb27SDimitry Andric   if (!C)
11706c3fb27SDimitry Andric     return Err(".BTF", C);
11806c3fb27SDimitry Andric   if (Version != 1)
11906c3fb27SDimitry Andric     return Err("unsupported .BTF version: ") << (unsigned)Version;
12006c3fb27SDimitry Andric   (void)Extractor.getU8(C); // flags
12106c3fb27SDimitry Andric   uint32_t HdrLen = Extractor.getU32(C);
12206c3fb27SDimitry Andric   if (!C)
12306c3fb27SDimitry Andric     return Err(".BTF", C);
12406c3fb27SDimitry Andric   if (HdrLen < 8)
12506c3fb27SDimitry Andric     return Err("unexpected .BTF header length: ") << HdrLen;
126*5f757f3fSDimitry Andric   uint32_t TypeOff = Extractor.getU32(C);
127*5f757f3fSDimitry Andric   uint32_t TypeLen = Extractor.getU32(C);
12806c3fb27SDimitry Andric   uint32_t StrOff = Extractor.getU32(C);
12906c3fb27SDimitry Andric   uint32_t StrLen = Extractor.getU32(C);
13006c3fb27SDimitry Andric   uint32_t StrStart = HdrLen + StrOff;
13106c3fb27SDimitry Andric   uint32_t StrEnd = StrStart + StrLen;
132*5f757f3fSDimitry Andric   uint32_t TypesInfoStart = HdrLen + TypeOff;
133*5f757f3fSDimitry Andric   uint32_t TypesInfoEnd = TypesInfoStart + TypeLen;
134*5f757f3fSDimitry Andric   uint32_t BytesExpected = std::max(StrEnd, TypesInfoEnd);
13506c3fb27SDimitry Andric   if (!C)
13606c3fb27SDimitry Andric     return Err(".BTF", C);
137*5f757f3fSDimitry Andric   if (Extractor.getData().size() < BytesExpected)
13806c3fb27SDimitry Andric     return Err("invalid .BTF section size, expecting at-least ")
139*5f757f3fSDimitry Andric            << BytesExpected << " bytes";
14006c3fb27SDimitry Andric 
141*5f757f3fSDimitry Andric   StringsTable = Extractor.getData().slice(StrStart, StrEnd);
142*5f757f3fSDimitry Andric 
143*5f757f3fSDimitry Andric   if (TypeLen > 0 && Ctx.Opts.LoadTypes) {
144*5f757f3fSDimitry Andric     StringRef RawData = Extractor.getData().slice(TypesInfoStart, TypesInfoEnd);
145*5f757f3fSDimitry Andric     if (Error E = parseTypesInfo(Ctx, TypesInfoStart, RawData))
146*5f757f3fSDimitry Andric       return E;
147*5f757f3fSDimitry Andric   }
148*5f757f3fSDimitry Andric 
149*5f757f3fSDimitry Andric   return Error::success();
150*5f757f3fSDimitry Andric }
151*5f757f3fSDimitry Andric 
152*5f757f3fSDimitry Andric // Compute record size for each BTF::CommonType sub-type
153*5f757f3fSDimitry Andric // (including entries in the tail position).
byteSize(BTF::CommonType * Type)154*5f757f3fSDimitry Andric static size_t byteSize(BTF::CommonType *Type) {
155*5f757f3fSDimitry Andric   size_t Size = sizeof(BTF::CommonType);
156*5f757f3fSDimitry Andric   switch (Type->getKind()) {
157*5f757f3fSDimitry Andric   case BTF::BTF_KIND_INT:
158*5f757f3fSDimitry Andric     Size += sizeof(uint32_t);
159*5f757f3fSDimitry Andric     break;
160*5f757f3fSDimitry Andric   case BTF::BTF_KIND_ARRAY:
161*5f757f3fSDimitry Andric     Size += sizeof(BTF::BTFArray);
162*5f757f3fSDimitry Andric     break;
163*5f757f3fSDimitry Andric   case BTF::BTF_KIND_VAR:
164*5f757f3fSDimitry Andric     Size += sizeof(uint32_t);
165*5f757f3fSDimitry Andric     break;
166*5f757f3fSDimitry Andric   case BTF::BTF_KIND_DECL_TAG:
167*5f757f3fSDimitry Andric     Size += sizeof(uint32_t);
168*5f757f3fSDimitry Andric     break;
169*5f757f3fSDimitry Andric   case BTF::BTF_KIND_STRUCT:
170*5f757f3fSDimitry Andric   case BTF::BTF_KIND_UNION:
171*5f757f3fSDimitry Andric     Size += sizeof(BTF::BTFMember) * Type->getVlen();
172*5f757f3fSDimitry Andric     break;
173*5f757f3fSDimitry Andric   case BTF::BTF_KIND_ENUM:
174*5f757f3fSDimitry Andric     Size += sizeof(BTF::BTFEnum) * Type->getVlen();
175*5f757f3fSDimitry Andric     break;
176*5f757f3fSDimitry Andric   case BTF::BTF_KIND_ENUM64:
177*5f757f3fSDimitry Andric     Size += sizeof(BTF::BTFEnum64) * Type->getVlen();
178*5f757f3fSDimitry Andric     break;
179*5f757f3fSDimitry Andric   case BTF::BTF_KIND_FUNC_PROTO:
180*5f757f3fSDimitry Andric     Size += sizeof(BTF::BTFParam) * Type->getVlen();
181*5f757f3fSDimitry Andric     break;
182*5f757f3fSDimitry Andric   case BTF::BTF_KIND_DATASEC:
183*5f757f3fSDimitry Andric     Size += sizeof(BTF::BTFDataSec) * Type->getVlen();
184*5f757f3fSDimitry Andric     break;
185*5f757f3fSDimitry Andric   }
186*5f757f3fSDimitry Andric   return Size;
187*5f757f3fSDimitry Andric }
188*5f757f3fSDimitry Andric 
189*5f757f3fSDimitry Andric // Guard value for voids, simplifies code a bit, but NameOff is not
190*5f757f3fSDimitry Andric // actually valid.
191*5f757f3fSDimitry Andric const BTF::CommonType VoidTypeInst = {0, BTF::BTF_KIND_UNKN << 24, {0}};
192*5f757f3fSDimitry Andric 
193*5f757f3fSDimitry Andric // Type information "parsing" is very primitive:
194*5f757f3fSDimitry Andric // - The `RawData` is copied to a buffer owned by `BTFParser` instance.
195*5f757f3fSDimitry Andric // - The buffer is treated as an array of `uint32_t` values, each value
196*5f757f3fSDimitry Andric //   is swapped to use native endianness. This is possible, because
197*5f757f3fSDimitry Andric //   according to BTF spec all buffer elements are structures comprised
198*5f757f3fSDimitry Andric //   of `uint32_t` fields.
199*5f757f3fSDimitry Andric // - `BTFParser::Types` vector is filled with pointers to buffer
200*5f757f3fSDimitry Andric //   elements, using `byteSize()` function to slice the buffer at type
201*5f757f3fSDimitry Andric //   record boundaries.
202*5f757f3fSDimitry Andric // - If at some point a type definition with incorrect size (logical size
203*5f757f3fSDimitry Andric //   exceeding buffer boundaries) is reached it is not added to the
204*5f757f3fSDimitry Andric //   `BTFParser::Types` vector and the process stops.
parseTypesInfo(ParseContext & Ctx,uint64_t TypesInfoStart,StringRef RawData)205*5f757f3fSDimitry Andric Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart,
206*5f757f3fSDimitry Andric                                 StringRef RawData) {
207*5f757f3fSDimitry Andric   using support::endian::byte_swap;
208*5f757f3fSDimitry Andric 
209*5f757f3fSDimitry Andric   TypesBuffer = OwningArrayRef<uint8_t>(arrayRefFromStringRef(RawData));
210*5f757f3fSDimitry Andric   // Switch endianness if necessary.
211*5f757f3fSDimitry Andric   endianness Endianness = Ctx.Obj.isLittleEndian() ? llvm::endianness::little
212*5f757f3fSDimitry Andric                                                    : llvm::endianness::big;
213*5f757f3fSDimitry Andric   uint32_t *TypesBuffer32 = (uint32_t *)TypesBuffer.data();
214*5f757f3fSDimitry Andric   for (uint64_t I = 0; I < TypesBuffer.size() / 4; ++I)
215*5f757f3fSDimitry Andric     TypesBuffer32[I] = byte_swap(TypesBuffer32[I], Endianness);
216*5f757f3fSDimitry Andric 
217*5f757f3fSDimitry Andric   // The type id 0 is reserved for void type.
218*5f757f3fSDimitry Andric   Types.push_back(&VoidTypeInst);
219*5f757f3fSDimitry Andric 
220*5f757f3fSDimitry Andric   uint64_t Pos = 0;
221*5f757f3fSDimitry Andric   while (Pos < RawData.size()) {
222*5f757f3fSDimitry Andric     uint64_t BytesLeft = RawData.size() - Pos;
223*5f757f3fSDimitry Andric     uint64_t Offset = TypesInfoStart + Pos;
224*5f757f3fSDimitry Andric     BTF::CommonType *Type = (BTF::CommonType *)&TypesBuffer[Pos];
225*5f757f3fSDimitry Andric     if (BytesLeft < sizeof(*Type))
226*5f757f3fSDimitry Andric       return Err("incomplete type definition in .BTF section:")
227*5f757f3fSDimitry Andric              << " offset " << Offset << ", index " << Types.size();
228*5f757f3fSDimitry Andric 
229*5f757f3fSDimitry Andric     uint64_t Size = byteSize(Type);
230*5f757f3fSDimitry Andric     if (BytesLeft < Size)
231*5f757f3fSDimitry Andric       return Err("incomplete type definition in .BTF section:")
232*5f757f3fSDimitry Andric              << " offset=" << Offset << ", index=" << Types.size()
233*5f757f3fSDimitry Andric              << ", vlen=" << Type->getVlen();
234*5f757f3fSDimitry Andric 
235*5f757f3fSDimitry Andric     LLVM_DEBUG({
236*5f757f3fSDimitry Andric       llvm::dbgs() << "Adding BTF type:\n"
237*5f757f3fSDimitry Andric                    << "  Id = " << Types.size() << "\n"
238*5f757f3fSDimitry Andric                    << "  Kind = " << Type->getKind() << "\n"
239*5f757f3fSDimitry Andric                    << "  Name = " << findString(Type->NameOff) << "\n"
240*5f757f3fSDimitry Andric                    << "  Record Size = " << Size << "\n";
241*5f757f3fSDimitry Andric     });
242*5f757f3fSDimitry Andric     Types.push_back(Type);
243*5f757f3fSDimitry Andric     Pos += Size;
244*5f757f3fSDimitry Andric   }
245*5f757f3fSDimitry Andric 
24606c3fb27SDimitry Andric   return Error::success();
24706c3fb27SDimitry Andric }
24806c3fb27SDimitry Andric 
parseBTFExt(ParseContext & Ctx,SectionRef BTFExt)24906c3fb27SDimitry Andric Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) {
25006c3fb27SDimitry Andric   Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTFExt);
25106c3fb27SDimitry Andric   if (!MaybeExtractor)
25206c3fb27SDimitry Andric     return MaybeExtractor.takeError();
25306c3fb27SDimitry Andric 
25406c3fb27SDimitry Andric   DataExtractor &Extractor = MaybeExtractor.get();
25506c3fb27SDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(0);
25606c3fb27SDimitry Andric   uint16_t Magic = Extractor.getU16(C);
25706c3fb27SDimitry Andric   if (!C)
25806c3fb27SDimitry Andric     return Err(".BTF.ext", C);
25906c3fb27SDimitry Andric   if (Magic != BTF::MAGIC)
26006c3fb27SDimitry Andric     return Err("invalid .BTF.ext magic: ").write_hex(Magic);
26106c3fb27SDimitry Andric   uint8_t Version = Extractor.getU8(C);
26206c3fb27SDimitry Andric   if (!C)
26306c3fb27SDimitry Andric     return Err(".BTF", C);
26406c3fb27SDimitry Andric   if (Version != 1)
26506c3fb27SDimitry Andric     return Err("unsupported .BTF.ext version: ") << (unsigned)Version;
26606c3fb27SDimitry Andric   (void)Extractor.getU8(C); // flags
26706c3fb27SDimitry Andric   uint32_t HdrLen = Extractor.getU32(C);
26806c3fb27SDimitry Andric   if (!C)
26906c3fb27SDimitry Andric     return Err(".BTF.ext", C);
27006c3fb27SDimitry Andric   if (HdrLen < 8)
27106c3fb27SDimitry Andric     return Err("unexpected .BTF.ext header length: ") << HdrLen;
27206c3fb27SDimitry Andric   (void)Extractor.getU32(C); // func_info_off
27306c3fb27SDimitry Andric   (void)Extractor.getU32(C); // func_info_len
27406c3fb27SDimitry Andric   uint32_t LineInfoOff = Extractor.getU32(C);
27506c3fb27SDimitry Andric   uint32_t LineInfoLen = Extractor.getU32(C);
276*5f757f3fSDimitry Andric   uint32_t RelocInfoOff = Extractor.getU32(C);
277*5f757f3fSDimitry Andric   uint32_t RelocInfoLen = Extractor.getU32(C);
27806c3fb27SDimitry Andric   if (!C)
27906c3fb27SDimitry Andric     return Err(".BTF.ext", C);
280*5f757f3fSDimitry Andric 
281*5f757f3fSDimitry Andric   if (LineInfoLen > 0 && Ctx.Opts.LoadLines) {
28206c3fb27SDimitry Andric     uint32_t LineInfoStart = HdrLen + LineInfoOff;
28306c3fb27SDimitry Andric     uint32_t LineInfoEnd = LineInfoStart + LineInfoLen;
28406c3fb27SDimitry Andric     if (Error E = parseLineInfo(Ctx, Extractor, LineInfoStart, LineInfoEnd))
28506c3fb27SDimitry Andric       return E;
286*5f757f3fSDimitry Andric   }
287*5f757f3fSDimitry Andric 
288*5f757f3fSDimitry Andric   if (RelocInfoLen > 0 && Ctx.Opts.LoadRelocs) {
289*5f757f3fSDimitry Andric     uint32_t RelocInfoStart = HdrLen + RelocInfoOff;
290*5f757f3fSDimitry Andric     uint32_t RelocInfoEnd = RelocInfoStart + RelocInfoLen;
291*5f757f3fSDimitry Andric     if (Error E = parseRelocInfo(Ctx, Extractor, RelocInfoStart, RelocInfoEnd))
292*5f757f3fSDimitry Andric       return E;
293*5f757f3fSDimitry Andric   }
29406c3fb27SDimitry Andric 
29506c3fb27SDimitry Andric   return Error::success();
29606c3fb27SDimitry Andric }
29706c3fb27SDimitry Andric 
parseLineInfo(ParseContext & Ctx,DataExtractor & Extractor,uint64_t LineInfoStart,uint64_t LineInfoEnd)29806c3fb27SDimitry Andric Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor,
29906c3fb27SDimitry Andric                                uint64_t LineInfoStart, uint64_t LineInfoEnd) {
30006c3fb27SDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(LineInfoStart);
30106c3fb27SDimitry Andric   uint32_t RecSize = Extractor.getU32(C);
30206c3fb27SDimitry Andric   if (!C)
30306c3fb27SDimitry Andric     return Err(".BTF.ext", C);
30406c3fb27SDimitry Andric   if (RecSize < 16)
30506c3fb27SDimitry Andric     return Err("unexpected .BTF.ext line info record length: ") << RecSize;
30606c3fb27SDimitry Andric 
30706c3fb27SDimitry Andric   while (C && C.tell() < LineInfoEnd) {
30806c3fb27SDimitry Andric     uint32_t SecNameOff = Extractor.getU32(C);
30906c3fb27SDimitry Andric     uint32_t NumInfo = Extractor.getU32(C);
31006c3fb27SDimitry Andric     StringRef SecName = findString(SecNameOff);
31106c3fb27SDimitry Andric     std::optional<SectionRef> Sec = Ctx.findSection(SecName);
31206c3fb27SDimitry Andric     if (!C)
31306c3fb27SDimitry Andric       return Err(".BTF.ext", C);
31406c3fb27SDimitry Andric     if (!Sec)
31506c3fb27SDimitry Andric       return Err("") << "can't find section '" << SecName
31606c3fb27SDimitry Andric                      << "' while parsing .BTF.ext line info";
31706c3fb27SDimitry Andric     BTFLinesVector &Lines = SectionLines[Sec->getIndex()];
31806c3fb27SDimitry Andric     for (uint32_t I = 0; C && I < NumInfo; ++I) {
31906c3fb27SDimitry Andric       uint64_t RecStart = C.tell();
32006c3fb27SDimitry Andric       uint32_t InsnOff = Extractor.getU32(C);
32106c3fb27SDimitry Andric       uint32_t FileNameOff = Extractor.getU32(C);
32206c3fb27SDimitry Andric       uint32_t LineOff = Extractor.getU32(C);
32306c3fb27SDimitry Andric       uint32_t LineCol = Extractor.getU32(C);
32406c3fb27SDimitry Andric       if (!C)
32506c3fb27SDimitry Andric         return Err(".BTF.ext", C);
32606c3fb27SDimitry Andric       Lines.push_back({InsnOff, FileNameOff, LineOff, LineCol});
32706c3fb27SDimitry Andric       C.seek(RecStart + RecSize);
32806c3fb27SDimitry Andric     }
32906c3fb27SDimitry Andric     llvm::stable_sort(Lines,
33006c3fb27SDimitry Andric                       [](const BTF::BPFLineInfo &L, const BTF::BPFLineInfo &R) {
33106c3fb27SDimitry Andric                         return L.InsnOffset < R.InsnOffset;
33206c3fb27SDimitry Andric                       });
33306c3fb27SDimitry Andric   }
33406c3fb27SDimitry Andric   if (!C)
33506c3fb27SDimitry Andric     return Err(".BTF.ext", C);
33606c3fb27SDimitry Andric 
33706c3fb27SDimitry Andric   return Error::success();
33806c3fb27SDimitry Andric }
33906c3fb27SDimitry Andric 
parseRelocInfo(ParseContext & Ctx,DataExtractor & Extractor,uint64_t RelocInfoStart,uint64_t RelocInfoEnd)340*5f757f3fSDimitry Andric Error BTFParser::parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor,
341*5f757f3fSDimitry Andric                                 uint64_t RelocInfoStart,
342*5f757f3fSDimitry Andric                                 uint64_t RelocInfoEnd) {
343*5f757f3fSDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(RelocInfoStart);
344*5f757f3fSDimitry Andric   uint32_t RecSize = Extractor.getU32(C);
345*5f757f3fSDimitry Andric   if (!C)
346*5f757f3fSDimitry Andric     return Err(".BTF.ext", C);
347*5f757f3fSDimitry Andric   if (RecSize < 16)
348*5f757f3fSDimitry Andric     return Err("unexpected .BTF.ext field reloc info record length: ")
349*5f757f3fSDimitry Andric            << RecSize;
350*5f757f3fSDimitry Andric   while (C && C.tell() < RelocInfoEnd) {
351*5f757f3fSDimitry Andric     uint32_t SecNameOff = Extractor.getU32(C);
352*5f757f3fSDimitry Andric     uint32_t NumInfo = Extractor.getU32(C);
353*5f757f3fSDimitry Andric     StringRef SecName = findString(SecNameOff);
354*5f757f3fSDimitry Andric     std::optional<SectionRef> Sec = Ctx.findSection(SecName);
355*5f757f3fSDimitry Andric     BTFRelocVector &Relocs = SectionRelocs[Sec->getIndex()];
356*5f757f3fSDimitry Andric     for (uint32_t I = 0; C && I < NumInfo; ++I) {
357*5f757f3fSDimitry Andric       uint64_t RecStart = C.tell();
358*5f757f3fSDimitry Andric       uint32_t InsnOff = Extractor.getU32(C);
359*5f757f3fSDimitry Andric       uint32_t TypeID = Extractor.getU32(C);
360*5f757f3fSDimitry Andric       uint32_t OffsetNameOff = Extractor.getU32(C);
361*5f757f3fSDimitry Andric       uint32_t RelocKind = Extractor.getU32(C);
362*5f757f3fSDimitry Andric       if (!C)
363*5f757f3fSDimitry Andric         return Err(".BTF.ext", C);
364*5f757f3fSDimitry Andric       Relocs.push_back({InsnOff, TypeID, OffsetNameOff, RelocKind});
365*5f757f3fSDimitry Andric       C.seek(RecStart + RecSize);
366*5f757f3fSDimitry Andric     }
367*5f757f3fSDimitry Andric     llvm::stable_sort(
368*5f757f3fSDimitry Andric         Relocs, [](const BTF::BPFFieldReloc &L, const BTF::BPFFieldReloc &R) {
369*5f757f3fSDimitry Andric           return L.InsnOffset < R.InsnOffset;
370*5f757f3fSDimitry Andric         });
371*5f757f3fSDimitry Andric   }
372*5f757f3fSDimitry Andric   if (!C)
373*5f757f3fSDimitry Andric     return Err(".BTF.ext", C);
374*5f757f3fSDimitry Andric 
375*5f757f3fSDimitry Andric   return Error::success();
376*5f757f3fSDimitry Andric }
377*5f757f3fSDimitry Andric 
parse(const ObjectFile & Obj,const ParseOptions & Opts)378*5f757f3fSDimitry Andric Error BTFParser::parse(const ObjectFile &Obj, const ParseOptions &Opts) {
37906c3fb27SDimitry Andric   StringsTable = StringRef();
38006c3fb27SDimitry Andric   SectionLines.clear();
381*5f757f3fSDimitry Andric   SectionRelocs.clear();
382*5f757f3fSDimitry Andric   Types.clear();
383*5f757f3fSDimitry Andric   TypesBuffer = OwningArrayRef<uint8_t>();
38406c3fb27SDimitry Andric 
385*5f757f3fSDimitry Andric   ParseContext Ctx(Obj, Opts);
38606c3fb27SDimitry Andric   std::optional<SectionRef> BTF;
38706c3fb27SDimitry Andric   std::optional<SectionRef> BTFExt;
38806c3fb27SDimitry Andric   for (SectionRef Sec : Obj.sections()) {
38906c3fb27SDimitry Andric     Expected<StringRef> MaybeName = Sec.getName();
39006c3fb27SDimitry Andric     if (!MaybeName)
39106c3fb27SDimitry Andric       return Err("error while reading section name: ") << MaybeName.takeError();
39206c3fb27SDimitry Andric     Ctx.Sections[*MaybeName] = Sec;
39306c3fb27SDimitry Andric     if (*MaybeName == BTFSectionName)
39406c3fb27SDimitry Andric       BTF = Sec;
39506c3fb27SDimitry Andric     if (*MaybeName == BTFExtSectionName)
39606c3fb27SDimitry Andric       BTFExt = Sec;
39706c3fb27SDimitry Andric   }
39806c3fb27SDimitry Andric   if (!BTF)
39906c3fb27SDimitry Andric     return Err("can't find .BTF section");
40006c3fb27SDimitry Andric   if (!BTFExt)
40106c3fb27SDimitry Andric     return Err("can't find .BTF.ext section");
40206c3fb27SDimitry Andric   if (Error E = parseBTF(Ctx, *BTF))
40306c3fb27SDimitry Andric     return E;
40406c3fb27SDimitry Andric   if (Error E = parseBTFExt(Ctx, *BTFExt))
40506c3fb27SDimitry Andric     return E;
40606c3fb27SDimitry Andric 
40706c3fb27SDimitry Andric   return Error::success();
40806c3fb27SDimitry Andric }
40906c3fb27SDimitry Andric 
hasBTFSections(const ObjectFile & Obj)41006c3fb27SDimitry Andric bool BTFParser::hasBTFSections(const ObjectFile &Obj) {
41106c3fb27SDimitry Andric   bool HasBTF = false;
41206c3fb27SDimitry Andric   bool HasBTFExt = false;
41306c3fb27SDimitry Andric   for (SectionRef Sec : Obj.sections()) {
41406c3fb27SDimitry Andric     Expected<StringRef> Name = Sec.getName();
41506c3fb27SDimitry Andric     if (Error E = Name.takeError()) {
41606c3fb27SDimitry Andric       logAllUnhandledErrors(std::move(E), errs());
41706c3fb27SDimitry Andric       continue;
41806c3fb27SDimitry Andric     }
41906c3fb27SDimitry Andric     HasBTF |= *Name == BTFSectionName;
42006c3fb27SDimitry Andric     HasBTFExt |= *Name == BTFExtSectionName;
42106c3fb27SDimitry Andric     if (HasBTF && HasBTFExt)
42206c3fb27SDimitry Andric       return true;
42306c3fb27SDimitry Andric   }
42406c3fb27SDimitry Andric   return false;
42506c3fb27SDimitry Andric }
42606c3fb27SDimitry Andric 
findString(uint32_t Offset) const42706c3fb27SDimitry Andric StringRef BTFParser::findString(uint32_t Offset) const {
42806c3fb27SDimitry Andric   return StringsTable.slice(Offset, StringsTable.find(0, Offset));
42906c3fb27SDimitry Andric }
43006c3fb27SDimitry Andric 
431*5f757f3fSDimitry Andric template <typename T>
findInfo(const DenseMap<uint64_t,SmallVector<T,0>> & SecMap,SectionedAddress Address)432*5f757f3fSDimitry Andric static const T *findInfo(const DenseMap<uint64_t, SmallVector<T, 0>> &SecMap,
433*5f757f3fSDimitry Andric                          SectionedAddress Address) {
434*5f757f3fSDimitry Andric   auto MaybeSecInfo = SecMap.find(Address.SectionIndex);
435*5f757f3fSDimitry Andric   if (MaybeSecInfo == SecMap.end())
436*5f757f3fSDimitry Andric     return nullptr;
437*5f757f3fSDimitry Andric 
438*5f757f3fSDimitry Andric   const SmallVector<T, 0> &SecInfo = MaybeSecInfo->second;
439*5f757f3fSDimitry Andric   const uint64_t TargetOffset = Address.Address;
440*5f757f3fSDimitry Andric   typename SmallVector<T, 0>::const_iterator MaybeInfo = llvm::partition_point(
441*5f757f3fSDimitry Andric       SecInfo, [=](const T &Entry) { return Entry.InsnOffset < TargetOffset; });
442*5f757f3fSDimitry Andric   if (MaybeInfo == SecInfo.end() || MaybeInfo->InsnOffset != Address.Address)
443*5f757f3fSDimitry Andric     return nullptr;
444*5f757f3fSDimitry Andric 
445*5f757f3fSDimitry Andric   return &*MaybeInfo;
446*5f757f3fSDimitry Andric }
447*5f757f3fSDimitry Andric 
44806c3fb27SDimitry Andric const BTF::BPFLineInfo *
findLineInfo(SectionedAddress Address) const44906c3fb27SDimitry Andric BTFParser::findLineInfo(SectionedAddress Address) const {
450*5f757f3fSDimitry Andric   return findInfo(SectionLines, Address);
451*5f757f3fSDimitry Andric }
45206c3fb27SDimitry Andric 
453*5f757f3fSDimitry Andric const BTF::BPFFieldReloc *
findFieldReloc(SectionedAddress Address) const454*5f757f3fSDimitry Andric BTFParser::findFieldReloc(SectionedAddress Address) const {
455*5f757f3fSDimitry Andric   return findInfo(SectionRelocs, Address);
456*5f757f3fSDimitry Andric }
45706c3fb27SDimitry Andric 
findType(uint32_t Id) const458*5f757f3fSDimitry Andric const BTF::CommonType *BTFParser::findType(uint32_t Id) const {
459*5f757f3fSDimitry Andric   if (Id < Types.size())
460*5f757f3fSDimitry Andric     return Types[Id];
461*5f757f3fSDimitry Andric   return nullptr;
462*5f757f3fSDimitry Andric }
463*5f757f3fSDimitry Andric 
464*5f757f3fSDimitry Andric enum RelocKindGroup {
465*5f757f3fSDimitry Andric   RKG_FIELD,
466*5f757f3fSDimitry Andric   RKG_TYPE,
467*5f757f3fSDimitry Andric   RKG_ENUMVAL,
468*5f757f3fSDimitry Andric   RKG_UNKNOWN,
469*5f757f3fSDimitry Andric };
470*5f757f3fSDimitry Andric 
relocKindGroup(const BTF::BPFFieldReloc * Reloc)471*5f757f3fSDimitry Andric static RelocKindGroup relocKindGroup(const BTF::BPFFieldReloc *Reloc) {
472*5f757f3fSDimitry Andric   switch (Reloc->RelocKind) {
473*5f757f3fSDimitry Andric   case BTF::FIELD_BYTE_OFFSET:
474*5f757f3fSDimitry Andric   case BTF::FIELD_BYTE_SIZE:
475*5f757f3fSDimitry Andric   case BTF::FIELD_EXISTENCE:
476*5f757f3fSDimitry Andric   case BTF::FIELD_SIGNEDNESS:
477*5f757f3fSDimitry Andric   case BTF::FIELD_LSHIFT_U64:
478*5f757f3fSDimitry Andric   case BTF::FIELD_RSHIFT_U64:
479*5f757f3fSDimitry Andric     return RKG_FIELD;
480*5f757f3fSDimitry Andric   case BTF::BTF_TYPE_ID_LOCAL:
481*5f757f3fSDimitry Andric   case BTF::BTF_TYPE_ID_REMOTE:
482*5f757f3fSDimitry Andric   case BTF::TYPE_EXISTENCE:
483*5f757f3fSDimitry Andric   case BTF::TYPE_MATCH:
484*5f757f3fSDimitry Andric   case BTF::TYPE_SIZE:
485*5f757f3fSDimitry Andric     return RKG_TYPE;
486*5f757f3fSDimitry Andric   case BTF::ENUM_VALUE_EXISTENCE:
487*5f757f3fSDimitry Andric   case BTF::ENUM_VALUE:
488*5f757f3fSDimitry Andric     return RKG_ENUMVAL;
489*5f757f3fSDimitry Andric   default:
490*5f757f3fSDimitry Andric     return RKG_UNKNOWN;
491*5f757f3fSDimitry Andric   }
492*5f757f3fSDimitry Andric }
493*5f757f3fSDimitry Andric 
isMod(const BTF::CommonType * Type)494*5f757f3fSDimitry Andric static bool isMod(const BTF::CommonType *Type) {
495*5f757f3fSDimitry Andric   switch (Type->getKind()) {
496*5f757f3fSDimitry Andric   case BTF::BTF_KIND_VOLATILE:
497*5f757f3fSDimitry Andric   case BTF::BTF_KIND_CONST:
498*5f757f3fSDimitry Andric   case BTF::BTF_KIND_RESTRICT:
499*5f757f3fSDimitry Andric   case BTF::BTF_KIND_TYPE_TAG:
500*5f757f3fSDimitry Andric     return true;
501*5f757f3fSDimitry Andric   default:
502*5f757f3fSDimitry Andric     return false;
503*5f757f3fSDimitry Andric   }
504*5f757f3fSDimitry Andric }
505*5f757f3fSDimitry Andric 
printMod(const BTFParser & BTF,const BTF::CommonType * Type,raw_ostream & Stream)506*5f757f3fSDimitry Andric static bool printMod(const BTFParser &BTF, const BTF::CommonType *Type,
507*5f757f3fSDimitry Andric                      raw_ostream &Stream) {
508*5f757f3fSDimitry Andric   switch (Type->getKind()) {
509*5f757f3fSDimitry Andric   case BTF::BTF_KIND_CONST:
510*5f757f3fSDimitry Andric     Stream << " const";
511*5f757f3fSDimitry Andric     break;
512*5f757f3fSDimitry Andric   case BTF::BTF_KIND_VOLATILE:
513*5f757f3fSDimitry Andric     Stream << " volatile";
514*5f757f3fSDimitry Andric     break;
515*5f757f3fSDimitry Andric   case BTF::BTF_KIND_RESTRICT:
516*5f757f3fSDimitry Andric     Stream << " restrict";
517*5f757f3fSDimitry Andric     break;
518*5f757f3fSDimitry Andric   case BTF::BTF_KIND_TYPE_TAG:
519*5f757f3fSDimitry Andric     Stream << " type_tag(\"" << BTF.findString(Type->NameOff) << "\")";
520*5f757f3fSDimitry Andric     break;
521*5f757f3fSDimitry Andric   default:
522*5f757f3fSDimitry Andric     return false;
523*5f757f3fSDimitry Andric   }
524*5f757f3fSDimitry Andric   return true;
525*5f757f3fSDimitry Andric }
526*5f757f3fSDimitry Andric 
skipModsAndTypedefs(const BTFParser & BTF,const BTF::CommonType * Type)527*5f757f3fSDimitry Andric static const BTF::CommonType *skipModsAndTypedefs(const BTFParser &BTF,
528*5f757f3fSDimitry Andric                                                   const BTF::CommonType *Type) {
529*5f757f3fSDimitry Andric   while (isMod(Type) || Type->getKind() == BTF::BTF_KIND_TYPEDEF) {
530*5f757f3fSDimitry Andric     auto *Base = BTF.findType(Type->Type);
531*5f757f3fSDimitry Andric     if (!Base)
532*5f757f3fSDimitry Andric       break;
533*5f757f3fSDimitry Andric     Type = Base;
534*5f757f3fSDimitry Andric   }
535*5f757f3fSDimitry Andric   return Type;
536*5f757f3fSDimitry Andric }
537*5f757f3fSDimitry Andric 
538*5f757f3fSDimitry Andric namespace {
539*5f757f3fSDimitry Andric struct StrOrAnon {
540*5f757f3fSDimitry Andric   const BTFParser &BTF;
541*5f757f3fSDimitry Andric   uint32_t Offset;
542*5f757f3fSDimitry Andric   uint32_t Idx;
543*5f757f3fSDimitry Andric };
544*5f757f3fSDimitry Andric 
operator <<(raw_ostream & Stream,const StrOrAnon & S)545*5f757f3fSDimitry Andric static raw_ostream &operator<<(raw_ostream &Stream, const StrOrAnon &S) {
546*5f757f3fSDimitry Andric   StringRef Str = S.BTF.findString(S.Offset);
547*5f757f3fSDimitry Andric   if (Str.empty())
548*5f757f3fSDimitry Andric     Stream << "<anon " << S.Idx << ">";
549*5f757f3fSDimitry Andric   else
550*5f757f3fSDimitry Andric     Stream << Str;
551*5f757f3fSDimitry Andric   return Stream;
552*5f757f3fSDimitry Andric }
553*5f757f3fSDimitry Andric } // anonymous namespace
554*5f757f3fSDimitry Andric 
relocKindName(uint32_t X,raw_ostream & Out)555*5f757f3fSDimitry Andric static void relocKindName(uint32_t X, raw_ostream &Out) {
556*5f757f3fSDimitry Andric   Out << "<";
557*5f757f3fSDimitry Andric   switch (X) {
558*5f757f3fSDimitry Andric   default:
559*5f757f3fSDimitry Andric     Out << "reloc kind #" << X;
560*5f757f3fSDimitry Andric     break;
561*5f757f3fSDimitry Andric   case BTF::FIELD_BYTE_OFFSET:
562*5f757f3fSDimitry Andric     Out << "byte_off";
563*5f757f3fSDimitry Andric     break;
564*5f757f3fSDimitry Andric   case BTF::FIELD_BYTE_SIZE:
565*5f757f3fSDimitry Andric     Out << "byte_sz";
566*5f757f3fSDimitry Andric     break;
567*5f757f3fSDimitry Andric   case BTF::FIELD_EXISTENCE:
568*5f757f3fSDimitry Andric     Out << "field_exists";
569*5f757f3fSDimitry Andric     break;
570*5f757f3fSDimitry Andric   case BTF::FIELD_SIGNEDNESS:
571*5f757f3fSDimitry Andric     Out << "signed";
572*5f757f3fSDimitry Andric     break;
573*5f757f3fSDimitry Andric   case BTF::FIELD_LSHIFT_U64:
574*5f757f3fSDimitry Andric     Out << "lshift_u64";
575*5f757f3fSDimitry Andric     break;
576*5f757f3fSDimitry Andric   case BTF::FIELD_RSHIFT_U64:
577*5f757f3fSDimitry Andric     Out << "rshift_u64";
578*5f757f3fSDimitry Andric     break;
579*5f757f3fSDimitry Andric   case BTF::BTF_TYPE_ID_LOCAL:
580*5f757f3fSDimitry Andric     Out << "local_type_id";
581*5f757f3fSDimitry Andric     break;
582*5f757f3fSDimitry Andric   case BTF::BTF_TYPE_ID_REMOTE:
583*5f757f3fSDimitry Andric     Out << "target_type_id";
584*5f757f3fSDimitry Andric     break;
585*5f757f3fSDimitry Andric   case BTF::TYPE_EXISTENCE:
586*5f757f3fSDimitry Andric     Out << "type_exists";
587*5f757f3fSDimitry Andric     break;
588*5f757f3fSDimitry Andric   case BTF::TYPE_MATCH:
589*5f757f3fSDimitry Andric     Out << "type_matches";
590*5f757f3fSDimitry Andric     break;
591*5f757f3fSDimitry Andric   case BTF::TYPE_SIZE:
592*5f757f3fSDimitry Andric     Out << "type_size";
593*5f757f3fSDimitry Andric     break;
594*5f757f3fSDimitry Andric   case BTF::ENUM_VALUE_EXISTENCE:
595*5f757f3fSDimitry Andric     Out << "enumval_exists";
596*5f757f3fSDimitry Andric     break;
597*5f757f3fSDimitry Andric   case BTF::ENUM_VALUE:
598*5f757f3fSDimitry Andric     Out << "enumval_value";
599*5f757f3fSDimitry Andric     break;
600*5f757f3fSDimitry Andric   }
601*5f757f3fSDimitry Andric   Out << ">";
602*5f757f3fSDimitry Andric }
603*5f757f3fSDimitry Andric 
604*5f757f3fSDimitry Andric // Produces a human readable description of a CO-RE relocation.
605*5f757f3fSDimitry Andric // Such relocations are generated by BPF backend, and processed
606*5f757f3fSDimitry Andric // by libbpf's BPF program loader [1].
607*5f757f3fSDimitry Andric //
608*5f757f3fSDimitry Andric // Each relocation record has the following information:
609*5f757f3fSDimitry Andric // - Relocation kind;
610*5f757f3fSDimitry Andric // - BTF type ID;
611*5f757f3fSDimitry Andric // - Access string offset in string table.
612*5f757f3fSDimitry Andric //
613*5f757f3fSDimitry Andric // There are different kinds of relocations, these kinds could be split
614*5f757f3fSDimitry Andric // in three groups:
615*5f757f3fSDimitry Andric // - load-time information about types (size, existence),
616*5f757f3fSDimitry Andric //   `BTFParser::symbolize()` output for such relocations uses the template:
617*5f757f3fSDimitry Andric //
618*5f757f3fSDimitry Andric //     <relocation-kind> [<id>] <type-name>
619*5f757f3fSDimitry Andric //
620*5f757f3fSDimitry Andric //   For example:
621*5f757f3fSDimitry Andric //   - "<type_exists> [7] struct foo"
622*5f757f3fSDimitry Andric //   - "<type_size> [7] struct foo"
623*5f757f3fSDimitry Andric //
624*5f757f3fSDimitry Andric // - load-time information about enums (literal existence, literal value),
625*5f757f3fSDimitry Andric //   `BTFParser::symbolize()` output for such relocations uses the template:
626*5f757f3fSDimitry Andric //
627*5f757f3fSDimitry Andric //     <relocation-kind> [<id>] <type-name>::<literal-name> = <original-value>
628*5f757f3fSDimitry Andric //
629*5f757f3fSDimitry Andric //   For example:
630*5f757f3fSDimitry Andric //   - "<enumval_exists> [5] enum foo::U = 1"
631*5f757f3fSDimitry Andric //   - "<enumval_value> [5] enum foo::V = 2"
632*5f757f3fSDimitry Andric //
633*5f757f3fSDimitry Andric // - load-time information about fields (e.g. field offset),
634*5f757f3fSDimitry Andric //   `BTFParser::symbolize()` output for such relocations uses the template:
635*5f757f3fSDimitry Andric //
636*5f757f3fSDimitry Andric //     <relocation-kind> [<id>] \
637*5f757f3fSDimitry Andric //       <type-name>::[N].<field-1-name>...<field-M-name> \
638*5f757f3fSDimitry Andric //       (<access string>)
639*5f757f3fSDimitry Andric //
640*5f757f3fSDimitry Andric //   For example:
641*5f757f3fSDimitry Andric //   - "<byte_off> [8] struct bar::[7].v (7:1)"
642*5f757f3fSDimitry Andric //   - "<field_exists> [8] struct bar::v (0:1)"
643*5f757f3fSDimitry Andric //
644*5f757f3fSDimitry Andric // If relocation description is not valid output follows the following pattern:
645*5f757f3fSDimitry Andric //
646*5f757f3fSDimitry Andric //     <relocation-kind> <type-id>::<unprocessedaccess-string> <<error-msg>>
647*5f757f3fSDimitry Andric //
648*5f757f3fSDimitry Andric // For example:
649*5f757f3fSDimitry Andric //
650*5f757f3fSDimitry Andric // - "<type_sz> [42] '' <unknown type id: 42>"
651*5f757f3fSDimitry Andric // - "<byte_off> [4] '0:' <field spec too short>"
652*5f757f3fSDimitry Andric //
653*5f757f3fSDimitry Andric // Additional examples could be found in unit tests, see
654*5f757f3fSDimitry Andric // llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp.
655*5f757f3fSDimitry Andric //
656*5f757f3fSDimitry Andric // [1] https://www.kernel.org/doc/html/latest/bpf/libbpf/index.html
symbolize(const BTF::BPFFieldReloc * Reloc,SmallVectorImpl<char> & Result) const657*5f757f3fSDimitry Andric void BTFParser::symbolize(const BTF::BPFFieldReloc *Reloc,
658*5f757f3fSDimitry Andric                           SmallVectorImpl<char> &Result) const {
659*5f757f3fSDimitry Andric   raw_svector_ostream Stream(Result);
660*5f757f3fSDimitry Andric   StringRef FullSpecStr = findString(Reloc->OffsetNameOff);
661*5f757f3fSDimitry Andric   SmallVector<uint32_t, 8> RawSpec;
662*5f757f3fSDimitry Andric 
663*5f757f3fSDimitry Andric   auto Fail = [&](auto Msg) {
664*5f757f3fSDimitry Andric     Result.resize(0);
665*5f757f3fSDimitry Andric     relocKindName(Reloc->RelocKind, Stream);
666*5f757f3fSDimitry Andric     Stream << " [" << Reloc->TypeID << "] '" << FullSpecStr << "'"
667*5f757f3fSDimitry Andric            << " <" << Msg << ">";
668*5f757f3fSDimitry Andric   };
669*5f757f3fSDimitry Andric 
670*5f757f3fSDimitry Andric   // Relocation access string follows pattern [0-9]+(:[0-9]+)*,
671*5f757f3fSDimitry Andric   // e.g.: 12:22:3. Code below splits `SpecStr` by ':', parses
672*5f757f3fSDimitry Andric   // numbers, and pushes them to `RawSpec`.
673*5f757f3fSDimitry Andric   StringRef SpecStr = FullSpecStr;
674*5f757f3fSDimitry Andric   while (SpecStr.size()) {
675*5f757f3fSDimitry Andric     unsigned long long Val;
676*5f757f3fSDimitry Andric     if (consumeUnsignedInteger(SpecStr, 10, Val))
677*5f757f3fSDimitry Andric       return Fail("spec string is not a number");
678*5f757f3fSDimitry Andric     RawSpec.push_back(Val);
679*5f757f3fSDimitry Andric     if (SpecStr.empty())
680*5f757f3fSDimitry Andric       break;
681*5f757f3fSDimitry Andric     if (SpecStr[0] != ':')
682*5f757f3fSDimitry Andric       return Fail(format("unexpected spec string delimiter: '%c'", SpecStr[0]));
683*5f757f3fSDimitry Andric     SpecStr = SpecStr.substr(1);
684*5f757f3fSDimitry Andric   }
685*5f757f3fSDimitry Andric 
686*5f757f3fSDimitry Andric   // Print relocation kind to `Stream`.
687*5f757f3fSDimitry Andric   relocKindName(Reloc->RelocKind, Stream);
688*5f757f3fSDimitry Andric 
689*5f757f3fSDimitry Andric   uint32_t CurId = Reloc->TypeID;
690*5f757f3fSDimitry Andric   const BTF::CommonType *Type = findType(CurId);
691*5f757f3fSDimitry Andric   if (!Type)
692*5f757f3fSDimitry Andric     return Fail(format("unknown type id: %d", CurId));
693*5f757f3fSDimitry Andric 
694*5f757f3fSDimitry Andric   Stream << " [" << CurId << "]";
695*5f757f3fSDimitry Andric 
696*5f757f3fSDimitry Andric   // `Type` might have modifiers, e.g. for type 'const int' the `Type`
697*5f757f3fSDimitry Andric   // would refer to BTF type of kind BTF_KIND_CONST.
698*5f757f3fSDimitry Andric   // Print all these modifiers to `Stream`.
699*5f757f3fSDimitry Andric   for (uint32_t ChainLen = 0; printMod(*this, Type, Stream); ++ChainLen) {
700*5f757f3fSDimitry Andric     if (ChainLen >= 32)
701*5f757f3fSDimitry Andric       return Fail("modifiers chain is too long");
702*5f757f3fSDimitry Andric 
703*5f757f3fSDimitry Andric     CurId = Type->Type;
704*5f757f3fSDimitry Andric     const BTF::CommonType *NextType = findType(CurId);
705*5f757f3fSDimitry Andric     if (!NextType)
706*5f757f3fSDimitry Andric       return Fail(format("unknown type id: %d in modifiers chain", CurId));
707*5f757f3fSDimitry Andric     Type = NextType;
708*5f757f3fSDimitry Andric   }
709*5f757f3fSDimitry Andric   // Print the type name to `Stream`.
710*5f757f3fSDimitry Andric   if (CurId == 0) {
711*5f757f3fSDimitry Andric     Stream << " void";
712*5f757f3fSDimitry Andric   } else {
713*5f757f3fSDimitry Andric     switch (Type->getKind()) {
714*5f757f3fSDimitry Andric     case BTF::BTF_KIND_TYPEDEF:
715*5f757f3fSDimitry Andric       Stream << " typedef";
716*5f757f3fSDimitry Andric       break;
717*5f757f3fSDimitry Andric     case BTF::BTF_KIND_STRUCT:
718*5f757f3fSDimitry Andric       Stream << " struct";
719*5f757f3fSDimitry Andric       break;
720*5f757f3fSDimitry Andric     case BTF::BTF_KIND_UNION:
721*5f757f3fSDimitry Andric       Stream << " union";
722*5f757f3fSDimitry Andric       break;
723*5f757f3fSDimitry Andric     case BTF::BTF_KIND_ENUM:
724*5f757f3fSDimitry Andric       Stream << " enum";
725*5f757f3fSDimitry Andric       break;
726*5f757f3fSDimitry Andric     case BTF::BTF_KIND_ENUM64:
727*5f757f3fSDimitry Andric       Stream << " enum";
728*5f757f3fSDimitry Andric       break;
729*5f757f3fSDimitry Andric     case BTF::BTF_KIND_FWD:
730*5f757f3fSDimitry Andric       if (Type->Info & BTF::FWD_UNION_FLAG)
731*5f757f3fSDimitry Andric         Stream << " fwd union";
732*5f757f3fSDimitry Andric       else
733*5f757f3fSDimitry Andric         Stream << " fwd struct";
734*5f757f3fSDimitry Andric       break;
735*5f757f3fSDimitry Andric     default:
736*5f757f3fSDimitry Andric       break;
737*5f757f3fSDimitry Andric     }
738*5f757f3fSDimitry Andric     Stream << " " << StrOrAnon({*this, Type->NameOff, CurId});
739*5f757f3fSDimitry Andric   }
740*5f757f3fSDimitry Andric 
741*5f757f3fSDimitry Andric   RelocKindGroup Group = relocKindGroup(Reloc);
742*5f757f3fSDimitry Andric   // Type-based relocations don't use access string but clang backend
743*5f757f3fSDimitry Andric   // generates '0' and libbpf checks it's value, do the same here.
744*5f757f3fSDimitry Andric   if (Group == RKG_TYPE) {
745*5f757f3fSDimitry Andric     if (RawSpec.size() != 1 || RawSpec[0] != 0)
746*5f757f3fSDimitry Andric       return Fail("unexpected type-based relocation spec: should be '0'");
747*5f757f3fSDimitry Andric     return;
748*5f757f3fSDimitry Andric   }
749*5f757f3fSDimitry Andric 
750*5f757f3fSDimitry Andric   Stream << "::";
751*5f757f3fSDimitry Andric 
752*5f757f3fSDimitry Andric   // For enum-based relocations access string is a single number,
753*5f757f3fSDimitry Andric   // corresponding to the enum literal sequential number.
754*5f757f3fSDimitry Andric   // E.g. for `enum E { U, V }`, relocation requesting value of `V`
755*5f757f3fSDimitry Andric   // would look as follows:
756*5f757f3fSDimitry Andric   // - kind: BTF::ENUM_VALUE
757*5f757f3fSDimitry Andric   // - BTF id: id for `E`
758*5f757f3fSDimitry Andric   // - access string: "1"
759*5f757f3fSDimitry Andric   if (Group == RKG_ENUMVAL) {
760*5f757f3fSDimitry Andric     Type = skipModsAndTypedefs(*this, Type);
761*5f757f3fSDimitry Andric 
762*5f757f3fSDimitry Andric     if (RawSpec.size() != 1)
763*5f757f3fSDimitry Andric       return Fail("unexpected enumval relocation spec size");
764*5f757f3fSDimitry Andric 
765*5f757f3fSDimitry Andric     uint32_t NameOff;
766*5f757f3fSDimitry Andric     uint64_t Val;
767*5f757f3fSDimitry Andric     uint32_t Idx = RawSpec[0];
768*5f757f3fSDimitry Andric     if (auto *T = dyn_cast<BTF::EnumType>(Type)) {
769*5f757f3fSDimitry Andric       if (T->values().size() <= Idx)
770*5f757f3fSDimitry Andric         return Fail(format("bad value index: %d", Idx));
771*5f757f3fSDimitry Andric       const BTF::BTFEnum &E = T->values()[Idx];
772*5f757f3fSDimitry Andric       NameOff = E.NameOff;
773*5f757f3fSDimitry Andric       Val = E.Val;
774*5f757f3fSDimitry Andric     } else if (auto *T = dyn_cast<BTF::Enum64Type>(Type)) {
775*5f757f3fSDimitry Andric       if (T->values().size() <= Idx)
776*5f757f3fSDimitry Andric         return Fail(format("bad value index: %d", Idx));
777*5f757f3fSDimitry Andric       const BTF::BTFEnum64 &E = T->values()[Idx];
778*5f757f3fSDimitry Andric       NameOff = E.NameOff;
779*5f757f3fSDimitry Andric       Val = (uint64_t)E.Val_Hi32 << 32u | E.Val_Lo32;
780*5f757f3fSDimitry Andric     } else {
781*5f757f3fSDimitry Andric       return Fail(format("unexpected type kind for enum relocation: %d",
782*5f757f3fSDimitry Andric                          Type->getKind()));
783*5f757f3fSDimitry Andric     }
784*5f757f3fSDimitry Andric 
785*5f757f3fSDimitry Andric     Stream << StrOrAnon({*this, NameOff, Idx});
786*5f757f3fSDimitry Andric     if (Type->Info & BTF::ENUM_SIGNED_FLAG)
787*5f757f3fSDimitry Andric       Stream << " = " << (int64_t)Val;
788*5f757f3fSDimitry Andric     else
789*5f757f3fSDimitry Andric       Stream << " = " << (uint64_t)Val;
790*5f757f3fSDimitry Andric     return;
791*5f757f3fSDimitry Andric   }
792*5f757f3fSDimitry Andric 
793*5f757f3fSDimitry Andric   // For type-based relocations access string is an array of numbers,
794*5f757f3fSDimitry Andric   // which resemble index parameters for `getelementptr` LLVM IR instruction.
795*5f757f3fSDimitry Andric   // E.g. for the following types:
796*5f757f3fSDimitry Andric   //
797*5f757f3fSDimitry Andric   //   struct foo {
798*5f757f3fSDimitry Andric   //     int a;
799*5f757f3fSDimitry Andric   //     int b;
800*5f757f3fSDimitry Andric   //   };
801*5f757f3fSDimitry Andric   //   struct bar {
802*5f757f3fSDimitry Andric   //     int u;
803*5f757f3fSDimitry Andric   //     struct foo v[7];
804*5f757f3fSDimitry Andric   //   };
805*5f757f3fSDimitry Andric   //
806*5f757f3fSDimitry Andric   // Relocation requesting `offsetof(struct bar, v[2].b)` will have
807*5f757f3fSDimitry Andric   // the following access string: 0:1:2:1
808*5f757f3fSDimitry Andric   //                              ^ ^ ^ ^
809*5f757f3fSDimitry Andric   //                              | | | |
810*5f757f3fSDimitry Andric   //                  initial index | | field 'b' is a field #1
811*5f757f3fSDimitry Andric   //                                | | (counting from 0)
812*5f757f3fSDimitry Andric   //                                | array index #2
813*5f757f3fSDimitry Andric   //           field 'v' is a field #1
814*5f757f3fSDimitry Andric   //              (counting from 0)
815*5f757f3fSDimitry Andric   if (Group == RKG_FIELD) {
816*5f757f3fSDimitry Andric     if (RawSpec.size() < 1)
817*5f757f3fSDimitry Andric       return Fail("field spec too short");
818*5f757f3fSDimitry Andric 
819*5f757f3fSDimitry Andric     if (RawSpec[0] != 0)
820*5f757f3fSDimitry Andric       Stream << "[" << RawSpec[0] << "]";
821*5f757f3fSDimitry Andric     for (uint32_t I = 1; I < RawSpec.size(); ++I) {
822*5f757f3fSDimitry Andric       Type = skipModsAndTypedefs(*this, Type);
823*5f757f3fSDimitry Andric       uint32_t Idx = RawSpec[I];
824*5f757f3fSDimitry Andric 
825*5f757f3fSDimitry Andric       if (auto *T = dyn_cast<BTF::StructType>(Type)) {
826*5f757f3fSDimitry Andric         if (T->getVlen() <= Idx)
827*5f757f3fSDimitry Andric           return Fail(
828*5f757f3fSDimitry Andric               format("member index %d for spec sub-string %d is out of range",
829*5f757f3fSDimitry Andric                      Idx, I));
830*5f757f3fSDimitry Andric 
831*5f757f3fSDimitry Andric         const BTF::BTFMember &Member = T->members()[Idx];
832*5f757f3fSDimitry Andric         if (I != 1 || RawSpec[0] != 0)
833*5f757f3fSDimitry Andric           Stream << ".";
834*5f757f3fSDimitry Andric         Stream << StrOrAnon({*this, Member.NameOff, Idx});
835*5f757f3fSDimitry Andric         Type = findType(Member.Type);
836*5f757f3fSDimitry Andric         if (!Type)
837*5f757f3fSDimitry Andric           return Fail(format("unknown member type id %d for spec sub-string %d",
838*5f757f3fSDimitry Andric                              Member.Type, I));
839*5f757f3fSDimitry Andric       } else if (auto *T = dyn_cast<BTF::ArrayType>(Type)) {
840*5f757f3fSDimitry Andric         Stream << "[" << Idx << "]";
841*5f757f3fSDimitry Andric         Type = findType(T->getArray().ElemType);
842*5f757f3fSDimitry Andric         if (!Type)
843*5f757f3fSDimitry Andric           return Fail(
844*5f757f3fSDimitry Andric               format("unknown element type id %d for spec sub-string %d",
845*5f757f3fSDimitry Andric                      T->getArray().ElemType, I));
846*5f757f3fSDimitry Andric       } else {
847*5f757f3fSDimitry Andric         return Fail(format("unexpected type kind %d for spec sub-string %d",
848*5f757f3fSDimitry Andric                            Type->getKind(), I));
849*5f757f3fSDimitry Andric       }
850*5f757f3fSDimitry Andric     }
851*5f757f3fSDimitry Andric 
852*5f757f3fSDimitry Andric     Stream << " (" << FullSpecStr << ")";
853*5f757f3fSDimitry Andric     return;
854*5f757f3fSDimitry Andric   }
855*5f757f3fSDimitry Andric 
856*5f757f3fSDimitry Andric   return Fail(format("unknown relocation kind: %d", Reloc->RelocKind));
85706c3fb27SDimitry Andric }
858