[llvm] 15a1f7f - [AppleTables] Implement iterator over all entries in table

Felipe de Azevedo Piovezan via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 21 03:45:23 PDT 2023


Author: Felipe de Azevedo Piovezan
Date: 2023-06-21T06:44:56-04:00
New Revision: 15a1f7f6f7be103820b6a0c4caea1ec58c01d906

URL: https://github.com/llvm/llvm-project/commit/15a1f7f6f7be103820b6a0c4caea1ec58c01d906
DIFF: https://github.com/llvm/llvm-project/commit/15a1f7f6f7be103820b6a0c4caea1ec58c01d906.diff

LOG: [AppleTables] Implement iterator over all entries in table

This commit adds functionality to the Apple Accelerator table allowing iteration
over all elements in the table.

Our iterators look like streaming iterators: when we increment the iterator we
check if there is still enough data in the "stream" (in our case, the blob of
data of the accelerator table) and extract the next entry. If any failures
occur, we immediately set the iterator to be the end iterator.

Since the ultimate user of this functionality is LLDB, there are roughly two
iteration methods we want support: one that also loads the name of each entry,
and one which does not. Loading names is measurably slower (one order the
magnitude) than only loading DIEs, so we used some template metaprograming to
implement both iteration methods.

Depends on D153066

Differential Revision: https://reviews.llvm.org/D153066

Added: 
    

Modified: 
    llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
    llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
    llvm/test/DebugInfo/Generic/apple-names-hash-collisions.ll
    llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
index f9f9cc7bf4cfb..3df8e2190a860 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -140,6 +140,11 @@ class AppleAcceleratorTable : public DWARFAcceleratorTable {
   /// Return the offset into the section where the offset list begins.
   uint64_t getOffsetBase() const { return getHashBase() + getNumHashes() * 4; }
 
+  /// Return the offset into the section where the table entries begin.
+  uint64_t getEntriesBase() const {
+    return getOffsetBase() + getNumHashes() * 4;
+  }
+
   /// Return the offset into the section where the I-th offset is.
   uint64_t getIthOffsetBase(uint32_t I) const {
     return getOffsetBase() + I * 4;
@@ -240,6 +245,58 @@ class AppleAcceleratorTable : public DWARFAcceleratorTable {
     }
   };
 
+  struct EntryWithName {
+    EntryWithName(const AppleAcceleratorTable &Table)
+        : BaseEntry(Table), StrOffset(0) {}
+
+    std::optional<StringRef> readName() const {
+      return BaseEntry.Table.readStringFromStrSection(StrOffset);
+    }
+
+    Entry BaseEntry;
+    uint32_t StrOffset;
+  };
+
+  /// An iterator for all entries in the table.
+  class Iterator
+      : public iterator_facade_base<Iterator, std::forward_iterator_tag,
+                                    EntryWithName> {
+    constexpr static auto EndMarker = std::numeric_limits<uint64_t>::max();
+
+    EntryWithName Current;
+    uint64_t Offset = EndMarker;
+    uint32_t NumEntriesToCome = 0;
+
+    void setToEnd() { Offset = EndMarker; }
+    bool isEnd() const { return Offset == EndMarker; }
+    const AppleAcceleratorTable &getTable() const {
+      return Current.BaseEntry.Table;
+    }
+
+    /// Reads the next Entry in the table, populating `Current`.
+    /// If not possible (e.g. end of the section), becomes the end iterator.
+    void prepareNextEntryOrEnd();
+
+    /// Reads the next string pointer and the entry count for that string,
+    /// populating `NumEntriesToCome`.
+    /// If not possible (e.g. end of the section), becomes the end iterator.
+    /// Assumes `Offset` points to a string reference.
+    void prepareNextStringOrEnd();
+
+  public:
+    Iterator(const AppleAcceleratorTable &Table, bool SetEnd = false);
+
+    Iterator &operator++() {
+      prepareNextEntryOrEnd();
+      return *this;
+    }
+    bool operator==(const Iterator &It) const { return Offset == It.Offset; }
+    const EntryWithName &operator*() const {
+      assert(!isEnd() && "dereferencing end iterator");
+      return Current;
+    }
+  };
+
   AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
                         DataExtractor StringSection)
       : DWARFAcceleratorTable(AccelSection, StringSection) {}
