[llvm] r332759 - [DWARF v5] Improved support for .debug_rnglists (consumer). Enables any consumer to

Wolfgang Pieb via llvm-commits llvm-commits at lists.llvm.org
Fri May 18 13:12:55 PDT 2018


Author: wolfgangp
Date: Fri May 18 13:12:54 2018
New Revision: 332759

URL: http://llvm.org/viewvc/llvm-project?rev=332759&view=rev
Log:
[DWARF v5] Improved support for .debug_rnglists (consumer). Enables any consumer to 
extract DWARF v5 encoded rangelists.

Reviewer: JDevlieghere

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

Added:
    llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s
Modified:
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h
    llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp
    llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h Fri May 18 13:12:54 2018
@@ -10,6 +10,7 @@
 #ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
 #define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
 
+#include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
@@ -30,6 +31,8 @@ public:
     uint32_t Offset;
     /// The DWARF encoding (DW_RLE_*).
     uint8_t EntryKind;
+    /// The index of the section this range belongs to.
+    uint64_t SectionIndex;
     /// The values making up the range list entry. Most represent a range with
     /// a start and end address or a start address and a length. Others are
     /// single value base addresses or end-of-list with no values. The unneeded
@@ -51,6 +54,9 @@ public:
   void clear() { Entries.clear(); }
   Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End,
                 uint32_t *OffsetPtr);
+  /// Build a DWARFAddressRangesVector from a rangelist.
+  DWARFAddressRangesVector
+  getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const;
 };
 
 /// A class representing a table of range lists as specified in DWARF v5.
@@ -77,6 +83,7 @@ public:
   };
 
 private:
+  dwarf::DwarfFormat Format;
   uint32_t HeaderOffset;
   Header HeaderData;
   std::vector<uint32_t> Offsets;
@@ -88,8 +95,31 @@ public:
   Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr);
   /// Extract an entire table, including all rangelists.
   Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
+  /// Look up a rangelist based on a given offset. Extract it and enter it into
+  /// the ranges map if necessary.
+  Optional<DWARFDebugRnglist> findRangeList(DWARFDataExtractor Data,
+                                            uint32_t Offset);
   uint32_t getHeaderOffset() const { return HeaderOffset; }
+  uint8_t getAddrSize() const { return HeaderData.AddrSize; }
   void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const;
+  /// Return the contents of the offset entry designated by a given index.
+  Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
+    if (Index < Offsets.size())
+      return Offsets[Index];
+    return None;
+  }
+  /// Return the size of the table header including the length but not including
+  /// the offsets. This is dependent on the table format, which is unambiguously
+  /// derived from parsing the table.
+  uint8_t getHeaderSize() const {
+    switch (Format) {
+    case dwarf::DwarfFormat::DWARF32:
+      return 12;
+    case dwarf::DwarfFormat::DWARF64:
+      return 20;
+    }
+    llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
+  }
 
   /// Returns the length of this table, including the length field, or 0 if the
   /// length has not been determined (e.g. because the table has not yet been

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=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFObject.h Fri May 18 13:12:54 2018
@@ -63,6 +63,7 @@ public:
     return Dummy;
   }
   virtual const DWARFSection &getRangeDWOSection() const { return Dummy; }
