1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

llvm-dwarfdump: implement --find for .apple_names

This patch implements the dwarfdump option --find=<name>.  This option
looks for a DIE in the accelerator tables and dumps it if found.  This
initial patch only adds support for .apple_names to keep the review
small, adding the other sections and pubnames support should be
trivial though.

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

llvm-svn: 314439
This commit is contained in:
Adrian Prantl 2017-09-28 18:10:52 +00:00
parent fdd0433d80
commit 9a78f28e7e
10 changed files with 201 additions and 13 deletions

View File

@ -491,6 +491,9 @@ private:
/// Constants that define the DWARF format as 32 or 64 bit.
enum DwarfFormat : uint8_t { DWARF32, DWARF64 };
/// The Bernstein hash function used by the accelerator tables.
uint32_t djbHash(StringRef Buffer);
} // End of namespace dwarf
} // End of namespace llvm

View File

@ -13,7 +13,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include <cstdint>
#include <utility>
@ -21,6 +21,9 @@ namespace llvm {
class raw_ostream;
/// This implements the Apple accelerator table format, a precursor of the
/// DWARF 5 accelerator table format.
/// TODO: Factor out a common base class for both formats.
class DWARFAcceleratorTable {
struct Header {
uint32_t Magic;
@ -43,8 +46,46 @@ class DWARFAcceleratorTable {
struct HeaderData HdrData;
DWARFDataExtractor AccelSection;
DataExtractor StringSection;
bool IsValid = false;
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 DWARFAcceleratorTable *AccelTable = nullptr;
SmallVector<DWARFFormValue, 3> AtomForms; ///< The decoded data entry.
unsigned DataOffset = 0; ///< Offset into the section.
unsigned Data = 0; ///< Current data entry.
unsigned NumData = 0; ///< Number of data entries.
/// Advance the iterator.
void Next();
public:
/// Construct a new iterator for the entries at \p DataOffset.
ValueIterator(const DWARFAcceleratorTable &AccelTable, unsigned DataOffset);
/// End marker.
ValueIterator() : NumData(0) {}
const ArrayRef<DWARFFormValue> operator*() const {
return AtomForms;
}
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.NumData == B.NumData && A.DataOffset == B.DataOffset;
}
friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
return !(A == B);
}
};
DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
DataExtractor StringSection)
: AccelSection(AccelSection), StringSection(StringSection) {}
@ -67,6 +108,9 @@ public:
/// DieTag is the tag of the DIE
std::pair<uint32_t, dwarf::Tag> readAtoms(uint32_t &HashDataOffset);
void dump(raw_ostream &OS) const;
/// Look up all entries in the accelerator table matching \c Key.
iterator_range<ValueIterator> equal_range(StringRef Key) const;
};
} // end namespace llvm

View File

@ -17,6 +17,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
@ -68,6 +69,7 @@ class DWARFContext : public DIContext {
std::unique_ptr<DWARFDebugFrame> DebugFrame;
std::unique_ptr<DWARFDebugFrame> EHFrame;
std::unique_ptr<DWARFDebugMacro> Macro;
std::unique_ptr<DWARFAcceleratorTable> AppleNames;
DWARFUnitSection<DWARFCompileUnit> DWOCUs;
std::deque<DWARFUnitSection<DWARFTypeUnit>> DWOTUs;
@ -237,6 +239,9 @@ public:
/// Get a pointer to the parsed DebugMacro object.
const DWARFDebugMacro *getDebugMacro();
/// Get a reference to the parsed accelerator table object.
const DWARFAcceleratorTable &getAppleNames();
/// Get a pointer to a parsed line table corresponding to a compile unit.
const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *cu);

View File

@ -575,3 +575,10 @@ bool llvm::dwarf::isValidFormForVersion(Form F, unsigned Version,
}
return ExtensionsOk;
}
uint32_t llvm::dwarf::djbHash(StringRef Buffer) {
uint32_t H = 5381;
for (char C : Buffer.bytes())
H = ((H << 5) + H) + C;
return H;
}

View File

@ -68,13 +68,6 @@ class AsmPrinter;
class DwarfDebug;
class DwarfAccelTable {
static uint32_t HashDJB(StringRef Str) {
uint32_t h = 5381;
for (unsigned i = 0, e = Str.size(); i != e; ++i)
h = ((h << 5) + h) + Str[i];
return h;
}
// Helper function to compute the number of buckets needed based on
// the number of unique hashes.
void ComputeBucketCount();
@ -199,7 +192,7 @@ private:
HashData(StringRef S, DwarfAccelTable::DataArray &Data)
: Str(S), Data(Data) {
HashValue = DwarfAccelTable::HashDJB(S);
HashValue = dwarf::djbHash(S);
}
#ifndef NDEBUG

View File

@ -12,7 +12,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
@ -52,6 +51,7 @@ bool DWARFAcceleratorTable::extract() {
HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
}
IsValid = true;
return true;
}
@ -109,6 +109,9 @@ DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
}
LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
if (!IsValid)
return;
// Dump the header.
OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
<< "Version = " << format("0x%04x", Hdr.Version) << '\n'
@ -190,3 +193,67 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
}
}
}
DWARFAcceleratorTable::ValueIterator::ValueIterator(
const DWARFAcceleratorTable &AccelTable, unsigned Offset)
: AccelTable(&AccelTable), 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();
}
void DWARFAcceleratorTable::ValueIterator::Next() {
assert(NumData > 0 && "attempted to increment iterator past the end");
auto &AccelSection = AccelTable->AccelSection;
if (Data >= NumData ||
!AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
NumData = 0;
return;
}
for (auto &Atom : AtomForms)
Atom.extractValue(AccelSection, &DataOffset, nullptr);
++Data;
}
iterator_range<DWARFAcceleratorTable::ValueIterator>
DWARFAcceleratorTable::equal_range(StringRef Key) const {
if (!IsValid)
return make_range(ValueIterator(), ValueIterator());
// Find the bucket.
unsigned HashValue = dwarf::djbHash(Key);
unsigned Bucket = HashValue % Hdr.NumBuckets;
unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
unsigned BucketOffset = BucketBase + Bucket * 4;
unsigned Index = AccelSection.getU32(&BucketOffset);
// Search through all hashes in the bucket.
for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
unsigned HashOffset = HashesBase + HashIdx * 4;
unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
uint32_t Hash = AccelSection.getU32(&HashOffset);
if (Hash % Hdr.NumBuckets != Bucket)
// We are already in the next bucket.
break;
unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
if (!StringOffset)
break;
// Finally, compare the key.
if (Key == StringSection.getCStr(&StringOffset))
return make_range({*this, DataOffset}, ValueIterator());
}
return make_range(ValueIterator(), ValueIterator());
}