@@ -271,6 +328,11 @@ class AppleAcceleratorTable : public DWARFAcceleratorTable {
 
   /// Look up all entries in the accelerator table matching \c Key.
   iterator_range<SameNameIterator> equal_range(StringRef Key) const;
+
+  /// Lookup all entries in the accelerator table.
+  auto entries() const {
+    return make_range(Iterator(*this), Iterator(*this, /*SetEnd*/ true));
+  }
 };
 
 /// .debug_names section consists of one or more units. Each unit starts with a

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 3e052f25f1da7..14962cd36c235 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -309,6 +309,43 @@ AppleAcceleratorTable::SameNameIterator::SameNameIterator(
     const AppleAcceleratorTable &AccelTable, uint64_t DataOffset)
     : Current(AccelTable), Offset(DataOffset) {}
 
+void AppleAcceleratorTable::Iterator::prepareNextEntryOrEnd() {
+  if (NumEntriesToCome == 0)
+    prepareNextStringOrEnd();
+  if (isEnd())
+    return;
+  uint64_t OffsetCopy = Offset;
+  Current.BaseEntry.extract(&OffsetCopy);
+  NumEntriesToCome--;
+  Offset += getTable().getHashDataEntryLength();
+}
+
+void AppleAcceleratorTable::Iterator::prepareNextStringOrEnd() {
+  std::optional<uint32_t> StrOffset = getTable().readStringOffsetAt(Offset);
+  if (!StrOffset)
+    return setToEnd();
+
+  // A zero denotes the end of the collision list. Read the next string
+  // again.
+  if (*StrOffset == 0)
+    return prepareNextStringOrEnd();
+  Current.StrOffset = *StrOffset;
+
+  std::optional<uint32_t> MaybeNumEntries = getTable().readU32FromAccel(Offset);
+  if (!MaybeNumEntries || *MaybeNumEntries == 0)
+    return setToEnd();
+  NumEntriesToCome = *MaybeNumEntries;
+}
+
+AppleAcceleratorTable::Iterator::Iterator(const AppleAcceleratorTable &Table,
+                                          bool SetEnd)
+    : Current(Table), Offset(Table.getEntriesBase()), NumEntriesToCome(0) {
+  if (SetEnd)
+    setToEnd();
+  else
+    prepareNextEntryOrEnd();
+}
+
 iterator_range<AppleAcceleratorTable::SameNameIterator>
 AppleAcceleratorTable::equal_range(StringRef Key) const {
   const auto EmptyRange =

diff  --git a/llvm/test/DebugInfo/Generic/apple-names-hash-collisions.ll b/llvm/test/DebugInfo/Generic/apple-names-hash-collisions.ll
index 4283055abb2fa..5664ec91d895f 100644
--- a/llvm/test/DebugInfo/Generic/apple-names-hash-collisions.ll
+++ b/llvm/test/DebugInfo/Generic/apple-names-hash-collisions.ll
@@ -2,6 +2,7 @@
 ; RUN: %llc_dwarf -accel-tables=Apple -filetype=obj -o %t < %s
 ; RUN: llvm-dwarfdump -apple-names %t | FileCheck %s --check-prefix=NUM_HASHES
 ; RUN: llvm-dwarfdump  --find=bb --find=cA %t | FileCheck %s --check-prefix=FOUND_VARS
+; RUN: llvm-dwarfdump  --find-all-apple %t | FileCheck %s --check-prefix=ALL_ENTRIES
 
 
 ; The strings 'bb' and 'cA' hash to the same value under the Apple accelerator
@@ -9,13 +10,23 @@
 ; We first test that there is exactly one bucket and one hash.
 ; Then we check that both values are found.
 
-; NUM_HASHES:      Bucket count: 1
-; NUM_HASHES-NEXT: Hashes count: 1
+; NUM_HASHES:      Bucket count: 2
+; NUM_HASHES-NEXT: Hashes count: 2
 ; FOUND_VARS: DW_AT_name        ("bb")
 ; FOUND_VARS: DW_AT_name        ("cA")
 
+; ALL_ENTRIES: Apple accelerator entries with name = "cA":
+; ALL_ENTRIES: DW_AT_name        ("cA")
+; ALL_ENTRIES: Apple accelerator entries with name = "some_other_hash":
+; ALL_ENTRIES: DW_AT_name        ("some_other_hash")
+; ALL_ENTRIES: Apple accelerator entries with name = "int":
+; ALL_ENTRIES: DW_AT_name        ("int")
+; ALL_ENTRIES: Apple accelerator entries with name = "bb":
+; ALL_ENTRIES: DW_AT_name        ("bb")
+
 @bb = global i32 200, align 4, !dbg !0
 @cA = global i32 10, align 4, !dbg !5
+ at some_other_hash = global i32 10, !dbg !17
 
 !llvm.module.flags = !{!9, !10, !11, !12, !13}
 !llvm.dbg.cu = !{!2}
@@ -25,7 +36,7 @@
 !1 = distinct !DIGlobalVariable(name: "bb", scope: !2, file: !3, line: 1, type: !7, isDefinition: true)
 !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "", emissionKind: FullDebug, globals: !4)
 !3 = !DIFile(filename: "test.cpp", directory: "blah")