+  virtual const DWARFSection &getRnglistsDWOSection() const { return Dummy; }
   virtual const DWARFSection &getAddrSection() const { return Dummy; }
   virtual const DWARFSection &getAppleNamesSection() const { return Dummy; }
   virtual const DWARFSection &getAppleTypesSection() const { return Dummy; }

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h Fri May 18 13:12:54 2018
@@ -18,6 +18,7 @@
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
@@ -261,6 +262,9 @@ class DWARFUnit {
   /// offsets table (DWARF v5).
   Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution;
 
+  /// A table of range lists (DWARF v5 and later).
+  Optional<DWARFDebugRnglistTable> RngListTable;
+
   mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
   llvm::Optional<BaseAddress> BaseAddr;
   /// The compile unit debug information entry items.
@@ -430,6 +434,24 @@ public:
   const char *getCompilationDir();
   Optional<uint64_t> getDWOId();
 
+  /// Return a vector of address ranges resulting from a (possibly encoded)
+  /// range list starting at a given offset in the appropriate ranges section.
+  DWARFAddressRangesVector findRnglistFromOffset(uint32_t Offset);
+
+  /// Return a vector of address ranges retrieved from an encoded range
+  /// list whose offset is found via a table lookup given an index (DWARF v5
+  /// and later).
+  DWARFAddressRangesVector findRnglistFromIndex(uint32_t Index);
+
+  /// Return a rangelist's offset based on an index. The index designates
+  /// an entry in the rangelist table's offset array and is supplied by
+  /// DW_FORM_rnglistx.
+  Optional<uint32_t> getRnglistOffset(uint32_t Index) {
+    if (RngListTable)
+      return RngListTable->getOffsetEntry(Index);
+    return None;
+  }
+
   void collectAddressRanges(DWARFAddressRangesVector &CURanges);
 
   /// Returns subprogram DIE with address range encompassing the provided

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Fri May 18 13:12:54 2018
@@ -248,6 +248,28 @@ static void dumpStringOffsetsSection(
   }
 }
 
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
+static void dumpRnglistsSection(raw_ostream &OS,
+                                DWARFDataExtractor &rnglistData,
+                                DIDumpOptions DumpOpts) {
+  uint32_t Offset = 0;
+  while (rnglistData.isValidOffset(Offset)) {
+    llvm::DWARFDebugRnglistTable Rnglists;
+    uint32_t TableOffset = Offset;
+    if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
+      WithColor::error() << toString(std::move(Err)) << '\n';
+      uint64_t Length = Rnglists.length();
+      // Keep going after an error, if we can, assuming that the length field
+      // could be read. If it couldn't, stop reading the section.
+      if (Length == 0)
+        break;
+      Offset = TableOffset + Length;
+    } else {
+      Rnglists.dump(OS, DumpOpts);
+    }
+  }
+}
+
 void DWARFContext::dump(
     raw_ostream &OS, DIDumpOptions DumpOpts,
     std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
@@ -455,24 +477,16 @@ void DWARFContext::dump(
 
   if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
                  DObj->getRnglistsSection().Data)) {
-    DWARFDataExtractor rnglistData(*DObj, DObj->getRnglistsSection(),
+    DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
                                    isLittleEndian(), 0);
-    uint32_t Offset = 0;
-    while (rnglistData.isValidOffset(Offset)) {
-      DWARFDebugRnglistTable Rnglists;
-      uint32_t TableOffset = Offset;
-      if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
-        WithColor::error() << toString(std::move(Err)) << '\n';
-        uint64_t Length = Rnglists.length();
-        // Keep going after an error, if we can, assuming that the length field
-        // could be read. If it couldn't, stop reading the section.
-        if (Length == 0)
-          break;
-        Offset = TableOffset + Length;
-      } else {
-        Rnglists.dump(OS, DumpOpts);
-      }
-    }
+    dumpRnglistsSection(OS, RnglistData, DumpOpts);
+  }
+
+  if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
+                 DObj->getRnglistsDWOSection().Data)) {
+    DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
+                                   isLittleEndian(), 0);
+    dumpRnglistsSection(OS, RnglistData, DumpOpts);
   }
 
   if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
@@ -1173,6 +1187,7 @@ class DWARFObjInMemory final : public DW
   DWARFSectionMap LocDWOSection;
   DWARFSectionMap StringOffsetDWOSection;
   DWARFSectionMap RangeDWOSection;
+  DWARFSectionMap RnglistsDWOSection;
   DWARFSectionMap AddrSection;
   DWARFSectionMap AppleNamesSection;
   DWARFSectionMap AppleTypesSection;
@@ -1192,6 +1207,7 @@ class DWARFObjInMemory final : public DW
         .Case("debug_loc.dwo", &LocDWOSection)
         .Case("debug_line.dwo", &LineDWOSection)
         .Case("debug_names", &DebugNamesSection)
+        .Case("debug_rnglists.dwo", &RnglistsDWOSection)
         .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
         .Case("debug_addr", &AddrSection)
         .Case("apple_names", &AppleNamesSection)
@@ -1450,6 +1466,9 @@ public:
   const DWARFSection &getRangeDWOSection() const override {
     return RangeDWOSection;
   }
