diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 3ef541aa303..3aa098d7c30 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -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 diff --git a/lib/DebugInfo/CMakeLists.txt b/lib/DebugInfo/CMakeLists.txt index 61a3fb066d1..81fc84d4a80 100644 --- a/lib/DebugInfo/CMakeLists.txt +++ b/lib/DebugInfo/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMDebugInfo DIContext.cpp DWARFAbbreviationDeclaration.cpp + DWARFAcceleratorTable.cpp DWARFCompileUnit.cpp DWARFContext.cpp DWARFDebugAbbrev.cpp diff --git a/lib/DebugInfo/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARFAcceleratorTable.cpp new file mode 100644 index 00000000000..c984769598f --- /dev/null +++ b/lib/DebugInfo/DWARFAcceleratorTable.cpp @@ -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'; + } + } + } + } +} +} diff --git a/lib/DebugInfo/DWARFAcceleratorTable.h b/lib/DebugInfo/DWARFAcceleratorTable.h new file mode 100644 index 00000000000..bb25917b47d --- /dev/null +++ b/lib/DebugInfo/DWARFAcceleratorTable.h @@ -0,0 +1,38 @@ + +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/DWARFFormValue.h" + +#include + +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, 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); +}; + +} diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index aa86f6aac03..845718d195d 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -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) { diff --git a/lib/DebugInfo/DWARFContext.h b/lib/DebugInfo/DWARFContext.h index c4586b0d4c1..926f7c39bd3 100644 --- a/lib/DebugInfo/DWARFContext.h +++ b/lib/DebugInfo/DWARFContext.h @@ -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, 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; } diff --git a/test/DebugInfo/Inputs/gmlt.ll b/test/DebugInfo/Inputs/gmlt.ll index 8de03decd76..ba8d11342ae 100644 --- a/test/DebugInfo/Inputs/gmlt.ll +++ b/test/DebugInfo/Inputs/gmlt.ll @@ -95,6 +95,8 @@ ; CHECK: .debug_pubtypes contents: ; CHECK-NOT: Offset +; CHECK: .apple{{.*}} contents: + ; Function Attrs: nounwind uwtable define void @_Z2f1v() #0 { entry: diff --git a/test/DebugInfo/dwarfdump-accel.test b/test/DebugInfo/dwarfdump-accel.test new file mode 100644 index 00000000000..e0205f6348f --- /dev/null +++ b/test/DebugInfo/dwarfdump-accel.test @@ -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} \ No newline at end of file diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index b4aeb6b8d4a..1c540c98842 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -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"),