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