-!4 = !{!0, !5}
+!4 = !{!0, !5, !17}
 !5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
 !6 = distinct !DIGlobalVariable(name: "cA", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
 !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
@@ -35,3 +46,5 @@
 !12 = !{i32 8, !"PIC Level", i32 2}
 !13 = !{i32 7, !"uwtable", i32 1}
 !15 = !{!"blah"}
+!16 = distinct !DIGlobalVariable(name: "some_other_hash", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
+!17 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression())

diff  --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index c49a32f95474d..cdcb5bbd8ab99 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm-dwarfdump.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
@@ -25,6 +26,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
@@ -171,6 +173,10 @@ static list<std::string>
          value_desc("name"), cat(DwarfDumpCategory));
 static alias FindAlias("f", desc("Alias for --find."), aliasopt(Find),
                        cl::NotHidden);
+static opt<bool> FindAllApple(
+    "find-all-apple",
+    desc("Print every debug information entry in the accelerator tables."),
+    cat(DwarfDumpCategory));
 static opt<bool> IgnoreCase("ignore-case",
                             desc("Ignore case distinctions when using --name."),
                             value_desc("i"), cat(DwarfDumpCategory));
@@ -453,6 +459,37 @@ static void filterByAccelName(
     Die.dump(OS, 0, DumpOpts);
 }
 
+/// Print all DIEs in apple accelerator tables
+static void findAllApple(
+    DWARFContext &DICtx, raw_ostream &OS,
+    std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
+  StringMap<llvm::SmallSet<DWARFDie, 2>> NameToDies;
+
+  auto PushDIEs = [&](const AppleAcceleratorTable &Accel) {
+    for (const auto &Entry : Accel.entries()) {
+      if (std::optional<uint64_t> Off = Entry.BaseEntry.getDIESectionOffset()) {
+        std::optional<StringRef> MaybeName = Entry.readName();
+        DWARFDie Die = DICtx.getDIEForOffset(*Off);
+        if (Die && MaybeName)
+          NameToDies[*MaybeName].insert(Die);
+      }
+    }
+  };
+
+  PushDIEs(DICtx.getAppleNames());
+  PushDIEs(DICtx.getAppleNamespaces());
+  PushDIEs(DICtx.getAppleTypes());
+
+  DIDumpOptions DumpOpts = getDumpOpts(DICtx);
+  DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;
+  for (const auto &[Name, Dies] : NameToDies) {
+    OS << llvm::formatv("\nApple accelerator entries with name = \"{0}\":\n",
+                        Name);
+    for (DWARFDie Die : Dies)
+      Die.dump(OS, 0, DumpOpts);
+  }
+}
+
 /// Handle the --lookup option and dump the DIEs and line info for the given
 /// address.
 /// TODO: specified Address for --lookup option could relate for several
@@ -625,6 +662,12 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
     return true;
   }
 
+  // Handle the --find-all-apple option and lower it to --debug-info=<offset>.
+  if (FindAllApple) {
+    findAllApple(DICtx, OS, GetRegName);
+    return true;
+  }
+
   // Dump the complete DWARF structure.
   auto DumpOpts = getDumpOpts(DICtx);
   DumpOpts.GetNameForDWARFReg = GetRegName;
@@ -782,7 +825,7 @@ int main(int argc, char **argv) {
 
   // Unless dumping a specific DIE, default to --show-children.
   if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() &&
-      Find.empty())
+      Find.empty() && !FindAllApple)
     ShowChildren = true;
 
   // Defaults to a.out if no filenames specified.


        


More information about the llvm-commits mailing list