[DWARF] Revert r345546: Refactor range list extraction and dumping

This patch caused some internal tests to break which are being investigated.

llvm-svn: 345687
diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
index 437c845..b4770e5 100644
--- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -15,6 +15,7 @@
   DWARFDebugLoc.cpp
   DWARFDebugMacro.cpp
   DWARFDebugPubTable.cpp
+  DWARFDebugRangeList.cpp
   DWARFDebugRnglists.cpp
   DWARFDie.cpp
   DWARFExpression.cpp
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 3a0f527..a29c9c2 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -25,6 +25,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.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"
@@ -267,31 +268,26 @@
   }
 }
 
-// Dump a section that contains a sequence of tables of lists, such as range
-// or location list tables. In DWARF v5 we expect to find properly formatted
-// tables with headers. In DWARF v4 and earlier we simply expect a sequence of
-// lists, which we treat, mutatis mutandis, like DWARF v5 tables.
-template <typename ListTable>
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
 static void
-dumpListSection(raw_ostream &OS, DWARFContext *C, StringRef SectionName,
-                uint16_t MaxVersion, DWARFDataExtractor &ListData,
-                llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
-                    LookupPooledAddress,
-                DIDumpOptions DumpOpts, bool isDWO = false) {
+dumpRnglistsSection(raw_ostream &OS, DWARFDataExtractor &rnglistData,
+                    llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
+                        LookupPooledAddress,
+                    DIDumpOptions DumpOpts) {
   uint32_t Offset = 0;
-  while (ListData.isValidOffset(Offset)) {
-    ListTable Table(C, SectionName, isDWO);
-    if (Error Err = Table.extract(ListData, MaxVersion, &Offset)) {
+  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';
-      // If table extraction set Offset to 0, it indicates that we cannot
-      // continue to read the section.
-      if (Offset == 0)
+      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;
-      // In DWARF v4 and earlier, dump as much of the lists as we can.
-      if (MaxVersion < 5)
-        Table.dump(OS, LookupPooledAddress, DumpOpts);
+      Offset = TableOffset + Length;
     } else {
-      Table.dump(OS, LookupPooledAddress, DumpOpts);
+      Rnglists.dump(OS, LookupPooledAddress, DumpOpts);
     }
   }
 }
@@ -512,6 +508,22 @@
     dumpAddrSection(OS, AddrData, DumpOpts, getMaxVersion(), getCUAddrSize());
   }
 
+  if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
+                 DObj->getRangeSection().Data)) {
+    uint8_t savedAddressByteSize = getCUAddrSize();
+    DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(),
+                                  isLittleEndian(), savedAddressByteSize);
+    uint32_t offset = 0;
+    DWARFDebugRangeList rangeList;
+    while (rangesData.isValidOffset(offset)) {
+      if (Error E = rangeList.extract(rangesData, &offset)) {
+        WithColor::error() << toString(std::move(E)) << '\n';
+        break;
+      }
+      rangeList.dump(OS);
+    }
+  }
+
   auto LookupPooledAddress = [&](uint32_t Index) -> Optional<SectionedAddress> {
     const auto &CUs = compile_units();
     auto I = CUs.begin();
@@ -520,32 +532,18 @@
     return (*I)->getAddrOffsetSectionItem(Index);
   };
 
-  if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
-                 DObj->getRangeSection().Data)) {
-    uint8_t savedAddressByteSize = getCUAddrSize();
-    DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(),
-                                  isLittleEndian(), savedAddressByteSize);
-    dumpListSection<DWARFDebugRnglistTable>(OS, this, ".debug_ranges",
-                                            /* MaxVersion = */ 4, rangesData,
-                                            LookupPooledAddress, DumpOpts);
-  }
-
   if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
                  DObj->getRnglistsSection().Data)) {
     DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
-                                   isLittleEndian(), getCUAddrSize());
-    dumpListSection<DWARFDebugRnglistTable>(OS, this, ".debug_rnglists",
-                                            getMaxVersion(5), RnglistData,
-                                            LookupPooledAddress, DumpOpts);
+                                   isLittleEndian(), 0);
+    dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
   }
 
   if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
                  DObj->getRnglistsDWOSection().Data)) {
     DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
-                                   isLittleEndian(), getCUAddrSize());
-    dumpListSection<DWARFDebugRnglistTable>(OS, this, ".debug_rnglists.dwo",
-                                            getMaxVersion(5), RnglistData,
-                                            LookupPooledAddress, DumpOpts);
+                                   isLittleEndian(), 0);
+    dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
   }
 
   if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
