1 //===- DWARFAcceleratorTable.h ----------------------------------*- C++ -*-===// 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 #ifndef LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H 10 #define LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H 11 12 #include "llvm/ADT/DenseSet.h" 13 #include "llvm/ADT/SmallString.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/BinaryFormat/Dwarf.h" 16 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 17 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 18 #include <cstdint> 19 #include <utility> 20 21 namespace llvm { 22 23 class raw_ostream; 24 class ScopedPrinter; 25 26 /// The accelerator tables are designed to allow efficient random access 27 /// (using a symbol name as a key) into debug info by providing an index of the 28 /// debug info DIEs. This class implements the common functionality of Apple and 29 /// DWARF 5 accelerator tables. 30 /// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it 31 /// to this class. 32 class DWARFAcceleratorTable { 33 protected: 34 DWARFDataExtractor AccelSection; 35 DataExtractor StringSection; 36 37 public: 38 /// An abstract class representing a single entry in the accelerator tables. 39 class Entry { 40 protected: 41 SmallVector<DWARFFormValue, 3> Values; 42 43 Entry() = default; 44 45 // Make these protected so only (final) subclasses can be copied around. 46 Entry(const Entry &) = default; 47 Entry(Entry &&) = default; 48 Entry &operator=(const Entry &) = default; 49 Entry &operator=(Entry &&) = default; 50 ~Entry() = default; 51 52 53 public: 54 /// Returns the Offset of the Compilation Unit associated with this 55 /// Accelerator Entry or std::nullopt if the Compilation Unit offset is not 56 /// recorded in this Accelerator Entry. 57 virtual std::optional<uint64_t> getCUOffset() const = 0; 58 59 /// Returns the Offset of the Type Unit associated with this 60 /// Accelerator Entry or std::nullopt if the Type Unit offset is not 61 /// recorded in this Accelerator Entry. getLocalTUOffset()62 virtual std::optional<uint64_t> getLocalTUOffset() const { 63 // Default return for accelerator tables that don't support type units. 64 return std::nullopt; 65 } 66 67 /// Returns the Tag of the Debug Info Entry associated with this 68 /// Accelerator Entry or std::nullopt if the Tag is not recorded in this 69 /// Accelerator Entry. 70 virtual std::optional<dwarf::Tag> getTag() const = 0; 71 72 /// Returns the raw values of fields in the Accelerator Entry. In general, 73 /// these can only be interpreted with the help of the metadata in the 74 /// owning Accelerator Table. getValues()75 ArrayRef<DWARFFormValue> getValues() const { return Values; } 76 }; 77 DWARFAcceleratorTable(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)78 DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, 79 DataExtractor StringSection) 80 : AccelSection(AccelSection), StringSection(StringSection) {} 81 virtual ~DWARFAcceleratorTable(); 82 83 virtual Error extract() = 0; 84 virtual void dump(raw_ostream &OS) const = 0; 85 86 DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete; 87 void operator=(const DWARFAcceleratorTable &) = delete; 88 }; 89 90 /// This implements the Apple accelerator table format, a precursor of the 91 /// DWARF 5 accelerator table format. 92 class AppleAcceleratorTable : public DWARFAcceleratorTable { 93 struct Header { 94 uint32_t Magic; 95 uint16_t Version; 96 uint16_t HashFunction; 97 uint32_t BucketCount; 98 uint32_t HashCount; 99 uint32_t HeaderDataLength; 100 101 void dump(ScopedPrinter &W) const; 102 }; 103 104 struct HeaderData { 105 using AtomType = uint16_t; 106 using Form = dwarf::Form; 107 108 uint64_t DIEOffsetBase; 109 SmallVector<std::pair<AtomType, Form>, 3> Atoms; 110 111 std::optional<uint64_t> 112 extractOffset(std::optional<DWARFFormValue> Value) const; 113 }; 114 115 Header Hdr; 116 HeaderData HdrData; 117 dwarf::FormParams FormParams; 118 uint32_t HashDataEntryLength; 119 bool IsValid = false; 120 121 /// Returns true if we should continue scanning for entries or false if we've 122 /// reached the last (sentinel) entry of encountered a parsing error. 123 bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms, 124 uint64_t *DataOffset) const; 125 126 /// Reads an uint32_t from the accelerator table at Offset, which is 127 /// incremented by the number of bytes read. 128 std::optional<uint32_t> readU32FromAccel(uint64_t &Offset, 129 bool UseRelocation = false) const; 130 131 /// Reads a StringRef from the string table at Offset. 132 std::optional<StringRef> 133 readStringFromStrSection(uint64_t StringSectionOffset) const; 134 135 /// Return the offset into the section where the Buckets begin. getBucketBase()136 uint64_t getBucketBase() const { return sizeof(Hdr) + Hdr.HeaderDataLength; } 137 138 /// Return the offset into the section where the I-th bucket is. getIthBucketBase(uint32_t I)139 uint64_t getIthBucketBase(uint32_t I) const { 140 return getBucketBase() + I * 4; 141 } 142 143 /// Return the offset into the section where the hash list begins. getHashBase()144 uint64_t getHashBase() const { return getBucketBase() + getNumBuckets() * 4; } 145 146 /// Return the offset into the section where the I-th hash is. getIthHashBase(uint32_t I)147 uint64_t getIthHashBase(uint32_t I) const { return getHashBase() + I * 4; } 148 149 /// Return the offset into the section where the offset list begins. getOffsetBase()150 uint64_t getOffsetBase() const { return getHashBase() + getNumHashes() * 4; } 151 152 /// Return the offset into the section where the table entries begin. getEntriesBase()153 uint64_t getEntriesBase() const { 154 return getOffsetBase() + getNumHashes() * 4; 155 } 156 157 /// Return the offset into the section where the I-th offset is. getIthOffsetBase(uint32_t I)158 uint64_t getIthOffsetBase(uint32_t I) const { 159 return getOffsetBase() + I * 4; 160 } 161 162 /// Returns the index of the bucket where a hypothetical Hash would be. hashToBucketIdx(uint32_t Hash)163 uint32_t hashToBucketIdx(uint32_t Hash) const { 164 return Hash % getNumBuckets(); 165 } 166 167 /// Returns true iff a hypothetical Hash would be assigned to the BucketIdx-th 168 /// bucket. wouldHashBeInBucket(uint32_t Hash,uint32_t BucketIdx)169 bool wouldHashBeInBucket(uint32_t Hash, uint32_t BucketIdx) const { 170 return hashToBucketIdx(Hash) == BucketIdx; 171 } 172 173 /// Reads the contents of the I-th bucket, that is, the index in the hash list 174 /// where the hashes corresponding to this bucket begin. readIthBucket(uint32_t I)175 std::optional<uint32_t> readIthBucket(uint32_t I) const { 176 uint64_t Offset = getIthBucketBase(I); 177 return readU32FromAccel(Offset); 178 } 179 180 /// Reads the I-th hash in the hash list. readIthHash(uint32_t I)181 std::optional<uint32_t> readIthHash(uint32_t I) const { 182 uint64_t Offset = getIthHashBase(I); 183 return readU32FromAccel(Offset); 184 } 185 186 /// Reads the I-th offset in the offset list. readIthOffset(uint32_t I)187 std::optional<uint32_t> readIthOffset(uint32_t I) const { 188 uint64_t Offset = getIthOffsetBase(I); 189 return readU32FromAccel(Offset); 190 } 191 192 /// Reads a string offset from the accelerator table at Offset, which is 193 /// incremented by the number of bytes read. readStringOffsetAt(uint64_t & Offset)194 std::optional<uint32_t> readStringOffsetAt(uint64_t &Offset) const { 195 return readU32FromAccel(Offset, /*UseRelocation*/ true); 196 } 197 198 /// Scans through all Hashes in the BucketIdx-th bucket, attempting to find 199 /// HashToFind. If it is found, its index in the list of hashes is returned. 200 std::optional<uint32_t> idxOfHashInBucket(uint32_t HashToFind, 201 uint32_t BucketIdx) const; 202 203 public: 204 /// Apple-specific implementation of an Accelerator Entry. 205 class Entry final : public DWARFAcceleratorTable::Entry { 206 const AppleAcceleratorTable &Table; 207 208 Entry(const AppleAcceleratorTable &Table); 209 void extract(uint64_t *Offset); 210 211 public: 212 std::optional<uint64_t> getCUOffset() const override; 213 214 /// Returns the Section Offset of the Debug Info Entry associated with this 215 /// Accelerator Entry or std::nullopt if the DIE offset is not recorded in 216 /// this Accelerator Entry. The returned offset is relative to the start of 217 /// the Section containing the DIE. 218 std::optional<uint64_t> getDIESectionOffset() const; 219 220 std::optional<dwarf::Tag> getTag() const override; 221 222 /// Returns the value of the Atom in this Accelerator Entry, if the Entry 223 /// contains such Atom. 224 std::optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const; 225 226 friend class AppleAcceleratorTable; 227 friend class ValueIterator; 228 }; 229 230 /// An iterator for Entries all having the same string as key. 231 class SameNameIterator 232 : public iterator_facade_base<SameNameIterator, std::forward_iterator_tag, 233 Entry> { 234 Entry Current; 235 uint64_t Offset = 0; 236 237 public: 238 /// Construct a new iterator for the entries at \p DataOffset. 239 SameNameIterator(const AppleAcceleratorTable &AccelTable, 240 uint64_t DataOffset); 241 242 const Entry &operator*() { 243 uint64_t OffsetCopy = Offset; 244 Current.extract(&OffsetCopy); 245 return Current; 246 } 247 SameNameIterator &operator++() { 248 Offset += Current.Table.getHashDataEntryLength(); 249 return *this; 250 } 251 friend bool operator==(const SameNameIterator &A, 252 const SameNameIterator &B) { 253 return A.Offset == B.Offset; 254 } 255 }; 256 257 struct EntryWithName { EntryWithNameEntryWithName258 EntryWithName(const AppleAcceleratorTable &Table) 259 : BaseEntry(Table), StrOffset(0) {} 260 readNameEntryWithName261 std::optional<StringRef> readName() const { 262 return BaseEntry.Table.readStringFromStrSection(StrOffset); 263 } 264 265 Entry BaseEntry; 266 uint32_t StrOffset; 267 }; 268 269 /// An iterator for all entries in the table. 270 class Iterator 271 : public iterator_facade_base<Iterator, std::forward_iterator_tag, 272 EntryWithName> { 273 constexpr static auto EndMarker = std::numeric_limits<uint64_t>::max(); 274 275 EntryWithName Current; 276 uint64_t Offset = EndMarker; 277 uint32_t NumEntriesToCome = 0; 278 setToEnd()279 void setToEnd() { Offset = EndMarker; } isEnd()280 bool isEnd() const { return Offset == EndMarker; } getTable()281 const AppleAcceleratorTable &getTable() const { 282 return Current.BaseEntry.Table; 283 } 284 285 /// Reads the next Entry in the table, populating `Current`. 286 /// If not possible (e.g. end of the section), becomes the end iterator. 287 void prepareNextEntryOrEnd(); 288 289 /// Reads the next string pointer and the entry count for that string, 290 /// populating `NumEntriesToCome`. 291 /// If not possible (e.g. end of the section), becomes the end iterator. 292 /// Assumes `Offset` points to a string reference. 293 void prepareNextStringOrEnd(); 294 295 public: 296 Iterator(const AppleAcceleratorTable &Table, bool SetEnd = false); 297 298 Iterator &operator++() { 299 prepareNextEntryOrEnd(); 300 return *this; 301 } 302 bool operator==(const Iterator &It) const { return Offset == It.Offset; } 303 const EntryWithName &operator*() const { 304 assert(!isEnd() && "dereferencing end iterator"); 305 return Current; 306 } 307 }; 308 AppleAcceleratorTable(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)309 AppleAcceleratorTable(const DWARFDataExtractor &AccelSection, 310 DataExtractor StringSection) 311 : DWARFAcceleratorTable(AccelSection, StringSection) {} 312 313 Error extract() override; 314 uint32_t getNumBuckets() const; 315 uint32_t getNumHashes() const; 316 uint32_t getSizeHdr() const; 317 uint32_t getHeaderDataLength() const; 318 319 /// Returns the size of one HashData entry. getHashDataEntryLength()320 uint32_t getHashDataEntryLength() const { return HashDataEntryLength; } 321 322 /// Return the Atom description, which can be used to interpret the raw values 323 /// of the Accelerator Entries in this table. 324 ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc(); 325 326 /// Returns true iff `AtomTy` is one of the atoms available in Entries of this 327 /// table. containsAtomType(HeaderData::AtomType AtomTy)328 bool containsAtomType(HeaderData::AtomType AtomTy) const { 329 return is_contained(make_first_range(HdrData.Atoms), AtomTy); 330 } 331 332 bool validateForms(); 333 334 /// Return information related to the DWARF DIE we're looking for when 335 /// performing a lookup by name. 336 /// 337 /// \param HashDataOffset an offset into the hash data table 338 /// \returns <DieOffset, DieTag> 339 /// DieOffset is the offset into the .debug_info section for the DIE 340 /// related to the input hash data offset. 341 /// DieTag is the tag of the DIE 342 std::pair<uint64_t, dwarf::Tag> readAtoms(uint64_t *HashDataOffset); 343 void dump(raw_ostream &OS) const override; 344 345 /// Look up all entries in the accelerator table matching \c Key. 346 iterator_range<SameNameIterator> equal_range(StringRef Key) const; 347 348 /// Lookup all entries in the accelerator table. entries()349 auto entries() const { 350 return make_range(Iterator(*this), Iterator(*this, /*SetEnd*/ true)); 351 } 352 }; 353 354 /// .debug_names section consists of one or more units. Each unit starts with a 355 /// header, which is followed by a list of compilation units, local and foreign 356 /// type units. 357 /// 358 /// These may be followed by an (optional) hash lookup table, which consists of 359 /// an array of buckets and hashes similar to the apple tables above. The only 360 /// difference is that the hashes array is 1-based, and consequently an empty 361 /// bucket is denoted by 0 and not UINT32_MAX. 362 /// 363 /// Next is the name table, which consists of an array of names and array of 364 /// entry offsets. This is different from the apple tables, which store names 365 /// next to the actual entries. 366 /// 367 /// The structure of the entries is described by an abbreviations table, which 368 /// comes after the name table. Unlike the apple tables, which have a uniform 369 /// entry structure described in the header, each .debug_names entry may have 370 /// different index attributes (DW_IDX_???) attached to it. 371 /// 372 /// The last segment consists of a list of entries, which is a 0-terminated list 373 /// referenced by the name table and interpreted with the help of the 374 /// abbreviation table. 375 class DWARFDebugNames : public DWARFAcceleratorTable { 376 public: 377 class NameIndex; 378 class NameIterator; 379 class ValueIterator; 380 381 /// DWARF v5 Name Index header. 382 struct Header { 383 uint64_t UnitLength; 384 dwarf::DwarfFormat Format; 385 uint16_t Version; 386 uint32_t CompUnitCount; 387 uint32_t LocalTypeUnitCount; 388 uint32_t ForeignTypeUnitCount; 389 uint32_t BucketCount; 390 uint32_t NameCount; 391 uint32_t AbbrevTableSize; 392 uint32_t AugmentationStringSize; 393 SmallString<8> AugmentationString; 394 395 Error extract(const DWARFDataExtractor &AS, uint64_t *Offset); 396 void dump(ScopedPrinter &W) const; 397 }; 398 399 /// Index attribute and its encoding. 400 struct AttributeEncoding { 401 dwarf::Index Index; 402 dwarf::Form Form; 403 AttributeEncodingAttributeEncoding404 constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form) 405 : Index(Index), Form(Form) {} 406 407 friend bool operator==(const AttributeEncoding &LHS, 408 const AttributeEncoding &RHS) { 409 return LHS.Index == RHS.Index && LHS.Form == RHS.Form; 410 } 411 }; 412 413 /// Abbreviation describing the encoding of Name Index entries. 414 struct Abbrev { 415 uint64_t AbbrevOffset; /// < Abbreviation offset in the .debug_names section 416 uint32_t Code; ///< Abbreviation code 417 dwarf::Tag Tag; ///< Dwarf Tag of the described entity. 418 std::vector<AttributeEncoding> Attributes; ///< List of index attributes. 419 AbbrevAbbrev420 Abbrev(uint32_t Code, dwarf::Tag Tag, uint64_t AbbrevOffset, 421 std::vector<AttributeEncoding> Attributes) 422 : AbbrevOffset(AbbrevOffset), Code(Code), Tag(Tag), 423 Attributes(std::move(Attributes)) {} 424 425 void dump(ScopedPrinter &W) const; 426 }; 427 428 /// DWARF v5-specific implementation of an Accelerator Entry. 429 class Entry final : public DWARFAcceleratorTable::Entry { 430 const NameIndex *NameIdx; 431 const Abbrev *Abbr; 432 433 Entry(const NameIndex &NameIdx, const Abbrev &Abbr); 434 435 public: 436 std::optional<uint64_t> getCUOffset() const override; 437 std::optional<uint64_t> getLocalTUOffset() const override; getTag()438 std::optional<dwarf::Tag> getTag() const override { return tag(); } 439 440 /// Returns the Index into the Compilation Unit list of the owning Name 441 /// Index or std::nullopt if this Accelerator Entry does not have an 442 /// associated Compilation Unit. It is up to the user to verify that the 443 /// returned Index is valid in the owning NameIndex (or use getCUOffset(), 444 /// which will handle that check itself). Note that entries in NameIndexes 445 /// which index just a single Compilation Unit are implicitly associated 446 /// with that unit, so this function will return 0 even without an explicit 447 /// DW_IDX_compile_unit attribute, unless there is a DW_IDX_type_unit 448 /// attribute. 449 std::optional<uint64_t> getCUIndex() const; 450 451 /// Returns the Index into the Local Type Unit list of the owning Name 452 /// Index or std::nullopt if this Accelerator Entry does not have an 453 /// associated Type Unit. It is up to the user to verify that the 454 /// returned Index is valid in the owning NameIndex (or use 455 /// getLocalTUOffset(), which will handle that check itself). 456 std::optional<uint64_t> getLocalTUIndex() const; 457 458 /// .debug_names-specific getter, which always succeeds (DWARF v5 index 459 /// entries always have a tag). tag()460 dwarf::Tag tag() const { return Abbr->Tag; } 461 462 /// Returns the Offset of the DIE within the containing CU or TU. 463 std::optional<uint64_t> getDIEUnitOffset() const; 464 465 /// Returns true if this Entry has information about its parent DIE (i.e. if 466 /// it has an IDX_parent attribute) 467 bool hasParentInformation() const; 468 469 /// Returns the Entry corresponding to the parent of the DIE represented by 470 /// `this` Entry. If the parent is not in the table, nullopt is returned. 471 /// Precondition: hasParentInformation() == true. 472 /// An error is returned for ill-formed tables. 473 Expected<std::optional<DWARFDebugNames::Entry>> getParentDIEEntry() const; 474 475 /// Return the Abbreviation that can be used to interpret the raw values of 476 /// this Accelerator Entry. getAbbrev()477 const Abbrev &getAbbrev() const { return *Abbr; } 478 479 /// Returns the value of the Index Attribute in this Accelerator Entry, if 480 /// the Entry contains such Attribute. 481 std::optional<DWARFFormValue> lookup(dwarf::Index Index) const; 482 483 void dump(ScopedPrinter &W) const; 484 void dumpParentIdx(ScopedPrinter &W, const DWARFFormValue &FormValue) const; 485 486 friend class NameIndex; 487 friend class ValueIterator; 488 }; 489 490 /// Error returned by NameIndex::getEntry to report it has reached the end of 491 /// the entry list. 492 class SentinelError : public ErrorInfo<SentinelError> { 493 public: 494 static char ID; 495 log(raw_ostream & OS)496 void log(raw_ostream &OS) const override { OS << "Sentinel"; } 497 std::error_code convertToErrorCode() const override; 498 }; 499 500 private: 501 /// DenseMapInfo for struct Abbrev. 502 struct AbbrevMapInfo { 503 static Abbrev getEmptyKey(); 504 static Abbrev getTombstoneKey(); getHashValueAbbrevMapInfo505 static unsigned getHashValue(uint32_t Code) { 506 return DenseMapInfo<uint32_t>::getHashValue(Code); 507 } getHashValueAbbrevMapInfo508 static unsigned getHashValue(const Abbrev &Abbr) { 509 return getHashValue(Abbr.Code); 510 } isEqualAbbrevMapInfo511 static bool isEqual(uint32_t LHS, const Abbrev &RHS) { 512 return LHS == RHS.Code; 513 } isEqualAbbrevMapInfo514 static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) { 515 return LHS.Code == RHS.Code; 516 } 517 }; 518 519 public: 520 /// A single entry in the Name Table (DWARF v5 sect. 6.1.1.4.6) of the Name 521 /// Index. 522 class NameTableEntry { 523 DataExtractor StrData; 524 525 uint32_t Index; 526 uint64_t StringOffset; 527 uint64_t EntryOffset; 528 529 public: NameTableEntry(const DataExtractor & StrData,uint32_t Index,uint64_t StringOffset,uint64_t EntryOffset)530 NameTableEntry(const DataExtractor &StrData, uint32_t Index, 531 uint64_t StringOffset, uint64_t EntryOffset) 532 : StrData(StrData), Index(Index), StringOffset(StringOffset), 533 EntryOffset(EntryOffset) {} 534 535 /// Return the index of this name in the parent Name Index. getIndex()536 uint32_t getIndex() const { return Index; } 537 538 /// Returns the offset of the name of the described entities. getStringOffset()539 uint64_t getStringOffset() const { return StringOffset; } 540 541 /// Return the string referenced by this name table entry or nullptr if the 542 /// string offset is not valid. getString()543 const char *getString() const { 544 uint64_t Off = StringOffset; 545 return StrData.getCStr(&Off); 546 } 547 548 /// Compares the name of this entry against Target, returning true if they 549 /// are equal. This is more efficient in hot code paths that do not need the 550 /// length of the name. sameNameAs(StringRef Target)551 bool sameNameAs(StringRef Target) const { 552 // Note: this is not the name, but the rest of debug_str starting from 553 // name. This handles corrupt data (non-null terminated) without 554 // overrunning the buffer. 555 StringRef Data = StrData.getData().substr(StringOffset); 556 size_t TargetSize = Target.size(); 557 return Data.size() > TargetSize && !Data[TargetSize] && 558 strncmp(Data.data(), Target.data(), TargetSize) == 0; 559 } 560 561 /// Returns the offset of the first Entry in the list. getEntryOffset()562 uint64_t getEntryOffset() const { return EntryOffset; } 563 }; 564 565 /// Offsets for the start of various important tables from the start of the 566 /// section. 567 struct DWARFDebugNamesOffsets { 568 uint64_t CUsBase; 569 uint64_t BucketsBase; 570 uint64_t HashesBase; 571 uint64_t StringOffsetsBase; 572 uint64_t EntryOffsetsBase; 573 uint64_t EntriesBase; 574 }; 575 576 /// Represents a single accelerator table within the DWARF v5 .debug_names 577 /// section. 578 class NameIndex { 579 DenseSet<Abbrev, AbbrevMapInfo> Abbrevs; 580 struct Header Hdr; 581 const DWARFDebugNames &Section; 582 583 // Base of the whole unit and of various important tables, as offsets from 584 // the start of the section. 585 uint64_t Base; 586 DWARFDebugNamesOffsets Offsets; 587 588 void dumpCUs(ScopedPrinter &W) const; 589 void dumpLocalTUs(ScopedPrinter &W) const; 590 void dumpForeignTUs(ScopedPrinter &W) const; 591 void dumpAbbreviations(ScopedPrinter &W) const; 592 bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const; 593 void dumpName(ScopedPrinter &W, const NameTableEntry &NTE, 594 std::optional<uint32_t> Hash) const; 595 void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const; 596 597 Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset); 598 599 Expected<std::vector<AttributeEncoding>> 600 extractAttributeEncodings(uint64_t *Offset); 601 602 Expected<Abbrev> extractAbbrev(uint64_t *Offset); 603 604 public: NameIndex(const DWARFDebugNames & Section,uint64_t Base)605 NameIndex(const DWARFDebugNames &Section, uint64_t Base) 606 : Section(Section), Base(Base) {} 607 608 /// Returns Hdr field getHeader()609 Header getHeader() const { return Hdr; } 610 611 /// Returns Offsets field getOffsets()612 DWARFDebugNamesOffsets getOffsets() const { return Offsets; } 613 614 /// Reads offset of compilation unit CU. CU is 0-based. 615 uint64_t getCUOffset(uint32_t CU) const; getCUCount()616 uint32_t getCUCount() const { return Hdr.CompUnitCount; } 617 618 /// Reads offset of local type unit TU, TU is 0-based. 619 uint64_t getLocalTUOffset(uint32_t TU) const; getLocalTUCount()620 uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; } 621 622 /// Reads signature of foreign type unit TU. TU is 0-based. 623 uint64_t getForeignTUSignature(uint32_t TU) const; getForeignTUCount()624 uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; } 625 626 /// Reads an entry in the Bucket Array for the given Bucket. The returned 627 /// value is a (1-based) index into the Names, StringOffsets and 628 /// EntryOffsets arrays. The input Bucket index is 0-based. 629 uint32_t getBucketArrayEntry(uint32_t Bucket) const; getBucketCount()630 uint32_t getBucketCount() const { return Hdr.BucketCount; } 631 632 /// Reads an entry in the Hash Array for the given Index. The input Index 633 /// is 1-based. 634 uint32_t getHashArrayEntry(uint32_t Index) const; 635 636 /// Reads an entry in the Name Table for the given Index. The Name Table 637 /// consists of two arrays -- String Offsets and Entry Offsets. The returned 638 /// offsets are relative to the starts of respective sections. Input Index 639 /// is 1-based. 640 NameTableEntry getNameTableEntry(uint32_t Index) const; 641 getNameCount()642 uint32_t getNameCount() const { return Hdr.NameCount; } 643 getAbbrevs()644 const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const { 645 return Abbrevs; 646 } 647 648 Expected<Entry> getEntry(uint64_t *Offset) const; 649 650 /// Returns the Entry at the relative `Offset` from the start of the Entry 651 /// pool. getEntryAtRelativeOffset(uint64_t Offset)652 Expected<Entry> getEntryAtRelativeOffset(uint64_t Offset) const { 653 auto OffsetFromSection = Offset + this->Offsets.EntriesBase; 654 return getEntry(&OffsetFromSection); 655 } 656 657 /// Look up all entries in this Name Index matching \c Key. 658 iterator_range<ValueIterator> equal_range(StringRef Key) const; 659 begin()660 NameIterator begin() const { return NameIterator(this, 1); } end()661 NameIterator end() const { return NameIterator(this, getNameCount() + 1); } 662 663 Error extract(); getUnitOffset()664 uint64_t getUnitOffset() const { return Base; } getNextUnitOffset()665 uint64_t getNextUnitOffset() const { 666 return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) + 667 Hdr.UnitLength; 668 } 669 void dump(ScopedPrinter &W) const; 670 671 friend class DWARFDebugNames; 672 }; 673 674 class ValueIterator { 675 public: 676 using iterator_category = std::input_iterator_tag; 677 using value_type = Entry; 678 using difference_type = std::ptrdiff_t; 679 using pointer = value_type *; 680 using reference = value_type &; 681 682 private: 683 /// The Name Index we are currently iterating through. The implementation 684 /// relies on the fact that this can also be used as an iterator into the 685 /// "NameIndices" vector in the Accelerator section. 686 const NameIndex *CurrentIndex = nullptr; 687 688 /// Whether this is a local iterator (searches in CurrentIndex only) or not 689 /// (searches all name indices). 690 bool IsLocal; 691 692 std::optional<Entry> CurrentEntry; 693 uint64_t DataOffset = 0; ///< Offset into the section. 694 std::string Key; ///< The Key we are searching for. 695 std::optional<uint32_t> Hash; ///< Hash of Key, if it has been computed. 696 697 bool getEntryAtCurrentOffset(); 698 std::optional<uint64_t> findEntryOffsetInCurrentIndex(); 699 bool findInCurrentIndex(); 700 void searchFromStartOfCurrentIndex(); 701 void next(); 702 703 /// Set the iterator to the "end" state. setEnd()704 void setEnd() { *this = ValueIterator(); } 705 706 public: 707 /// Create a "begin" iterator for looping over all entries in the 708 /// accelerator table matching Key. The iterator will run through all Name 709 /// Indexes in the section in sequence. 710 ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key); 711 712 /// Create a "begin" iterator for looping over all entries in a specific 713 /// Name Index. Other indices in the section will not be visited. 714 ValueIterator(const NameIndex &NI, StringRef Key); 715 716 /// End marker. 717 ValueIterator() = default; 718 719 const Entry &operator*() const { return *CurrentEntry; } 720 ValueIterator &operator++() { 721 next(); 722 return *this; 723 } 724 ValueIterator operator++(int) { 725 ValueIterator I = *this; 726 next(); 727 return I; 728 } 729 730 friend bool operator==(const ValueIterator &A, const ValueIterator &B) { 731 return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset; 732 } 733 friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { 734 return !(A == B); 735 } 736 }; 737 738 class NameIterator { 739 740 /// The Name Index we are iterating through. 741 const NameIndex *CurrentIndex; 742 743 /// The current name in the Name Index. 744 uint32_t CurrentName; 745 next()746 void next() { 747 assert(CurrentName <= CurrentIndex->getNameCount()); 748 ++CurrentName; 749 } 750 751 public: 752 using iterator_category = std::input_iterator_tag; 753 using value_type = NameTableEntry; 754 using difference_type = uint32_t; 755 using pointer = NameTableEntry *; 756 using reference = NameTableEntry; // We return entries by value. 757 758 /// Creates an iterator whose initial position is name CurrentName in 759 /// CurrentIndex. NameIterator(const NameIndex * CurrentIndex,uint32_t CurrentName)760 NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName) 761 : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {} 762 763 NameTableEntry operator*() const { 764 return CurrentIndex->getNameTableEntry(CurrentName); 765 } 766 NameIterator &operator++() { 767 next(); 768 return *this; 769 } 770 NameIterator operator++(int) { 771 NameIterator I = *this; 772 next(); 773 return I; 774 } 775 776 friend bool operator==(const NameIterator &A, const NameIterator &B) { 777 return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName; 778 } 779 friend bool operator!=(const NameIterator &A, const NameIterator &B) { 780 return !(A == B); 781 } 782 }; 783 784 private: 785 SmallVector<NameIndex, 0> NameIndices; 786 DenseMap<uint64_t, const NameIndex *> CUToNameIndex; 787 788 public: DWARFDebugNames(const DWARFDataExtractor & AccelSection,DataExtractor StringSection)789 DWARFDebugNames(const DWARFDataExtractor &AccelSection, 790 DataExtractor StringSection) 791 : DWARFAcceleratorTable(AccelSection, StringSection) {} 792 793 Error extract() override; 794 void dump(raw_ostream &OS) const override; 795 796 /// Look up all entries in the accelerator table matching \c Key. 797 iterator_range<ValueIterator> equal_range(StringRef Key) const; 798 799 using const_iterator = SmallVector<NameIndex, 0>::const_iterator; begin()800 const_iterator begin() const { return NameIndices.begin(); } end()801 const_iterator end() const { return NameIndices.end(); } 802 803 /// Return the Name Index covering the compile unit at CUOffset, or nullptr if 804 /// there is no Name Index covering that unit. 805 const NameIndex *getCUNameIndex(uint64_t CUOffset); 806 }; 807 808 /// Calculates the starting offsets for various sections within the 809 /// .debug_names section. 810 namespace dwarf { 811 DWARFDebugNames::DWARFDebugNamesOffsets 812 findDebugNamesOffsets(uint64_t EndOfHeaderOffset, 813 const DWARFDebugNames::Header &Hdr); 814 } 815 816 /// If `Name` is the name of a templated function that includes template 817 /// parameters, returns a substring of `Name` containing no template 818 /// parameters. 819 /// E.g.: StripTemplateParameters("foo<int>") = "foo". 820 std::optional<StringRef> StripTemplateParameters(StringRef Name); 821 822 struct ObjCSelectorNames { 823 /// For "-[A(Category) method:]", this would be "method:" 824 StringRef Selector; 825 /// For "-[A(Category) method:]", this would be "A(category)" 826 StringRef ClassName; 827 /// For "-[A(Category) method:]", this would be "A" 828 std::optional<StringRef> ClassNameNoCategory; 829 /// For "-[A(Category) method:]", this would be "A method:" 830 std::optional<std::string> MethodNameNoCategory; 831 }; 832 833 /// If `Name` is the AT_name of a DIE which refers to an Objective-C selector, 834 /// returns an instance of ObjCSelectorNames. The Selector and ClassName fields 835 /// are guaranteed to be non-empty in the result. 836 std::optional<ObjCSelectorNames> getObjCNamesIfSelector(StringRef Name); 837 838 } // end namespace llvm 839 840 #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H 841