[llvm] r323638 - [DebugInfo] Basic .debug_names dumping support

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 29 03:08:32 PST 2018


Author: labath
Date: Mon Jan 29 03:08:32 2018
New Revision: 323638

URL: http://llvm.org/viewvc/llvm-project?rev=323638&view=rev
Log:
[DebugInfo] Basic .debug_names dumping support

Summary:
This commit renames DWARFAcceleratorTable to AppleAcceleratorTable to free up
the first name as an interface for the different accelerator tables.
Then I add a DWARFDebugNames class for the dwarf5 table.

Presently, the only common functionality of the two classes is the dump()
method, because this is the only method that was necessary to implement
dwarfdump -debug-names; and because the rest of the
AppleAcceleratorTable interface does not directly transfer to the dwarf5
tables (the main reason for that is that the present interface assumes
the tables are homogeneous, but the dwarf5 tables can have different
keys associated with each entry).

I expect to make the common interface richer as I add more functionality
to the new class (and invent a way to represent it in generic way).

In terms of sharing the implementation, I found the format of the two
tables sufficiently different to frustrate any attempts to have common
parsing or dumping code, so presently the implementations share just low
level code for formatting dwarf constants.

Reviewers: vleschuk, JDevlieghere, clayborg, aprantl, probinson, echristo, dblaikie

Subscribers: llvm-commits

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

Added:
    llvm/trunk/test/DebugInfo/X86/dwarfdump-debug-names.s
Modified:
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h
    llvm/trunk/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
    llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h?rev=323638&r1=323637&r2=323638&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h Mon Jan 29 03:08:32 2018
@@ -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

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h?rev=323638&r1=323637&r2=323638&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h Mon Jan 29 03:08:32 2018
@@ -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.

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h?rev=323638&r1=323637&r2=323638&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h Mon Jan 29 03:08:32 2018
@@ -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 ""; }

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp?rev=323638&r1=323637&r2=323638&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp Mon Jan 29 03:08:32 2018
@@ -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 AppleAcceleratorTa
   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(Strin
   }
   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);
+}

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp?rev=323638&r1=323637&r2=323638&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Mon Jan 29 03:08:32 2018
@@ -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::get
   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 DW
   DWARFSectionMap AppleTypesSection;
   DWARFSectionMap AppleNamespacesSection;
   DWARFSectionMap AppleObjCSection;
+  DWARFSectionMap DebugNamesSection;
 
   DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
     return StringSwitch<DWARFSectionMap *>(Name)
@@ -1178,6 +1187,7 @@ class DWARFObjInMemory final : public DW
         .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; }

Added: llvm/trunk/test/DebugInfo/X86/dwarfdump-debug-names.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/dwarfdump-debug-names.s?rev=323638&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/dwarfdump-debug-names.s (added)
+++ llvm/trunk/test/DebugInfo/X86/dwarfdump-debug-names.s Mon Jan 29 03:08:32 2018
@@ -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", at 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,"", at progbits
+.Lcu_begin0:
+	.byte	0
+.Ldie0:
+	.byte	0
+.Lcu_begin1:
+	.byte	0
+.Ldie1:
+	.byte	0
+
+	.section	.debug_names,"", at 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: }

Modified: llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp?rev=323638&r1=323637&r2=323638&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp (original)
+++ llvm/trunk/tools/llvm-dwarfdump/llvm-dwarfdump.cpp Mon Jan 29 03:08:32 2018
@@ -377,6 +377,7 @@ static bool dumpObjectFile(ObjectFile &O
           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;
     }();




More information about the llvm-commits mailing list