new file mode 100644
index 0000000..dfb9130
--- /dev/null
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
@@ -0,0 +1,96 @@
+//===- DWARFDebugRangesList.cpp -------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+void DWARFDebugRangeList::clear() {
+  Offset = -1U;
+  AddressSize = 0;
+  Entries.clear();
+}
+
+Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
+                                   uint32_t *offset_ptr) {
+  clear();
+  if (!data.isValidOffset(*offset_ptr))
+    return createStringError(errc::invalid_argument,
+                       "invalid range list offset 0x%" PRIx32, *offset_ptr);
+
+  AddressSize = data.getAddressSize();
+  if (AddressSize != 4 && AddressSize != 8)
+    return createStringError(errc::invalid_argument,
+                       "invalid address size: %" PRIu8, AddressSize);
+  Offset = *offset_ptr;
+  while (true) {
+    RangeListEntry Entry;
+    Entry.SectionIndex = -1ULL;
+
+    uint32_t prev_offset = *offset_ptr;
+    Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
+    Entry.EndAddress =
+        data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
+
+    // Check that both values were extracted correctly.
+    if (*offset_ptr != prev_offset + 2 * AddressSize) {
+      clear();
+      return createStringError(errc::invalid_argument,
+                         "invalid range list entry at offset 0x%" PRIx32,
+                         prev_offset);
+    }
+    if (Entry.isEndOfListEntry())
+      break;
+    Entries.push_back(Entry);
+  }
+  return Error::success();
+}
+
+void DWARFDebugRangeList::dump(raw_ostream &OS) const {
+  for (const RangeListEntry &RLE : Entries) {
+    const char *format_str = (AddressSize == 4
+                              ? "%08x %08"  PRIx64 " %08"  PRIx64 "\n"
+                              : "%08x %016" PRIx64 " %016" PRIx64 "\n");
+    OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
+  }
+  OS << format("%08x <End of list>\n", Offset);
+}
+
+DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
+    llvm::Optional<SectionedAddress> BaseAddr) const {
+  DWARFAddressRangesVector Res;
+  for (const RangeListEntry &RLE : Entries) {
+    if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
+      BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
+      continue;
+    }
+
+    DWARFAddressRange E;
+    E.LowPC = RLE.StartAddress;
+    E.HighPC = RLE.EndAddress;
+    E.SectionIndex = RLE.SectionIndex;
+    // Base address of a range list entry is determined by the closest preceding
+    // base address selection entry in the same range list. It defaults to the
+    // base address of the compilation unit if there is no such entry.
+    if (BaseAddr) {
+      E.LowPC += BaseAddr->Address;
+      E.HighPC += BaseAddr->Address;
+      if (E.SectionIndex == -1ULL)
+        E.SectionIndex = BaseAddr->SectionIndex;
+    }
+    Res.push_back(E);
+  }
+  return Res;
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
index 737603b..cb5fb0d 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -13,30 +13,19 @@
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Format.h"
-#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
 Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