+  const DWARFSection &getRnglistsDWOSection() const override {
+    return RnglistsDWOSection;
+  }
   const DWARFSection &getAddrSection() const override { return AddrSection; }
   StringRef getCUIndexSection() const override { return CUIndexSection; }
   StringRef getGdbIndexSection() const override { return GdbIndexSection; }

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp Fri May 18 13:12:54 2018
@@ -8,8 +8,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
-
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/raw_ostream.h"
@@ -44,6 +44,7 @@ Error DWARFDebugRnglistTable::extractHea
     return createError(
         "DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32,
         HeaderOffset);
+  Format = dwarf::DwarfFormat::DWARF32;
   if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
     return createError(".debug_rnglists table at offset 0x%" PRIx32
                        " has too small length (0x%" PRIx32
@@ -90,6 +91,7 @@ Error DWARFDebugRnglist::RangeListEntry:
                                                  uint32_t End,
                                                  uint32_t *OffsetPtr) {
   Offset = *OffsetPtr;
+  SectionIndex = -1ULL;
   // The caller should guarantee that we have at least 1 byte available, so
   // we just assert instead of revalidate.
   assert(*OffsetPtr < End &&
@@ -128,7 +130,7 @@ Error DWARFDebugRnglist::RangeListEntry:
       return createError("insufficient space remaining in table for "
                          "DW_RLE_base_address encoding at offset 0x%" PRIx32,
                          *OffsetPtr - 1);
-    Value0 = Data.getAddress(OffsetPtr);
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
     break;
   }
   case dwarf::DW_RLE_start_end: {
@@ -137,13 +139,13 @@ Error DWARFDebugRnglist::RangeListEntry:
                          "DW_RLE_start_end encoding "
                          "at offset 0x%" PRIx32,
                          *OffsetPtr - 1);
-    Value0 = Data.getAddress(OffsetPtr);
-    Value1 = Data.getAddress(OffsetPtr);
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+    Value1 = Data.getRelocatedAddress(OffsetPtr);
     break;
   }
   case dwarf::DW_RLE_start_length: {
     uint32_t PreviousOffset = *OffsetPtr - 1;
-    Value0 = Data.getAddress(OffsetPtr);
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
     Value1 = Data.getULEB128(OffsetPtr);
     if (End < *OffsetPtr)
       return createError("read past end of table when reading "
@@ -161,6 +163,49 @@ Error DWARFDebugRnglist::RangeListEntry:
   return Error::success();
 }
 
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+    llvm::Optional<BaseAddress> BaseAddr) const {
+  DWARFAddressRangesVector Res;
+  for (const RangeListEntry &RLE : Entries) {
+    if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
+      break;
+    if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
+      BaseAddr = {RLE.Value0, RLE.SectionIndex};
+      continue;
+    }
+
+    DWARFAddressRange E;
+    E.SectionIndex = RLE.SectionIndex;
+    if (BaseAddr && E.SectionIndex == -1ULL)
+      E.SectionIndex = BaseAddr->SectionIndex;
+
+    switch (RLE.EntryKind) {
+    case dwarf::DW_RLE_offset_pair:
+      E.LowPC = RLE.Value0;
+      E.HighPC = RLE.Value1;
+      if (BaseAddr) {
+        E.LowPC += BaseAddr->Address;
+        E.HighPC += BaseAddr->Address;
+      }
+      break;
+    case dwarf::DW_RLE_start_end:
+      E.LowPC = RLE.Value0;
+      E.HighPC = RLE.Value1;
+      break;
+    case dwarf::DW_RLE_start_length:
+      E.LowPC = RLE.Value0;
+      E.HighPC = E.LowPC + RLE.Value1;
+      break;
+    default:
+      // Unsupported encodings should have been reported during extraction,
+      // so we should not run into any here.
+      llvm_unreachable("Unsupported range list encoding");
+    }
+    Res.push_back(E);
+  }
+  return Res;
+}
+
 Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
                                  uint32_t End, uint32_t *OffsetPtr) {
   Entries.clear();
@@ -305,3 +350,22 @@ uint32_t DWARFDebugRnglistTable::length(
   // TODO: DWARF64 support.
   return HeaderData.Length + sizeof(uint32_t);
 }
+
+Optional<DWARFDebugRnglist>
+DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data,
+                                      uint32_t Offset) {
+  auto Entry = Ranges.find(Offset);
+  if (Entry != Ranges.end())
+    return Entry->second;
+
+  // Extract the rangelist from the section and enter it into the ranges map.
+  DWARFDebugRnglist RngList;
+  uint32_t End = HeaderOffset + length();
+  uint32_t StartingOffset = Offset;
+  if (Error E = RngList.extract(Data, HeaderOffset, End, &Offset)) {
+    llvm::consumeError(std::move(E));
+    return None;
+  }
+  Ranges[StartingOffset] = RngList;
+  return RngList;
+}

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp Fri May 18 13:12:54 2018
@@ -257,6 +257,16 @@ static void dumpAttribute(raw_ostream &O
       dumpApplePropertyAttribute(OS, *OptVal);
   } else if (Attr == DW_AT_ranges) {
     const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
+    // For DW_FORM_rnglistx we need to dump the offset separately, since
+    // we have only dumped the index so far.
+    Optional<DWARFFormValue> Value = Die.find(DW_AT_ranges);
+    if (Value && Value->getForm() == DW_FORM_rnglistx)
+      if (auto RangeListOffset =
+              U->getRnglistOffset(*Value->getAsSectionOffset())) {
+        DWARFFormValue FV(dwarf::DW_FORM_sec_offset);
+        FV.setUValue(*RangeListOffset);
+        FV.dump(OS, DumpOpts);
+      }
     dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
                sizeof(BaseIndent) + Indent + 4, DumpOpts);
   }
