Reapply "[dwarfdump] Add support for dumping accelerator tables."

This reverts commit r221842 which was a revert of r221836 and of the
test parts of r221837.

This new version fixes an UB bug pointed out by David (along with
addressing some other review comments), makes some dumping more
resilient to broken input data and forces the accelerator tables
to be dumped in the tests where we use them (this decision is
platform specific otherwise).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222003 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Frederic Riss 2014-11-14 16:15:53 +00:00
parent b3625eb445
commit e26d79386b
10 changed files with 285 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,116 @@
#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) {
uint16_t AtomType = AccelSection.getU16(&Offset);
DWARFFormValue AtomForm(AccelSection.getU16(&Offset));
HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
}
return true;
}
void DWARFAcceleratorTable::dump(raw_ostream &OS) {
// Dump the header.
OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
<< "Version = " << format("0x%04x", Hdr.Version) << '\n'
<< "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
<< "Bucket count = " << Hdr.NumBuckets << '\n'
<< "Hashes count = " << Hdr.NumHashes << '\n'
<< "HeaderData length = " << Hdr.HeaderDataLength << '\n'
<< "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
<< "Number of atoms = " << HdrData.Atoms.size() << '\n';
unsigned i = 0;
for (const auto &Atom: HdrData.Atoms) {
OS << format("Atom[%d] Type: ", i++);
if (const char *TypeString = dwarf::AtomTypeString(Atom.first))
OS << TypeString;
else
OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
OS << " Form: ";
if (const char *FormString = dwarf::FormEncodingString(Atom.second.getForm()))
OS << FormString;
else
OS << format("DW_FORM_Unknown_0x%x", 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 = 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

@ -1,6 +1,7 @@
; REQUIRES: object-emission
; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck -implicit-check-not=DW_TAG %s
; RUN: %llc_dwarf -dwarf-accel-tables=Enable -O0 -filetype=obj < %s | llvm-dwarfdump - | FileCheck --check-prefix=CHECK-ACCEL --check-prefix=CHECK %s
; Build from source:
; $ clang++ a.cpp b.cpp -g -c -emit-llvm
@ -52,6 +53,16 @@
; CHECK: DW_AT_location
; CHECK: DW_AT_abstract_origin {{.*}} {0x[[ABS_VAR]]} "x"
; Check that both the inline and the non out of line version of func are
; correctly referenced in the accelerator table. Before r221837, the one
; in the second compilation unit had a wrong offset
; CHECK-ACCEL: .apple_names contents:
; CHECK-ACCEL: Name{{.*}}"func"
; CHECK-ACCEL-NOT: Name
; CHECK-ACCEL: Atom[0]{{.*}}[[INLINED]]
; CHECK-ACCEL-NOT: Name
; CHECK-ACCEL: Atom[0]{{.*}}[[FUNC]]
@i = external global i32
; Function Attrs: uwtable

View File

@ -0,0 +1,63 @@
RUN: llvm-dwarfdump %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s
Gather some DIE indexes to verify the accelerator table contents.
CHECK: .debug_info contents
CHECK: [[TESTINTERFACE:0x[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
CHECK-NOT: DW_TAG
CHECK: DW_AT_name{{.*}}"TestInterface"
CHECK: [[READONLY:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
CHECK-NOT: DW_TAG
CHECK: DW_AT_name{{.*}}"-[TestInterface ReadOnly]"
CHECK: [[ASSIGN:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
CHECK-NOT: DW_TAG
CHECK: DW_AT_name{{.*}}"-[TestInterface Assign]"
CHECK: [[SETASSIGN:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
CHECK-NOT: DW_TAG
CHECK: DW_AT_name{{.*}}"-[TestInterface setAssign:]"
Check that the section header is printed correclty.
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 that empty buckets are handled correctly.
CHECK: Bucket[2]
CHECK: EMPTY
CHECK: Bucket[3]
Check that the accelerators point to the right DIEs.
CHECK: Name:{{.*}}"-[TestInterface ReadOnly]"
CHECK-NOT: Name
CHECK: {Atom[0]: [[READONLY]]}
CHECK: Name:{{.*}}"-[TestInterface setAssign:]"
CHECK-NOT: Name
CHECK: {Atom[0]: [[SETASSIGN]]}
CHECK: Name:{{.*}}"-[TestInterface Assign]"
CHECK-NOT: Name
CHECK: {Atom[0]: [[ASSIGN]]}
Check that types are referenced correctly.
CHECK: .apple_types contents:
CHECK: Name{{.*}}"TestInterface"
CHECK-NOT: Name
CHECK: {Atom[0]: [[TESTINTERFACE]]}
Check that an empty ecceleratorsection is handled correctly.
CHECK: .apple_namespaces contents:
CHECK-NOT: Magic
Check ObjC specific accelerators.
CHECK: .apple_objc contents:
CHECK: Name{{.*}}"TestInterface"
CHECK-NOT Name
CHECK: {Atom[0]: [[READONLY]]}
CHECK: {Atom[0]: [[ASSIGN]]}
CHECK: {Atom[0]: [[SETASSIGN]]}

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"),