-                              uint16_t Version, StringRef /* SectionName */,
-                              uint32_t *OffsetPtr, bool /* isDWO */) {
+                              uint32_t *OffsetPtr) {
   Offset = *OffsetPtr;
   SectionIndex = -1ULL;
-
-  assert((Data.getAddressSize() == 4 || Data.getAddressSize() == 8) &&
-         "Unsupported address size");
-
-  // We model a DWARF v4 range list entry like DWARF v5 DW_RLE_offset_pair,
-  // since it is subject to base adjustment.
-  uint8_t Encoding = dwarf::DW_RLE_offset_pair;
-  if (Version > 4) {
-    // The caller should guarantee that we have at least 1 byte available, so
-    // we just assert instead of revalidate.
-    assert(*OffsetPtr < End &&
-           "not enough space to extract a rangelist encoding");
-    Encoding = Data.getU8(OffsetPtr);
-  }
+  // The caller should guarantee that we have at least 1 byte available, so
+  // we just assert instead of revalidate.
+  assert(*OffsetPtr < End &&
+         "not enough space to extract a rangelist encoding");
+  uint8_t Encoding = Data.getU8(OffsetPtr);
 
   switch (Encoding) {
   case dwarf::DW_RLE_end_of_list:
@@ -72,23 +61,6 @@
     break;
   }
   case dwarf::DW_RLE_offset_pair: {
-    if (Version < 5) {
-      if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
-        return createStringError(
-            errc::illegal_byte_sequence,
-            "invalid range list entry at offset 0x%" PRIx32, *OffsetPtr);
-      Value0 = Data.getRelocatedAddress(OffsetPtr);
-      Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
-      // Adjust the EntryKind for end-of-list and base_address based on the
-      // contents.
-      if (Value0 == maxUIntN(Data.getAddressSize() * 8)) {
-        Encoding = dwarf::DW_RLE_base_address;
-        Value0 = Value1;
-        Value1 = 0;
-      } else if (Value0 == 0 && Value1 == 0)
-        Encoding = dwarf::DW_RLE_end_of_list;
-      break;
-    }
     uint32_t PreviousOffset = *OffsetPtr - 1;
     Value0 = Data.getULEB128(OffsetPtr);
     Value1 = Data.getULEB128(OffsetPtr);
@@ -99,7 +71,7 @@
                          PreviousOffset);
     break;
   }
-  case dwarf::DW_RLE_base_address:
+  case dwarf::DW_RLE_base_address: {
     if ((End - *OffsetPtr) < Data.getAddressSize())
       return createStringError(errc::invalid_argument,
                          "insufficient space remaining in table for "
@@ -107,16 +79,18 @@
                          *OffsetPtr - 1);
     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
     break;
-  case dwarf::DW_RLE_start_end:
+  }
+  case dwarf::DW_RLE_start_end: {
     if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
       return createStringError(errc::invalid_argument,
                          "insufficient space remaining in table for "
                          "DW_RLE_start_end encoding "
                          "at offset 0x%" PRIx32,
                          *OffsetPtr - 1);
-    Value0 = Data.getRelocatedAddress(OffsetPtr);
-    Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+    Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+    Value1 = Data.getRelocatedAddress(OffsetPtr);
     break;
+  }
   case dwarf::DW_RLE_start_length: {
     uint32_t PreviousOffset = *OffsetPtr - 1;
     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
@@ -199,9 +173,8 @@
 }
 
 void RangeListEntry::dump(
-    raw_ostream &OS, DWARFContext *, uint8_t AddrSize, uint64_t &CurrentBase,
-    unsigned Indent, uint16_t Version, uint8_t MaxEncodingStringLength,
-    DIDumpOptions DumpOpts,
+    raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
+    uint64_t &CurrentBase, DIDumpOptions DumpOpts,
     llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
         LookupPooledAddress) const {
   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
@@ -214,34 +187,21 @@
     }
   };
 
