[dwarfdump] Add support for dumping accelerator tables.

The class used for the dump only allows to dump for the moment, but
it can (and will) be easily extended to support search also.

llvm-svn: 221836
This commit is contained in:
Frederic Riss 2014-11-12 23:48:10 +00:00
parent ab7dbc1c68
commit 040ceb7848
9 changed files with 359 additions and 1 deletions

View File

@ -107,7 +107,11 @@ enum DIDumpType {
DIDT_GnuPubtypes,
DIDT_Str,
DIDT_StrDwo,
DIDT_StrOffsetsDwo
DIDT_StrOffsetsDwo,
DIDT_AppleNames,
DIDT_AppleTypes,
DIDT_AppleNamespaces,
DIDT_AppleObjC
};
// In place of applying the relocations to the data we've read from disk we use

View File

@ -1,6 +1,7 @@
add_llvm_library(LLVMDebugInfo
DIContext.cpp
DWARFAbbreviationDeclaration.cpp
DWARFAcceleratorTable.cpp
DWARFCompileUnit.cpp
DWARFContext.cpp
DWARFDebugAbbrev.cpp

View File

@ -0,0 +1,110 @@
#include "DWARFAcceleratorTable.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
bool DWARFAcceleratorTable::extract() {
uint32_t Offset = 0;
// Check that we can at least read the header.
if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
return false;
Hdr.Magic = AccelSection.getU32(&Offset);
Hdr.Version = AccelSection.getU16(&Offset);
Hdr.HashFunction = AccelSection.getU16(&Offset);
Hdr.NumBuckets = AccelSection.getU32(&Offset);
Hdr.NumHashes = AccelSection.getU32(&Offset);
Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
// Check that we can read all the hashes and offsets from the
// section (see SourceLevelDebugging.rst for the structure of the index).
if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
Hdr.NumBuckets*4 + Hdr.NumHashes*8))
return false;
HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
uint32_t NumAtoms = AccelSection.getU32(&Offset);
for (unsigned i = 0; i < NumAtoms; ++i) {
auto Atom = std::make_pair(AccelSection.getU16(&Offset),
DWARFFormValue(AccelSection.getU16(&Offset)));
HdrData.Atoms.push_back(Atom);
}
return true;
}
void DWARFAcceleratorTable::dump(raw_ostream &OS) {
// Dump the header.
OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n';
OS << "Version = " << format("0x%04x", Hdr.Version) << '\n';
OS << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n';
OS << "Bucket count = " << Hdr.NumBuckets << '\n';
OS << "Hashes count = " << Hdr.NumHashes << '\n';
OS << "HeaderData length = " << Hdr.HeaderDataLength << '\n';
OS << "DIE offset base = " << HdrData.DIEOffsetBase << '\n';
OS << "Number of atoms = " << HdrData.Atoms.size() << '\n';
unsigned i = 0;
for (const auto &Atom: HdrData.Atoms) {
OS << format("Atom[%d] ", i++);
OS << " Type: " << dwarf::AtomTypeString(Atom.first);
OS << " Form: " << dwarf::FormEncodingString(Atom.second.getForm());
OS << "\n";
}
// Now go through the actual tables and dump them.
uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
unsigned HashesBase = Offset + Hdr.NumBuckets * 4;
unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
unsigned Index;
Index = AccelSection.getU32(&Offset);
OS << format("Bucket[%d]\n", Bucket);
if (Index == UINT32_MAX) {
OS << " EMPTY\n";
continue;
}
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)
break;
unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
if (!AccelSection.isValidOffset(DataOffset)) {
OS << " Invalid section offset\n";
continue;
}
while (unsigned StringOffset = AccelSection.getU32(&DataOffset)) {
OS << format(" Name: %08x \"%s\"\n", StringOffset,
StringSection.getCStr(&StringOffset));
unsigned NumData = AccelSection.getU32(&DataOffset);
for (unsigned Data = 0; Data < NumData; ++Data) {
OS << format(" Data[%d] => ", Data);
unsigned i = 0;
for (auto &Atom : HdrData.Atoms) {
OS << format("{Atom[%d]: ", i++);
if (Atom.second.extractValue(AccelSection, &DataOffset, nullptr))
Atom.second.dump(OS, nullptr);
else
OS << "Error extracting the value";
OS << "} ";
}
OS << '\n';
}
}
}
}
}
}

View File

