Index: include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -35,6 +35,43 @@ DataExtractor StringSection; public: + /// An abstract class representing a single entry in the accelerator tables. + class Entry { + protected: + SmallVector Values; + + Entry() = default; + + // Make these protected so only (final) subclasses can be copied around. + Entry(const Entry &) = default; + Entry(Entry &&) = default; + Entry &operator=(const Entry &) = default; + Entry &operator=(Entry &&) = default; + + public: + virtual ~Entry(); + + /// Returns the Offset of the Compilation Unit associated with this + /// Accelerator Entry or None if the Compilation Unit offset is not recorded + /// in this Accelerator Entry. + virtual Optional getCUOffset() const = 0; + + /// Returns the Offset of the Debug Info Entry associated with this + /// Accelerator Entry or None if the DIE offset is not recorded in this + /// Accelerator Entry. + virtual Optional getDIEOffset() const = 0; + + /// Returns the Tag of the Debug Info Entry associated with this + /// Accelerator Entry or None if the Tag is not recorded in this + /// Accelerator Entry. + virtual Optional getTag() const = 0; + + /// Returns the raw values of fields in the Accelerator Entry. In general, + /// these can only be interpreted with the help of the metadata in the + /// owning Accelerator Table. + ArrayRef getValues() const { return Values; } + }; + DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, DataExtractor StringSection) : AccelSection(AccelSection), StringSection(StringSection) {} @@ -79,13 +116,32 @@ uint32_t *DataOffset) const; public: - /// An iterator for the entries associated with one key. Each entry can have - /// multiple DWARFFormValues. - class ValueIterator : public std::iterator> { - const AppleAcceleratorTable *AccelTable = nullptr; - SmallVector AtomForms; ///< The decoded data entry. + /// Apple-specific implementation of an Accelerator Entry. + class Entry final : public DWARFAcceleratorTable::Entry { + const HeaderData *HdrData = nullptr; + + Entry(const HeaderData &Data); + Entry() = default; + + void extract(const AppleAcceleratorTable &AccelTable, uint32_t *Offset); + public: + Entry(const Entry &RHS) : HdrData(RHS.HdrData) { Values = RHS.Values; } + Optional getCUOffset() const override; + Optional getDIEOffset() const override; + Optional getTag() const override; + + /// Returns the value of the Atom in this Accelerator Entry, if the Entry + /// contains such Atom. + Optional lookup(HeaderData::AtomType Atom) const; + + friend class AppleAcceleratorTable; + friend class ValueIterator; + }; + + class ValueIterator : public std::iterator { + const AppleAcceleratorTable *AccelTable = nullptr; + Entry Current; ///< The current entry. unsigned DataOffset = 0; ///< Offset into the section. unsigned Data = 0; ///< Current data entry. unsigned NumData = 0; ///< Number of data entries. @@ -98,9 +154,7 @@ /// End marker. ValueIterator() = default; - const ArrayRef operator*() const { - return AtomForms; - } + const Entry &operator*() const { return Current; } ValueIterator &operator++() { Next(); return *this; } ValueIterator operator++(int) { ValueIterator I = *this; @@ -124,6 +178,9 @@ uint32_t getNumHashes(); uint32_t getSizeHdr(); uint32_t getHeaderDataLength(); + + /// Return the Atom description, which can be used to interpret the raw values + /// of the Accelerator Entries in this table. ArrayRef> getAtomsDesc(); bool validateForms(); @@ -179,6 +236,9 @@ }; public: + class NameIndex; + class ValueIterator; + /// Dwarf 5 Name Index header. struct Header : public HeaderPOD { SmallString<8> AugmentationString; @@ -214,16 +274,41 @@ void dump(ScopedPrinter &W) const; }; - /// A single entry in the Name Index. - struct Entry { - const Abbrev &Abbr; + /// DWARF v5-specific implementation of an Accelerator Entry. + class Entry final : public DWARFAcceleratorTable::Entry { + const NameIndex *NameIdx; + const Abbrev *Abbr; + + Entry(const NameIndex &NameIdx, const Abbrev &Abbr); + + /// Returns the Index into the Compilation Unit list of the owning Name + /// Index or None if this Accelerator Entry does not have an associated + /// Compilation Unit. It is up to the user to verify that the returned Index + /// is valid in the owning NameIndex (or use getCUOffset(), which will + /// handle that check itself). + Optional getCUIndex() const; + + public: + Optional getCUOffset() const override; + Optional getDIEOffset() const override; + Optional getTag() const override { return tag(); } - /// Values of the index attributes described by Abbr. - std::vector Values; + /// .debug_names-specific getter, which always succeeds (DWARF v5 index + /// entries always have a tag). + dwarf::Tag tag() const { return Abbr->Tag; } - Entry(const Abbrev &Abbr); + /// Return the Abbreviation that can be used to interpret the raw values of + /// this Accelerator Entry. + const Abbrev &getAbbrev() const { return *Abbr; } + + /// Returns the value of the Index Attribute in this Accelerator Entry, if + /// the Entry contains such Attribute. + Optional lookup(dwarf::Index Index) const; void dump(ScopedPrinter &W) const; + + friend class NameIndex; + friend class ValueIterator; }; private: @@ -280,15 +365,6 @@ uint32_t EntryOffsetsBase; uint32_t EntriesBase; - /// Reads offset of compilation unit CU. CU is 0-based. - uint32_t getCUOffset(uint32_t CU) const; - - /// Reads offset of local type unit TU, TU is 0-based. - uint32_t getLocalTUOffset(uint32_t TU) const; - - /// Reads signature of foreign type unit TU. TU is 0-based. - uint64_t getForeignTUOffset(uint32_t TU) const; - /// Reads an entry in the Bucket Array for the given Bucket. The returned /// value is a (1-based) index into the Names, StringOffsets and /// EntryOffsets arrays. The input Bucket index is 0-based. @@ -326,13 +402,76 @@ NameIndex(const DWARFDebugNames &Section, uint32_t Base) : Section(Section), Base(Base) {} + /// Reads offset of compilation unit CU. CU is 0-based. + uint32_t getCUOffset(uint32_t CU) const; + uint32_t getCUCount() const { return Hdr.CompUnitCount; } + + /// Reads offset of local type unit TU, TU is 0-based. + uint32_t getLocalTUOffset(uint32_t TU) const; + uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; } + + /// Reads signature of foreign type unit TU. TU is 0-based. + uint64_t getForeignTUSignature(uint32_t TU) const; + uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; } + llvm::Error extract(); uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; } void dump(ScopedPrinter &W) const; + + friend class DWARFDebugNames; + }; + + class ValueIterator : public std::iterator { + + /// The Name Index we are currently iterating through. The implementation + /// relies on the fact that this can also be used as an iterator into the + /// "NameIndices" vector in the Accelerator section. + const NameIndex *CurrentIndex = nullptr; + + Optional CurrentEntry; + unsigned DataOffset = 0; ///< Offset into the section. + std::string Key; ///< The Key we are searching for. + Optional Hash; ///< Hash of Key, if it has been computed. + + bool getEntryAtCurrentOffset(); + Optional findEntryOffsetInCurrentIndex(); + bool findInCurrentIndex(); + void searchFromStartOfCurrentIndex(); + void next(); + + /// Set the iterator to the "end" state. + void setEnd() { *this = ValueIterator(); } + + public: + /// Create a "begin" iterator for looping over all entries in the + /// accelerator table matching Key. The iterator will run through all Name + /// Indexes in the section in sequence. + ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key); + + /// End marker. + ValueIterator() = default; + + const Entry &operator*() const { return *CurrentEntry; } + ValueIterator &operator++() { + next(); + return *this; + } + ValueIterator operator++(int) { + ValueIterator I = *this; + next(); + return I; + } + + friend bool operator==(const ValueIterator &A, const ValueIterator &B) { + return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset; + } + friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { + return !(A == B); + } }; private: - std::vector NameIndices; + llvm::SmallVector NameIndices; public: DWARFDebugNames(const DWARFDataExtractor &AccelSection, @@ -341,6 +480,9 @@ llvm::Error extract() override; void dump(raw_ostream &OS) const override; + + /// Look up all entries in the accelerator table matching \c Key. + iterator_range equal_range(StringRef Key) const; }; } // end namespace llvm Index: lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -55,6 +55,7 @@ } DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; +DWARFAcceleratorTable::Entry::~Entry() = default; llvm::Error AppleAcceleratorTable::extract() { uint32_t Offset = 0; @@ -248,15 +249,61 @@ } } +AppleAcceleratorTable::Entry::Entry( + const AppleAcceleratorTable::HeaderData &HdrData) + : HdrData(&HdrData) { + Values.reserve(HdrData.Atoms.size()); + for (const auto &Atom : HdrData.Atoms) + Values.push_back(DWARFFormValue(Atom.second)); +} + +void AppleAcceleratorTable::Entry::extract( + const AppleAcceleratorTable &AccelTable, uint32_t *Offset) { + + DWARFFormParams FormParams = {AccelTable.Hdr.Version, 0, + dwarf::DwarfFormat::DWARF32}; + for (auto &Atom : Values) + Atom.extractValue(AccelTable.AccelSection, Offset, FormParams); +} + +Optional +AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const { + assert(HdrData && "Dereferencing end iterator?"); + assert(HdrData->Atoms.size() == Values.size()); + for (const auto &Tuple : zip_first(HdrData->Atoms, Values)) { + if (std::get<0>(Tuple).first == Atom) + return std::get<1>(Tuple); + } + return None; +} + +Optional AppleAcceleratorTable::Entry::getDIEOffset() const { + if (Optional Off = lookup(dwarf::DW_ATOM_die_offset)) + return Off->getAsSectionOffset(); + return None; +} + +Optional AppleAcceleratorTable::Entry::getCUOffset() const { + if (Optional Off = lookup(dwarf::DW_ATOM_cu_offset)) + return Off->getAsSectionOffset(); + return None; +} + +Optional AppleAcceleratorTable::Entry::getTag() const { + Optional Tag = lookup(dwarf::DW_ATOM_die_tag); + if (!Tag) + return None; + if (Optional Value = Tag->getAsUnsignedConstant()) + return dwarf::Tag(*Value); + return None; +} + AppleAcceleratorTable::ValueIterator::ValueIterator( const AppleAcceleratorTable &AccelTable, unsigned Offset) - : AccelTable(&AccelTable), DataOffset(Offset) { + : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) { if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) return; - for (const auto &Atom : AccelTable.HdrData.Atoms) - AtomForms.push_back(DWARFFormValue(Atom.second)); - // Read the first entry. NumData = AccelTable.AccelSection.getU32(&DataOffset); Next(); @@ -270,10 +317,7 @@ NumData = 0; return; } - DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0, - dwarf::DwarfFormat::DWARF32}; - for (auto &Atom : AtomForms) - Atom.extractValue(AccelSection, &DataOffset, FormParams); + Current.extract(*AccelTable, &DataOffset); ++Data; } @@ -475,8 +519,8 @@ } } } - -DWARFDebugNames::Entry::Entry(const Abbrev &Abbr) : Abbr(Abbr) { +DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr) + : NameIdx(&NameIdx), Abbr(&Abbr) { // This merely creates form values. It is up to the caller // (NameIndex::getEntry) to populate them. Values.reserve(Abbr.Attributes.size()); @@ -484,14 +528,43 @@ Values.emplace_back(Attr.Form); } +Optional +DWARFDebugNames::Entry::lookup(dwarf::Index Index) const { + assert(Abbr->Attributes.size() == Values.size()); + for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) { + if (std::get<0>(Tuple).Index == Index) + return std::get<1>(Tuple); + } + return None; +} + +Optional DWARFDebugNames::Entry::getDIEOffset() const { + if (Optional Off = lookup(dwarf::DW_IDX_die_offset)) + return Off->getAsSectionOffset(); + return None; +} + +Optional DWARFDebugNames::Entry::getCUIndex() const { + if (Optional Off = lookup(dwarf::DW_IDX_compile_unit)) + return Off->getAsUnsignedConstant(); + return None; +} + +Optional DWARFDebugNames::Entry::getCUOffset() const { + Optional Index = getCUIndex(); + if (!Index || *Index >= NameIdx->getCUCount()) + return None; + return NameIdx->getCUOffset(*Index); +} + void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { - W.printHex("Abbrev", Abbr.Code); - W.startLine() << "Tag: " << formatTag(Abbr.Tag) << "\n"; + W.printHex("Abbrev", Abbr->Code); + W.startLine() << "Tag: " << formatTag(Abbr->Tag) << "\n"; - assert(Abbr.Attributes.size() == Values.size()); - for (uint32_t I = 0, E = Values.size(); I < E; ++I) { - W.startLine() << formatIndex(Abbr.Attributes[I].Index) << ": "; - Values[I].dump(W.getOStream()); + assert(Abbr->Attributes.size() == Values.size()); + for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) { + W.startLine() << formatIndex(std::get<0>(Tuple).Index) << ": "; + std::get<1>(Tuple).dump(W.getOStream()); W.getOStream() << '\n'; } } @@ -513,7 +586,7 @@ return Section.AccelSection.getRelocatedValue(4, &Offset); } -uint64_t DWARFDebugNames::NameIndex::getForeignTUOffset(uint32_t TU) const { +uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const { assert(TU < Hdr.ForeignTypeUnitCount); uint32_t Offset = CUsBase + (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) * 4; return Section.AccelSection.getU64(&Offset); @@ -535,7 +608,7 @@ return make_error("Invalid abbreviation", inconvertibleErrorCode()); - Entry E(*AbbrevIt); + Entry E(*this, *AbbrevIt); DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; for (auto &Value : E.Values) { @@ -629,7 +702,7 @@ ListScope TUScope(W, "Foreign Type Unit signatures"); for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) { W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU, - getForeignTUOffset(TU)); + getForeignTUSignature(TU)); } } @@ -697,3 +770,89 @@ for (const NameIndex &NI : NameIndices) NI.dump(W); } + +Optional +DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { + const Header &Hdr = CurrentIndex->Hdr; + if (Hdr.BucketCount == 0) { + // No Hash Table, We need to search through all names in the Name Index. + for (uint32_t Index = 1; Index <= Hdr.NameCount; ++Index) { + NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); + if (CurrentIndex->Section.StringSection.getCStr(&NTE.StringOffset) == Key) + return NTE.EntryOffset; + } + return None; + } + + // The Name Index has a Hash Table, so use that to speed up the search. + // Compute the Key Hash, if it has not been done already. + if (!Hash) + Hash = caseFoldingDjbHash(Key); + uint32_t Bucket = *Hash % Hdr.BucketCount; + uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket); + if (Index == 0) + return None; // Empty bucket + + for (; Index <= Hdr.NameCount; ++Index) { + uint32_t Hash = CurrentIndex->getHashArrayEntry(Index); + if (Hash % Hdr.BucketCount != Bucket) + return None; // End of bucket + + NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); + if (CurrentIndex->Section.StringSection.getCStr(&NTE.StringOffset) == Key) + return NTE.EntryOffset; + } + return None; +} + +bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() { + auto EntryOr = CurrentIndex->getEntry(&DataOffset); + if (!EntryOr) { + consumeError(EntryOr.takeError()); + return false; + } + CurrentEntry = std::move(*EntryOr); + return true; +} + +bool DWARFDebugNames::ValueIterator::findInCurrentIndex() { + Optional Offset = findEntryOffsetInCurrentIndex(); + if (!Offset) + return false; + DataOffset = *Offset; + return getEntryAtCurrentOffset(); +} + +void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() { + for (const NameIndex *End = CurrentIndex->Section.NameIndices.end(); + CurrentIndex != End; ++CurrentIndex) { + if (findInCurrentIndex()) + return; + } + setEnd(); +} + +void DWARFDebugNames::ValueIterator::next() { + assert(CurrentIndex && "Incrementing an end() iterator?"); + + // First try the next entry in the current Index. + if (getEntryAtCurrentOffset()) + return; + + // Try the next Name Index. + ++CurrentIndex; + searchFromStartOfCurrentIndex(); +} + +DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable, + StringRef Key) + : CurrentIndex(AccelTable.NameIndices.begin()), Key(Key) { + searchFromStartOfCurrentIndex(); +} + +iterator_range +DWARFDebugNames::equal_range(StringRef Key) const { + if (NameIndices.empty()) + return make_range(ValueIterator(), ValueIterator()); + return make_range(ValueIterator(*this, Key), ValueIterator()); +} Index: test/tools/llvm-dwarfdump/X86/debug-names-find.s =================================================================== --- /dev/null +++ test/tools/llvm-dwarfdump/X86/debug-names-find.s @@ -0,0 +1,182 @@ +# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj -o %t +# RUN: llvm-dwarfdump -find=foo %t | FileCheck --check-prefix=FOO %s +# RUN: llvm-dwarfdump -find=baz %t | FileCheck --check-prefix=BAZ %s +# RUN: llvm-dwarfdump -find=missing %t | FileCheck --check-prefix=MISSING %s + +# FOO: DW_TAG_subprogram +# FOO-NEXT: DW_AT_name ("foo") +# FOO-NEXT: DW_AT_external + +# BAZ: DW_TAG_subprogram +# BAZ-NEXT: DW_AT_name ("baz") +# BAZ-NEXT: DW_AT_external + +# MISSING-NOT: foo +# MISSING-NOT: bar +# MISSING-NOT: baz +# MISSING-NOT: bazz + + .section .debug_str,"MS",@progbits,1 +.Lstring_foo: + .asciz "foo" +.Lstring_foo_mangled: + .asciz "_Z3foov" +.Lstring_bar: + .asciz "bar" +.Lstring_baz: + .asciz "baz" +.Lstring_bazz: + .asciz "bazz" +.Lstring_producer: + .asciz "Hand-written dwarf" + + .section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Lcu_end0-.Lcu_start0 # Length of Unit +.Lcu_start0: + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Lstring_producer # DW_AT_producer + .short 12 # DW_AT_language +.Ldie_foo: + .byte 2 # Abbrev [2] DW_TAG_subprogram + .long .Lstring_foo # DW_AT_name + # DW_AT_external +.Ldie_bar: + .byte 2 # Abbrev [2] DW_TAG_subprogram + .long .Lstring_bar # DW_AT_name + # DW_AT_external + .byte 0 # End Of Children Mark +.Lcu_end0: + +.Lcu_begin1: + .long .Lcu_end1-.Lcu_start1 # Length of Unit +.Lcu_start1: + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Lstring_producer # DW_AT_producer + .short 12 # DW_AT_language +.Ldie_baz: + .byte 2 # Abbrev [2] DW_TAG_subprogram + .long .Lstring_baz # DW_AT_name + # DW_AT_external +.Ldie_bazz: + .byte 2 # Abbrev [2] DW_TAG_subprogram + .long .Lstring_bazz # DW_AT_name + # DW_AT_external + .byte 0 # End Of Children Mark +.Lcu_end1: + + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: contribution length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 0 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 2 # Header: bucket count + .long 3 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 0 # Header: augmentation length + .long .Lcu_begin0 # Compilation unit 0 + .long 1 # Bucket 0 + .long 2 # Bucket 1 + .long 193487034 # Hash in Bucket 0 + .long 193491849 # Hash in Bucket 1 + .long -1257882357 # Hash in Bucket 1 + .long .Lstring_bar # String in Bucket 1: bar + .long .Lstring_foo # String in Bucket 1: foo + .long .Lstring_foo_mangled # String in Bucket 1: _Z3foov + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1 + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 1 +.Lnames_abbrev_start0: + .byte 46 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 6 # DW_FORM_data4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames0: + .byte 46 # Abbrev code + .long .Ldie_bar # DW_IDX_die_offset + .long 0 # End of list: bar +.Lnames1: + .byte 46 # Abbrev code + .long .Ldie_foo # DW_IDX_die_offset + .long 0 # End of list: foo +.Lnames2: + .byte 46 # Abbrev code + .long .Ldie_foo # DW_IDX_die_offset + .long 0 # End of list: _Z3foov + .p2align 2 +.Lnames_end0: + +# Index of compilation unit 1. This one has no hash table. + .long .Lnames_end1-.Lnames_start1 # Header: contribution length +.Lnames_start1: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 0 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 0 # Header: bucket count + .long 2 # Header: name count + .long .Lnames_abbrev_end1-.Lnames_abbrev_start1 # Header: abbreviation table size + .long 0 # Header: augmentation length + .long .Lcu_begin1 # Compilation unit 0 + .long .Lstring_baz # String in Bucket 1: baz + .long .Lstring_bazz # String in Bucket 1: bazz + .long .Lnames3-.Lnames_entries1 # Offset in Bucket 1 + .long .Lnames4-.Lnames_entries1 # Offset in Bucket 1 +.Lnames_abbrev_start1: + .byte 46 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 6 # DW_FORM_data4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end1: +.Lnames_entries1: +.Lnames3: + .byte 46 # Abbrev code + .long .Ldie_baz # DW_IDX_die_offset + .long 0 # End of list: baz + .p2align 2 +.Lnames4: + .byte 46 # Abbrev code + .long .Ldie_bazz # DW_IDX_die_offset + .long 0 # End of list: baz + .p2align 2 +.Lnames_end1: Index: tools/llvm-dwarfdump/llvm-dwarfdump.cpp =================================================================== --- tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -336,6 +336,15 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename, raw_ostream &OS); +template +static Optional getDIEOffset(const AccelTable &Accel, + StringRef Name) { + for (const auto &Entry : Accel.equal_range(Name)) + if (Optional Off = Entry.getDIEOffset()) + return *Off; + return None; +} + static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename, raw_ostream &OS) { logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(), @@ -363,21 +372,14 @@ if (!Find.empty()) { DumpOffsets[DIDT_ID_DebugInfo] = [&]() -> llvm::Optional { for (auto Name : Find) { - auto find = [&](const AppleAcceleratorTable &Accel) - -> llvm::Optional { - for (auto Entry : Accel.equal_range(Name)) - for (auto Atom : Entry) - if (auto Offset = Atom.getAsSectionOffset()) - return Offset; - return None; - }; - if (auto Offset = find(DICtx.getAppleNames())) + if (auto Offset = getDIEOffset(DICtx.getAppleNames(), Name)) + return DumpOffsets[DIDT_ID_DebugInfo] = *Offset; + if (auto Offset = getDIEOffset(DICtx.getAppleTypes(), Name)) return DumpOffsets[DIDT_ID_DebugInfo] = *Offset; - if (auto Offset = find(DICtx.getAppleTypes())) + if (auto Offset = getDIEOffset(DICtx.getAppleNamespaces(), Name)) return DumpOffsets[DIDT_ID_DebugInfo] = *Offset; - if (auto Offset = find(DICtx.getAppleNamespaces())) + if (auto Offset = getDIEOffset(DICtx.getDebugNames(), Name)) return DumpOffsets[DIDT_ID_DebugInfo] = *Offset; - // TODO: Add .debug_names support } return None; }();