[DWARF v5] Refactor range lists dumping by using a more generic way of handling tables of lists.
The intent is to use it for location list tables as well. Change is almost NFC with the exception
of the spelling of some strings used during dumping (all lowercase now).

Reviewer: JDevlieghere

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

llvm-svn: 337763
diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
index 8dd4edc..d88a027 100644
--- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -20,6 +20,7 @@
   DWARFExpression.cpp
   DWARFFormValue.cpp
   DWARFGdbIndex.cpp
+  DWARFListTable.cpp
   DWARFTypeUnit.cpp
   DWARFUnitIndex.cpp
   DWARFUnit.cpp
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
index 533b092..fac075b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -16,12 +16,6 @@
 
 using namespace llvm;
 
-void DWARFDebugRnglistTable::clear() {
-  HeaderData = {};
-  Offsets.clear();
-  Ranges.clear();
-}
-
 template <typename... Ts>
 static Error createError(char const *Fmt, const Ts &... Vals) {
   std::string Buffer;
@@ -30,66 +24,14 @@
   return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
 }
 
-Error DWARFDebugRnglistTable::extractHeaderAndOffsets(DWARFDataExtractor Data,
-                                                      uint32_t *OffsetPtr) {
-  HeaderOffset = *OffsetPtr;
-  // Read and verify the length field.
-  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
-    return createError("section is not large enough to contain a "
-                       ".debug_rnglists table length at offset 0x%" PRIx32,
-                       *OffsetPtr);
-  // TODO: Add support for DWARF64.
-  HeaderData.Length = Data.getU32(OffsetPtr);
-  if (HeaderData.Length == 0xffffffffu)
-    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
-                       ") to contain a complete header",
-                       HeaderOffset, length());
-  uint32_t End = HeaderOffset + length();
-  if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset))
-    return createError(
-        "section is not large enough to contain a .debug_rnglists table "
-        "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
-        length(), HeaderOffset);
-
-  HeaderData.Version = Data.getU16(OffsetPtr);
-  HeaderData.AddrSize = Data.getU8(OffsetPtr);
-  HeaderData.SegSize = Data.getU8(OffsetPtr);
-  HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
-
-  // Perform basic validation of the remaining header fields.
-  if (HeaderData.Version != 5)
-    return createError("unrecognised .debug_rnglists table version %" PRIu16
-                       " in table at offset 0x%" PRIx32,
-                       HeaderData.Version, HeaderOffset);
-  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
-    return createError(".debug_rnglists table at offset 0x%" PRIx32
-                       " has unsupported address size %hhu",
-                       HeaderOffset, HeaderData.AddrSize);
-  if (HeaderData.SegSize != 0)
-    return createError(".debug_rnglists table at offset 0x%" PRIx32
-                       " has unsupported segment selector size %" PRIu8,
-                       HeaderOffset, HeaderData.SegSize);
-  if (End < HeaderOffset + sizeof(HeaderData) +
-                HeaderData.OffsetEntryCount * sizeof(uint32_t))
-    return createError(".debug_rnglists table at offset 0x%" PRIx32
-                       " has more offset entries (%" PRIu32
-                       ") than there is space for",
-                       HeaderOffset, HeaderData.OffsetEntryCount);
-  Data.setAddressSize(HeaderData.AddrSize);
-  for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
-    Offsets.push_back(Data.getU32(OffsetPtr));
-  return Error::success();
+template <>
+Error DWARFListType<RangeListEntry>::createError(const char *Fmt, const char *s,
+                                                 uint32_t Val) {
+  return ::createError(Fmt, s, Val);
 }
 
-Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
-                                                 uint32_t End,
-                                                 uint32_t *OffsetPtr) {
+Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
+                              uint32_t *OffsetPtr) {
   Offset = *OffsetPtr;
   SectionIndex = -1ULL;
   // The caller should guarantee that we have at least 1 byte available, so
@@ -206,53 +148,10 @@
   return Res;
 }
 
-Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
-                                 uint32_t End, uint32_t *OffsetPtr) {
-  if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
-    return createError("invalid range list offset 0x%" PRIx32, *OffsetPtr);
-  Entries.clear();
-  while (*OffsetPtr < End) {
-    RangeListEntry Entry{0, 0, 0, 0, 0};
-    if (Error E = Entry.extract(Data, End, OffsetPtr))
-      return E;
-    Entries.push_back(Entry);
-    if (Entry.EntryKind == dwarf::DW_RLE_end_of_list)
-      return Error::success();
-  }
-  return createError(
-      "no end of list marker detected at end of .debug_rnglists table "
-      "starting at offset 0x%" PRIx32,
-      HeaderOffset);
-}
-
-Error DWARFDebugRnglistTable::extract(DWARFDataExtractor Data,
-                                      uint32_t *OffsetPtr) {
-  clear();
-  if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
-    return E;
-
-  Data.setAddressSize(HeaderData.AddrSize);
-  uint32_t End = HeaderOffset + length();
-  while (*OffsetPtr < End) {
-    DWARFDebugRnglist CurrentRangeList;
-    uint32_t Off = *OffsetPtr;
-    if (Error E = CurrentRangeList.extract(Data, HeaderOffset, End, OffsetPtr))
-      return E;
-    Ranges[Off] = CurrentRangeList;
-  }
-
-  assert(*OffsetPtr == End &&
-         "mismatch between expected length of .debug_rnglists table and length "
-         "of extracted data");
-  return Error::success();
-}
-
-static void dumpRangeEntry(raw_ostream &OS,
-                           DWARFDebugRnglist::RangeListEntry Entry,
-                           uint8_t AddrSize, uint8_t MaxEncodingStringLength,
-                           uint64_t &CurrentBase, DIDumpOptions DumpOpts) {
-  auto PrintRawEntry = [](raw_ostream &OS,
-                          DWARFDebugRnglist::RangeListEntry Entry,
+void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize,
+                          uint8_t MaxEncodingStringLength,
+                          uint64_t &CurrentBase, DIDumpOptions DumpOpts) const {
+  auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
     if (DumpOpts.Verbose) {
       DumpOpts.DisplayRawContents = true;
@@ -264,108 +163,41 @@
 
   if (DumpOpts.Verbose) {
     // Print the section offset in verbose mode.
-    OS << format("0x%8.8" PRIx32 ":", Entry.Offset);
-    auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind);
+    OS << format("0x%8.8" PRIx32 ":", Offset);
+    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 (Entry.EntryKind != dwarf::DW_RLE_end_of_list)
+    if (EntryKind != dwarf::DW_RLE_end_of_list)
       OS << ": ";
   }
 
-  switch (Entry.EntryKind) {
+  switch (EntryKind) {
   case dwarf::DW_RLE_end_of_list:
     OS << (DumpOpts.Verbose ? "" : "<End of list>");
     break;
   case dwarf::DW_RLE_base_address:
     // In non-verbose mode we do not print anything for this entry.
-    CurrentBase = Entry.Value0;
+    CurrentBase = Value0;
     if (!DumpOpts.Verbose)
       return;
-    OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Entry.Value0);
+    OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
     break;
   case dwarf::DW_RLE_start_length:
-    PrintRawEntry(OS, Entry, AddrSize, DumpOpts);
-    DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1)
-        .dump(OS, AddrSize, DumpOpts);
+    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+    DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
     break;
   case dwarf::DW_RLE_offset_pair:
-    PrintRawEntry(OS, Entry, AddrSize, DumpOpts);
-    DWARFAddressRange(Entry.Value0 + CurrentBase, Entry.Value1 + CurrentBase)
+    PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+    DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
         .dump(OS, AddrSize, DumpOpts);
     break;
   case dwarf::DW_RLE_start_end:
-    DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts);
+    DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
     break;
   default:
     llvm_unreachable("Unsupported range list encoding");
   }
   OS << "\n";
 }