@ -0,0 +1,38 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DWARFFormValue.h"
#include <cstdint>
namespace llvm {
class DWARFAcceleratorTable {
struct Header {
uint32_t Magic;
uint16_t Version;
uint16_t HashFunction;
uint32_t NumBuckets;
uint32_t NumHashes;
uint32_t HeaderDataLength;
};
struct HeaderData {
typedef uint16_t AtomType;
uint32_t DIEOffsetBase;
SmallVector<std::pair<AtomType, DWARFFormValue>, 1> Atoms;
};
struct Header Hdr;
struct HeaderData HdrData;
DataExtractor AccelSection;
DataExtractor StringSection;
public:
DWARFAcceleratorTable(DataExtractor AccelSection, DataExtractor StringSection)
: AccelSection(AccelSection), StringSection(StringSection) {}
bool extract();
void dump(raw_ostream &OS);
};
}

View File

@ -9,6 +9,7 @@
#include "DWARFContext.h"
#include "DWARFDebugArangeSet.h"
#include "DWARFAcceleratorTable.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@ -59,6 +60,17 @@ static void dumpPubSection(raw_ostream &OS, StringRef Name, StringRef Data,
}
}
static void dumpAccelSection(raw_ostream &OS, StringRef Name, StringRef Data,
StringRef StringSection, bool LittleEndian) {
DataExtractor AccelSection(Data, LittleEndian, 0);
DataExtractor StrData(StringSection, LittleEndian, 0);
OS << "\n." << Name << " contents:\n";
DWARFAcceleratorTable Accel(AccelSection, StrData);
if (!Accel.extract())
return;
Accel.dump(OS);
}
void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
OS << ".debug_abbrev contents:\n";
@ -218,6 +230,22 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
OS << format("%8.8x\n", strOffsetExt.getU32(&offset));
}
}
if (DumpType == DIDT_All || DumpType == DIDT_AppleNames)
dumpAccelSection(OS, "apple_names", getAppleNamesSection(),
getStringSection(), isLittleEndian());
if (DumpType == DIDT_All || DumpType == DIDT_AppleTypes)
dumpAccelSection(OS, "apple_types", getAppleTypesSection(),
getStringSection(), isLittleEndian());
if (DumpType == DIDT_All || DumpType == DIDT_AppleNamespaces)
dumpAccelSection(OS, "apple_namespaces", getAppleNamespacesSection(),
getStringSection(), isLittleEndian());
if (DumpType == DIDT_All || DumpType == DIDT_AppleObjC)
dumpAccelSection(OS, "apple_objc", getAppleObjCSection(),
getStringSection(), isLittleEndian());
}
const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
@ -565,6 +593,11 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj)
.Case("debug_str.dwo", &StringDWOSection)
.Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
.Case("debug_addr", &AddrSection)
.Case("apple_names", &AppleNamesSection)
.Case("apple_types", &AppleTypesSection)
.Case("apple_namespaces", &AppleNamespacesSection)
.Case("apple_namespac", &AppleNamespacesSection)
.Case("apple_objc", &AppleObjCSection)
// Any more debug info sections go here.
.Default(nullptr);
if (SectionData) {

View File

@ -192,6 +192,10 @@ public:
virtual StringRef getStringOffsetDWOSection() = 0;
virtual StringRef getRangeDWOSection() = 0;
virtual StringRef getAddrSection() = 0;
virtual StringRef getAppleNamesSection() = 0;
virtual StringRef getAppleTypesSection() = 0;
virtual StringRef getAppleNamespacesSection() = 0;
virtual StringRef getAppleObjCSection() = 0;
static bool isSupportedVersion(unsigned version) {
return version == 2 || version == 3 || version == 4;
@ -236,6 +240,10 @@ class DWARFContextInMemory : public DWARFContext {
StringRef StringOffsetDWOSection;
StringRef RangeDWOSection;
StringRef AddrSection;
StringRef AppleNamesSection;
StringRef AppleTypesSection;
StringRef AppleNamespacesSection;
StringRef AppleObjCSection;
SmallVector<SmallString<32>, 4> UncompressedSections;
@ -256,6 +264,10 @@ public:
StringRef getPubTypesSection() override { return PubTypesSection; }
StringRef getGnuPubNamesSection() override { return GnuPubNamesSection; }
StringRef getGnuPubTypesSection() override { return GnuPubTypesSection; }
StringRef getAppleNamesSection() override { return AppleNamesSection; }
StringRef getAppleTypesSection() override { return AppleTypesSection; }
StringRef getAppleNamespacesSection() override { return AppleNamespacesSection; }
StringRef getAppleObjCSection() override { return AppleObjCSection; }
// Sections for DWARF5 split dwarf proposal.
const DWARFSection &getInfoDWOSection() override { return InfoDWOSection; }

View File

@ -95,6 +95,8 @@
; CHECK: .debug_pubtypes contents:
; CHECK-NOT: Offset
; CHECK: .apple{{.*}} contents:
; Function Attrs: nounwind uwtable
define void @_Z2f1v() #0 {
entry:

View File

@ -0,0 +1,154 @@
RUN: llvm-dwarfdump %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s
CHECK: .apple_names contents:
CHECK: Magic = 0x48415348
CHECK: Version = 0x0001
CHECK: Hash function = 0x00000000
CHECK: Bucket count = 11
CHECK: Hashes count = 22
CHECK: HeaderData length = 12
CHECK: DIE offset base = 0
CHECK: Number of atoms = 1
CHECK: Atom[0] Type: DW_ATOM_die_offset Form: DW_FORM_data4
CHECK: Bucket[0]
CHECK: Hash = 0x248050fe Offset = 0x000000fc
CHECK: Name: 00000165 "-[TestInterface Retain]"
CHECK: Data[0] => {Atom[0]: 0x0000024f}
CHECK: Bucket[1]
CHECK: Hash = 0x926d42cc Offset = 0x0000010c
CHECK: Name: 00000057 "ReadWrite"
CHECK: Data[0] => {Atom[0]: 0x000001cb}
CHECK: Bucket[2]
CHECK: EMPTY
CHECK: Bucket[3]
CHECK: Hash = 0x99254268 Offset = 0x0000011c
CHECK: Name: 0000013f "-[TestInterface setReadWrite:]"
CHECK: Data[0] => {Atom[0]: 0x00000209}
CHECK: Hash = 0x946f52b9 Offset = 0x0000012c
CHECK: Name: 000000c6 "-[TestInterface ReadOnly]"
CHECK: Data[0] => {Atom[0]: 0x00000109}
CHECK: Bucket[4]
CHECK: EMPTY
CHECK: Bucket[5]
CHECK: EMPTY
CHECK: Bucket[6]
CHECK: Hash = 0x6e8e91a3 Offset = 0x0000013c
CHECK: Name: 000001e0 "-[TestInterface NonAtomic]"
CHECK: Data[0] => {Atom[0]: 0x00000357}
CHECK: Hash = 0x7d1a5012 Offset = 0x0000014c
CHECK: Name: 0000014d "setReadWrite:"
CHECK: Data[0] => {Atom[0]: 0x00000209}
CHECK: Hash = 0xb65f49d3 Offset = 0x0000015c
CHECK: Name: 0000020d "setNonAtomic:"
CHECK: Data[0] => {Atom[0]: 0x00000395}
CHECK: Hash = 0x354997e2 Offset = 0x0000016c
CHECK: Name: 00000120 "-[TestInterface ReadWrite]"
CHECK: Data[0] => {Atom[0]: 0x000001cb}
CHECK: Bucket[7]
CHECK: Hash = 0xce8af9c8 Offset = 0x0000017c
CHECK: Name: 0000005e "Retain"
CHECK: Data[0] => {Atom[0]: 0x0000024f}
CHECK: Hash = 0xa7e0338a Offset = 0x0000018c
CHECK: Name: 0000004d "Assign"
CHECK: Data[0] => {Atom[0]: 0x00000147}
CHECK: Hash = 0xa9812410 Offset = 0x0000019c
CHECK: Name: 00000105 "setAssign:"
CHECK: Data[0] => {Atom[0]: 0x00000185}
CHECK: Hash = 0x218d07f6 Offset = 0x000001ac
CHECK: Name: 000001a2 "-[TestInterface Copy]"
CHECK: Data[0] => {Atom[0]: 0x000002d3}
CHECK: Hash = 0x0456817c Offset = 0x000001bc
CHECK: Name: 000001bc "-[TestInterface setCopy:]"
CHECK: Data[0] => {Atom[0]: 0x00000311}
CHECK: Hash = 0x7c83b400 Offset = 0x000001cc
CHECK: Name: 0000006c "Copy"
CHECK: Data[0] => {Atom[0]: 0x000002d3}
CHECK: Bucket[8]
CHECK: Hash = 0x0f918046 Offset = 0x000001dc
CHECK: Name: 000001c5 "setCopy:"
CHECK: Data[0] => {Atom[0]: 0x00000311}
CHECK: Hash = 0xfb097449 Offset = 0x000001ec
CHECK: Name: 000001ff "-[TestInterface setNonAtomic:]"
CHECK: Data[0] => {Atom[0]: 0x00000395}
CHECK: Hash = 0x71069de3 Offset = 0x000001fc
CHECK: Name: 00000042 "ReadOnly"
CHECK: Data[0] => {Atom[0]: 0x00000109}
CHECK: Bucket[9]
CHECK: Hash = 0xd55908c6 Offset = 0x0000020c
CHECK: Name: 000000fa "-[TestInterface setAssign:]"
CHECK: Data[0] => {Atom[0]: 0x00000185}
CHECK: Hash = 0xa584b20e Offset = 0x0000021c
CHECK: Name: 0000018c "setRetain:"
CHECK: Data[0] => {Atom[0]: 0x0000028d}
CHECK: Hash = 0x9429886d Offset = 0x0000022c
CHECK: Name: 00000076 "NonAtomic"
CHECK: Data[0] => {Atom[0]: 0x00000357}
CHECK: Hash = 0x287cc300 Offset = 0x0000023c
CHECK: Name: 000000de "-[TestInterface Assign]"
CHECK: Data[0] => {Atom[0]: 0x00000147}
CHECK: Hash = 0x51ce5684 Offset = 0x0000024c
CHECK: Name: 00000181 "-[TestInterface setRetain:]"
CHECK: Data[0] => {Atom[0]: 0x0000028d}
CHECK: Bucket[10]
CHECK: EMPTY
CHECK: .apple_types contents:
CHECK: Magic = 0x48415348
CHECK: Version = 0x0001
CHECK: Hash function = 0x00000000
CHECK: Bucket count = 4
CHECK: Hashes count = 4
CHECK: HeaderData length = 20
CHECK: DIE offset base = 0
CHECK: Number of atoms = 3
CHECK: Atom[0] Type: DW_ATOM_die_offset Form: DW_FORM_data4
CHECK: Atom[1] Type: DW_ATOM_die_tag Form: DW_FORM_data2
CHECK: Atom[2] Type: DW_ATOM_type_flags Form: DW_FORM_data1
CHECK: Bucket[0]
CHECK: Hash = 0x0b888030 Offset = 0x00000058
CHECK: Name: 00000046 "int"
CHECK: Data[0] => {Atom[0]: 0x000000f4} {Atom[1]: 0x0024} {Atom[2]: 0x00}
CHECK: Bucket[1]
CHECK: Hash = 0x0b881d29 Offset = 0x0000006b
CHECK: Name: 0000021b "SEL"
CHECK: Data[0] => {Atom[0]: 0x000003e0} {Atom[1]: 0x0016} {Atom[2]: 0x00}
CHECK: Hash = 0x2c549f3d Offset = 0x0000007e
CHECK: Name: 00000067 "NSObject"
CHECK: Data[0] => {Atom[0]: 0x00000100} {Atom[1]: 0x0013} {Atom[2]: 0x00}
CHECK: Bucket[2]
CHECK: Hash = 0x16a83cb6 Offset = 0x00000091
CHECK: Name: 00000039 "TestInterface"
CHECK: Data[0] => {Atom[0]: 0x0000002f} {Atom[1]: 0x0013} {Atom[2]: 0x00}
CHECK: Bucket[3]
CHECK: EMPTY
CHECK: .apple_namespaces contents:
CHECK-NOT: Magic
CHECK: .apple_objc contents:
CHECK: Magic = 0x48415348
CHECK: Version = 0x0001
CHECK: Hash function = 0x00000000
CHECK: Bucket count = 1
CHECK: Hashes count = 1
CHECK: HeaderData length = 12
CHECK: DIE offset base = 0
CHECK: Number of atoms = 1
CHECK: Atom[0] Type: DW_ATOM_die_offset Form: DW_FORM_data4
CHECK: Bucket[0]
CHECK: Hash = 0x16a83cb6 Offset = 0x0000002c
CHECK: Name: 00000039 "TestInterface"
CHECK: Data[0] => {Atom[0]: 0x00000109}
CHECK: Data[1] => {Atom[0]: 0x00000147}
CHECK: Data[2] => {Atom[0]: 0x00000185}
CHECK: Data[3] => {Atom[0]: 0x000001cb}
CHECK: Data[4] => {Atom[0]: 0x00000209}
CHECK: Data[5] => {Atom[0]: 0x0000024f}
CHECK: Data[6] => {Atom[0]: 0x0000028d}
CHECK: Data[7] => {Atom[0]: 0x000002d3}
CHECK: Data[8] => {Atom[0]: 0x00000311}
CHECK: Data[9] => {Atom[0]: 0x00000357}
CHECK: Data[10] => {Atom[0]: 0x00000395}

View File

@ -45,6 +45,10 @@ DumpType("debug-dump", cl::init(DIDT_All),
clEnumValN(DIDT_All, "all", "Dump all debug sections"),
clEnumValN(DIDT_Abbrev, "abbrev", ".debug_abbrev"),
clEnumValN(DIDT_AbbrevDwo, "abbrev.dwo", ".debug_abbrev.dwo"),
clEnumValN(DIDT_AppleNames, "apple_names", ".apple_names"),
clEnumValN(DIDT_AppleTypes, "apple_types", ".apple_types"),
clEnumValN(DIDT_AppleNamespaces, "apple_namespaces", ".apple_namespaces"),
clEnumValN(DIDT_AppleObjC, "apple_objc", ".apple_objc"),
clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"),
clEnumValN(DIDT_Info, "info", ".debug_info"),
clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"),