-  // Output indentations before we print the actual entry. We only print
-  // anything for DW_RLE_base_address when we are in verbose mode.
-  if (Version < 5 || DumpOpts.Verbose || !isBaseAddressSelectionEntry())
-    OS.indent(Indent);
-
-  // Always print the section offset in DWARF v4 and earlier.
-  if (Version < 5) {
-    OS << format("%08x", Offset);
-    DumpOpts.Verbose = false;
-  }
-
   if (DumpOpts.Verbose) {
     // Print the section offset in verbose mode.
     OS << format("0x%8.8" PRIx32 ":", Offset);
-    if (Version > 4) {
-      auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
-      // Unsupported encodings should have been reported during parsing.
-      assert(!EncodingString.empty() && "Unknown range entry encoding");
-      OS << format(" [%s%*c", EncodingString.data(),
-                   MaxEncodingStringLength - EncodingString.size() + 1, ']');
-      if (!isEndOfList())
-        OS << ": ";
-    }
+    auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
+    // Unsupported encodings should have been reported during parsing.
+    assert(!EncodingString.empty() && "Unknown range entry encoding");
+    OS << format(" [%s%*c", EncodingString.data(),
+                 MaxEncodingStringLength - EncodingString.size() + 1, ']');
+    if (EntryKind != dwarf::DW_RLE_end_of_list)
+      OS << ": ";
   }
 
   switch (EntryKind) {
   case dwarf::DW_RLE_end_of_list:
-    OS << (DumpOpts.Verbose ? "" : " <End of list>");
+    OS << (DumpOpts.Verbose ? "" : "<End of list>");
     break;
     //  case dwarf::DW_RLE_base_addressx:
   case dwarf::DW_RLE_base_addressx: {
@@ -257,13 +217,6 @@
   case dwarf::DW_RLE_base_address:
     // In non-verbose mode we do not print anything for this entry.
     CurrentBase = Value0;
-    if (Version < 5) {
-      // Dump the entry in pre-DWARF v5 format, i.e. with a -1 as Value0.
-      uint64_t allOnes = maxUIntN(AddrSize * 8);
-      OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, allOnes);
-      OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
-      break;
-    }
     if (!DumpOpts.Verbose)
       return;
     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
@@ -273,11 +226,6 @@
     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
     break;
   case dwarf::DW_RLE_offset_pair:
-    if (Version < 5) {
-      OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
-      OS << format(" %*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value1);
-      break;
-    }
     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
     DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
         .dump(OS, AddrSize, DumpOpts);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 874a2ba..31c4cd5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -15,6 +15,7 @@
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
index 69a9231..462c036 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
@@ -20,43 +20,30 @@
                                     uint32_t *OffsetPtr) {
   HeaderOffset = *OffsetPtr;
   // Read and verify the length field.
-  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) {
-    // By setting *OffsetPtr to 0, we indicate to the caller that
-    // we could not detemine the length of the table.
-    *OffsetPtr = 0;
+  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
     return createStringError(errc::invalid_argument,
-                             "section is not large enough to contain a "
-                             "%s table length at offset 0x%" PRIx32,
-                             SectionName.data(), HeaderOffset);
-  }
+                       "section is not large enough to contain a "
+                       "%s table length at offset 0x%" PRIx32,
+                       SectionName.data(), *OffsetPtr);
   // TODO: Add support for DWARF64.
   HeaderData.Length = Data.getU32(OffsetPtr);
-  if (HeaderData.Length == 0xffffffffu) {
-    *OffsetPtr = 0;
+  if (HeaderData.Length == 0xffffffffu)
     return createStringError(errc::not_supported,
                        "DWARF64 is not supported in %s at offset 0x%" PRIx32,
                        SectionName.data(), HeaderOffset);
-  }
-
-  uint32_t TableLength = HeaderData.Length + sizeof(uint32_t);
-  uint32_t End = HeaderOffset + TableLength;
   Format = dwarf::DwarfFormat::DWARF32;
