Implement equal_range for the DWARF v5 accelerator table
authorPavel Labath <labath@google.com>
Sat, 24 Feb 2018 00:35:21 +0000 (00:35 +0000)
committerPavel Labath <labath@google.com>
Sat, 24 Feb 2018 00:35:21 +0000 (00:35 +0000)
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/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
llvm/test/tools/llvm-dwarfdump/X86/debug-names-find.s [new file with mode: 0644]
llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

index 517f7a4..3917df4 100644 (file)
@@ -35,6 +35,43 @@ protected:
   DataExtractor StringSection;
 
 public:
+  /// An abstract class representing a single entry in the accelerator tables.
+  class Entry {
+  protected:
+    SmallVector<DWARFFormValue, 3> 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<uint64_t> 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<uint64_t> 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<dwarf::Tag> 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<DWARFFormValue> 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<std::input_iterator_tag,
-                                            ArrayRef<DWARFFormValue>> {
-    const AppleAcceleratorTable *AccelTable = nullptr;
-    SmallVector<DWARFFormValue, 3> 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<uint64_t> getCUOffset() const override;
+    Optional<uint64_t> getDIEOffset() const override;
+    Optional<dwarf::Tag> getTag() const override;
+
+    /// Returns the value of the Atom in this Accelerator Entry, if the Entry
+    /// contains such Atom.
+    Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
+
+    friend class AppleAcceleratorTable;
+    friend class ValueIterator;
+  };
+
+  class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
+    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<DWARFFormValue> 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<std::pair<HeaderData::AtomType, HeaderData::Form>> 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<uint64_t> getCUIndex() const;
+
+  public:
+    Optional<uint64_t> getCUOffset() const override;
+    Optional<uint64_t> getDIEOffset() const override;
+    Optional<dwarf::Tag> getTag() const override { return tag(); }
 
-    /// Values of the index attributes described by Abbr.
-    std::vector<DWARFFormValue> 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<DWARFFormValue> 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<std::input_iterator_tag, Entry> {
+
+    /// 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<Entry> CurrentEntry;
+    unsigned DataOffset = 0; ///< Offset into the section.
+    std::string Key;         ///< The Key we are searching for.
+    Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
+
+    bool getEntryAtCurrentOffset();
+    Optional<uint32_t> 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<NameIndex> NameIndices;
+  llvm::SmallVector<NameIndex, 0> 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<ValueIterator> equal_range(StringRef Key) const;
 };
 
 } // end namespace llvm
index 9111d73..3d26cf6 100644 (file)
@@ -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<DWARFFormValue>
+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<uint64_t> AppleAcceleratorTable::Entry::getDIEOffset() const {
+  if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_ATOM_die_offset))
+    return Off->getAsSectionOffset();
+  return None;
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
+  if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_ATOM_cu_offset))
+    return Off->getAsSectionOffset();
+  return None;
+}
+
+Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {
+  Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);
+  if (!Tag)
+    return None;
+  if (Optional<uint64_t> 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<DWARFFormValue>
+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<uint64_t> DWARFDebugNames::Entry::getDIEOffset() const {
+  if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
+    return Off->getAsSectionOffset();
+  return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
+  if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
+    return Off->getAsUnsignedConstant();
+  return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
+  Optional<uint64_t> 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<StringError>("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<uint32_t>
+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<uint32_t> 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::ValueIterator>
+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 (file)
index 0000000..280c3d7
--- /dev/null
@@ -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 f2a837d..b110480 100644 (file)
@@ -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 <typename AccelTable>
+static Optional<uint64_t> getDIEOffset(const AccelTable &Accel,
+                                       StringRef Name) {
+  for (const auto &Entry : Accel.equal_range(Name))
+    if (Optional<uint64_t> 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<uint64_t> {
       for (auto Name : Find) {
-        auto find = [&](const AppleAcceleratorTable &Accel)
-            -> llvm::Optional<uint64_t> {
-          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;
     }();