mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 23:51:56 +00:00
[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
This commit is contained in:
parent
ecb07f481b
commit
15a1f7f6f7
@ -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 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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 @@ public:
|
||||
|
||||
/// 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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
@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())
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user