From d99072bc9749874a7885740959e35ac08d99e324 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Sat, 24 Feb 2018 00:35:21 +0000 Subject: [PATCH] Implement equal_range for the DWARF v5 accelerator table Summary: This patch implements the name lookup functionality of the .debug_names accelerator table and hooks it up to "llvm-dwarfdump -find". To make the interface of the two kinds of accelerator tables more consistent, I've created an abstract "DWARFAcceleratorTable::Entry" class, which provides a consistent interface to access the common functionality of the table entries (such as getting the die offset, die tag, etc.). I've also modified the apple table to vend entries conforming to this interface. Reviewers: JDevlieghere, aprantl, probinson, dblaikie Subscribers: vleschuk, clayborg, echristo, llvm-commits Differential Revision: https://reviews.llvm.org/D43067 llvm-svn: 326003 --- .../llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h | 192 +++++++++++++++++--- llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 196 +++++++++++++++++++-- .../tools/llvm-dwarfdump/X86/debug-names-find.s | 182 +++++++++++++++++++ llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp | 26 +-- 4 files changed, 540 insertions(+), 56 deletions(-) create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/debug-names-find.s diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 517f7a4..3917df4 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -35,6 +35,43 @@ protected: 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; + ~Entry() = default; + + + public: + /// 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 @@ class AppleAcceleratorTable : public DWARFAcceleratorTable { 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 @@ public: /// 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 @@ public: 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 @@ class DWARFDebugNames : public DWARFAcceleratorTable { }; public: + class NameIndex; + class ValueIterator; + /// Dwarf 5 Name Index header. struct Header : public HeaderPOD { SmallString<8> AugmentationString; @@ -214,16 +274,41 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 9111d73..3d26cf6 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -248,15 +248,61 @@ LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { } } +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 +316,7 @@ void AppleAcceleratorTable::ValueIterator::Next() { 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 +518,8 @@ Error DWARFDebugNames::NameIndex::extract() { } } } - -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 +527,43 @@ DWARFDebugNames::Entry::Entry(const Abbrev &Abbr) : Abbr(Abbr) { 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 +585,7 @@ uint32_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const { 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 +607,7 @@ DWARFDebugNames::NameIndex::getEntry(uint32_t *Offset) const { 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 +701,7 @@ void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const { 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 +769,89 @@ LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const { 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()); +} diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-find.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-find.s new file mode 100644 index 0000000..280c3d7 --- /dev/null +++ b/llvm/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: diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index f2a837d..b110480 100644 --- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -336,6 +336,15 @@ static bool lookup(DWARFContext &DICtx, uint64_t Address, raw_ostream &OS) { 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 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename, 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; }(); -- 2.7.4