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