-  if (TableLength < sizeof(Header)) {
-    *OffsetPtr = End;
+  if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
     return createStringError(errc::invalid_argument,
-                             "%s table at offset 0x%" PRIx32
-                             " has too small length (0x%" PRIx32
-                             ") to contain a complete header",
-                             SectionName.data(), HeaderOffset, TableLength);
-  }
-  if (!Data.isValidOffsetForDataOfSize(HeaderOffset, TableLength)) {
-    *OffsetPtr = 0; // No recovery if the length exceeds the section size.
-    return createStringError(
-        errc::invalid_argument,
-        "section is not large enough to contain a %s table "
-        "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
-        SectionName.data(), TableLength, HeaderOffset);
-  }
+                       "%s table at offset 0x%" PRIx32
+                       " has too small length (0x%" PRIx32
+                       ") to contain a complete header",
+                       SectionName.data(), HeaderOffset, length());
+  uint32_t End = HeaderOffset + length();
+  if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset))
+    return createStringError(errc::invalid_argument,
+                       "section is not large enough to contain a %s table "
+                       "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
+                       SectionName.data(), length(), HeaderOffset);
 
   HeaderData.Version = Data.getU16(OffsetPtr);
   HeaderData.AddrSize = Data.getU8(OffsetPtr);
@@ -64,36 +51,27 @@
   HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
 
   // Perform basic validation of the remaining header fields.
-  if (HeaderData.Version != 5) {
-    *OffsetPtr = End;
+  if (HeaderData.Version != 5)
     return createStringError(errc::invalid_argument,
-                             "unrecognised %s table version %" PRIu16
-                             " in table at offset 0x%" PRIx32,
-                             SectionName.data(), HeaderData.Version,
-                             HeaderOffset);
-  }
-  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) {
-    *OffsetPtr = End;
+                       "unrecognised %s table version %" PRIu16
+                       " in table at offset 0x%" PRIx32,
+                       SectionName.data(), HeaderData.Version, HeaderOffset);
+  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
     return createStringError(errc::not_supported,
                        "%s table at offset 0x%" PRIx32
                        " has unsupported address size %" PRIu8,
                        SectionName.data(), HeaderOffset, HeaderData.AddrSize);
-  }
-  if (HeaderData.SegSize != 0) {
-    *OffsetPtr = End;
+  if (HeaderData.SegSize != 0)
     return createStringError(errc::not_supported,
                        "%s table at offset 0x%" PRIx32
                        " has unsupported segment selector size %" PRIu8,
                        SectionName.data(), HeaderOffset, HeaderData.SegSize);
-  }
   if (End < HeaderOffset + sizeof(HeaderData) +
-                HeaderData.OffsetEntryCount * sizeof(uint32_t)) {
-    *OffsetPtr = End;
+                HeaderData.OffsetEntryCount * sizeof(uint32_t))
     return createStringError(errc::invalid_argument,
         "%s table at offset 0x%" PRIx32 " has more offset entries (%" PRIu32
         ") than there is space for",
         SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount);
-  }
   Data.setAddressSize(HeaderData.AddrSize);
   for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
     Offsets.push_back(Data.getU32(OffsetPtr));
@@ -123,11 +101,9 @@
   }
 }
 
-uint32_t DWARFListTableHeader::getTableLength() const {
+uint32_t DWARFListTableHeader::length() const {
   if (HeaderData.Length == 0)
     return 0;
-  assert(HeaderData.Version > 0 &&
-         "No DWARF version in header when using getTableLength()");
   // TODO: DWARF64 support.
-  return HeaderData.Length + (HeaderData.Version > 4) * sizeof(uint32_t);
+  return HeaderData.Length + sizeof(uint32_t);
 }
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 88565af..d475c44 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -296,16 +296,13 @@
   return true;
 }
 
-// Parse a list table header, including the optional array of offsets
+// Parse the rangelist table header, including the optional array of offsets
 // following it (DWARF v5 and later).
-template <typename DWARFListTable>
-static Expected<DWARFListTable>
-parseListTableHeader(DWARFDataExtractor DA, DWARFContext *C,
-                     StringRef SectionName, uint32_t Offset, bool isDWO) {
+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.
-  DWARFListTable Table(C, SectionName, isDWO);
   if (Offset > 0) {
     if (Offset < 12U)
       return createStringError(errc::invalid_argument, "Did not detect a valid"
@@ -313,46 +310,20 @@
                                Offset);
     Offset -= 12U;
   }
+  llvm::DWARFDebugRnglistTable Table;
   if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
     return std::move(E);
   return Table;
 }
 
