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/ADT/StringExtras.h" 16 #include "llvm/Support/Endian.h" 17 #include "llvm/Support/Errc.h" 18 19 #define DEBUG_TYPE "debug-info-btf-parser" 20 21 using namespace llvm; 22 using object::ObjectFile; 23 using object::SectionedAddress; 24 using object::SectionRef; 25 26 const char BTFSectionName[] = ".BTF"; 27 const char BTFExtSectionName[] = ".BTF.ext"; 28 29 // Utility class with API similar to raw_ostream but can be cast 30 // to Error, e.g.: 31 // 32 // Error foo(...) { 33 // ... 34 // if (Error E = bar(...)) 35 // return Err("error while foo(): ") << E; 36 // ... 37 // } 38 // 39 namespace { 40 class Err { 41 std::string Buffer; 42 raw_string_ostream Stream; 43 44 public: 45 Err(const char *InitialMsg) : Buffer(InitialMsg), Stream(Buffer) {} 46 Err(const char *SectionName, DataExtractor::Cursor &C) 47 : Buffer(), Stream(Buffer) { 48 *this << "error while reading " << SectionName 49 << " section: " << C.takeError(); 50 }; 51 52 template <typename T> Err &operator<<(T Val) { 53 Stream << Val; 54 return *this; 55 } 56 57 Err &write_hex(unsigned long long Val) { 58 Stream.write_hex(Val); 59 return *this; 60 } 61 62 Err &operator<<(Error Val) { 63 handleAllErrors(std::move(Val), 64 [=](ErrorInfoBase &Info) { Stream << Info.message(); }); 65 return *this; 66 } 67 68 operator Error() const { 69 return make_error<StringError>(Buffer, errc::invalid_argument); 70 } 71 }; 72 } // anonymous namespace 73 74 // ParseContext wraps information that is only necessary while parsing 75 // ObjectFile and can be discarded once parsing is done. 76 // Used by BTFParser::parse* auxiliary functions. 77 struct BTFParser::ParseContext { 78 const ObjectFile &Obj; 79 const ParseOptions &Opts; 80 // Map from ELF section name to SectionRef 81 DenseMap<StringRef, SectionRef> Sections; 82 83 public: 84 ParseContext(const ObjectFile &Obj, const ParseOptions &Opts) 85 : Obj(Obj), Opts(Opts) {} 86 87 Expected<DataExtractor> makeExtractor(SectionRef Sec) { 88 Expected<StringRef> Contents = Sec.getContents(); 89 if (!Contents) 90 return Contents.takeError(); 91 return DataExtractor(Contents.get(), Obj.isLittleEndian(), 92 Obj.getBytesInAddress()); 93 } 94 95 std::optional<SectionRef> findSection(StringRef Name) const { 96 auto It = Sections.find(Name); 97 if (It != Sections.end()) 98 return It->second; 99 return std::nullopt; 100 } 101 }; 102 103 Error BTFParser::parseBTF(ParseContext &Ctx, SectionRef BTF) { 104 Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTF); 105 if (!MaybeExtractor) 106 return MaybeExtractor.takeError(); 107 108 DataExtractor &Extractor = MaybeExtractor.get(); 109 DataExtractor::Cursor C = DataExtractor::Cursor(0); 110 uint16_t Magic = Extractor.getU16(C); 111 if (!C) 112 return Err(".BTF", C); 113 if (Magic != BTF::MAGIC) 114 return Err("invalid .BTF magic: ").write_hex(Magic); 115 uint8_t Version = Extractor.getU8(C); 116 if (!C) 117 return Err(".BTF", C); 118 if (Version != 1) 119 return Err("unsupported .BTF version: ") << (unsigned)Version; 120 (void)Extractor.getU8(C); // flags 121 uint32_t HdrLen = Extractor.getU32(C); 122 if (!C) 123 return Err(".BTF", C); 124 if (HdrLen < 8) 125 return Err("unexpected .BTF header length: ") << HdrLen; 126 uint32_t TypeOff = Extractor.getU32(C); 127 uint32_t TypeLen = Extractor.getU32(C); 128 uint32_t StrOff = Extractor.getU32(C); 129 uint32_t StrLen = Extractor.getU32(C); 130 uint32_t StrStart = HdrLen + StrOff; 131 uint32_t StrEnd = StrStart + StrLen; 132 uint32_t TypesInfoStart = HdrLen + TypeOff; 133 uint32_t TypesInfoEnd = TypesInfoStart + TypeLen; 134 uint32_t BytesExpected = std::max(StrEnd, TypesInfoEnd); 135 if (!C) 136 return Err(".BTF", C); 137 if (Extractor.getData().size() < BytesExpected) 138 return Err("invalid .BTF section size, expecting at-least ") 139 << BytesExpected << " bytes"; 140 141 StringsTable = Extractor.getData().slice(StrStart, StrEnd); 142 143 if (TypeLen > 0 && Ctx.Opts.LoadTypes) { 144 StringRef RawData = Extractor.getData().slice(TypesInfoStart, TypesInfoEnd); 145 if (Error E = parseTypesInfo(Ctx, TypesInfoStart, RawData)) 146 return E; 147 } 148 149 return Error::success(); 150 } 151 152 // Compute record size for each BTF::CommonType sub-type 153 // (including entries in the tail position). 154 static size_t byteSize(BTF::CommonType *Type) { 155 size_t Size = sizeof(BTF::CommonType); 156 switch (Type->getKind()) { 157 case BTF::BTF_KIND_INT: 158 Size += sizeof(uint32_t); 159 break; 160 case BTF::BTF_KIND_ARRAY: 161 Size += sizeof(BTF::BTFArray); 162 break; 163 case BTF::BTF_KIND_VAR: 164 Size += sizeof(uint32_t); 165 break; 166 case BTF::BTF_KIND_DECL_TAG: 167 Size += sizeof(uint32_t); 168 break; 169 case BTF::BTF_KIND_STRUCT: 170 case BTF::BTF_KIND_UNION: 171 Size += sizeof(BTF::BTFMember) * Type->getVlen(); 172 break; 173 case BTF::BTF_KIND_ENUM: 174 Size += sizeof(BTF::BTFEnum) * Type->getVlen(); 175 break; 176 case BTF::BTF_KIND_ENUM64: 177 Size += sizeof(BTF::BTFEnum64) * Type->getVlen(); 178 break; 179 case BTF::BTF_KIND_FUNC_PROTO: 180 Size += sizeof(BTF::BTFParam) * Type->getVlen(); 181 break; 182 case BTF::BTF_KIND_DATASEC: 183 Size += sizeof(BTF::BTFDataSec) * Type->getVlen(); 184 break; 185 } 186 return Size; 187 } 188 189 // Guard value for voids, simplifies code a bit, but NameOff is not 190 // actually valid. 191 const BTF::CommonType VoidTypeInst = {0, BTF::BTF_KIND_UNKN << 24, {0}}; 192 193 // Type information "parsing" is very primitive: 194 // - The `RawData` is copied to a buffer owned by `BTFParser` instance. 195 // - The buffer is treated as an array of `uint32_t` values, each value 196 // is swapped to use native endianness. This is possible, because 197 // according to BTF spec all buffer elements are structures comprised 198 // of `uint32_t` fields. 199 // - `BTFParser::Types` vector is filled with pointers to buffer 200 // elements, using `byteSize()` function to slice the buffer at type 201 // record boundaries. 202 // - If at some point a type definition with incorrect size (logical size 203 // exceeding buffer boundaries) is reached it is not added to the 204 // `BTFParser::Types` vector and the process stops. 205 Error BTFParser::parseTypesInfo(ParseContext &Ctx, uint64_t TypesInfoStart, 206 StringRef RawData) { 207 using support::endian::byte_swap; 208 209 TypesBuffer = OwningArrayRef<uint8_t>(arrayRefFromStringRef(RawData)); 210 // Switch endianness if necessary. 211 endianness Endianness = Ctx.Obj.isLittleEndian() ? llvm::endianness::little 212 : llvm::endianness::big; 213 uint32_t *TypesBuffer32 = (uint32_t *)TypesBuffer.data(); 214 for (uint64_t I = 0; I < TypesBuffer.size() / 4; ++I) 215 TypesBuffer32[I] = byte_swap(TypesBuffer32[I], Endianness); 216 217 // The type id 0 is reserved for void type. 218 Types.push_back(&VoidTypeInst); 219 220 uint64_t Pos = 0; 221 while (Pos < RawData.size()) { 222 uint64_t BytesLeft = RawData.size() - Pos; 223 uint64_t Offset = TypesInfoStart + Pos; 224 BTF::CommonType *Type = (BTF::CommonType *)&TypesBuffer[Pos]; 225 if (BytesLeft < sizeof(*Type)) 226 return Err("incomplete type definition in .BTF section:") 227 << " offset " << Offset << ", index " << Types.size(); 228 229 uint64_t Size = byteSize(Type); 230 if (BytesLeft < Size) 231 return Err("incomplete type definition in .BTF section:") 232 << " offset=" << Offset << ", index=" << Types.size() 233 << ", vlen=" << Type->getVlen(); 234 235 LLVM_DEBUG({ 236 llvm::dbgs() << "Adding BTF type:\n" 237 << " Id = " << Types.size() << "\n" 238 << " Kind = " << Type->getKind() << "\n" 239 << " Name = " << findString(Type->NameOff) << "\n" 240 << " Record Size = " << Size << "\n"; 241 }); 242 Types.push_back(Type); 243 Pos += Size; 244 } 245 246 return Error::success(); 247 } 248 249 Error BTFParser::parseBTFExt(ParseContext &Ctx, SectionRef BTFExt) { 250 Expected<DataExtractor> MaybeExtractor = Ctx.makeExtractor(BTFExt); 251 if (!MaybeExtractor) 252 return MaybeExtractor.takeError(); 253 254 DataExtractor &Extractor = MaybeExtractor.get(); 255 DataExtractor::Cursor C = DataExtractor::Cursor(0); 256 uint16_t Magic = Extractor.getU16(C); 257 if (!C) 258 return Err(".BTF.ext", C); 259 if (Magic != BTF::MAGIC) 260 return Err("invalid .BTF.ext magic: ").write_hex(Magic); 261 uint8_t Version = Extractor.getU8(C); 262 if (!C) 263 return Err(".BTF", C); 264 if (Version != 1) 265 return Err("unsupported .BTF.ext version: ") << (unsigned)Version; 266 (void)Extractor.getU8(C); // flags 267 uint32_t HdrLen = Extractor.getU32(C); 268 if (!C) 269 return Err(".BTF.ext", C); 270 if (HdrLen < 8) 271 return Err("unexpected .BTF.ext header length: ") << HdrLen; 272 (void)Extractor.getU32(C); // func_info_off 273 (void)Extractor.getU32(C); // func_info_len 274 uint32_t LineInfoOff = Extractor.getU32(C); 275 uint32_t LineInfoLen = Extractor.getU32(C); 276 uint32_t RelocInfoOff = Extractor.getU32(C); 277 uint32_t RelocInfoLen = Extractor.getU32(C); 278 if (!C) 279 return Err(".BTF.ext", C); 280 281 if (LineInfoLen > 0 && Ctx.Opts.LoadLines) { 282 uint32_t LineInfoStart = HdrLen + LineInfoOff; 283 uint32_t LineInfoEnd = LineInfoStart + LineInfoLen; 284 if (Error E = parseLineInfo(Ctx, Extractor, LineInfoStart, LineInfoEnd)) 285 return E; 286 } 287 288 if (RelocInfoLen > 0 && Ctx.Opts.LoadRelocs) { 289 uint32_t RelocInfoStart = HdrLen + RelocInfoOff; 290 uint32_t RelocInfoEnd = RelocInfoStart + RelocInfoLen; 291 if (Error E = parseRelocInfo(Ctx, Extractor, RelocInfoStart, RelocInfoEnd)) 292 return E; 293 } 294 295 return Error::success(); 296 } 297 298 Error BTFParser::parseLineInfo(ParseContext &Ctx, DataExtractor &Extractor, 299 uint64_t LineInfoStart, uint64_t LineInfoEnd) { 300 DataExtractor::Cursor C = DataExtractor::Cursor(LineInfoStart); 301 uint32_t RecSize = Extractor.getU32(C); 302 if (!C) 303 return Err(".BTF.ext", C); 304 if (RecSize < 16) 305 return Err("unexpected .BTF.ext line info record length: ") << RecSize; 306 307 while (C && C.tell() < LineInfoEnd) { 308 uint32_t SecNameOff = Extractor.getU32(C); 309 uint32_t NumInfo = Extractor.getU32(C); 310 StringRef SecName = findString(SecNameOff); 311 std::optional<SectionRef> Sec = Ctx.findSection(SecName); 312 if (!C) 313 return Err(".BTF.ext", C); 314 if (!Sec) 315 return Err("") << "can't find section '" << SecName 316 << "' while parsing .BTF.ext line info"; 317 BTFLinesVector &Lines = SectionLines[Sec->getIndex()]; 318 for (uint32_t I = 0; C && I < NumInfo; ++I) { 319 uint64_t RecStart = C.tell(); 320 uint32_t InsnOff = Extractor.getU32(C); 321 uint32_t FileNameOff = Extractor.getU32(C); 322 uint32_t LineOff = Extractor.getU32(C); 323 uint32_t LineCol = Extractor.getU32(C); 324 if (!C) 325 return Err(".BTF.ext", C); 326 Lines.push_back({InsnOff, FileNameOff, LineOff, LineCol}); 327 C.seek(RecStart + RecSize); 328 } 329 llvm::stable_sort(Lines, 330 [](const BTF::BPFLineInfo &L, const BTF::BPFLineInfo &R) { 331 return L.InsnOffset < R.InsnOffset; 332 }); 333 } 334 if (!C) 335 return Err(".BTF.ext", C); 336 337 return Error::success(); 338 } 339 340 Error BTFParser::parseRelocInfo(ParseContext &Ctx, DataExtractor &Extractor, 341 uint64_t RelocInfoStart, 342 uint64_t RelocInfoEnd) { 343 DataExtractor::Cursor C = DataExtractor::Cursor(RelocInfoStart); 344 uint32_t RecSize = Extractor.getU32(C); 345 if (!C) 346 return Err(".BTF.ext", C); 347 if (RecSize < 16) 348 return Err("unexpected .BTF.ext field reloc info record length: ") 349 << RecSize; 350 while (C && C.tell() < RelocInfoEnd) { 351 uint32_t SecNameOff = Extractor.getU32(C); 352 uint32_t NumInfo = Extractor.getU32(C); 353 StringRef SecName = findString(SecNameOff); 354 std::optional<SectionRef> Sec = Ctx.findSection(SecName); 355 BTFRelocVector &Relocs = SectionRelocs[Sec->getIndex()]; 356 for (uint32_t I = 0; C && I < NumInfo; ++I) { 357 uint64_t RecStart = C.tell(); 358 uint32_t InsnOff = Extractor.getU32(C); 359 uint32_t TypeID = Extractor.getU32(C); 360 uint32_t OffsetNameOff = Extractor.getU32(C); 361 uint32_t RelocKind = Extractor.getU32(C); 362 if (!C) 363 return Err(".BTF.ext", C); 364 Relocs.push_back({InsnOff, TypeID, OffsetNameOff, RelocKind}); 365 C.seek(RecStart + RecSize); 366 } 367 llvm::stable_sort( 368 Relocs, [](const BTF::BPFFieldReloc &L, const BTF::BPFFieldReloc &R) { 369 return L.InsnOffset < R.InsnOffset; 370 }); 371 } 372 if (!C) 373 return Err(".BTF.ext", C); 374 375 return Error::success(); 376 } 377 378 Error BTFParser::parse(const ObjectFile &Obj, const ParseOptions &Opts) { 379 StringsTable = StringRef(); 380 SectionLines.clear(); 381 SectionRelocs.clear(); 382 Types.clear(); 383 TypesBuffer = OwningArrayRef<uint8_t>(); 384 385 ParseContext Ctx(Obj, Opts); 386 std::optional<SectionRef> BTF; 387 std::optional<SectionRef> BTFExt; 388 for (SectionRef Sec : Obj.sections()) { 389 Expected<StringRef> MaybeName = Sec.getName(); 390 if (!MaybeName) 391 return Err("error while reading section name: ") << MaybeName.takeError(); 392 Ctx.Sections[*MaybeName] = Sec; 393 if (*MaybeName == BTFSectionName) 394 BTF = Sec; 395 if (*MaybeName == BTFExtSectionName) 396 BTFExt = Sec; 397 } 398 if (!BTF) 399 return Err("can't find .BTF section"); 400 if (!BTFExt) 401 return Err("can't find .BTF.ext section"); 402 if (Error E = parseBTF(Ctx, *BTF)) 403 return E; 404 if (Error E = parseBTFExt(Ctx, *BTFExt)) 405 return E; 406 407 return Error::success(); 408 } 409 410 bool BTFParser::hasBTFSections(const ObjectFile &Obj) { 411 bool HasBTF = false; 412 bool HasBTFExt = false; 413 for (SectionRef Sec : Obj.sections()) { 414 Expected<StringRef> Name = Sec.getName(); 415 if (Error E = Name.takeError()) { 416 logAllUnhandledErrors(std::move(E), errs()); 417 continue; 418 } 419 HasBTF |= *Name == BTFSectionName; 420 HasBTFExt |= *Name == BTFExtSectionName; 421 if (HasBTF && HasBTFExt) 422 return true; 423 } 424 return false; 425 } 426 427 StringRef BTFParser::findString(uint32_t Offset) const { 428 return StringsTable.slice(Offset, StringsTable.find(0, Offset)); 429 } 430 431 template <typename T> 432 static const T *findInfo(const DenseMap<uint64_t, SmallVector<T, 0>> &SecMap, 433 SectionedAddress Address) { 434 auto MaybeSecInfo = SecMap.find(Address.SectionIndex); 435 if (MaybeSecInfo == SecMap.end()) 436 return nullptr; 437 438 const SmallVector<T, 0> &SecInfo = MaybeSecInfo->second; 439 const uint64_t TargetOffset = Address.Address; 440 typename SmallVector<T, 0>::const_iterator MaybeInfo = llvm::partition_point( 441 SecInfo, [=](const T &Entry) { return Entry.InsnOffset < TargetOffset; }); 442 if (MaybeInfo == SecInfo.end() || MaybeInfo->InsnOffset != Address.Address) 443 return nullptr; 444 445 return &*MaybeInfo; 446 } 447 448 const BTF::BPFLineInfo * 449 BTFParser::findLineInfo(SectionedAddress Address) const { 450 return findInfo(SectionLines, Address); 451 } 452 453 const BTF::BPFFieldReloc * 454 BTFParser::findFieldReloc(SectionedAddress Address) const { 455 return findInfo(SectionRelocs, Address); 456 } 457 458 const BTF::CommonType *BTFParser::findType(uint32_t Id) const { 459 if (Id < Types.size()) 460 return Types[Id]; 461 return nullptr; 462 } 463 464 enum RelocKindGroup { 465 RKG_FIELD, 466 RKG_TYPE, 467 RKG_ENUMVAL, 468 RKG_UNKNOWN, 469 }; 470 471 static RelocKindGroup relocKindGroup(const BTF::BPFFieldReloc *Reloc) { 472 switch (Reloc->RelocKind) { 473 case BTF::FIELD_BYTE_OFFSET: 474 case BTF::FIELD_BYTE_SIZE: 475 case BTF::FIELD_EXISTENCE: 476 case BTF::FIELD_SIGNEDNESS: 477 case BTF::FIELD_LSHIFT_U64: 478 case BTF::FIELD_RSHIFT_U64: 479 return RKG_FIELD; 480 case BTF::BTF_TYPE_ID_LOCAL: 481 case BTF::BTF_TYPE_ID_REMOTE: 482 case BTF::TYPE_EXISTENCE: 483 case BTF::TYPE_MATCH: 484 case BTF::TYPE_SIZE: 485 return RKG_TYPE; 486 case BTF::ENUM_VALUE_EXISTENCE: 487 case BTF::ENUM_VALUE: 488 return RKG_ENUMVAL; 489 default: 490 return RKG_UNKNOWN; 491 } 492 } 493 494 static bool isMod(const BTF::CommonType *Type) { 495 switch (Type->getKind()) { 496 case BTF::BTF_KIND_VOLATILE: 497 case BTF::BTF_KIND_CONST: 498 case BTF::BTF_KIND_RESTRICT: 499 case BTF::BTF_KIND_TYPE_TAG: 500 return true; 501 default: 502 return false; 503 } 504 } 505 506 static bool printMod(const BTFParser &BTF, const BTF::CommonType *Type, 507 raw_ostream &Stream) { 508 switch (Type->getKind()) { 509 case BTF::BTF_KIND_CONST: 510 Stream << " const"; 511 break; 512 case BTF::BTF_KIND_VOLATILE: 513 Stream << " volatile"; 514 break; 515 case BTF::BTF_KIND_RESTRICT: 516 Stream << " restrict"; 517 break; 518 case BTF::BTF_KIND_TYPE_TAG: 519 Stream << " type_tag(\"" << BTF.findString(Type->NameOff) << "\")"; 520 break; 521 default: 522 return false; 523 } 524 return true; 525 } 526 527 static const BTF::CommonType *skipModsAndTypedefs(const BTFParser &BTF, 528 const BTF::CommonType *Type) { 529 while (isMod(Type) || Type->getKind() == BTF::BTF_KIND_TYPEDEF) { 530 auto *Base = BTF.findType(Type->Type); 531 if (!Base) 532 break; 533 Type = Base; 534 } 535 return Type; 536 } 537 538 namespace { 539 struct StrOrAnon { 540 const BTFParser &BTF; 541 uint32_t Offset; 542 uint32_t Idx; 543 }; 544 545 static raw_ostream &operator<<(raw_ostream &Stream, const StrOrAnon &S) { 546 StringRef Str = S.BTF.findString(S.Offset); 547 if (Str.empty()) 548 Stream << "<anon " << S.Idx << ">"; 549 else 550 Stream << Str; 551 return Stream; 552 } 553 } // anonymous namespace 554 555 static void relocKindName(uint32_t X, raw_ostream &Out) { 556 Out << "<"; 557 switch (X) { 558 default: 559 Out << "reloc kind #" << X; 560 break; 561 case BTF::FIELD_BYTE_OFFSET: 562 Out << "byte_off"; 563 break; 564 case BTF::FIELD_BYTE_SIZE: 565 Out << "byte_sz"; 566 break; 567 case BTF::FIELD_EXISTENCE: 568 Out << "field_exists"; 569 break; 570 case BTF::FIELD_SIGNEDNESS: 571 Out << "signed"; 572 break; 573 case BTF::FIELD_LSHIFT_U64: 574 Out << "lshift_u64"; 575 break; 576 case BTF::FIELD_RSHIFT_U64: 577 Out << "rshift_u64"; 578 break; 579 case BTF::BTF_TYPE_ID_LOCAL: 580 Out << "local_type_id"; 581 break; 582 case BTF::BTF_TYPE_ID_REMOTE: 583 Out << "target_type_id"; 584 break; 585 case BTF::TYPE_EXISTENCE: 586 Out << "type_exists"; 587 break; 588 case BTF::TYPE_MATCH: 589 Out << "type_matches"; 590 break; 591 case BTF::TYPE_SIZE: 592 Out << "type_size"; 593 break; 594 case BTF::ENUM_VALUE_EXISTENCE: 595 Out << "enumval_exists"; 596 break; 597 case BTF::ENUM_VALUE: 598 Out << "enumval_value"; 599 break; 600 } 601 Out << ">"; 602 } 603 604 // Produces a human readable description of a CO-RE relocation. 605 // Such relocations are generated by BPF backend, and processed 606 // by libbpf's BPF program loader [1]. 607 // 608 // Each relocation record has the following information: 609 // - Relocation kind; 610 // - BTF type ID; 611 // - Access string offset in string table. 612 // 613 // There are different kinds of relocations, these kinds could be split 614 // in three groups: 615 // - load-time information about types (size, existence), 616 // `BTFParser::symbolize()` output for such relocations uses the template: 617 // 618 // <relocation-kind> [<id>] <type-name> 619 // 620 // For example: 621 // - "<type_exists> [7] struct foo" 622 // - "<type_size> [7] struct foo" 623 // 624 // - load-time information about enums (literal existence, literal value), 625 // `BTFParser::symbolize()` output for such relocations uses the template: 626 // 627 // <relocation-kind> [<id>] <type-name>::<literal-name> = <original-value> 628 // 629 // For example: 630 // - "<enumval_exists> [5] enum foo::U = 1" 631 // - "<enumval_value> [5] enum foo::V = 2" 632 // 633 // - load-time information about fields (e.g. field offset), 634 // `BTFParser::symbolize()` output for such relocations uses the template: 635 // 636 // <relocation-kind> [<id>] \ 637 // <type-name>::[N].<field-1-name>...<field-M-name> \ 638 // (<access string>) 639 // 640 // For example: 641 // - "<byte_off> [8] struct bar::[7].v (7:1)" 642 // - "<field_exists> [8] struct bar::v (0:1)" 643 // 644 // If relocation description is not valid output follows the following pattern: 645 // 646 // <relocation-kind> <type-id>::<unprocessedaccess-string> <<error-msg>> 647 // 648 // For example: 649 // 650 // - "<type_sz> [42] '' <unknown type id: 42>" 651 // - "<byte_off> [4] '0:' <field spec too short>" 652 // 653 // Additional examples could be found in unit tests, see 654 // llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp. 655 // 656 // [1] https://www.kernel.org/doc/html/latest/bpf/libbpf/index.html 657 void BTFParser::symbolize(const BTF::BPFFieldReloc *Reloc, 658 SmallVectorImpl<char> &Result) const { 659 raw_svector_ostream Stream(Result); 660 StringRef FullSpecStr = findString(Reloc->OffsetNameOff); 661 SmallVector<uint32_t, 8> RawSpec; 662 663 auto Fail = [&](auto Msg) { 664 Result.resize(0); 665 relocKindName(Reloc->RelocKind, Stream); 666 Stream << " [" << Reloc->TypeID << "] '" << FullSpecStr << "'" 667 << " <" << Msg << ">"; 668 }; 669 670 // Relocation access string follows pattern [0-9]+(:[0-9]+)*, 671 // e.g.: 12:22:3. Code below splits `SpecStr` by ':', parses 672 // numbers, and pushes them to `RawSpec`. 673 StringRef SpecStr = FullSpecStr; 674 while (SpecStr.size()) { 675 unsigned long long Val; 676 if (consumeUnsignedInteger(SpecStr, 10, Val)) 677 return Fail("spec string is not a number"); 678 RawSpec.push_back(Val); 679 if (SpecStr.empty()) 680 break; 681 if (SpecStr[0] != ':') 682 return Fail(format("unexpected spec string delimiter: '%c'", SpecStr[0])); 683 SpecStr = SpecStr.substr(1); 684 } 685 686 // Print relocation kind to `Stream`. 687 relocKindName(Reloc->RelocKind, Stream); 688 689 uint32_t CurId = Reloc->TypeID; 690 const BTF::CommonType *Type = findType(CurId); 691 if (!Type) 692 return Fail(format("unknown type id: %d", CurId)); 693 694 Stream << " [" << CurId << "]"; 695 696 // `Type` might have modifiers, e.g. for type 'const int' the `Type` 697 // would refer to BTF type of kind BTF_KIND_CONST. 698 // Print all these modifiers to `Stream`. 699 for (uint32_t ChainLen = 0; printMod(*this, Type, Stream); ++ChainLen) { 700 if (ChainLen >= 32) 701 return Fail("modifiers chain is too long"); 702 703 CurId = Type->Type; 704 const BTF::CommonType *NextType = findType(CurId); 705 if (!NextType) 706 return Fail(format("unknown type id: %d in modifiers chain", CurId)); 707 Type = NextType; 708 } 709 // Print the type name to `Stream`. 710 if (CurId == 0) { 711 Stream << " void"; 712 } else { 713 switch (Type->getKind()) { 714 case BTF::BTF_KIND_TYPEDEF: 715 Stream << " typedef"; 716 break; 717 case BTF::BTF_KIND_STRUCT: 718 Stream << " struct"; 719 break; 720 case BTF::BTF_KIND_UNION: 721 Stream << " union"; 722 break; 723 case BTF::BTF_KIND_ENUM: 724 Stream << " enum"; 725 break; 726 case BTF::BTF_KIND_ENUM64: 727 Stream << " enum"; 728 break; 729 case BTF::BTF_KIND_FWD: 730 if (Type->Info & BTF::FWD_UNION_FLAG) 731 Stream << " fwd union"; 732 else 733 Stream << " fwd struct"; 734 break; 735 default: 736 break; 737 } 738 Stream << " " << StrOrAnon({*this, Type->NameOff, CurId}); 739 } 740 741 RelocKindGroup Group = relocKindGroup(Reloc); 742 // Type-based relocations don't use access string but clang backend 743 // generates '0' and libbpf checks it's value, do the same here. 744 if (Group == RKG_TYPE) { 745 if (RawSpec.size() != 1 || RawSpec[0] != 0) 746 return Fail("unexpected type-based relocation spec: should be '0'"); 747 return; 748 } 749 750 Stream << "::"; 751 752 // For enum-based relocations access string is a single number, 753 // corresponding to the enum literal sequential number. 754 // E.g. for `enum E { U, V }`, relocation requesting value of `V` 755 // would look as follows: 756 // - kind: BTF::ENUM_VALUE 757 // - BTF id: id for `E` 758 // - access string: "1" 759 if (Group == RKG_ENUMVAL) { 760 Type = skipModsAndTypedefs(*this, Type); 761 762 if (RawSpec.size() != 1) 763 return Fail("unexpected enumval relocation spec size"); 764 765 uint32_t NameOff; 766 uint64_t Val; 767 uint32_t Idx = RawSpec[0]; 768 if (auto *T = dyn_cast<BTF::EnumType>(Type)) { 769 if (T->values().size() <= Idx) 770 return Fail(format("bad value index: %d", Idx)); 771 const BTF::BTFEnum &E = T->values()[Idx]; 772 NameOff = E.NameOff; 773 Val = E.Val; 774 } else if (auto *T = dyn_cast<BTF::Enum64Type>(Type)) { 775 if (T->values().size() <= Idx) 776 return Fail(format("bad value index: %d", Idx)); 777 const BTF::BTFEnum64 &E = T->values()[Idx]; 778 NameOff = E.NameOff; 779 Val = (uint64_t)E.Val_Hi32 << 32u | E.Val_Lo32; 780 } else { 781 return Fail(format("unexpected type kind for enum relocation: %d", 782 Type->getKind())); 783 } 784 785 Stream << StrOrAnon({*this, NameOff, Idx}); 786 if (Type->Info & BTF::ENUM_SIGNED_FLAG) 787 Stream << " = " << (int64_t)Val; 788 else 789 Stream << " = " << (uint64_t)Val; 790 return; 791 } 792 793 // For type-based relocations access string is an array of numbers, 794 // which resemble index parameters for `getelementptr` LLVM IR instruction. 795 // E.g. for the following types: 796 // 797 // struct foo { 798 // int a; 799 // int b; 800 // }; 801 // struct bar { 802 // int u; 803 // struct foo v[7]; 804 // }; 805 // 806 // Relocation requesting `offsetof(struct bar, v[2].b)` will have 807 // the following access string: 0:1:2:1 808 // ^ ^ ^ ^ 809 // | | | | 810 // initial index | | field 'b' is a field #1 811 // | | (counting from 0) 812 // | array index #2 813 // field 'v' is a field #1 814 // (counting from 0) 815 if (Group == RKG_FIELD) { 816 if (RawSpec.size() < 1) 817 return Fail("field spec too short"); 818 819 if (RawSpec[0] != 0) 820 Stream << "[" << RawSpec[0] << "]"; 821 for (uint32_t I = 1; I < RawSpec.size(); ++I) { 822 Type = skipModsAndTypedefs(*this, Type); 823 uint32_t Idx = RawSpec[I]; 824 825 if (auto *T = dyn_cast<BTF::StructType>(Type)) { 826 if (T->getVlen() <= Idx) 827 return Fail( 828 format("member index %d for spec sub-string %d is out of range", 829 Idx, I)); 830 831 const BTF::BTFMember &Member = T->members()[Idx]; 832 if (I != 1 || RawSpec[0] != 0) 833 Stream << "."; 834 Stream << StrOrAnon({*this, Member.NameOff, Idx}); 835 Type = findType(Member.Type); 836 if (!Type) 837 return Fail(format("unknown member type id %d for spec sub-string %d", 838 Member.Type, I)); 839 } else if (auto *T = dyn_cast<BTF::ArrayType>(Type)) { 840 Stream << "[" << Idx << "]"; 841 Type = findType(T->getArray().ElemType); 842 if (!Type) 843 return Fail( 844 format("unknown element type id %d for spec sub-string %d", 845 T->getArray().ElemType, I)); 846 } else { 847 return Fail(format("unexpected type kind %d for spec sub-string %d", 848 Type->getKind(), I)); 849 } 850 } 851 852 Stream << " (" << FullSpecStr << ")"; 853 return; 854 } 855 856 return Fail(format("unknown relocation kind: %d", Reloc->RelocKind)); 857 } 858