@@ -380,12 +390,11 @@ DWARFAddressRangesVector DWARFDie::getAd
   if (getLowAndHighPC(LowPC, HighPC, Index))
     return {{LowPC, HighPC, Index}};
 
-  // Multiple ranges from .debug_ranges section.
-  auto RangesOffset = toSectionOffset(find(DW_AT_ranges));
-  if (RangesOffset) {
-    DWARFDebugRangeList RangeList;
-    if (U->extractRangeList(*RangesOffset, RangeList))
-      return RangeList.getAbsoluteRanges(U->getBaseAddress());
+  Optional<DWARFFormValue> Value = find(DW_AT_ranges);
+  if (Value) {
+    if (Value->getForm() == DW_FORM_rnglistx)
+      return U->findRnglistFromIndex(*Value->getAsSectionOffset());
+    return U->findRnglistFromOffset(*Value->getAsSectionOffset());
   }
   return DWARFAddressRangesVector();
 }

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp Fri May 18 13:12:54 2018
@@ -280,6 +280,7 @@ bool DWARFFormValue::extractValue(const
       break;
     case DW_FORM_udata:
     case DW_FORM_ref_udata:
+    case DW_FORM_rnglistx:
       Value.uval = Data.getULEB128(OffsetPtr);
       break;
     case DW_FORM_string:
@@ -483,6 +484,10 @@ void DWARFFormValue::dump(raw_ostream &O
     OS << "DW_FORM_indirect";
     break;
 
+  case DW_FORM_rnglistx:
+    OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
+    break;
+
   // Should be formatted to 64-bit for DWARF64.
   case DW_FORM_sec_offset:
     AddrOS << format("0x%08x", (uint32_t)UValue);

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp?rev=332759&r1=332758&r2=332759&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp Fri May 18 13:12:54 2018
@@ -14,6 +14,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 #include "llvm/Support/DataExtractor.h"
@@ -150,6 +151,29 @@ bool DWARFUnitHeader::extract(DWARFConte
   return true;
 }
 
+// Parse the rangelist table header, including the optional array of offsets
+// following it (DWARF v5 and later).
+static Expected<DWARFDebugRnglistTable>
+parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
+  // TODO: Support DWARF64
+  // We are expected to be called with Offset 0 or pointing just past the table
+  // header, which is 12 bytes long for DWARF32.
+  if (Offset > 0) {
+    if (Offset < 12U) {
+      std::string Buffer;
+      raw_string_ostream Stream(Buffer);
+      Stream << format(
+          "Did not detect a valid range list table with base = 0x%x", Offset);
+      return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+    }
+    Offset -= 12U;
+  }
+  llvm::DWARFDebugRnglistTable Table;
+  if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
+    return E;
+  return Table;
+}
+
 bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
                                  DWARFDebugRangeList &RangeList) const {
   // Require that compile unit is extracted.
@@ -281,6 +305,32 @@ size_t DWARFUnit::extractDIEsIfNeeded(bo
       StringOffsetsTableContribution = determineStringOffsetsTableContribution(
           DA, StringOffsetsContributionBase);
 
+    // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
+    // describe address ranges.
+    if (getVersion() >= 5) {
+      if (isDWO)
+        setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+      else
+        setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
+                         toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0));
+      // Parse the range list table header. Individual range lists are
+      // extracted lazily.
+      DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+                                  isLittleEndian, 0);
+      if (auto TableOrError =
+              parseRngListTableHeader(RangesDA, RangeSectionBase))
+        RngListTable = TableOrError.get();
+      else
+        WithColor::error() << "parsing a range list table: "
+                           << toString(std::move(TableOrError.takeError()))
+                           << '\n';
+
+      // In a split dwarf unit, there is no DW_AT_rnglists_base attribute.
+      // Adjust RangeSectionBase to point past the table header.
+      if (isDWO && RngListTable)
+        RangeSectionBase = RngListTable->getHeaderSize();
+    }
+
     // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
     // skeleton CU DIE, so that DWARF users not aware of it are not broken.
   }