View File

@ -453,8 +453,7 @@ void DWARFContext::dump(
if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
DObj->getAppleNamesSection().Data))
dumpAccelSection(OS, *DObj, DObj->getAppleNamesSection(),
DObj->getStringSection(), isLittleEndian());
getAppleNames().dump(OS);
if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
DObj->getAppleTypesSection().Data))
@ -638,6 +637,24 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() {
return Macro.get();
}
static DWARFAcceleratorTable &
getAccelTable(std::unique_ptr<DWARFAcceleratorTable> &Cache,
const DWARFObject &Obj, const DWARFSection &Section,
StringRef StringSection, bool IsLittleEndian) {
if (Cache)
return *Cache;
DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
DataExtractor StrData(StringSection, IsLittleEndian, 0);
Cache.reset(new DWARFAcceleratorTable(AccelSection, StrData));
Cache->extract();
return *Cache;
}
const DWARFAcceleratorTable &DWARFContext::getAppleNames() {
return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
DObj->getStringSection(), isLittleEndian());
}
const DWARFLineTable *
DWARFContext::getLineTableForUnit(DWARFUnit *U) {
if (!Line)

View File

@ -0,0 +1,28 @@
RUN: llvm-mc %S/brief.s -filetype obj -triple x86_64-apple-darwin -o - \
RUN: | llvm-dwarfdump -find=not_there_at_all - | \
RUN: FileCheck %s --check-prefix=EMPTY --allow-empty
EMPTY: {{^$}}
RUN: llvm-mc %S/brief.s -filetype obj -triple x86_64-apple-darwin -o - \
RUN: | llvm-dwarfdump -find=main - | FileCheck %s
CHECK: .debug_info contents:
CHECK-NOT: {{:}}
CHECK: : DW_TAG_subprogram
CHECK-NOT: {{:}}
CHECK: DW_AT_name ("main")
CHECK-NOT: {{:}}
RUN: llvm-dwarfdump --debug-info %S/../../dsymutil/Inputs/libfat-test.a \
RUN: -find=x86_64h_var -find=i386_var \
RUN: | FileCheck %s --check-prefix=MULTI
MULTI: .debug_info contents:
MULTI-NOT: {{: DW}}
MULTI: : DW_TAG_variable
MULTI-NOT: {{: DW}}
MULTI: DW_AT_name ("i386_var")
MULTI-NOT: {{: DW}}
MULTI: .debug_info contents:
MULTI: : DW_TAG_variable
MULTI-NOT: {{: DW}}
MULTI: DW_AT_name ("x86_64h_var")
MULTI-NOT: {{: DW}}

View File

@ -6,6 +6,7 @@ HELP: Section-specific Dump Options
HELP: -debug-info - Dump the .debug_info section
HELP: -eh-frame
HELP: Specific Options
HELP: -find
HELP: -recurse-depth=<N>
HELP: -show-children
HELP: -show-parents

View File

@ -134,6 +134,13 @@ static list<std::string>
"name or by number. This option can be specified "
"multiple times, once for each desired architecture."),
cat(DwarfDumpCategory));
static list<std::string>
Find("find",
desc("Search for the exact match for <name> in the accelerator tables "
"and print the matching debug information entries."),
value_desc("name"), cat(DwarfDumpCategory));
static alias FindAlias("f", desc("Alias for -find"), aliasopt(Find));
static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture"),
cat(DwarfDumpCategory));
static alias DumpUUIDAlias("u", desc("Alias for -uuid"), aliasopt(DumpUUID));
@ -164,7 +171,7 @@ static opt<unsigned> RecurseDepth(
cat(DwarfDumpCategory), init(-1U), value_desc("N"));
static alias RecurseDepthAlias("r", desc("Alias for -recurse-depth"),
aliasopt(RecurseDepth));
static opt<bool>
SummarizeTypes("summarize-types",
desc("Abbreviate the description of type unit entries"),
@ -236,6 +243,22 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
raw_ostream &OS) {
logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
Filename.str() + ": ");
// Handle the --find option and lower it to --debug-info=<offset>.
if (!Find.empty()) {
DumpOffsets[DIDT_ID_DebugInfo] = [&]() -> Optional<uint64_t> {
for (auto Name : Find)
for (auto Entry : DICtx.getAppleNames().equal_range(Name))
for (auto Atom : Entry)
if (auto Offset = Atom.getAsSectionOffset())
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
return None;
}();
// Early exit if --find was specified but the current file doesn't have it.
if (!DumpOffsets[DIDT_ID_DebugInfo])
return true;
}
// The UUID dump already contains all the same information.
if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';