-// Parse a DWARF v5 list table (e.g. either a rangelist table or a location
-// list table). For DWARF units with version 4 or earlier, we instead create
-// the table artifically by giving it a size that equals the section size.
-template <typename DWARFListTable>
-static Optional<DWARFListTable>
-setupListTable(DWARFUnit *U, const DWARFSection *Section, StringRef SectionName,
-               uint32_t &Base, bool isDWO, bool isLittleEndian) {
-  if (!Section->Data.size())
-    return None;
-  DWARFContext &Ctx = U->getContext();
-  DWARFListTable Table(&Ctx, SectionName, isDWO);
-  // Parse the list table header. Individual lists are extracted lazily.
-  DWARFDataExtractor DA(Ctx.getDWARFObj(), *Section, isLittleEndian,
-                        U->getAddressByteSize());
-  if (U->getVersion() < 5) {
-    Base = 0;
-    Table.setHeaderData(Section->Data.size(), U->getVersion(),
-                        DA.getAddressSize());
-    return Table;
-  }
-  if (auto TableOrError = parseListTableHeader<DWARFListTable>(
-          DA, &Ctx, SectionName, Base, isDWO))
-    Table = TableOrError.get();
-  else {
-    WithColor::error() << "parsing a " << Table.getListTypeString().data()
-                       << " list table: " << toString(TableOrError.takeError())
-                       << '\n';
-    return None;
-  }
-  // In a split dwarf unit, there are no attributes like DW_AT_rnglists_base or
-  // DW_AT_loclists_base that describe the table base. Adjust Base to point past
-  // the table header which is expected to start at offset 0.
-  if (isDWO)
-    Base = Table.getHeaderSize();
-  return Table;
+Error DWARFUnit::extractRangeList(uint32_t RangeListOffset,
+                                  DWARFDebugRangeList &RangeList) const {
+  // Require that compile unit is extracted.
+  assert(!DieArray.empty());
+  DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+                                isLittleEndian, getAddressByteSize());
+  uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
+  return RangeList.extract(RangesData, &ActualRangeListOffset);
 }
 
 void DWARFUnit::clear() {
@@ -466,24 +437,35 @@
 
     // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
     // describe address ranges.
-    StringRef RangeSectionName = ".debug_ranges";
     if (getVersion() >= 5) {
-      if (IsDWO) {
-        RangeSectionName = ".debug_rnglists.dwo";
+      if (IsDWO)
         setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
-      } else {
-        RangeSectionName = ".debug_rnglists";
+      else
         setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
                          toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0));
+      if (RangeSection->Data.size()) {
+        // 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(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();
       }
     }
-    RngListTable = setupListTable<DWARFDebugRnglistTable>(
-        this, RangeSection, RangeSectionName, RangeSectionBase, IsDWO,
-        isLittleEndian);
 
     // 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.
-  }
+    }
 
   return DieArray.size();
 }
@@ -521,9 +503,16 @@
   DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
   if (getVersion() >= 5) {
     DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
-    DWO->RngListTable = setupListTable<DWARFDebugRnglistTable>(
-        DWOCU, DWO->RangeSection, ".debug_rnglists.dwo", DWO->RangeSectionBase,
-        /* isDWO =*/true, isLittleEndian);
+    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(TableOrError.takeError())
+                         << '\n';
+    if (DWO->RngListTable)
+      DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize();
   } else {
     auto DWORangesBase = UnitDie.getRangesBaseAttribute();
     DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
@@ -541,6 +530,12 @@
 
 Expected<DWARFAddressRangesVector>
 DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
+  if (getVersion() <= 4) {
+    DWARFDebugRangeList RangeList;
+    if (Error E = extractRangeList(Offset, RangeList))
+      return std::move(E);
+    return RangeList.getAbsoluteRanges(getBaseAddress());
+  }
   if (RngListTable) {
     DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
                                   isLittleEndian, RngListTable->getAddrSize());