-
-void DWARFDebugRnglistTable::dump(raw_ostream &OS,
-                                  DIDumpOptions DumpOpts) const {
-  if (DumpOpts.Verbose)
-    OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
-  OS << format("Range List Header: length = 0x%8.8" PRIx32
-               ", version = 0x%4.4" PRIx16 ", "
-               "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
-               ", offset_entry_count = "
-               "0x%8.8" PRIx32 "\n",
-               HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
-               HeaderData.SegSize, HeaderData.OffsetEntryCount);
-
-  if (HeaderData.OffsetEntryCount > 0) {
-    OS << "Offsets: [";
-    for (const auto &Off : Offsets) {
-      OS << format("\n0x%8.8" PRIx32, Off);
-      if (DumpOpts.Verbose)
-        OS << format(" => 0x%8.8" PRIx32,
-                     Off + HeaderOffset + sizeof(HeaderData));
-    }
-    OS << "\n]\n";
-  }
-  OS << "Ranges:\n";
-
-  // Determine the length of the longest encoding string we have in the table,
-  // so we can align the output properly. We only need this in verbose mode.
-  size_t MaxEncodingStringLength = 0;
-  if (DumpOpts.Verbose) {
-    for (const auto &List : Ranges)
-      for (const auto &Entry : List.second.getEntries())
-        MaxEncodingStringLength =
-            std::max(MaxEncodingStringLength,
-                     dwarf::RangeListEncodingString(Entry.EntryKind).size());
-  }
-
-  uint64_t CurrentBase = 0;
-  for (const auto &List : Ranges)
-    for (const auto &Entry : List.second.getEntries())
-      dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength,
-                     CurrentBase, DumpOpts);
-}
-
-uint32_t DWARFDebugRnglistTable::length() const {
-  if (HeaderData.Length == 0)
-    return 0;
-  // TODO: DWARF64 support.
-  return HeaderData.Length + sizeof(uint32_t);
-}
-
-Expected<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))
-    return std::move(E);
-  Ranges[StartingOffset] = RngList;
-  return RngList;
-}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
new file mode 100644
index 0000000..559afc7
--- /dev/null
+++ b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
@@ -0,0 +1,109 @@
+//===- DWARFListTable.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/DWARFListTable.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+template <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+  std::string Buffer;
+  raw_string_ostream Stream(Buffer);
+  Stream << format(Fmt, Vals...);
+  return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+}
+
+Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
+                                    uint32_t *OffsetPtr) {
+  HeaderOffset = *OffsetPtr;
+  // Read and verify the length field.
+  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
+    return createError("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)
+    return createError("DWARF64 is not supported in %s at offset 0x%" PRIx32,
+                       SectionName.data(), HeaderOffset);
+  Format = dwarf::DwarfFormat::DWARF32;
+  if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
+    return createError("%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 createError("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);
+  HeaderData.SegSize = Data.getU8(OffsetPtr);
+  HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
+
+  // Perform basic validation of the remaining header fields.
+  if (HeaderData.Version != 5)
+    return createError("unrecognised %s table version %" PRIu16
+                       " in table at offset 0x%" PRIx32,
+                       SectionName.data(), HeaderData.Version, HeaderOffset);
+  if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+    return createError("%s table at offset 0x%" PRIx32
+                       " has unsupported address size %hhu",
+                       SectionName.data(), HeaderOffset, HeaderData.AddrSize);
+  if (HeaderData.SegSize != 0)
+    return createError("%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))
+    return createError(
+        "%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));
+  return Error::success();
+}
+
+void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+  if (DumpOpts.Verbose)
+    OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
+  OS << format(
+      "%s list header: length = 0x%8.8" PRIx32 ", version = 0x%4.4" PRIx16 ", "
+      "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
+      ", offset_entry_count = "
+      "0x%8.8" PRIx32 "\n",
+      ListTypeString.data(), HeaderData.Length, HeaderData.Version,
+      HeaderData.AddrSize, HeaderData.SegSize, HeaderData.OffsetEntryCount);
+
+  if (HeaderData.OffsetEntryCount > 0) {
+    OS << "offsets: [";
+    for (const auto &Off : Offsets) {
+      OS << format("\n0x%8.8" PRIx32, Off);
+      if (DumpOpts.Verbose)
+        OS << format(" => 0x%8.8" PRIx32,
+                     Off + HeaderOffset + sizeof(HeaderData));
+    }
+    OS << "\n]\n";
+  }
+}
+
+uint32_t DWARFListTableHeader::length() const {
+  if (HeaderData.Length == 0)
+    return 0;
+  // TODO: DWARF64 support.
+  return HeaderData.Length + sizeof(uint32_t);
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 2e965e0..51d0865 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -408,7 +408,7 @@
   if (RngListTable) {
     DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
                                   isLittleEndian, RngListTable->getAddrSize());
-    auto RangeListOrError = RngListTable->findRangeList(RangesData, Offset);
+    auto RangeListOrError = RngListTable->findList(RangesData, Offset);
     if (RangeListOrError)
       return RangeListOrError.get().getAbsoluteRanges(getBaseAddress());
     return RangeListOrError.takeError();