@@ -319,8 +369,23 @@ bool DWARFUnit::parseDWO() {
   DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
   // Share .debug_addr and .debug_ranges section with compile unit in .dwo
   DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
-  auto DWORangesBase = UnitDie.getRangesBaseAttribute();
-  DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+  if (getVersion() >= 5) {
+    DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+    DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+                                isLittleEndian, 0);
+    if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase))
+      DWO->RngListTable = TableOrError.get();
+    else
+      WithColor::error() << "parsing a range list table: "
+                         << toString(std::move(TableOrError.takeError()))
+                         << '\n';
+    if (DWO->RngListTable)
+      DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize();
+  } else {
+    auto DWORangesBase = UnitDie.getRangesBaseAttribute();
+    DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+  }
+
   return true;
 }
 
@@ -331,6 +396,28 @@ void DWARFUnit::clearDIEs(bool KeepCUDie
   }
 }
 
+DWARFAddressRangesVector DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
+  if (getVersion() <= 4) {
+    DWARFDebugRangeList RangeList;
+    if (extractRangeList(Offset, RangeList))
+      return RangeList.getAbsoluteRanges(getBaseAddress());
+    return DWARFAddressRangesVector();
+  }
+  if (RngListTable) {
+    DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+                                  isLittleEndian, RngListTable->getAddrSize());
+    if (auto RangeList = RngListTable->findRangeList(RangesData, Offset))
+      return RangeList->getAbsoluteRanges(getBaseAddress());
+  }
+  return DWARFAddressRangesVector();
+}
+
+DWARFAddressRangesVector DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+  if (auto Offset = getRnglistOffset(Index))
+    return findRnglistFromOffset(*Offset + RangeSectionBase);
+  return DWARFAddressRangesVector();
+}
+
 void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
   DWARFDie UnitDie = getUnitDIE();
   if (!UnitDie)

