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