xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/BTF/BTFParser.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- BTFParser.cpp ------------------------------------------------------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric //
9*06c3fb27SDimitry Andric // BTFParser reads/interprets .BTF and .BTF.ext ELF sections.
10*06c3fb27SDimitry Andric // Refer to BTFParser.h for API description.
11*06c3fb27SDimitry Andric //
12*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
13*06c3fb27SDimitry Andric 
14*06c3fb27SDimitry Andric #include "llvm/DebugInfo/BTF/BTFParser.h"
15*06c3fb27SDimitry Andric #include "llvm/Support/Errc.h"
16*06c3fb27SDimitry Andric 
17*06c3fb27SDimitry Andric #define DEBUG_TYPE "debug-info-btf-parser"
18*06c3fb27SDimitry Andric 
19*06c3fb27SDimitry Andric using namespace llvm;
20*06c3fb27SDimitry Andric using object::ObjectFile;
21*06c3fb27SDimitry Andric using object::SectionedAddress;
22*06c3fb27SDimitry Andric using object::SectionRef;
23*06c3fb27SDimitry Andric 
24*06c3fb27SDimitry Andric const char BTFSectionName[] = ".BTF";
25*06c3fb27SDimitry Andric const char BTFExtSectionName[] = ".BTF.ext";
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric // Utility class with API similar to raw_ostream but can be cast
28*06c3fb27SDimitry Andric // to Error, e.g.:
29*06c3fb27SDimitry Andric //
30*06c3fb27SDimitry Andric // Error foo(...) {
31*06c3fb27SDimitry Andric //   ...
32*06c3fb27SDimitry Andric //   if (Error E = bar(...))
33*06c3fb27SDimitry Andric //     return Err("error while foo(): ") << E;
34*06c3fb27SDimitry Andric //   ...
35*06c3fb27SDimitry Andric // }
36*06c3fb27SDimitry Andric //
37*06c3fb27SDimitry Andric namespace {
38*06c3fb27SDimitry Andric class Err {
39*06c3fb27SDimitry Andric   std::string Buffer;
40*06c3fb27SDimitry Andric   raw_string_ostream Stream;
41*06c3fb27SDimitry Andric 
42*06c3fb27SDimitry Andric public:
43*06c3fb27SDimitry Andric   Err(const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {}
44*06c3fb27SDimitry Andric   Err(const char *SectionName, DataExtractor::Cursor &C)
45*06c3fb27SDimitry Andric       : Buffer(), Stream(Buffer) {
46*06c3fb27SDimitry Andric     *this << "error while reading " << SectionName
47*06c3fb27SDimitry Andric           << " section: " << C.takeError();
48*06c3fb27SDimitry Andric   };
49*06c3fb27SDimitry Andric 
50*06c3fb27SDimitry Andric   template <typename T> Err &operator<<(T Val) {
51*06c3fb27SDimitry Andric     Stream << Val;
52*06c3fb27SDimitry Andric     return *this;
53*06c3fb27SDimitry Andric   }
54*06c3fb27SDimitry Andric 
55*06c3fb27SDimitry Andric   Err &write_hex(unsigned long long Val) {
56*06c3fb27SDimitry Andric     Stream.write_hex(Val);
57*06c3fb27SDimitry Andric     return *this;
58*06c3fb27SDimitry Andric   }
59*06c3fb27SDimitry Andric 
60*06c3fb27SDimitry Andric   Err &operator<<(Error Val) {
61*06c3fb27SDimitry Andric     handleAllErrors(std::move(Val),
62*06c3fb27SDimitry Andric                     [=](ErrorInfoBase &Info) { Stream << Info.message(); });
63*06c3fb27SDimitry Andric     return *this;
64*06c3fb27SDimitry Andric   }
65*06c3fb27SDimitry Andric 
66*06c3fb27SDimitry Andric   operator Error() const {
67*06c3fb27SDimitry Andric     return make_error<StringError>(Buffer, errc::invalid_argument);
68*06c3fb27SDimitry Andric   }
69*06c3fb27SDimitry Andric };
70*06c3fb27SDimitry Andric } // anonymous namespace
71*06c3fb27SDimitry Andric 
72*06c3fb27SDimitry Andric // ParseContext wraps information that is only necessary while parsing
73*06c3fb27SDimitry Andric // ObjectFile and can be discarded once parsing is done.
74*06c3fb27SDimitry Andric // Used by BTFParser::parse* auxiliary functions.
75*06c3fb27SDimitry Andric struct BTFParser::ParseContext {
76*06c3fb27SDimitry Andric   const ObjectFile &Obj;
77*06c3fb27SDimitry Andric   // Map from ELF section name to SectionRef
78*06c3fb27SDimitry Andric   DenseMap<StringRef, SectionRef> Sections;
79*06c3fb27SDimitry Andric 
80*06c3fb27SDimitry Andric public:
81*06c3fb27SDimitry Andric   ParseContext(const ObjectFile &Obj) : Obj(Obj) {}
82*06c3fb27SDimitry Andric 
83*06c3fb27SDimitry Andric   Expected<DataExtractor> makeExtractor(SectionRef Sec) {
84*06c3fb27SDimitry Andric     Expected<StringRef> Contents = Sec.getContents();
85*06c3fb27SDimitry Andric     if (!Contents)
86*06c3fb27SDimitry Andric       return Contents.takeError();
87*06c3fb27SDimitry Andric     return DataExtractor(Contents.get(), Obj.isLittleEndian(),
88*06c3fb27SDimitry Andric                          Obj.getBytesInAddress());
89*06c3fb27SDimitry Andric   }
90*06c3fb27SDimitry Andric 
91*06c3fb27SDimitry Andric   std::optional<SectionRef> findSection(StringRef Name) const {
92*06c3fb27SDimitry Andric     auto It = Sections.find(Name);
93*06c3fb27SDimitry Andric     if (It != Sections.end())
94*06c3fb27SDimitry Andric       return It->second;
95*06c3fb27SDimitry Andric     return std::nullopt;
96*06c3fb27SDimitry Andric   }
97*06c3fb27SDimitry Andric };
98*06c3fb27SDimitry Andric 
99*06c3fb27SDimitry Andric Error BTFParser::parseBTF(ParseContext &Ctx, SectionRef BTF) {
100*06c3fb27SDimitry Andric   Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTF);
101*06c3fb27SDimitry Andric   if (!MaybeExtractor)
102*06c3fb27SDimitry Andric     return MaybeExtractor.takeError();
103*06c3fb27SDimitry Andric 
104*06c3fb27SDimitry Andric   DataExtractor &Extractor = MaybeExtractor.get();
105*06c3fb27SDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(0);
106*06c3fb27SDimitry Andric   uint16_t Magic = Extractor.getU16(C);
107*06c3fb27SDimitry Andric   if (!C)
108*06c3fb27SDimitry Andric     return Err(".BTF", C);
109*06c3fb27SDimitry Andric   if (Magic != BTF::MAGIC)
110*06c3fb27SDimitry Andric     return Err("invalid .BTF magic: ").write_hex(Magic);
111*06c3fb27SDimitry Andric   uint8_t Version = Extractor.getU8(C);
112*06c3fb27SDimitry Andric   if (!C)
113*06c3fb27SDimitry Andric     return Err(".BTF", C);
114*06c3fb27SDimitry Andric   if (Version != 1)
115*06c3fb27SDimitry Andric     return Err("unsupported .BTF version: ") << (unsigned)Version;
116*06c3fb27SDimitry Andric   (void)Extractor.getU8(C); // flags
117*06c3fb27SDimitry Andric   uint32_t HdrLen = Extractor.getU32(C);
118*06c3fb27SDimitry Andric   if (!C)
119*06c3fb27SDimitry Andric     return Err(".BTF", C);
120*06c3fb27SDimitry Andric   if (HdrLen < 8)
121*06c3fb27SDimitry Andric     return Err("unexpected .BTF header length: ") << HdrLen;
122*06c3fb27SDimitry Andric   (void)Extractor.getU32(C); // type_off
123*06c3fb27SDimitry Andric   (void)Extractor.getU32(C); // type_len
124*06c3fb27SDimitry Andric   uint32_t StrOff = Extractor.getU32(C);
125*06c3fb27SDimitry Andric   uint32_t StrLen = Extractor.getU32(C);
126*06c3fb27SDimitry Andric   uint32_t StrStart = HdrLen + StrOff;
127*06c3fb27SDimitry Andric   uint32_t StrEnd = StrStart + StrLen;
128*06c3fb27SDimitry Andric   if (!C)
129*06c3fb27SDimitry Andric     return Err(".BTF", C);
130*06c3fb27SDimitry Andric   if (Extractor.getData().size() < StrEnd)
131*06c3fb27SDimitry Andric     return Err("invalid .BTF section size, expecting at-least ")
132*06c3fb27SDimitry Andric            << StrEnd << " bytes";
133*06c3fb27SDimitry Andric 
134*06c3fb27SDimitry Andric   StringsTable = Extractor.getData().substr(StrStart, StrLen);
135*06c3fb27SDimitry Andric   return Error::success();
136*06c3fb27SDimitry Andric }
137*06c3fb27SDimitry Andric 
138*06c3fb27SDimitry Andric Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) {
139*06c3fb27SDimitry Andric   Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTFExt);
140*06c3fb27SDimitry Andric   if (!MaybeExtractor)
141*06c3fb27SDimitry Andric     return MaybeExtractor.takeError();
142*06c3fb27SDimitry Andric 
143*06c3fb27SDimitry Andric   DataExtractor &Extractor = MaybeExtractor.get();
144*06c3fb27SDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(0);
145*06c3fb27SDimitry Andric   uint16_t Magic = Extractor.getU16(C);
146*06c3fb27SDimitry Andric   if (!C)
147*06c3fb27SDimitry Andric     return Err(".BTF.ext", C);
148*06c3fb27SDimitry Andric   if (Magic != BTF::MAGIC)
149*06c3fb27SDimitry Andric     return Err("invalid .BTF.ext magic: ").write_hex(Magic);
150*06c3fb27SDimitry Andric   uint8_t Version = Extractor.getU8(C);
151*06c3fb27SDimitry Andric   if (!C)
152*06c3fb27SDimitry Andric     return Err(".BTF", C);
153*06c3fb27SDimitry Andric   if (Version != 1)
154*06c3fb27SDimitry Andric     return Err("unsupported .BTF.ext version: ") << (unsigned)Version;
155*06c3fb27SDimitry Andric   (void)Extractor.getU8(C); // flags
156*06c3fb27SDimitry Andric   uint32_t HdrLen = Extractor.getU32(C);
157*06c3fb27SDimitry Andric   if (!C)
158*06c3fb27SDimitry Andric     return Err(".BTF.ext", C);
159*06c3fb27SDimitry Andric   if (HdrLen < 8)
160*06c3fb27SDimitry Andric     return Err("unexpected .BTF.ext header length: ") << HdrLen;
161*06c3fb27SDimitry Andric   (void)Extractor.getU32(C); // func_info_off
162*06c3fb27SDimitry Andric   (void)Extractor.getU32(C); // func_info_len
163*06c3fb27SDimitry Andric   uint32_t LineInfoOff = Extractor.getU32(C);
164*06c3fb27SDimitry Andric   uint32_t LineInfoLen = Extractor.getU32(C);
165*06c3fb27SDimitry Andric   if (!C)
166*06c3fb27SDimitry Andric     return Err(".BTF.ext", C);
167*06c3fb27SDimitry Andric   uint32_t LineInfoStart = HdrLen + LineInfoOff;
168*06c3fb27SDimitry Andric   uint32_t LineInfoEnd = LineInfoStart + LineInfoLen;
169*06c3fb27SDimitry Andric   if (Error E = parseLineInfo(Ctx, Extractor, LineInfoStart, LineInfoEnd))
170*06c3fb27SDimitry Andric     return E;
171*06c3fb27SDimitry Andric 
172*06c3fb27SDimitry Andric   return Error::success();
173*06c3fb27SDimitry Andric }
174*06c3fb27SDimitry Andric 
175*06c3fb27SDimitry Andric Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor,
176*06c3fb27SDimitry Andric                                uint64_t LineInfoStart, uint64_t LineInfoEnd) {
177*06c3fb27SDimitry Andric   DataExtractor::Cursor C = DataExtractor::Cursor(LineInfoStart);
178*06c3fb27SDimitry Andric   uint32_t RecSize = Extractor.getU32(C);
179*06c3fb27SDimitry Andric   if (!C)
180*06c3fb27SDimitry Andric     return Err(".BTF.ext", C);
181*06c3fb27SDimitry Andric   if (RecSize < 16)
182*06c3fb27SDimitry Andric     return Err("unexpected .BTF.ext line info record length: ") << RecSize;
183*06c3fb27SDimitry Andric 
184*06c3fb27SDimitry Andric   while (C && C.tell() < LineInfoEnd) {
185*06c3fb27SDimitry Andric     uint32_t SecNameOff = Extractor.getU32(C);
186*06c3fb27SDimitry Andric     uint32_t NumInfo = Extractor.getU32(C);
187*06c3fb27SDimitry Andric     StringRef SecName = findString(SecNameOff);
188*06c3fb27SDimitry Andric     std::optional<SectionRef> Sec = Ctx.findSection(SecName);
189*06c3fb27SDimitry Andric     if (!C)
190*06c3fb27SDimitry Andric       return Err(".BTF.ext", C);
191*06c3fb27SDimitry Andric     if (!Sec)
192*06c3fb27SDimitry Andric       return Err("") << "can't find section '" << SecName
193*06c3fb27SDimitry Andric                      << "' while parsing .BTF.ext line info";
194*06c3fb27SDimitry Andric     BTFLinesVector &Lines = SectionLines[Sec->getIndex()];
195*06c3fb27SDimitry Andric     for (uint32_t I = 0; C && I < NumInfo; ++I) {
196*06c3fb27SDimitry Andric       uint64_t RecStart = C.tell();
197*06c3fb27SDimitry Andric       uint32_t InsnOff = Extractor.getU32(C);
198*06c3fb27SDimitry Andric       uint32_t FileNameOff = Extractor.getU32(C);
199*06c3fb27SDimitry Andric       uint32_t LineOff = Extractor.getU32(C);
200*06c3fb27SDimitry Andric       uint32_t LineCol = Extractor.getU32(C);
201*06c3fb27SDimitry Andric       if (!C)
202*06c3fb27SDimitry Andric         return Err(".BTF.ext", C);
203*06c3fb27SDimitry Andric       Lines.push_back({InsnOff, FileNameOff, LineOff, LineCol});
204*06c3fb27SDimitry Andric       C.seek(RecStart + RecSize);
205*06c3fb27SDimitry Andric     }
206*06c3fb27SDimitry Andric     llvm::stable_sort(Lines,
207*06c3fb27SDimitry Andric                       [](const BTF::BPFLineInfo &L, const BTF::BPFLineInfo &R) {
208*06c3fb27SDimitry Andric                         return L.InsnOffset < R.InsnOffset;
209*06c3fb27SDimitry Andric                       });
210*06c3fb27SDimitry Andric   }
211*06c3fb27SDimitry Andric   if (!C)
212*06c3fb27SDimitry Andric     return Err(".BTF.ext", C);
213*06c3fb27SDimitry Andric 
214*06c3fb27SDimitry Andric   return Error::success();
215*06c3fb27SDimitry Andric }
216*06c3fb27SDimitry Andric 
217*06c3fb27SDimitry Andric Error BTFParser::parse(const ObjectFile &Obj) {
218*06c3fb27SDimitry Andric   StringsTable = StringRef();
219*06c3fb27SDimitry Andric   SectionLines.clear();
220*06c3fb27SDimitry Andric 
221*06c3fb27SDimitry Andric   ParseContext Ctx(Obj);
222*06c3fb27SDimitry Andric   std::optional<SectionRef> BTF;
223*06c3fb27SDimitry Andric   std::optional<SectionRef> BTFExt;
224*06c3fb27SDimitry Andric   for (SectionRef Sec : Obj.sections()) {
225*06c3fb27SDimitry Andric     Expected<StringRef> MaybeName = Sec.getName();
226*06c3fb27SDimitry Andric     if (!MaybeName)
227*06c3fb27SDimitry Andric       return Err("error while reading section name: ") << MaybeName.takeError();
228*06c3fb27SDimitry Andric     Ctx.Sections[*MaybeName] = Sec;
229*06c3fb27SDimitry Andric     if (*MaybeName == BTFSectionName)
230*06c3fb27SDimitry Andric       BTF = Sec;
231*06c3fb27SDimitry Andric     if (*MaybeName == BTFExtSectionName)
232*06c3fb27SDimitry Andric       BTFExt = Sec;
233*06c3fb27SDimitry Andric   }
234*06c3fb27SDimitry Andric   if (!BTF)
235*06c3fb27SDimitry Andric     return Err("can't find .BTF section");
236*06c3fb27SDimitry Andric   if (!BTFExt)
237*06c3fb27SDimitry Andric     return Err("can't find .BTF.ext section");
238*06c3fb27SDimitry Andric   if (Error E = parseBTF(Ctx, *BTF))
239*06c3fb27SDimitry Andric     return E;
240*06c3fb27SDimitry Andric   if (Error E = parseBTFExt(Ctx, *BTFExt))
241*06c3fb27SDimitry Andric     return E;
242*06c3fb27SDimitry Andric 
243*06c3fb27SDimitry Andric   return Error::success();
244*06c3fb27SDimitry Andric }
245*06c3fb27SDimitry Andric 
246*06c3fb27SDimitry Andric bool BTFParser::hasBTFSections(const ObjectFile &Obj) {
247*06c3fb27SDimitry Andric   bool HasBTF = false;
248*06c3fb27SDimitry Andric   bool HasBTFExt = false;
249*06c3fb27SDimitry Andric   for (SectionRef Sec : Obj.sections()) {
250*06c3fb27SDimitry Andric     Expected<StringRef> Name = Sec.getName();
251*06c3fb27SDimitry Andric     if (Error E = Name.takeError()) {
252*06c3fb27SDimitry Andric       logAllUnhandledErrors(std::move(E), errs());
253*06c3fb27SDimitry Andric       continue;
254*06c3fb27SDimitry Andric     }
255*06c3fb27SDimitry Andric     HasBTF |= *Name == BTFSectionName;
256*06c3fb27SDimitry Andric     HasBTFExt |= *Name == BTFExtSectionName;
257*06c3fb27SDimitry Andric     if (HasBTF && HasBTFExt)
258*06c3fb27SDimitry Andric       return true;
259*06c3fb27SDimitry Andric   }
260*06c3fb27SDimitry Andric   return false;
261*06c3fb27SDimitry Andric }
262*06c3fb27SDimitry Andric 
263*06c3fb27SDimitry Andric StringRef BTFParser::findString(uint32_t Offset) const {
264*06c3fb27SDimitry Andric   return StringsTable.slice(Offset, StringsTable.find(0, Offset));
265*06c3fb27SDimitry Andric }
266*06c3fb27SDimitry Andric 
267*06c3fb27SDimitry Andric const BTF::BPFLineInfo *
268*06c3fb27SDimitry Andric BTFParser::findLineInfo(SectionedAddress Address) const {
269*06c3fb27SDimitry Andric   auto MaybeSecInfo = SectionLines.find(Address.SectionIndex);
270*06c3fb27SDimitry Andric   if (MaybeSecInfo == SectionLines.end())
271*06c3fb27SDimitry Andric     return nullptr;
272*06c3fb27SDimitry Andric 
273*06c3fb27SDimitry Andric   const BTFLinesVector &SecInfo = MaybeSecInfo->second;
274*06c3fb27SDimitry Andric   const uint64_t TargetOffset = Address.Address;
275*06c3fb27SDimitry Andric   BTFLinesVector::const_iterator LineInfo =
276*06c3fb27SDimitry Andric       llvm::partition_point(SecInfo, [=](const BTF::BPFLineInfo &Line) {
277*06c3fb27SDimitry Andric         return Line.InsnOffset < TargetOffset;
278*06c3fb27SDimitry Andric       });
279*06c3fb27SDimitry Andric   if (LineInfo == SecInfo.end() || LineInfo->InsnOffset != Address.Address)
280*06c3fb27SDimitry Andric     return nullptr;
281*06c3fb27SDimitry Andric 
282*06c3fb27SDimitry Andric   return LineInfo;
283*06c3fb27SDimitry Andric }
284