Added: llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s?rev=332759&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s (added)
+++ llvm/trunk/test/DebugInfo/X86/dwarfdump-rnglists.s Fri May 18 13:12:54 2018
@@ -0,0 +1,192 @@
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o
+# RUN: llvm-dwarfdump -v -debug-info %t.o 2> %t.err | FileCheck %s
+# RUN: FileCheck %s --input-file %t.err --check-prefix=ERR
+
+# Test object to verify dwarfdump handles v5 range lists.
+# We use very simplified compile unit dies.
+# There are 2 full CUs with DW_AT_rnglists_base, one with a DW_AT_ranges
+# attribute using DW_FORM_sec_offset, the other with DW_AT_ranges using
+# DW_FORM_rnglistx.
+
+        .section .debug_abbrev,"", at progbits
+        .byte 0x01  # Abbrev code
+        .byte 0x11  # DW_TAG_compile_unit
+        .byte 0x00  # DW_CHILDREN_no
+        .byte 0x74  # DW_AT_rnglists_base
+        .byte 0x17  # DW_FORM_sec_offset
+        .byte 0x55  # DW_AT_ranges
+        .byte 0x17  # DW_FORM_sec_offset
+        .byte 0x00  # EOM(1)
+        .byte 0x00  # EOM(2)
+        .byte 0x02  # Abbrev code
+        .byte 0x11  # DW_TAG_compile_unit
+        .byte 0x00  # DW_CHILDREN_no
+        .byte 0x74  # DW_AT_rnglists_base
+        .byte 0x17  # DW_FORM_sec_offset
+        .byte 0x55  # DW_AT_ranges
+        .byte 0x23  # DW_FORM_rnglistx
+        .byte 0x00  # EOM(1)
+        .byte 0x00  # EOM(2)
+        .byte 0x00  # EOM(3)
+
+# The split CU uses DW_FORM_rnglistx (the only correct option).
+# There is no DW_AT_rnglists_base in split units.
+        .section .debug_abbrev.dwo,"", at progbits
+        .byte 0x01  # Abbrev code
+        .byte 0x11  # DW_TAG_compile_unit
+        .byte 0x00  # DW_CHILDREN_no
+        .byte 0x55  # DW_AT_ranges
+        .byte 0x23  # DW_FORM_rnglistx
+        .byte 0x00  # EOM(1)
+        .byte 0x00  # EOM(2)
+        .byte 0x00  # EOM(3)
+        
+        .section .debug_info,"", at progbits
+# DWARF v5 CU header.
+        .long  CU1_5_end-CU1_5_version  # Length of Unit
+CU1_5_version:
+        .short 5               # DWARF version number
+        .byte 1                # DWARF Unit Type
+        .byte 4                # Address Size (in bytes)
+        .long .debug_abbrev    # Offset Into Abbrev. Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+        .byte 1                # Abbreviation code
+        .long Rnglist_Table0_base     # DW_AT_rnglists_base
+        .long Rnglist_Table0_Rnglist0 # DW_AT_ranges
+        .byte 0 # NULL
+        .byte 0 # NULL
+CU1_5_end:
+
+# DWARF v5 CU header
+        .long  CU2_5_end-CU2_5_version  # Length of Unit
+CU2_5_version:
+        .short 5               # DWARF version number
+        .byte 1                # DWARF Unit Type
+        .byte 4                # Address Size (in bytes)
+        .long .debug_abbrev    # Offset Into Abbrev. Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+        .byte 2                # Abbreviation code
+        .long Rnglist_Table0_base   # DW_AT_rnglists_base
+        .uleb128 1             # DW_AT_ranges
+        .byte 0                # NULL
+CU2_5_end:
+# A CU with an invalid DW_AT_rnglists_base attribute
+        .long  CU3_5_end-CU3_5_version  # Length of Unit
+CU3_5_version:
+        .short 5               # DWARF version number
+        .byte 1                # DWARF Unit Type
+        .byte 4                # Address Size (in bytes)
+        .long .debug_abbrev    # Offset Into Abbrev. Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+        .byte 2                # Abbreviation code
+        .long 0x8              # DW_AT_rnglists_base
+        .long 0                # DW_AT_ranges
+        .byte 0                # NULL
+CU3_5_end:
+
+        .section .debug_info.dwo,"", at progbits
+
+# DWARF v5 split CU header.
+        .long  CU_split_5_end-CU_split_5_version  # Length of Unit
+CU_split_5_version:
+        .short 5               # DWARF version number
+        .byte 5                # DWARF Unit Type
+        .byte 4                # Address Size (in bytes)
+        .long 0                # Offset Into Abbrev Section
+# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
+        .byte 1                # Abbreviation code
+        .uleb128 1             # DW_AT_ranges
+        .byte 0                # NULL
+CU_split_5_end:
+
+        .section .debug_rnglists,"", at progbits
+# A rnglist table with 2 range lists. The first one uses DW_RLE_start_end
+# and DW_RLE_start_length. The second one uses DW_RLE_base_address and
+# DW_RLE_offset_pair. The range lists have entries in the offset table.
+        .long Rnglist_Table0_end - Rnglist_Table0   # table length
+Rnglist_Table0:
+        .short 5                                    # version
+        .byte 4                                     # address size
+        .byte 0                                     # segment selector size
+        .long 2                                     # offset entry count
+Rnglist_Table0_base:
+# 2 offset entries which can be used by DW_FORM_rnglistx.
+        .long Rnglist_Table0_Rnglist0 - Rnglist_Table0_base
+        .long Rnglist_Table0_Rnglist1 - Rnglist_Table0_base
+Rnglist_Table0_Rnglist0:
+        .byte 6                                     # DW_RLE_start_end
+        .long Range0_start
+        .long Range0_end
+        .byte 7                                     # DW_RLE_start_length
+        .long Range1_start
+        .uleb128 Range1_end - Range1_start 
+        .byte 0                                     # DW_RLE_end_of_list
+Rnglist_Table0_Rnglist1:
+        .byte 5                                     # DW_RLE_base_address
+        .long Range0_start
+        .byte 4                                     # DW_RLE_offset_pair
+        .uleb128 Range1_start - Range0_start
+        .uleb128 Range1_end - Range0_start
+        .byte 0                                     # DW_RLE_end_of_list
+Rnglist_Table0_end:
+
+# A rnglist table for the split unit with an empty rangelist and one that
+# uses DW_RLE_base_address and DW_RLE_offset_pair. The ranges have entries
+# in the offset table. We use the empty range list so we can test 
+# DW_FORM_rnglistx with an index other than 0.
+        .section .debug_rnglists.dwo,"", at progbits
+        .long Rnglist_Table0_dwo_end - Rnglist_Table0_dwo   # table length
+Rnglist_Table0_dwo:
+        .short 5                                    # version
+        .byte 4                                     # address size
+        .byte 0                                     # segment selector size
+        .long 2                                     # offset entry count
+Rnglist_Table0_base_dwo:
+# 2 offset entries which can be used by DW_FORM_rnglistx.
+        .long Rnglist_Table0_Rnglist0_dwo - Rnglist_Table0_base_dwo
+        .long Rnglist_Table0_Rnglist1_dwo - Rnglist_Table0_base_dwo
+Rnglist_Table0_Rnglist0_dwo:
+        .byte 0                                     # DW_RLE_start_end
+Rnglist_Table0_Rnglist1_dwo:
+        .byte 5                                     # DW_RLE_base_address
+        .long Range0_start - .text
+        .byte 4                                     # DW_RLE_offset_pair
+        .uleb128 Range1_start - Range0_start
+        .uleb128 Range1_end - Range0_start
+        .byte 0                                     # DW_RLE_end_of_list
+Rnglist_Table0_dwo_end:
+
+.text
+        .space 20
+Range0_start:               # Range0: 0x14 - 0x1c
+        .space 10
+Range0_end:
+        .space 12
+Range1_start:               # Range1: 0x2a - 0x34
+        .space 10
+Range1_end:
+
+# CHECK:      .debug_info contents:
+# CHECK:      Compile Unit: 
+# CHECK-NOT:  Compile Unit:
+# CHECK:      DW_TAG_compile_unit
+# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x0000000c)
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000014
+# CHECK-NEXT: [0x00000014, 0x0000001e) ".text"
+# CHECK-NEXT: [0x0000002a, 0x00000034) ".text")
+
+# CHECK:      Compile Unit:
+# CHECK-NOT:  Compile Unit:
+# CHECK:      DW_TAG_compile_unit
+# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x0000000c)
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000018
+# CHECK-NEXT: [0x0000002a, 0x00000034) ".text")
+
+# CHECK:      .debug_info.dwo contents:
+# CHECK:      Compile Unit:
+# CHECK-NOT:  contents:
+# CHECK:      DW_TAG_compile_unit
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000009
+# CHECK-NEXT: [0x0000002a, 0x00000034))
+
+#ERR: error: parsing a range list table: Did not detect a valid range list table with base = 0x8




More information about the llvm-commits mailing list