summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h235
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h4
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h1
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp433
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFContext.cpp23
-rw-r--r--llvm/test/DebugInfo/X86/dwarfdump-debug-names.s176
-rw-r--r--llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp1
7 files changed, 847 insertions, 26 deletions
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
index 391c72018ae..2eff1194726 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
@@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
#define LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
@@ -20,11 +21,35 @@
namespace llvm {
class raw_ostream;
+class ScopedPrinter;
+
+/// The accelerator tables are designed to allow efficient random access
+/// (using a symbol name as a key) into debug info by providing an index of the
+/// debug info DIEs. This class implements the common functionality of Apple and
+/// DWARF 5 accelerator tables.
+/// TODO: Generalize the rest of the AppleAcceleratorTable interface and move it
+/// to this class.
+class DWARFAcceleratorTable {
+protected:
+ DWARFDataExtractor AccelSection;
+ DataExtractor StringSection;
+
+public:
+ DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
+ DataExtractor StringSection)
+ : AccelSection(AccelSection), StringSection(StringSection) {}
+ virtual ~DWARFAcceleratorTable();
+
+ virtual llvm::Error extract() = 0;
+ virtual void dump(raw_ostream &OS) const = 0;
+
+ DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete;
+ void operator=(const DWARFAcceleratorTable &) = delete;
+};
/// 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 AppleAcceleratorTable {
+class AppleAcceleratorTable : public DWARFAcceleratorTable {
struct Header {
uint32_t Magic;
uint16_t Version;
@@ -44,8 +69,6 @@ class AppleAcceleratorTable {
struct Header Hdr;
struct HeaderData HdrData;
- DWARFDataExtractor AccelSection;
- DataExtractor StringSection;
bool IsValid = false;
public:
@@ -85,12 +108,11 @@ public:
}
};
-
AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
DataExtractor StringSection)
- : AccelSection(AccelSection), StringSection(StringSection) {}
+ : DWARFAcceleratorTable(AccelSection, StringSection) {}
- llvm::Error extract();
+ llvm::Error extract() override;
uint32_t getNumBuckets();
uint32_t getNumHashes();
uint32_t getSizeHdr();
@@ -107,12 +129,209 @@ public:
/// related to the input hash data offset.
/// DieTag is the tag of the DIE
std::pair<uint32_t, dwarf::Tag> readAtoms(uint32_t &HashDataOffset);
- void dump(raw_ostream &OS) const;
+ void dump(raw_ostream &OS) const override;
/// Look up all entries in the accelerator table matching \c Key.
iterator_range<ValueIterator> equal_range(StringRef Key) const;
};
+/// .debug_names section consists of one or more units. Each unit starts with a
+/// header, which is followed by a list of compilation units, local and foreign
+/// type units.
+///
+/// These may be followed by an (optional) hash lookup table, which consists of
+/// an array of buckets and hashes similar to the apple tables above. The only
+/// difference is that the hashes array is 1-based, and consequently an empty
+/// bucket is denoted by 0 and not UINT32_MAX.
+///
+/// Next is the name table, which consists of an array of names and array of
+/// entry offsets. This is different from the apple tables, which store names
+/// next to the actual entries.
+///
+/// The structure of the entries is described by an abbreviations table, which
+/// comes after the name table. Unlike the apple tables, which have a uniform
+/// entry structure described in the header, each .debug_names entry may have
+/// different index attributes (DW_IDX_???) attached to it.
+///
+/// The last segment consists of a list of entries, which is a 0-terminated list
+/// referenced by the name table and interpreted with the help of the
+/// abbreviation table.
+class DWARFDebugNames : public DWARFAcceleratorTable {
+public:
+ /// Dwarf 5 Name Index header.
+ struct Header {
+ uint32_t UnitLength;
+ uint16_t Version;
+ uint16_t Padding;
+ uint32_t CompUnitCount;
+ uint32_t LocalTypeUnitCount;
+ uint32_t ForeignTypeUnitCount;
+ uint32_t BucketCount;
+ uint32_t NameCount;
+ uint32_t AbbrevTableSize;
+ uint32_t AugmentationStringSize;
+ SmallString<8> AugmentationString;
+
+ Error extract(const DWARFDataExtractor &AS, uint32_t *Offset);
+ void dump(ScopedPrinter &W) const;
+ };
+
+ /// Index attribute and its encoding.
+ struct AttributeEncoding {
+ dwarf::Index Index;
+ dwarf::Form Form;
+
+ constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form)
+ : Index(Index), Form(Form) {}
+
+ friend bool operator==(const AttributeEncoding &LHS,
+ const AttributeEncoding &RHS) {
+ return LHS.Index == RHS.Index && LHS.Form == RHS.Form;
+ }
+ };
+
+ /// Abbreviation describing the encoding of Name Index entries.
+ struct Abbrev {
+ uint32_t Code; ///< Abbreviation code
+ dwarf::Tag Tag; ///< Dwarf Tag of the described entity.
+ std::vector<AttributeEncoding> Attributes; ///< List of index attributes.
+
+ Abbrev(uint32_t Code, dwarf::Tag Tag,
+ std::vector<AttributeEncoding> Attributes)
+ : Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {}
+
+ void dump(ScopedPrinter &W) const;
+ };
+
+ /// A single entry in the Name Index.
+ struct Entry {
+ const Abbrev &Abbr;
+
+ /// Values of the index attributes described by Abbr.
+ std::vector<DWARFFormValue> Values;
+
+ Entry(const Abbrev &Abbr);
+
+ void dump(ScopedPrinter &W) const;
+ };
+
+private:
+ /// Error returned by NameIndex::getEntry to report it has reached the end of
+ /// the entry list.
+ class SentinelError : public ErrorInfo<SentinelError> {
+ public:
+ static char ID;
+
+ void log(raw_ostream &OS) const override { OS << "Sentinel"; }
+ std::error_code convertToErrorCode() const override;
+ };
+
+ /// DenseMapInfo for struct Abbrev.
+ struct AbbrevMapInfo {
+ static Abbrev getEmptyKey();
+ static Abbrev getTombstoneKey();
+ static unsigned getHashValue(uint32_t Code) {
+ return DenseMapInfo<uint32_t>::getHashValue(Code);
+ }
+ static unsigned getHashValue(const Abbrev &Abbr) {
+ return getHashValue(Abbr.Code);
+ }
+ static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
+ return LHS == RHS.Code;
+ }
+ static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
+ return LHS.Code == RHS.Code;
+ }
+ };
+
+ /// A single entry in the Name Table (Dwarf 5 sect. 6.1.1.4.6) of the Name
+ /// Index.
+ struct NameTableEntry {
+ uint32_t StringOffset; ///< Offset of the name of the described entities.
+ uint32_t EntryOffset; ///< Offset of the first Entry in the list.
+ };
+
+public:
+ /// Represents a single accelerator table within the Dwarf 5 .debug_names
+ /// section.
+ class NameIndex {
+ DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
+ struct Header Hdr;
+ const DWARFDebugNames &Section;
+
+ // Base of the whole unit and of various important tables, as offsets from
+ // the start of the section.
+ uint32_t Base;
+ uint32_t CUsBase;
+ uint32_t BucketsBase;
+ uint32_t HashesBase;
+ uint32_t StringOffsetsBase;
+ uint32_t EntryOffsetsBase;
+ uint32_t EntriesBase;
+
+ /// Reads offset of compilation unit CU. CU is 0-based.
+ uint32_t getCUOffset(uint32_t CU) const;
+
+ /// Reads offset of local type unit TU, TU is 0-based.
+ uint32_t getLocalTUOffset(uint32_t TU) const;
+
+ /// Reads signature of foreign type unit TU. TU is 0-based.
+ uint64_t getForeignTUOffset(uint32_t TU) const;
+
+ /// Reads an entry in the Bucket Array for the given Bucket. The returned
+ /// value is a (1-based) index into the Names, StringOffsets and
+ /// EntryOffsets arrays. The input Bucket index is 0-based.
+ uint32_t getBucketArrayEntry(uint32_t Bucket) const;
+
+ /// Reads an entry in the Hash Array for the given Index. The input Index
+ /// is 1-based.
+ uint32_t getHashArrayEntry(uint32_t Index) const;
+
+ /// Reads an entry in the Name Table for the given Index. The Name Table
+ /// consists of two arrays -- String Offsets and Entry Offsets. The returned
+ /// offsets are relative to the starts of respective sections. Input Index
+ /// is 1-based.
+ NameTableEntry getNameTableEntry(uint32_t Index) const;
+
+ Expected<Entry> getEntry(uint32_t *Offset) const;
+
+ void dumpCUs(ScopedPrinter &W) const;
+ void dumpLocalTUs(ScopedPrinter &W) const;
+ void dumpForeignTUs(ScopedPrinter &W) const;
+ void dumpAbbreviations(ScopedPrinter &W) const;
+ bool dumpEntry(ScopedPrinter &W, uint32_t *Offset) const;
+ void dumpName(ScopedPrinter &W, uint32_t Index,
+ Optional<uint32_t> Hash) const;
+ void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
+
+ Expected<AttributeEncoding> extractAttributeEncoding(uint32_t *Offset);
+
+ Expected<std::vector<AttributeEncoding>>
+ extractAttributeEncodings(uint32_t *Offset);
+
+ Expected<Abbrev> extractAbbrev(uint32_t *Offset);
+
+ public:
+ NameIndex(const DWARFDebugNames &Section, uint32_t Base)
+ : Section(Section), Base(Base) {}
+
+ llvm::Error extract();
+ uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; }
+ void dump(ScopedPrinter &W) const;
+ };
+
+private:
+ std::vector<NameIndex> NameIndices;
+
+public:
+ DWARFDebugNames(const DWARFDataExtractor &AccelSection,
+ DataExtractor StringSection)
+ : DWARFAcceleratorTable(AccelSection, StringSection) {}
+
+ llvm::Error extract() override;
+ void dump(raw_ostream &OS) const override;
+};
+
} // end namespace llvm
#endif // LLVM_DEBUGINFO_DWARFACCELERATORTABLE_H
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
index 476c0f1bdfe..7a8bc0a7e71 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -69,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<DWARFDebugNames> Names;
std::unique_ptr<AppleAcceleratorTable> AppleNames;
std::unique_ptr<AppleAcceleratorTable> AppleTypes;
std::unique_ptr<AppleAcceleratorTable> AppleNamespaces;
@@ -243,6 +244,9 @@ public:
const DWARFDebugMacro *getDebugMacro();
/// Get a reference to the parsed accelerator table object.
+ const DWARFDebugNames &getDebugNames();
+
+ /// Get a reference to the parsed accelerator table object.
const AppleAcceleratorTable &getAppleNames();
/// Get a reference to the parsed accelerator table object.
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h
index 8091119ef03..7575cf9a9c5 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h
@@ -68,6 +68,7 @@ public:
virtual const DWARFSection &getAppleNamespacesSection() const {
return Dummy;
}
+ virtual const DWARFSection &getDebugNamesSection() const { return Dummy; }
virtual const DWARFSection &getAppleObjCSection() const { return Dummy; }
virtual StringRef getCUIndexSection() const { return ""; }
virtual StringRef getGdbIndexSection() const { return ""; }
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 8bb14876f15..86879ea0fd2 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -15,6 +15,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <cstdint>
@@ -22,6 +23,39 @@
using namespace llvm;
+namespace {
+struct DwarfConstant {
+ StringRef (*StringFn)(unsigned);
+ StringRef Type;
+ unsigned Value;
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const DwarfConstant &C) {
+ StringRef Str = C.StringFn(C.Value);
+ if (!Str.empty())
+ return OS << Str;
+ return OS << "DW_" << C.Type << "_Unknown_0x" << format("%x", C.Value);
+}
+} // namespace
+
+static DwarfConstant formatTag(unsigned Tag) {
+ return {dwarf::TagString, "TAG", Tag};
+}
+
+static DwarfConstant formatForm(unsigned Form) {
+ return {dwarf::FormEncodingString, "FORM", Form};
+}
+
+static DwarfConstant formatIndex(unsigned Idx) {
+ return {dwarf::IndexString, "IDX", Idx};
+}
+
+static DwarfConstant formatAtom(unsigned Atom) {
+ return {dwarf::AtomTypeString, "ATOM", Atom};
+}
+
+DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
+
llvm::Error AppleAcceleratorTable::extract() {
uint32_t Offset = 0;
@@ -132,19 +166,8 @@ LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
unsigned i = 0;
SmallVector<DWARFFormValue, 3> AtomForms;
for (const auto &Atom: HdrData.Atoms) {
- OS << format("Atom[%d] Type: ", i++);
- auto TypeString = dwarf::AtomTypeString(Atom.first);
- if (!TypeString.empty())
- OS << TypeString;
- else
- OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
- OS << " Form: ";
- auto FormString = dwarf::FormEncodingString(Atom.second);
- if (!FormString.empty())
- OS << FormString;
- else
- OS << format("DW_FORM_Unknown_0x%x", Atom.second);
- OS << '\n';
+ OS << format("Atom[%d] Type: ", i++) << formatAtom(Atom.first)
+ << " Form: " << formatForm(Atom.second) << '\n';
AtomForms.push_back(DWARFFormValue(Atom.second));
}
@@ -267,3 +290,387 @@ AppleAcceleratorTable::equal_range(StringRef Key) const {
}
return make_range(ValueIterator(), ValueIterator());
}
+
+void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
+ DictScope HeaderScope(W, "Header");
+ W.printHex("Length", UnitLength);
+ W.printNumber("Version", Version);
+ W.printHex("Padding", Padding);
+ W.printNumber("CU count", CompUnitCount);
+ W.printNumber("Local TU count", LocalTypeUnitCount);
+ W.printNumber("Foreign TU count", ForeignTypeUnitCount);
+ W.printNumber("Bucket count", BucketCount);
+ W.printNumber("Name count", NameCount);
+ W.printHex("Abbreviations table size", AbbrevTableSize);
+ W.startLine() << "Augmentation: '" << AugmentationString << "'\n";
+}
+
+llvm::Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
+ uint32_t *Offset) {
+ // Check that we can read the fixed-size part.
+ if (!AS.isValidOffset(*Offset + sizeof(Header) - 1))
+ return make_error<StringError>("Section too small: cannot read header.",
+ inconvertibleErrorCode());
+
+ UnitLength = AS.getU32(Offset);
+ Version = AS.getU16(Offset);
+ Padding = AS.getU16(Offset);
+ CompUnitCount = AS.getU32(Offset);
+ LocalTypeUnitCount = AS.getU32(Offset);
+ ForeignTypeUnitCount = AS.getU32(Offset);
+ BucketCount = AS.getU32(Offset);
+ NameCount = AS.getU32(Offset);
+ AbbrevTableSize = AS.getU32(Offset);
+ AugmentationStringSize = AS.getU32(Offset);
+
+ if (!AS.isValidOffsetForDataOfSize(*Offset, AugmentationStringSize))
+ return make_error<StringError>(
+ "Section too small: cannot read header augmentation.",
+ inconvertibleErrorCode());
+ AugmentationString.resize(AugmentationStringSize);
+ AS.getU8(Offset, reinterpret_cast<uint8_t *>(AugmentationString.data()),
+ AugmentationStringSize);
+ *Offset = alignTo(*Offset, 4);
+ return Error::success();
+}
+
+void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {
+ DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());
+ W.startLine() << "Tag: " << formatTag(Tag) << '\n';
+
+ for (const auto &Attr : Attributes) {
+ W.startLine() << formatIndex(Attr.Index) << ": " << formatForm(Attr.Form)
+ << '\n';
+ }
+}
+
+static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
+ return {dwarf::Index(0), dwarf::Form(0)};
+}
+
+static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
+ return AE == sentinelAttrEnc();
+}
+
+static DWARFDebugNames::Abbrev sentinelAbbrev() {
+ return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
+}
+
+static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
+ return Abbr.Code == 0;
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
+ return sentinelAbbrev();
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
+ return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
+}
+
+Expected<DWARFDebugNames::AttributeEncoding>
+DWARFDebugNames::NameIndex::extractAttributeEncoding(uint32_t *Offset) {
+ if (*Offset >= EntriesBase) {
+ return make_error<StringError>("Incorrectly terminated abbreviation table.",
+ inconvertibleErrorCode());
+ }
+
+ uint32_t Index = Section.AccelSection.getULEB128(Offset);
+ uint32_t Form = Section.AccelSection.getULEB128(Offset);
+ return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));
+}
+
+Expected<std::vector<DWARFDebugNames::AttributeEncoding>>
+DWARFDebugNames::NameIndex::extractAttributeEncodings(uint32_t *Offset) {
+ std::vector<AttributeEncoding> Result;
+ for (;;) {
+ auto AttrEncOr = extractAttributeEncoding(Offset);
+ if (!AttrEncOr)
+ return AttrEncOr.takeError();
+ if (isSentinel(*AttrEncOr))
+ return std::move(Result);
+
+ Result.emplace_back(*AttrEncOr);
+ }
+}
+
+Expected<DWARFDebugNames::Abbrev>
+DWARFDebugNames::NameIndex::extractAbbrev(uint32_t *Offset) {
+ if (*Offset >= EntriesBase) {
+ return make_error<StringError>("Incorrectly terminated abbreviation table.",
+ inconvertibleErrorCode());
+ }
+
+ uint32_t Code = Section.AccelSection.getULEB128(Offset);
+ if (Code == 0)
+ return sentinelAbbrev();
+
+ uint32_t Tag = Section.AccelSection.getULEB128(Offset);
+ auto AttrEncOr = extractAttributeEncodings(Offset);
+ if (!AttrEncOr)
+ return AttrEncOr.takeError();
+ return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr));
+}
+
+Error DWARFDebugNames::NameIndex::extract() {
+ const DWARFDataExtractor &AS = Section.AccelSection;
+ uint32_t Offset = Base;
+ if (Error E = Hdr.extract(AS, &Offset))
+ return E;
+
+ CUsBase = Offset;
+ Offset += Hdr.CompUnitCount * 4;
+ Offset += Hdr.LocalTypeUnitCount * 4;
+ Offset += Hdr.ForeignTypeUnitCount * 8;
+ BucketsBase = Offset;
+ Offset += Hdr.BucketCount * 4;
+ HashesBase = Offset;
+ if (Hdr.BucketCount > 0)
+ Offset += Hdr.NameCount * 4;
+ StringOffsetsBase = Offset;
+ Offset += Hdr.NameCount * 4;
+ EntryOffsetsBase = Offset;
+ Offset += Hdr.NameCount * 4;
+
+ if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))
+ return make_error<StringError>(
+ "Section too small: cannot read abbreviations.",
+ inconvertibleErrorCode());
+
+ EntriesBase = Offset + Hdr.AbbrevTableSize;
+
+ for (;;) {
+ auto AbbrevOr = extractAbbrev(&Offset);
+ if (!AbbrevOr)
+ return AbbrevOr.takeError();
+ if (isSentinel(*AbbrevOr))
+ return Error::success();
+
+ if (!Abbrevs.insert(std::move(*AbbrevOr)).second) {
+ return make_error<StringError>("Duplicate abbreviation code.",
+ inconvertibleErrorCode());
+ }
+ }
+}
+
+DWARFDebugNames::Entry::Entry(const Abbrev &Abbr) : Abbr(Abbr) {
+ // This merely creates form values. It is up to the caller
+ // (NameIndex::getEntry) to populate them.
+ Values.reserve(Abbr.Attributes.size());
+ for (const auto &Attr : Abbr.Attributes)
+ Values.emplace_back(Attr.Form);
+}
+
+void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
+ W.printHex("Abbrev", Abbr.Code);
+ W.startLine() << "Tag: " << formatTag(Abbr.Tag) << "\n";
+
+ assert(Abbr.Attributes.size() == Values.size());
+ for (uint32_t I = 0, E = Values.size(); I < E; ++I) {
+ W.startLine() << formatIndex(Abbr.Attributes[I].Index) << ": ";
+ Values[I].dump(W.getOStream());
+ W.getOStream() << '\n';
+ }
+}
+
+char DWARFDebugNames::SentinelError::ID;
+std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
+ return inconvertibleErrorCode();
+}
+
+uint32_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {
+ assert(CU < Hdr.CompUnitCount);
+ uint32_t Offset = CUsBase + 4 * CU;
+ return Section.AccelSection.getRelocatedValue(4, &Offset);
+}
+
+uint32_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
+ assert(TU < Hdr.LocalTypeUnitCount);
+ uint32_t Offset = CUsBase + Hdr.CompUnitCount * 4;
+ return Section.AccelSection.getRelocatedValue(4, &Offset);
+}
+
+uint64_t DWARFDebugNames::NameIndex::getForeignTUOffset(uint32_t TU) const {
+ assert(TU < Hdr.ForeignTypeUnitCount);
+ uint32_t Offset = CUsBase + (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) * 4;
+ return Section.AccelSection.getU64(&Offset);
+}
+
+Expected<DWARFDebugNames::Entry>
+DWARFDebugNames::NameIndex::getEntry(uint32_t *Offset) const {
+ const DWARFDataExtractor &AS = Section.AccelSection;
+ if (!AS.isValidOffset(*Offset))
+ return make_error<StringError>("Incorrectly terminated entry list",
+ inconvertibleErrorCode());
+
+ uint32_t AbbrevCode = AS.getULEB128(Offset);
+ if (AbbrevCode == 0)
+ return make_error<SentinelError>();
+
+ const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);
+ if (AbbrevIt == Abbrevs.end())
+ return make_error<StringError>("Invalid abbreviation",
+ inconvertibleErrorCode());
+
+ Entry E(*AbbrevIt);
+
+ DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+ for (auto &Value : E.Values) {
+ if (!Value.extractValue(AS, Offset, FormParams))
+ return make_error<StringError>("Error extracting index attribute values",
+ inconvertibleErrorCode());
+ }
+ return std::move(E);
+}
+
+DWARFDebugNames::NameTableEntry
+DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {
+ assert(0 < Index && Index <= Hdr.NameCount);
+ uint32_t StringOffsetOffset = StringOffsetsBase + 4 * (Index - 1);
+ uint32_t EntryOffsetOffset = EntryOffsetsBase + 4 * (Index - 1);
+ const DWARFDataExtractor &AS = Section.AccelSection;
+
+ uint32_t StringOffset = AS.getRelocatedValue(4, &StringOffsetOffset);
+ uint32_t EntryOffset = AS.getU32(&EntryOffsetOffset);
+ EntryOffset += EntriesBase;
+ return {StringOffset, EntryOffset};
+}
+
+uint32_t
+DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {
+ assert(Bucket < Hdr.BucketCount);
+ uint32_t BucketOffset = BucketsBase + 4 * Bucket;
+ return Section.AccelSection.getU32(&BucketOffset);
+}
+
+uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {
+ assert(0 < Index && Index <= Hdr.NameCount);
+ uint32_t HashOffset = HashesBase + 4 * (Index - 1);
+ return Section.AccelSection.getU32(&HashOffset);
+}
+
+// Returns true if we should continue scanning for entries, false if this is the
+// last (sentinel) entry). In case of a parsing error we also return false, as
+// it's not possible to recover this entry list (but the other lists may still
+// parse OK).
+bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
+ uint32_t *Offset) const {
+ uint32_t EntryId = *Offset;
+ auto EntryOr = getEntry(Offset);
+ if (!EntryOr) {
+ handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
+ [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
+ return false;
+ }
+
+ DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());
+ EntryOr->dump(W);
+ return true;
+}
+
+void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W, uint32_t Index,
+ Optional<uint32_t> Hash) const {
+ const DataExtractor &SS = Section.StringSection;
+ NameTableEntry NTE = getNameTableEntry(Index);
+
+ DictScope NameScope(W, ("Name " + Twine(Index)).str());
+ if (Hash)
+ W.printHex("Hash", *Hash);
+
+ W.startLine() << format("String: 0x%08x", NTE.StringOffset);
+ W.getOStream() << " \"" << SS.getCStr(&NTE.StringOffset) << "\"\n";
+
+ while (dumpEntry(W, &NTE.EntryOffset))
+ /*empty*/;
+}
+
+void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {
+ ListScope CUScope(W, "Compilation Unit offsets");
+ for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)
+ W.startLine() << format("CU[%u]: 0x%08x\n", CU, getCUOffset(CU));
+}
+
+void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {
+ if (Hdr.LocalTypeUnitCount == 0)
+ return;
+
+ ListScope TUScope(W, "Local Type Unit offsets");
+ for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)
+ W.startLine() << format("LocalTU[%u]: 0x%08x\n", TU, getLocalTUOffset(TU));
+}
+
+void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
+ if (Hdr.ForeignTypeUnitCount == 0)
+ return;
+
+ ListScope TUScope(W, "Foreign Type Unit signatures");
+ for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
+ W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
+ getForeignTUOffset(TU));
+ }
+}
+
+void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {
+ ListScope AbbrevsScope(W, "Abbreviations");
+ for (const auto &Abbr : Abbrevs)
+ Abbr.dump(W);
+}
+
+void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,
+ uint32_t Bucket) const {
+ ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+ uint32_t Index = getBucketArrayEntry(Bucket);
+ if (Index == 0) {
+ W.printString("EMPTY");
+ return;
+ }
+ if (Index > Hdr.NameCount) {
+ W.printString("Name index is invalid");
+ return;
+ }
+
+ for (; Index <= Hdr.NameCount; ++Index) {
+ uint32_t Hash = getHashArrayEntry(Index);
+ if (Hash % Hdr.BucketCount != Bucket)
+ break;
+
+ dumpName(W, Index, Hash);
+ }
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {
+ DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());
+ Hdr.dump(W);
+ dumpCUs(W);
+ dumpLocalTUs(W);
+ dumpForeignTUs(W);
+ dumpAbbreviations(W);
+
+ if (Hdr.BucketCount > 0) {
+ for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)
+ dumpBucket(W, Bucket);
+ return;
+ }
+
+ W.startLine() << "Hash table not present\n";
+ for (uint32_t Index = 1; Index <= Hdr.NameCount; ++Index)
+ dumpName(W, Index, None);
+}
+
+llvm::Error DWARFDebugNames::extract() {
+ uint32_t Offset = 0;
+ while (AccelSection.isValidOffset(Offset)) {
+ NameIndex Next(*this, Offset);
+ if (llvm::Error E = Next.extract())
+ return E;
+ Offset = Next.getNextUnitOffset();
+ NameIndices.push_back(std::move(Next));
+ }
+ return Error::success();
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
+ ScopedPrinter W(OS);
+ for (const NameIndex &NI : NameIndices)
+ NI.dump(W);
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index aa55294ff4c..decf7a284b3 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -545,6 +545,9 @@ void DWARFContext::dump(
if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
DObj->getAppleObjCSection().Data))
getAppleObjC().dump(OS);
+ if (shouldDump(Explicit, ".debug_names", DIDT_ID_DebugNames,
+ DObj->getDebugNamesSection().Data))
+ getDebugNames().dump(OS);
}
DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
@@ -713,20 +716,25 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() {
return Macro.get();
}
-static AppleAcceleratorTable &
-getAccelTable(std::unique_ptr<AppleAcceleratorTable> &Cache,
- const DWARFObject &Obj, const DWARFSection &Section,
- StringRef StringSection, bool IsLittleEndian) {
+template <typename T>
+static T &getAccelTable(std::unique_ptr<T> &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 AppleAcceleratorTable(AccelSection, StrData));
+ Cache.reset(new T(AccelSection, StrData));
if (Error E = Cache->extract())
llvm::consumeError(std::move(E));
return *Cache;
}
+const DWARFDebugNames &DWARFContext::getDebugNames() {
+ return getAccelTable(Names, *DObj, DObj->getDebugNamesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
const AppleAcceleratorTable &DWARFContext::getAppleNames() {
return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
DObj->getStringSection(), isLittleEndian());
@@ -1167,6 +1175,7 @@ class DWARFObjInMemory final : public DWARFObject {
DWARFSectionMap AppleTypesSection;
DWARFSectionMap AppleNamespacesSection;
DWARFSectionMap AppleObjCSection;
+ DWARFSectionMap DebugNamesSection;
DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
return StringSwitch<DWARFSectionMap *>(Name)
@@ -1178,6 +1187,7 @@ class DWARFObjInMemory final : public DWARFObject {
.Case("debug_info.dwo", &InfoDWOSection)
.Case("debug_loc.dwo", &LocDWOSection)
.Case("debug_line.dwo", &LineDWOSection)
+ .Case("debug_names", &DebugNamesSection)
.Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
.Case("debug_addr", &AddrSection)
.Case("apple_names", &AppleNamesSection)
@@ -1486,6 +1496,9 @@ public:
const DWARFSection &getAppleObjCSection() const override {
return AppleObjCSection;
}
+ const DWARFSection &getDebugNamesSection() const override {
+ return DebugNamesSection;
+ }
StringRef getFileName() const override { return FileName; }
uint8_t getAddressSize() const override { return AddressSize; }
diff --git a/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s b/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s
new file mode 100644
index 00000000000..0291591f4ab
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/dwarfdump-debug-names.s
@@ -0,0 +1,176 @@
+# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj -o - | llvm-dwarfdump -debug-names - | FileCheck %s
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "foo"
+.Linfo_string1:
+ .asciz "_Z3foov"
+.Linfo_string2:
+ .asciz "bar"
+
+# Fake .debug_info. We just need it for the offsets to two "compile units" and
+# two "DIEs"
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .byte 0
+.Ldie0:
+ .byte 0
+.Lcu_begin1:
+ .byte 0
+.Ldie1:
+ .byte 0
+
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: contribution length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 2 # Header: bucket count
+ .long 2 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 0 # Header: augmentation length
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 0 # Bucket 0
+ .long 1 # Bucket 1
+ .long 193491849 # Hash in Bucket 1
+ .long -1257882357 # Hash in Bucket 1
+ .long .Linfo_string0 # String in Bucket 1: foo
+ .long .Linfo_string1 # String in Bucket 1: _Z3foov
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1
+.Lnames_abbrev_start0:
+ .byte 46 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 6 # DW_FORM_data4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+ .byte 46 # Abbrev code
+ .long .Ldie0 # DW_IDX_die_offset
+ .long 0 # End of list: foo
+.Lnames1:
+ .byte 46 # Abbrev code
+ .long .Ldie0 # DW_IDX_die_offset
+ .long 0 # End of list: _Z3foov
+ .p2align 2
+.Lnames_end0:
+
+ .long .Lnames_end1-.Lnames_start1 # Header: contribution length
+.Lnames_start1:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 1 # Header: bucket count
+ .long 1 # Header: name count
+ .long .Lnames_abbrev_end1-.Lnames_abbrev_start1 # Header: abbreviation table size
+ .long 0 # Header: augmentation length
+ .long .Lcu_begin1 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 193487034 # Hash in Bucket 0
+ .long .Linfo_string2 # String in Bucket 0: bar
+ .long .Lnames2-.Lnames_entries1 # Offset in Bucket 0
+.Lnames_abbrev_start1:
+ .byte 52 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 3 # DW_IDX_die_offset
+ .byte 6 # DW_FORM_data4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end1:
+.Lnames_entries1:
+.Lnames2:
+ .byte 52 # Abbrev code
+ .long .Ldie1 # DW_IDX_die_offset
+ .long 0 # End of list: bar
+ .p2align 2
+.Lnames_end1:
+# CHECK: .debug_names contents:
+# CHECK-NEXT: Name Index @ 0x0 {
+# CHECK-NEXT: Header {
+# CHECK-NEXT: Length: 0x60
+# CHECK-NEXT: Version: 5
+# CHECK-NEXT: Padding: 0x0
+# CHECK-NEXT: CU count: 1
+# CHECK-NEXT: Local TU count: 0
+# CHECK-NEXT: Foreign TU count: 0
+# CHECK-NEXT: Bucket count: 2
+# CHECK-NEXT: Name count: 2
+# CHECK-NEXT: Abbreviations table size: 0x7
+# CHECK-NEXT: Augmentation: ''
+# CHECK-NEXT: }
+# CHECK-NEXT: Compilation Unit offsets [
+# CHECK-NEXT: CU[0]: 0x00000000
+# CHECK-NEXT: ]
+# CHECK-NEXT: Abbreviations [
+# CHECK-NEXT: Abbreviation 0x2e {
+# CHECK-NEXT: Tag: DW_TAG_subprogram
+# CHECK-NEXT: DW_IDX_die_offset: DW_FORM_data4
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Bucket 0 [
+# CHECK-NEXT: EMPTY
+# CHECK-NEXT: ]
+# CHECK-NEXT: Bucket 1 [
+# CHECK-NEXT: Name 1 {
+# CHECK-NEXT: Hash: 0xB887389
+# CHECK-NEXT: String: 0x00000000 "foo"
+# CHECK-NEXT: Entry @ 0x4f {
+# CHECK-NEXT: Abbrev: 0x2E
+# CHECK-NEXT: Tag: DW_TAG_subprogram
+# CHECK-NEXT: DW_IDX_die_offset: 0x00000001
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: Name 2 {
+# CHECK-NEXT: Hash: 0xB5063D0B
+# CHECK-NEXT: String: 0x00000004 "_Z3foov"
+# CHECK-NEXT: Entry @ 0x58 {
+# CHECK-NEXT: Abbrev: 0x2E
+# CHECK-NEXT: Tag: DW_TAG_subprogram
+# CHECK-NEXT: DW_IDX_die_offset: 0x00000001
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: Name Index @ 0x64 {
+# CHECK-NEXT: Header {
+# CHECK-NEXT: Length: 0x44
+# CHECK-NEXT: Version: 5
+# CHECK-NEXT: Padding: 0x0
+# CHECK-NEXT: CU count: 1
+# CHECK-NEXT: Local TU count: 0
+# CHECK-NEXT: Foreign TU count: 0
+# CHECK-NEXT: Bucket count: 1
+# CHECK-NEXT: Name count: 1
+# CHECK-NEXT: Abbreviations table size: 0x7
+# CHECK-NEXT: Augmentation: ''
+# CHECK-NEXT: }
+# CHECK-NEXT: Compilation Unit offsets [
+# CHECK-NEXT: CU[0]: 0x00000002
+# CHECK-NEXT: ]
+# CHECK-NEXT: Abbreviations [
+# CHECK-NEXT: Abbreviation 0x34 {
+# CHECK-NEXT: Tag: DW_TAG_variable
+# CHECK-NEXT: DW_IDX_die_offset: DW_FORM_data4
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: Bucket 0 [
+# CHECK-NEXT: Name 1 {
+# CHECK-NEXT: Hash: 0xB8860BA
+# CHECK-NEXT: String: 0x0000000c "bar"
+# CHECK-NEXT: Entry @ 0xa3 {
+# CHECK-NEXT: Abbrev: 0x34
+# CHECK-NEXT: Tag: DW_TAG_variable
+# CHECK-NEXT: DW_IDX_die_offset: 0x00000003
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 1142fe3319c..21493774dc9 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -377,6 +377,7 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
if (auto Offset = find(DICtx.getAppleNamespaces()))
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
+ // TODO: Add .debug_names support
}
return None;
}();
OpenPOWER on IntegriCloud