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. 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. 75 ArrayRef<DWARFFormValue> getValues() const { return Values; } 76 }; 77 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. 136 uint64_t getBucketBase() const { return sizeof(Hdr) + Hdr.HeaderDataLength; } 137 138 /// Return the offset into the section where the I-th bucket is. 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. 144 uint64_t getHashBase() const { return getBucketBase() + getNumBuckets() * 4; } 145 146 /// Return the offset into the section where the I-th hash is. 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. 150 uint64_t getOffsetBase() const { return getHashBase() + getNumHashes() * 4; } 151 152 /// Return the offset into the section where the table entries begin. 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. 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. 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. 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. 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. 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. 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. 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 { 258 EntryWithName(const AppleAcceleratorTable &Table) 259 : BaseEntry(Table), StrOffset(0) {} 260 261 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 279 void setToEnd() { Offset = EndMarker; } 280 bool isEnd() const { return Offset == EndMarker; } 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 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. 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. 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. 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 404 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 uint32_t Code; ///< Abbreviation code 416 dwarf::Tag Tag; ///< Dwarf Tag of the described entity. 417 std::vector<AttributeEncoding> Attributes; ///< List of index attributes. 418 419 Abbrev(uint32_t Code, dwarf::Tag Tag, 420 std::vector<AttributeEncoding> Attributes) 421 : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {} 422 423 void dump(ScopedPrinter &W) const; 424 }; 425 426 /// DWARF v5-specific implementation of an Accelerator Entry. 427 class Entry final : public DWARFAcceleratorTable::Entry { 428 const NameIndex *NameIdx; 429 const Abbrev *Abbr; 430 431 Entry(const NameIndex &NameIdx, const Abbrev &Abbr); 432 433 public: 434 std::optional<uint64_t> getCUOffset() const override; 435 std::optional<uint64_t> getLocalTUOffset() const override; 436 std::optional<dwarf::Tag> getTag() const override { return tag(); } 437 438 /// Returns the Index into the Compilation Unit list of the owning Name 439 /// Index or std::nullopt if this Accelerator Entry does not have an 440 /// associated Compilation Unit. It is up to the user to verify that the 441 /// returned Index is valid in the owning NameIndex (or use getCUOffset(), 442 /// which will handle that check itself). Note that entries in NameIndexes 443 /// which index just a single Compilation Unit are implicitly associated 444 /// with that unit, so this function will return 0 even without an explicit 445 /// DW_IDX_compile_unit attribute, unless there is a DW_IDX_type_unit 446 /// attribute. 447 std::optional<uint64_t> getCUIndex() const; 448 449 /// Returns the Index into the Local Type Unit list of the owning Name 450 /// Index or std::nullopt if this Accelerator Entry does not have an 451 /// associated Type Unit. It is up to the user to verify that the 452 /// returned Index is valid in the owning NameIndex (or use 453 /// getLocalTUOffset(), which will handle that check itself). 454 std::optional<uint64_t> getLocalTUIndex() const; 455 456 /// .debug_names-specific getter, which always succeeds (DWARF v5 index 457 /// entries always have a tag). 458 dwarf::Tag tag() const { return Abbr->Tag; } 459 460 /// Returns the Offset of the DIE within the containing CU or TU. 461 std::optional<uint64_t> getDIEUnitOffset() const; 462 463 /// Return the Abbreviation that can be used to interpret the raw values of 464 /// this Accelerator Entry. 465 const Abbrev &getAbbrev() const { return *Abbr; } 466 467 /// Returns the value of the Index Attribute in this Accelerator Entry, if 468 /// the Entry contains such Attribute. 469 std::optional<DWARFFormValue> lookup(dwarf::Index Index) const; 470 471 void dump(ScopedPrinter &W) const; 472 473 friend class NameIndex; 474 friend class ValueIterator; 475 }; 476 477 /// Error returned by NameIndex::getEntry to report it has reached the end of 478 /// the entry list. 479 class SentinelError : public ErrorInfo<SentinelError> { 480 public: 481 static char ID; 482 483 void log(raw_ostream &OS) const override { OS << "Sentinel"; } 484 std::error_code convertToErrorCode() const override; 485 }; 486 487 private: 488 /// DenseMapInfo for struct Abbrev. 489 struct AbbrevMapInfo { 490 static Abbrev getEmptyKey(); 491 static Abbrev getTombstoneKey(); 492 static unsigned getHashValue(uint32_t Code) { 493 return DenseMapInfo<uint32_t>::getHashValue(Code); 494 } 495 static unsigned getHashValue(const Abbrev &Abbr) { 496 return getHashValue(Abbr.Code); 497 } 498 static bool isEqual(uint32_t LHS, const Abbrev &RHS) { 499 return LHS == RHS.Code; 500 } 501 static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) { 502 return LHS.Code == RHS.Code; 503 } 504 }; 505 506 public: 507 /// A single entry in the Name Table (DWARF v5 sect. 6.1.1.4.6) of the Name 508 /// Index. 509 class NameTableEntry { 510 DataExtractor StrData; 511 512 uint32_t Index; 513 uint64_t StringOffset; 514 uint64_t EntryOffset; 515 516 public: 517 NameTableEntry(const DataExtractor &StrData, uint32_t Index, 518 uint64_t StringOffset, uint64_t EntryOffset) 519 : StrData(StrData), Index(Index), StringOffset(StringOffset), 520 EntryOffset(EntryOffset) {} 521 522 /// Return the index of this name in the parent Name Index. 523 uint32_t getIndex() const { return Index; } 524 525 /// Returns the offset of the name of the described entities. 526 uint64_t getStringOffset() const { return StringOffset; } 527 528 /// Return the string referenced by this name table entry or nullptr if the 529 /// string offset is not valid. 530 const char *getString() const { 531 uint64_t Off = StringOffset; 532 return StrData.getCStr(&Off); 533 } 534 535 /// Returns the offset of the first Entry in the list. 536 uint64_t getEntryOffset() const { return EntryOffset; } 537 }; 538 539 /// Represents a single accelerator table within the DWARF v5 .debug_names 540 /// section. 541 class NameIndex { 542 DenseSet<Abbrev, AbbrevMapInfo> Abbrevs; 543 struct Header Hdr; 544 const DWARFDebugNames &Section; 545 546 // Base of the whole unit and of various important tables, as offsets from 547 // the start of the section. 548 uint64_t Base; 549 uint64_t CUsBase; 550 uint64_t BucketsBase; 551 uint64_t HashesBase; 552 uint64_t StringOffsetsBase; 553 uint64_t EntryOffsetsBase; 554 uint64_t EntriesBase; 555 556 void dumpCUs(ScopedPrinter &W) const; 557 void dumpLocalTUs(ScopedPrinter &W) const; 558 void dumpForeignTUs(ScopedPrinter &W) const; 559 void dumpAbbreviations(ScopedPrinter &W) const; 560 bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const; 561 void dumpName(ScopedPrinter &W, const NameTableEntry &NTE, 562 std::optional<uint32_t> Hash) const; 563 void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const; 564 565 Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset); 566 567 Expected<std::vector<AttributeEncoding>> 568 extractAttributeEncodings(uint64_t *Offset); 569 570 Expected<Abbrev> extractAbbrev(uint64_t *Offset); 571 572 public: 573 NameIndex(const DWARFDebugNames &Section, uint64_t Base) 574 : Section(Section), Base(Base) {} 575 576 /// Reads offset of compilation unit CU. CU is 0-based. 577 uint64_t getCUOffset(uint32_t CU) const; 578 uint32_t getCUCount() const { return Hdr.CompUnitCount; } 579 580 /// Reads offset of local type unit TU, TU is 0-based. 581 uint64_t getLocalTUOffset(uint32_t TU) const; 582 uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; } 583 584 /// Reads signature of foreign type unit TU. TU is 0-based. 585 uint64_t getForeignTUSignature(uint32_t TU) const; 586 uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; } 587 588 /// Reads an entry in the Bucket Array for the given Bucket. The returned 589 /// value is a (1-based) index into the Names, StringOffsets and 590 /// EntryOffsets arrays. The input Bucket index is 0-based. 591 uint32_t getBucketArrayEntry(uint32_t Bucket) const; 592 uint32_t getBucketCount() const { return Hdr.BucketCount; } 593 594 /// Reads an entry in the Hash Array for the given Index. The input Index 595 /// is 1-based. 596 uint32_t getHashArrayEntry(uint32_t Index) const; 597 598 /// Reads an entry in the Name Table for the given Index. The Name Table 599 /// consists of two arrays -- String Offsets and Entry Offsets. The returned 600 /// offsets are relative to the starts of respective sections. Input Index 601 /// is 1-based. 602 NameTableEntry getNameTableEntry(uint32_t Index) const; 603 604 uint32_t getNameCount() const { return Hdr.NameCount; } 605 606 const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const { 607 return Abbrevs; 608 } 609 610 Expected<Entry> getEntry(uint64_t *Offset) const; 611 612 /// Look up all entries in this Name Index matching \c Key. 613 iterator_range<ValueIterator> equal_range(StringRef Key) const; 614 615 NameIterator begin() const { return NameIterator(this, 1); } 616 NameIterator end() const { return NameIterator(this, getNameCount() + 1); } 617 618 Error extract(); 619 uint64_t getUnitOffset() const { return Base; } 620 uint64_t getNextUnitOffset() const { 621 return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) + 622 Hdr.UnitLength; 623 } 624 void dump(ScopedPrinter &W) const; 625 626 friend class DWARFDebugNames; 627 }; 628 629 class ValueIterator { 630 public: 631 using iterator_category = std::input_iterator_tag; 632 using value_type = Entry; 633 using difference_type = std::ptrdiff_t; 634 using pointer = value_type *; 635 using reference = value_type &; 636 637 private: 638 /// The Name Index we are currently iterating through. The implementation 639 /// relies on the fact that this can also be used as an iterator into the 640 /// "NameIndices" vector in the Accelerator section. 641 const NameIndex *CurrentIndex = nullptr; 642 643 /// Whether this is a local iterator (searches in CurrentIndex only) or not 644 /// (searches all name indices). 645 bool IsLocal; 646 647 std::optional<Entry> CurrentEntry; 648 uint64_t DataOffset = 0; ///< Offset into the section. 649 std::string Key; ///< The Key we are searching for. 650 std::optional<uint32_t> Hash; ///< Hash of Key, if it has been computed. 651 652 bool getEntryAtCurrentOffset(); 653 std::optional<uint64_t> findEntryOffsetInCurrentIndex(); 654 bool findInCurrentIndex(); 655 void searchFromStartOfCurrentIndex(); 656 void next(); 657 658 /// Set the iterator to the "end" state. 659 void setEnd() { *this = ValueIterator(); } 660 661 public: 662 /// Create a "begin" iterator for looping over all entries in the 663 /// accelerator table matching Key. The iterator will run through all Name 664 /// Indexes in the section in sequence. 665 ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key); 666 667 /// Create a "begin" iterator for looping over all entries in a specific 668 /// Name Index. Other indices in the section will not be visited. 669 ValueIterator(const NameIndex &NI, StringRef Key); 670 671 /// End marker. 672 ValueIterator() = default; 673 674 const Entry &operator*() const { return *CurrentEntry; } 675 ValueIterator &operator++() { 676 next(); 677 return *this; 678 } 679 ValueIterator operator++(int) { 680 ValueIterator I = *this; 681 next(); 682 return I; 683 } 684 685 friend bool operator==(const ValueIterator &A, const ValueIterator &B) { 686 return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset; 687 } 688 friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { 689 return !(A == B); 690 } 691 }; 692 693 class NameIterator { 694 695 /// The Name Index we are iterating through. 696 const NameIndex *CurrentIndex; 697 698 /// The current name in the Name Index. 699 uint32_t CurrentName; 700 701 void next() { 702 assert(CurrentName <= CurrentIndex->getNameCount()); 703 ++CurrentName; 704 } 705 706 public: 707 using iterator_category = std::input_iterator_tag; 708 using value_type = NameTableEntry; 709 using difference_type = uint32_t; 710 using pointer = NameTableEntry *; 711 using reference = NameTableEntry; // We return entries by value. 712 713 /// Creates an iterator whose initial position is name CurrentName in 714 /// CurrentIndex. 715 NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName) 716 : CurrentIndex(CurrentIndex), CurrentName(CurrentName) {} 717 718 NameTableEntry operator*() const { 719 return CurrentIndex->getNameTableEntry(CurrentName); 720 } 721 NameIterator &operator++() { 722 next(); 723 return *this; 724 } 725 NameIterator operator++(int) { 726 NameIterator I = *this; 727 next(); 728 return I; 729 } 730 731 friend bool operator==(const NameIterator &A, const NameIterator &B) { 732 return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName; 733 } 734 friend bool operator!=(const NameIterator &A, const NameIterator &B) { 735 return !(A == B); 736 } 737 }; 738 739 private: 740 SmallVector<NameIndex, 0> NameIndices; 741 DenseMap<uint64_t, const NameIndex *> CUToNameIndex; 742 743 public: 744 DWARFDebugNames(const DWARFDataExtractor &AccelSection, 745 DataExtractor StringSection) 746 : DWARFAcceleratorTable(AccelSection, StringSection) {} 747 748 Error extract() override; 749 void dump(raw_ostream &OS) const override; 750 751 /// Look up all entries in the accelerator table matching \c Key. 752 iterator_range<ValueIterator> equal_range(StringRef Key) const; 753 754 using const_iterator = SmallVector<NameIndex, 0>::const_iterator; 755 const_iterator begin() const { return NameIndices.begin(); } 756 const_iterator end() const { return NameIndices.end(); } 757 758 /// Return the Name Index covering the compile unit at CUOffset, or nullptr if 759 /// there is no Name Index covering that unit. 760 const NameIndex *getCUNameIndex(uint64_t CUOffset); 761 }; 762 763 /// If `Name` is the name of a templated function that includes template 764 /// parameters, returns a substring of `Name` containing no template 765 /// parameters. 766 /// E.g.: StripTemplateParameters("foo<int>") = "foo". 767 std::optional<StringRef> StripTemplateParameters(StringRef Name); 768 769 struct ObjCSelectorNames { 770 /// For "-[A(Category) method:]", this would be "method:" 771 StringRef Selector; 772 /// For "-[A(Category) method:]", this would be "A(category)" 773 StringRef ClassName; 774 /// For "-[A(Category) method:]", this would be "A" 775 std::optional<StringRef> ClassNameNoCategory; 776 /// For "-[A(Category) method:]", this would be "A method:" 777 std::optional<std::string> MethodNameNoCategory; 778 }; 779 780 /// If `Name` is the AT_name of a DIE which refers to an Objective-C selector, 781 /// returns an instance of ObjCSelectorNames. The Selector and ClassName fields 782 /// are guaranteed to be non-empty in the result. 783 std::optional<ObjCSelectorNames> getObjCNamesIfSelector(StringRef Name); 784 785 } // end namespace llvm 786 787 #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H 788