[llvm] r345546 - [DWARF][NFC] Refactor range list extraction and dumping

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 6 19:28:18 PST 2018


On Tue, Nov 6, 2018 at 4:15 PM <wolfgang.pieb at sony.com> wrote:

> Thanks again, Dave, for the test case. Here is a brief summary of what the
> issue is, if you’re curious:
>
>
>
> My patch added a new field, a function reference, to the  range list table
> data structure, using std::function.
>
> In the libcxx headers, std::function is 16-byte aligned when compiled for
> x86_64, and so forces 16-byte alignment on the range list table and
> consequently on the DWARFUnit class object. DWARFUnits are allocated via
> make_unique/new, and AFAICT, there is no support for stronger alignments
> than what new() gives you.
>
> So what happens is that, since the internal symbolizer and the other DWARF
> reading components are built with libcxx by the build_symbolizer script,
> the constructor for DWARFUnit happily uses aligned move instructions, which
> fails when the allocated memory is not 16-byte aligned.
>

Wow, how on earth did you track that down? I spent the last couple of days
trying to help investigate & didn't really make all that much progress -
mostly using optnone to disable optimizations on some functions to try to
isolate where the failure was. Furthest I got was that the I could get the
crash to happen reliably somewhere in the StringOffsetsTableContribution
initialization in extractDIEsIfNeeded... - but sounds like I might've been
barking up the wrong tree? Unclear.

In any case, super glad you were able to track that down!


>
>
> When the DWARF reading components are built with the GNU libraries,
> std::function is 8-byte aligned, and everything is fine.
>
>
>
> The symbolizer doesn’t even look at any range lists in what it’s doing
> (it’s just using aranges).
>
>
>
> The obvious fix is to use llvm::function_ref instead of std::function,
>

Though llvm::function_ref only works when the lifetime of the underlying
functor is guaranteed to outlive the use of the function_ref - is that the
case here?


> but it seems that the 16-byte alignment of std::function in libcxx is
> probably unintended. I’m inclined to file a bug against libcxx since this
> is something that might easily bite somewhere else.
>

Yeah, totally worth filing a bug/talking with libcxx folks to get that
fixed. And unfortunately I think either it needs to be fixed, or a
workaround applied before your patch should be resubmitted. (also wouldn't
mind doing some more review (yeah, really sorry it didn't get more last
time, I'll pull up the second Phab review & see what I can see tomorrow) -
see if we can split it up a bit just to simplify (if only a little bit)
some of these sorts of investigation if they come up again, etc)

- Dave


>
>
> -          wolfgang
>
>
>
> *From:* David Blaikie <dblaikie at gmail.com>
>
> *Sent:* Friday, November 2, 2018 3:23 PM
> *To:* Eric Christopher <echristo at gmail.com>
> *Cc:* Ilya Biryukov <ibiryukov at google.com>; Pieb, Wolfgang <
> wolfgang.pieb at sony.com>; Eric Christopher <echristo at google.com>;
> llvm-commits <llvm-commits at lists.llvm.org>; Richard Trieu <
> rtrieu at google.com>
>
> *Subject:* Re: [llvm] r345546 - [DWARF][NFC] Refactor range list
> extraction and dumping
>
>
>
> Well, I've got /something/ at least.
>
> Build Clang with compiler_rt (& libcxx and libcxxabi), then run:
>
>   CLANG=... ZLIB_SRC=...
> path/to/src/projects/compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
> lib/clang/8.0.0/lib/linux
>
> Then compile the following file:
>
>   extern "C" void __sanitizer_print_stack_trace(void);
>
>   int main() { __sanitizer_print_stack_trace(); }
>
>   $ clang++ -fsanitize=thread symbolizer_test.cc -g
>
> & run the resulting binary:
>
>   ./a.out
>   ThreadSanitizer:DEADLYSIGNAL
>   ==91375==ERROR: ThreadSanitizer: SEGV on unknown address 0x000000000000
> (pc 0x0000005615fd bp 0x7fa81c703830 sp 0x7fff330149d0 T91375)
>   ==91375==The signal is caused by a READ memory access.
>   ==91375==Hint: address points to the zero page.
>
> whereas it should print:
>   #0 __sanitizer_print_stack_trace
> .../projects/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc:753:25
> (a.out+0x4a9d09)
>   #1 main .../dev/scratch/symbolizer_test.cc:2:14 (a.out+0x4affa5)
>   #2 __libc_start_main <null> (libc.so.6+0x202b0)
>   #3 _start <null> (a.out+0x41f2d9)
>
> Though I don't know much about this integrated symbolizer... - I'm poking
> around more, but this at least gets you a reproduction/you can debug it
> maybe about as easily as I can :/
>
> As Eric said - smaller patches might help (& would generally be good
> regardless) - but wouldn't be sure it'd make it super obvious.
>
>
>
> On Tue, Oct 30, 2018 at 5:23 PM Eric Christopher <echristo at gmail.com>
> wrote:
>
> On Tue, Oct 30, 2018 at 5:16 PM David Blaikie <dblaikie at gmail.com> wrote:
>
> On Tue, Oct 30, 2018 at 4:51 PM Eric Christopher <echristo at gmail.com>
> wrote:
>
> Hi Wolfgang,
>
>
>
> I'm seeing this as losing inline information in the presence of split
> dwarf. Something in this patch is still NFC - using the llvm-symbolize
> support.
>
>
> There are test cases in tree that run llvm-symbolizer with split DWARF
> inputs - so I expect it's something more nuanced than that & it seems
> reasonable to expect/provide a test case to allow Wolfgang to make progress
> here.
>
>
>
>
> Agreed. Breaking it into smaller pieces will help this, but someone should
> work on getting a test case here. I'm out of town the rest of the week so
> I'm going to leave it up to David, Richard, and Ilya here to try to reduce
> down something.
>
>
>
> Thanks.
>
>
>
> -eric
>
>
>
>
>
> I'll see if I can come up with it, but you'll likely need to make this
> patch smaller to track down changes of this sort.
>
>
>
> Thanks!
>
>
>
> -eric
>
>
>
> On Tue, Oct 30, 2018 at 9:38 AM Ilya Biryukov via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
> I don't have time to integrate the changes anyway, so leaving this to the
> US timezone buildcop.
>
>
>
> On Tue, Oct 30, 2018 at 5:16 PM Ilya Biryukov <ibiryukov at google.com>
> wrote:
>
> This change seems to break our integrate. I *think* this is not NFC, but I
> don't have enough context to come up with a minimal repro.
>
> +Eric Christopher <echristo at google.com> +David Blaikie
> <dblaikie at gmail.com>, could you please try creating a small repro based
> on our internal test failures?
>
>
>
> Meanwhile, I'll probably have to revert the change, sorry about that.
>
>
>
> On Mon, Oct 29, 2018 at 11:19 PM Wolfgang Pieb via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
> Author: wolfgangp
> Date: Mon Oct 29 15:16:47 2018
> New Revision: 345546
>
> URL: http://llvm.org/viewvc/llvm-project?rev=345546&view=rev
> Log:
> [DWARF][NFC] Refactor range list extraction and dumping
>
> The purpose of this patch is twofold:
> - Fold pre-DWARF v5 functionality into v5 to eliminate the need for 2
> different
>   versions of range list handling. We get rid of
> DWARFDebugRangelist{.cpp,.h}.
> - Templatize the handling of range list tables so that location list
> handling
>   can take advantage of it as well. Location list and range list tables
> have the
>   same basic layout.
>
> A non-NFC version of this patch was previously submitted with r342218, but
> it caused
> errors with some TSan tests. This patch has no functional changes. The
> difference to
> the non-NFC patch is that there are no changes to rangelist dumping in
> this patch.
>
> Differential Revision: https://reviews.llvm.org/D53545
>
>
> Removed:
>     llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
>     llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
> Modified:
>     llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h
>     llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h
>     llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFListTable.h
>     llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h
>     llvm/trunk/lib/DebugInfo/DWARF/CMakeLists.txt
>     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/DWARFListTable.cpp
>     llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp
>     llvm/trunk/tools/dsymutil/DwarfLinker.cpp
>     llvm/trunk/tools/dsymutil/DwarfStreamer.cpp
>     llvm/trunk/tools/dsymutil/DwarfStreamer.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=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h (original)
> +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFContext.h Mon Oct 29
> 15:16:47 2018
> @@ -231,16 +231,16 @@ public:
>    /// Get a DIE given an exact offset.
>    DWARFDie getDIEForOffset(uint32_t Offset);
>
> -  unsigned getMaxVersion() {
> +  unsigned getMaxVersion(uint16_t DefaultVersion = 0) {
>      // Ensure info units have been parsed to discover MaxVersion
>      info_section_units();
> -    return MaxVersion;
> +    return MaxVersion ? MaxVersion : DefaultVersion;
>    }
>
> -  unsigned getMaxDWOVersion() {
> +  unsigned getMaxDWOVersion(uint16_t DefaultVersion = 0) {
>      // Ensure DWO info units have been parsed to discover MaxVersion
>      dwo_info_section_units();
> -    return MaxVersion;
> +    return MaxVersion ? MaxVersion : DefaultVersion;
>    }
>
>    void setMaxVersionIfGreater(unsigned Version) {
>
> Removed: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h?rev=345545&view=auto
>
> ==============================================================================
> --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
> (original)
> +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h (removed)
> @@ -1,85 +0,0 @@
> -//===- DWARFDebugRangeList.h ------------------------------------*- C++
> -*-===//
> -//
> -//                     The LLVM Compiler Infrastructure
> -//
> -// This file is distributed under the University of Illinois Open Source
> -// License. See LICENSE.TXT for details.
> -//
>
> -//===----------------------------------------------------------------------===//
> -
> -#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
> -#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
> -
> -#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
> -#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
> -#include <cassert>
> -#include <cstdint>
> -#include <vector>
> -
> -namespace llvm {
> -
> -class raw_ostream;
> -
> -class DWARFDebugRangeList {
> -public:
> -  struct RangeListEntry {
> -    /// A beginning address offset. This address offset has the size of an
> -    /// address and is relative to the applicable base address of the
> -    /// compilation unit referencing this range list. It marks the
> beginning
> -    /// of an address range.
> -    uint64_t StartAddress;
> -    /// An ending address offset. This address offset again has the size
> of
> -    /// an address and is relative to the applicable base address of the
> -    /// compilation unit referencing this range list. It marks the first
> -    /// address past the end of the address range. The ending address must
> -    /// be greater than or equal to the beginning address.
> -    uint64_t EndAddress;
> -    /// A section index this range belongs to.
> -    uint64_t SectionIndex;
> -
> -    /// The end of any given range list is marked by an end of list entry,
> -    /// which consists of a 0 for the beginning address offset
> -    /// and a 0 for the ending address offset.
> -    bool isEndOfListEntry() const {
> -      return (StartAddress == 0) && (EndAddress == 0);
> -    }
> -
> -    /// A base address selection entry consists of:
> -    /// 1. The value of the largest representable address offset
> -    /// (for example, 0xffffffff when the size of an address is 32 bits).
> -    /// 2. An address, which defines the appropriate base address for
> -    /// use in interpreting the beginning and ending address offsets of
> -    /// subsequent entries of the location list.
> -    bool isBaseAddressSelectionEntry(uint8_t AddressSize) const {
> -      assert(AddressSize == 4 || AddressSize == 8);
> -      if (AddressSize == 4)
> -        return StartAddress == -1U;
> -      else
> -        return StartAddress == -1ULL;
> -    }
> -  };
> -
> -private:
> -  /// Offset in .debug_ranges section.
> -  uint32_t Offset;
> -  uint8_t AddressSize;
> -  std::vector<RangeListEntry> Entries;
> -
> -public:
> -  DWARFDebugRangeList() { clear(); }
> -
> -  void clear();
> -  void dump(raw_ostream &OS) const;
> -  Error extract(const DWARFDataExtractor &data, uint32_t *offset_ptr);
> -  const std::vector<RangeListEntry> &getEntries() { return Entries; }
> -
> -  /// getAbsoluteRanges - Returns absolute address ranges defined by this
> range
> -  /// list. Has to be passed base address of the compile unit referencing
> this
> -  /// range list.
> -  DWARFAddressRangesVector
> -  getAbsoluteRanges(llvm::Optional<SectionedAddress> BaseAddr) const;
> -};
> -
> -} // end namespace llvm
> -
> -#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
>
> 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=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h (original)
> +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h Mon Oct
> 29 15:16:47 2018
> @@ -13,8 +13,8 @@
>  #include "llvm/ADT/Optional.h"
>  #include "llvm/BinaryFormat/Dwarf.h"
>  #include "llvm/DebugInfo/DIContext.h"
> +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
>  #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
> -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
>  #include "llvm/DebugInfo/DWARF/DWARFListTable.h"
>  #include <cstdint>
>  #include <map>
> @@ -22,6 +22,8 @@
>
>  namespace llvm {
>
> +struct BaseAddress;
> +class DWARFContext;
>  class Error;
>  class raw_ostream;
>  class DWARFUnit;
> @@ -35,12 +37,30 @@ struct RangeListEntry : public DWARFList
>    uint64_t Value0;
>    uint64_t Value1;
>
> -  Error extract(DWARFDataExtractor Data, uint32_t End, uint32_t
> *OffsetPtr);
> -  void dump(raw_ostream &OS, uint8_t AddrSize, uint8_t
> MaxEncodingStringLength,
> -            uint64_t &CurrentBase, DIDumpOptions DumpOpts,
> +  Error extract(DWARFDataExtractor Data, uint32_t End, uint16_t Version,
> +                StringRef SectionName, uint32_t *OffsetPtr, bool isDWO =
> false);
> +  bool isEndOfList() const { return EntryKind ==
> dwarf::DW_RLE_end_of_list; }
> +  bool isBaseAddressSelectionEntry() const {
> +    return EntryKind == dwarf::DW_RLE_base_address;
> +  }
> +  uint64_t getStartAddress() const {
> +    assert((EntryKind == dwarf::DW_RLE_start_end ||
> +            EntryKind == dwarf::DW_RLE_offset_pair ||
> +            EntryKind == dwarf::DW_RLE_startx_length) &&
> +           "Unexpected range list entry kind");
> +    return Value0;
> +  }
> +  uint64_t getEndAddress() const {
> +    assert((EntryKind == dwarf::DW_RLE_start_end ||
> +            EntryKind == dwarf::DW_RLE_offset_pair) &&
> +           "Unexpected range list entry kind");
> +    return Value1;
> +  }
> +  void dump(raw_ostream &OS, DWARFContext *C, uint8_t AddrSize,
> +            uint64_t &CurrentBase, unsigned Indent, uint16_t Version,
> +            uint8_t MaxEncodingStringLength, DIDumpOptions DumpOpts,
>              llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
>                  LookupPooledAddress) const;
> -  bool isSentinel() const { return EntryKind ==
> dwarf::DW_RLE_end_of_list; }
>  };
>
>  /// A class representing a single rangelist.
> @@ -54,10 +74,12 @@ public:
>
>  class DWARFDebugRnglistTable : public
> DWARFListTableBase<DWARFDebugRnglist> {
>  public:
> -  DWARFDebugRnglistTable()
> -      : DWARFListTableBase(/* SectionName    = */ ".debug_rnglists",
> +  DWARFDebugRnglistTable(DWARFContext *C, StringRef SectionName,
> +                         bool isDWO = false)
> +      : DWARFListTableBase(C, SectionName, isDWO,
>                             /* HeaderString   = */ "ranges:",
> -                           /* ListTypeString = */ "range") {}
> +                           /* ListTypeString = */ "range",
> +                           dwarf::RangeListEncodingString) {}
>  };
>
>  } // end namespace llvm
>
> Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFListTable.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFListTable.h?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFListTable.h (original)
> +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFListTable.h Mon Oct 29
> 15:16:47 2018
> @@ -23,6 +23,8 @@
>
>  namespace llvm {
>
> +class DWARFContext;
> +
>  /// A base class for DWARF list entries, such as range or location list
>  /// entries.
>  struct DWARFListEntryBase {
> @@ -37,6 +39,7 @@ struct DWARFListEntryBase {
>  /// A base class for lists of entries that are extracted from a particular
>  /// section, such as range lists or location lists.
>  template <typename ListEntryType> class DWARFListType {
> +public:
>    using EntryType = ListEntryType;
>    using ListEntries = std::vector<EntryType>;
>
> @@ -45,11 +48,26 @@ protected:
>
>  public:
>    const ListEntries &getEntries() const { return Entries; }
> -  bool empty() const { return Entries.empty(); }
> +  bool empty() const {
> +    return Entries.empty() || Entries.begin()->isEndOfList();
> +  }
>    void clear() { Entries.clear(); }
> +  uint32_t getOffset() const {
> +    if (Entries.empty())
> +      return 0;
> +    return Entries.begin()->Offset;
> +  }
> +
> +  /// Extract a list. The caller must pass the correct DWARF version.
> +  /// The end-of-list entry is retained as the last element of the vector
> of
> +  /// entries.
>    Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t
> End,
> -                uint32_t *OffsetPtr, StringRef SectionName,
> -                StringRef ListStringName);
> +                uint16_t Version, uint32_t *OffsetPtr, StringRef
> SectionName,
> +                StringRef ListStringName, bool isDWO = false);
> +  void dump(raw_ostream &OS, DWARFContext *C, uint8_t AddressSize,
> +            uint64_t BaseAddress, unsigned Indent, uint16_t Version,
> +            size_t MaxEncodingStringLength,
> +            DIDumpOptions DumpOpts,
> llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
> LookupPooledAddress) const;
>  };
>
>  /// A class representing the header of a list table such as the range list
> @@ -67,9 +85,9 @@ class DWARFListTableHeader {
>      uint8_t AddrSize;
>      /// The size in bytes of a segment selector on the target
> architecture.
>      /// If the target system uses a flat address space, this value is 0.
> -    uint8_t SegSize;
> +    uint8_t SegSize = 0;
>      /// The number of offsets that follow the header before the range
> lists.
> -    uint32_t OffsetEntryCount;
> +    uint32_t OffsetEntryCount = 0;
>    };
>
>    Header HeaderData;
> @@ -78,10 +96,10 @@ class DWARFListTableHeader {
>    /// FIXME: Generate the table and use the appropriate forms.
>    std::vector<uint32_t> Offsets;
>    /// The table's format, either DWARF32 or DWARF64.
> -  dwarf::DwarfFormat Format;
> +  dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32;
>    /// The offset at which the header (and hence the table) is located
> within
>    /// its section.
> -  uint32_t HeaderOffset;
> +  uint32_t HeaderOffset = 0;
>    /// The name of the section the list is located in.
>    StringRef SectionName;
>    /// A characterization of the list for dumping purposes, e.g. "range" or
> @@ -97,9 +115,19 @@ public:
>      Offsets.clear();
>    }
>    uint32_t getHeaderOffset() const { return HeaderOffset; }
> +
>    uint8_t getAddrSize() const { return HeaderData.AddrSize; }
> +  void setAddrSize(uint8_t AddrSize) { HeaderData.AddrSize = AddrSize; }
> +
>    uint32_t getLength() const { return HeaderData.Length; }
> +  void setLength(uint32_t Length) { HeaderData.Length = Length; }
> +
>    uint16_t getVersion() const { return HeaderData.Version; }
> +  void setVersion(uint16_t Version) { HeaderData.Version = Version; }
> +
> +  uint8_t getSegSize() const { return HeaderData.SegSize; }
> +  uint32_t getOffsetEntryCount() const { return
> HeaderData.OffsetEntryCount; }
> +
>    StringRef getSectionName() const { return SectionName; }
>    StringRef getListTypeString() const { return ListTypeString; }
>    dwarf::DwarfFormat getFormat() const { return Format; }
> @@ -116,8 +144,10 @@ public:
>
>    /// Returns the length of the table, including the length field, or 0
> if the
>    /// length has not been determined (e.g. because the table has not yet
> been
> -  /// parsed, or there was a problem in parsing).
> -  uint32_t length() const;
> +  /// parsed, or there was a problem in parsing). In fake tables, such as
> for
> +  /// DWARF v4 and earlier, there is no header, so the length simply
> reflects
> +  /// the size of the section.
> +  uint32_t getTableLength() const;
>  };
>
>  /// A class representing a table of lists as specified in the DWARF v5
> @@ -130,14 +160,22 @@ template <typename DWARFListType> class
>    /// A mapping between file offsets and lists. It is used to find a
> particular
>    /// list based on an offset (obtained from DW_AT_ranges, for example).
>    std::map<uint32_t, DWARFListType> ListMap;
> +  DWARFContext *Ctx;
> +  /// True if this list is located in a split-DWARF (dwo or dwp) file.
> +  bool isDWO;
>    /// This string is displayed as a heading before the list is dumped
>    /// (e.g. "ranges:").
>    StringRef HeaderString;
> +  /// A function returning the encoding string for a given list entry
> encoding,
> +  /// e.g. "DW_RLE_start_end".
> +  std::function<StringRef(unsigned)> EncodingString;
>
>  protected:
> -  DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
> -                     StringRef ListTypeString)
> -      : Header(SectionName, ListTypeString), HeaderString(HeaderString) {}
> +  DWARFListTableBase(DWARFContext *C, StringRef SectionName, bool isDWO,
> +                     StringRef HeaderString, StringRef ListTypeString,
> +                     std::function<StringRef(unsigned)> EncodingString)
> +      : Header(SectionName, ListTypeString), Ctx(C), isDWO(isDWO),
> +        HeaderString(HeaderString), EncodingString(EncodingString) {}
>
>  public:
>    void clear() {
> @@ -148,14 +186,28 @@ public:
>    Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t
> *OffsetPtr) {
>      return Header.extract(Data, OffsetPtr);
>    }
> +
> +  /// Initialize the table header to explicit values. This is used for
> DWARF v4
> +  /// and earlier since there is no header that can be extracted from a
> section.
> +  void setHeaderData(uint32_t Length, uint16_t Version, uint8_t AddrSize)
> {
> +    assert(Header.getSegSize() == 0 &&
> +           "Unexpected segsize in list table header.");
> +    assert(Header.getOffsetEntryCount() == 0 &&
> +           "Unexpected offset entry count in list table header.");
> +    Header.setLength(Length);
> +    Header.setVersion(Version);
> +    Header.setAddrSize(AddrSize);
> +  }
> +
>    /// Extract an entire table, including all list entries.
> -  Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
> +  Error extract(DWARFDataExtractor Data, uint16_t Version, uint32_t
> *OffsetPtr);
>    /// Look up a list based on a given offset. Extract it and enter it
> into the
>    /// list map if necessary.
>    Expected<DWARFListType> findList(DWARFDataExtractor Data, uint32_t
> Offset);
>
>    uint32_t getHeaderOffset() const { return Header.getHeaderOffset(); }
>    uint8_t getAddrSize() const { return Header.getAddrSize(); }
> +  StringRef getListTypeString() const { return
> Header.getListTypeString(); }
>
>    void dump(raw_ostream &OS,
>              llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
> @@ -179,25 +231,35 @@ public:
>      llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
>    }
>
> -  uint32_t length() { return Header.length(); }
> +  uint16_t getVersion() const { return Header.getVersion(); }
> +  uint32_t getLength() const { return Header.getTableLength(); }
>  };
>
>  template <typename DWARFListType>
>  Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data,
> +                                                 uint16_t Version,
>                                                   uint32_t *OffsetPtr) {
> +  assert(Version > 0 && "DWARF version required and not given.");
>    clear();
> -  if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
> +  // For DWARF v4 and earlier, we cannot extract a table header, so we
> +  // initialize it explicitly.
> +  if (Version < 5)
> +    setHeaderData(Data.size(), Version, Data.getAddressSize());
> +  else if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
>      return E;
>
>    Data.setAddressSize(Header.getAddrSize());
> -  uint32_t End = getHeaderOffset() + Header.length();
> +  uint32_t End = getHeaderOffset() + getLength();
> +  // Extract all lists.
>    while (*OffsetPtr < End) {
>      DWARFListType CurrentList;
>      uint32_t Off = *OffsetPtr;
> -    if (Error E = CurrentList.extract(Data, getHeaderOffset(), End,
> OffsetPtr,
> -                                      Header.getSectionName(),
> -                                      Header.getListTypeString()))
> +    if (Error E = CurrentList.extract(
> +            Data, getHeaderOffset(), End, Header.getVersion(), OffsetPtr,
> +            Header.getSectionName(), Header.getListTypeString(), isDWO)) {
> +      *OffsetPtr = End;
>        return E;
> +    }
>      ListMap[Off] = CurrentList;
>    }
>
> @@ -208,22 +270,25 @@ Error DWARFListTableBase<DWARFListType>:
>  }
>
>  template <typename ListEntryType>
> -Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
> -                                            uint32_t HeaderOffset,
> uint32_t End,
> -                                            uint32_t *OffsetPtr,
> -                                            StringRef SectionName,
> -                                            StringRef ListTypeString) {
> +Error DWARFListType<ListEntryType>::extract(
> +    DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End,
> +    uint16_t Version, uint32_t *OffsetPtr, StringRef SectionName,
> +    StringRef ListTypeString, bool isDWO) {
>    if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
>      return createStringError(errc::invalid_argument,
>                         "invalid %s list offset 0x%" PRIx32,
>                         ListTypeString.data(), *OffsetPtr);
>    Entries.clear();
> +  uint32_t StartingOffset = *OffsetPtr;
>    while (*OffsetPtr < End) {
>      ListEntryType Entry;
> -    if (Error E = Entry.extract(Data, End, OffsetPtr))
> +    if (Error E =
> +            Entry.extract(Data, End, Version, SectionName, OffsetPtr,
> isDWO))
>        return E;
> +    if (Version < 5)
> +      Entry.Offset = StartingOffset;
>      Entries.push_back(Entry);
> -    if (Entry.isSentinel())
> +    if (Entry.isEndOfList())
>        return Error::success();
>    }
>    return createStringError(errc::illegal_byte_sequence,
> @@ -232,31 +297,47 @@ Error DWARFListType<ListEntryType>::extr
>                       SectionName.data(), HeaderOffset);
>  }
>
> +template <typename ListEntryType>
> +void DWARFListType<ListEntryType>::dump(raw_ostream &OS, DWARFContext *C,
> +                                        uint8_t AddressSize,
> +                                        uint64_t BaseAddress, unsigned
> Indent,
> +                                        uint16_t Version,
> +                                        size_t MaxEncodingStringLength,
> +                                        DIDumpOptions DumpOpts,
> +
> llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
> LookupPooledAddress) const {
> +  uint64_t CurrentBase = BaseAddress;
> +  for (const auto &Entry : Entries)
> +    Entry.dump(OS, C, AddressSize, CurrentBase, Indent, Version,
> +               MaxEncodingStringLength, DumpOpts, LookupPooledAddress);
> +}
> +
>  template <typename DWARFListType>
>  void DWARFListTableBase<DWARFListType>::dump(
>      raw_ostream &OS,
>      llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
>          LookupPooledAddress,
>      DIDumpOptions DumpOpts) const {
> -  Header.dump(OS, DumpOpts);
> -  OS << HeaderString << "\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 : ListMap)
> -      for (const auto &Entry : List.second.getEntries())
> -        MaxEncodingStringLength =
> -            std::max(MaxEncodingStringLength,
> -
>  dwarf::RangeListEncodingString(Entry.EntryKind).size());
> +  // Don't dump the fake table header we create for DWARF v4 and earlier.
> +  if (Header.getVersion() > 4) {
> +    Header.dump(OS, DumpOpts);
> +    OS << HeaderString << '\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.
> +    if (DumpOpts.Verbose)
> +      for (const auto &List : ListMap)
> +        for (const auto &Entry : List.second.getEntries())
> +          MaxEncodingStringLength = std::max(
> +              MaxEncodingStringLength,
> EncodingString(Entry.EntryKind).size());
>    }
>
>    uint64_t CurrentBase = 0;
>    for (const auto &List : ListMap)
> -    for (const auto &Entry : List.second.getEntries())
> -      Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase,
> -                 DumpOpts, LookupPooledAddress);
> +    List.second.dump(OS, Ctx, getAddrSize(), CurrentBase, 0,
> +                     Header.getVersion(), MaxEncodingStringLength,
> DumpOpts,
> +                     LookupPooledAddress);
>  }
>
>  template <typename DWARFListType>
> @@ -269,11 +350,11 @@ DWARFListTableBase<DWARFListType>::findL
>
>    // Extract the list from the section and enter it into the list map.
>    DWARFListType List;
> -  uint32_t End = getHeaderOffset() + Header.length();
> +  uint32_t End = getHeaderOffset() + getLength();
>    uint32_t StartingOffset = Offset;
> -  if (Error E =
> -          List.extract(Data, getHeaderOffset(), End, &Offset,
> -                       Header.getSectionName(),
> Header.getListTypeString()))
> +  if (Error E = List.extract(Data, getHeaderOffset(), End,
> Header.getVersion(),
> +                             &Offset, Header.getSectionName(),
> +                             Header.getListTypeString(), isDWO))
>      return std::move(E);
>    ListMap[StartingOffset] = List;
>    return List;
>
> 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=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h (original)
> +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFUnit.h Mon Oct 29
> 15:16:47 2018
> @@ -17,7 +17,6 @@
>  #include "llvm/ADT/iterator_range.h"
>  #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"
> @@ -312,12 +311,6 @@ public:
>      return DataExtractor(StringSection, false, 0);
>    }
>
> -  /// Extract the range list referenced by this compile unit from the
> -  /// .debug_ranges section. If the extraction is unsuccessful, an error
> -  /// is returned. Successful extraction requires that the compile unit
> -  /// has already been extracted.
> -  Error extractRangeList(uint32_t RangeListOffset,
> -                         DWARFDebugRangeList &RangeList) const;
>    void clear();
>
>    const Optional<StrOffsetsContributionDescriptor> &
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/CMakeLists.txt?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/CMakeLists.txt (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/CMakeLists.txt Mon Oct 29 15:16:47 2018
> @@ -15,7 +15,6 @@ add_llvm_library(LLVMDebugInfoDWARF
>    DWARFDebugLoc.cpp
>    DWARFDebugMacro.cpp
>    DWARFDebugPubTable.cpp
> -  DWARFDebugRangeList.cpp
>    DWARFDebugRnglists.cpp
>    DWARFDie.cpp
>    DWARFExpression.cpp
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Mon Oct 29 15:16:47
> 2018
> @@ -25,7 +25,6 @@
>  #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"
> @@ -268,26 +267,31 @@ static void dumpAddrSection(raw_ostream
>    }
>  }
>
> -// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
> +// 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>
>  static void
> -dumpRnglistsSection(raw_ostream &OS, DWARFDataExtractor &rnglistData,
> -
> llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
> -                        LookupPooledAddress,
> -                    DIDumpOptions DumpOpts) {
> +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) {
>    uint32_t Offset = 0;
> -  while (rnglistData.isValidOffset(Offset)) {
> -    llvm::DWARFDebugRnglistTable Rnglists;
> -    uint32_t TableOffset = Offset;
> -    if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
> +  while (ListData.isValidOffset(Offset)) {
> +    ListTable Table(C, SectionName, isDWO);
> +    if (Error Err = Table.extract(ListData, MaxVersion, &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)
> +      // If table extraction set Offset to 0, it indicates that we cannot
> +      // continue to read the section.
> +      if (Offset == 0)
>          break;
> -      Offset = TableOffset + Length;
> +      // In DWARF v4 and earlier, dump as much of the lists as we can.
> +      if (MaxVersion < 5)
> +        Table.dump(OS, LookupPooledAddress, DumpOpts);
>      } else {
> -      Rnglists.dump(OS, LookupPooledAddress, DumpOpts);
> +      Table.dump(OS, LookupPooledAddress, DumpOpts);
>      }
>    }
>  }
> @@ -508,22 +512,6 @@ void DWARFContext::dump(
>      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();
> @@ -532,18 +520,32 @@ void DWARFContext::dump(
>      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(), 0);
> -    dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
> +                                   isLittleEndian(), getCUAddrSize());
> +    dumpListSection<DWARFDebugRnglistTable>(OS, this, ".debug_rnglists",
> +                                            getMaxVersion(5), RnglistData,
> +                                            LookupPooledAddress,
> DumpOpts);
>    }
>
>    if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo",
> DIDT_ID_DebugRnglists,
>                   DObj->getRnglistsDWOSection().Data)) {
>      DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
> -                                   isLittleEndian(), 0);
> -    dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
> +                                   isLittleEndian(), getCUAddrSize());
> +    dumpListSection<DWARFDebugRnglistTable>(OS, this,
> ".debug_rnglists.dwo",
> +                                            getMaxVersion(5), RnglistData,
> +                                            LookupPooledAddress,
> DumpOpts);
>    }
>
>    if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
>
> Removed: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp?rev=345545&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp (removed)
> @@ -1,96 +0,0 @@
> -//===- 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;
> -}
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp Mon Oct 29
> 15:16:47 2018
> @@ -13,19 +13,30 @@
>  #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,
> -                              uint32_t *OffsetPtr) {
> +                              uint16_t Version, StringRef /* SectionName
> */,
> +                              uint32_t *OffsetPtr, bool /* isDWO */) {
>    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 &&
> -         "not enough space to extract a rangelist encoding");
> -  uint8_t Encoding = Data.getU8(OffsetPtr);
> +
> +  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);
> +  }
>
>    switch (Encoding) {
>    case dwarf::DW_RLE_end_of_list:
> @@ -61,6 +72,23 @@ Error RangeListEntry::extract(DWARFDataE
>      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);
> @@ -71,7 +99,7 @@ Error RangeListEntry::extract(DWARFDataE
>                           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 "
> @@ -79,18 +107,16 @@ Error RangeListEntry::extract(DWARFDataE
>                           *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, &SectionIndex);
> -    Value1 = Data.getRelocatedAddress(OffsetPtr);
> +    Value0 = Data.getRelocatedAddress(OffsetPtr);
> +    Value1 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
>      break;
> -  }
>    case dwarf::DW_RLE_start_length: {
>      uint32_t PreviousOffset = *OffsetPtr - 1;
>      Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
> @@ -173,8 +199,9 @@ DWARFDebugRnglist::getAbsoluteRanges(llv
>  }
>
>  void RangeListEntry::dump(
> -    raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
> -    uint64_t &CurrentBase, DIDumpOptions DumpOpts,
> +    raw_ostream &OS, DWARFContext *, uint8_t AddrSize, uint64_t
> &CurrentBase,
> +    unsigned Indent, uint16_t Version, uint8_t MaxEncodingStringLength,
> +    DIDumpOptions DumpOpts,
>      llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
>          LookupPooledAddress) const {
>    auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
> @@ -187,21 +214,34 @@ void RangeListEntry::dump(
>      }
>    };
>
> +  // 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);
> -    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 << ": ";
> +    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 << ": ";
> +    }
>    }
>
>    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: {
> @@ -217,6 +257,13 @@ void RangeListEntry::dump(
>    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);
> @@ -226,6 +273,11 @@ void RangeListEntry::dump(
>      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);
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp Mon Oct 29 15:16:47 2018
> @@ -15,7 +15,6 @@
>  #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"
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFListTable.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFListTable.cpp?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFListTable.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFListTable.cpp Mon Oct 29 15:16:47
> 2018
> @@ -20,30 +20,43 @@ Error DWARFListTableHeader::extract(DWAR
>                                      uint32_t *OffsetPtr) {
>    HeaderOffset = *OffsetPtr;
>    // Read and verify the length field.
> -  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
> +  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;
>      return createStringError(errc::invalid_argument,
> -                       "section is not large enough to contain a "
> -                       "%s table length at offset 0x%" PRIx32,
> -                       SectionName.data(), *OffsetPtr);
> +                             "section is not large enough to contain a "
> +                             "%s table length at offset 0x%" PRIx32,
> +                             SectionName.data(), HeaderOffset);
> +  }
>    // TODO: Add support for DWARF64.
>    HeaderData.Length = Data.getU32(OffsetPtr);
> -  if (HeaderData.Length == 0xffffffffu)
> +  if (HeaderData.Length == 0xffffffffu) {
> +    *OffsetPtr = 0;
>      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 (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
> +  if (TableLength < sizeof(Header)) {
> +    *OffsetPtr = End;
>      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, 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);
> +                             "%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);
> +  }
>
>    HeaderData.Version = Data.getU16(OffsetPtr);
>    HeaderData.AddrSize = Data.getU8(OffsetPtr);
> @@ -51,27 +64,36 @@ Error DWARFListTableHeader::extract(DWAR
>    HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
>
>    // Perform basic validation of the remaining header fields.
> -  if (HeaderData.Version != 5)
> +  if (HeaderData.Version != 5) {
> +    *OffsetPtr = End;
>      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)
> +                             "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;
>      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)
> +  }
> +  if (HeaderData.SegSize != 0) {
> +    *OffsetPtr = End;
>      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))
> +                HeaderData.OffsetEntryCount * sizeof(uint32_t)) {
> +    *OffsetPtr = End;
>      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));
> @@ -101,9 +123,11 @@ void DWARFListTableHeader::dump(raw_ostr
>    }
>  }
>
> -uint32_t DWARFListTableHeader::length() const {
> +uint32_t DWARFListTableHeader::getTableLength() 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 + sizeof(uint32_t);
> +  return HeaderData.Length + (HeaderData.Version > 4) * sizeof(uint32_t);
>  }
>
> Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp?rev=345546&r1=345545&r2=345546&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp (original)
> +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp Mon Oct 29 15:16:47 2018
> @@ -296,13 +296,16 @@ bool DWARFUnitHeader::extract(DWARFConte
>    return true;
>  }
>
> -// Parse the rangelist table header, including the optional array of
> offsets
> +// Parse a list table header, including the optional array of offsets
>  // following it (DWARF v5 and later).
> -static Expected<DWARFDebugRnglistTable>
> -parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
> +template <typename DWARFListTable>
> +static Expected<DWARFListTable>
> +parseListTableHeader(DWARFDataExtractor DA, DWARFContext *C,
> +                     StringRef SectionName, uint32_t Offset, bool isDWO) {
>    // 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"
> @@ -310,20 +313,46 @@ parseRngListTableHeader(DWARFDataExtract
>                                 Offset);
>      Offset -= 12U;
>    }
> -  llvm::DWARFDebugRnglistTable Table;
>    if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
>      return std::move(E);
>    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);
> +// 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;
>  }
>
>  void DWARFUnit::clear() {
> @@ -437,35 +466,24 @@ size_t DWARFUnit::extractDIEsIfNeeded(bo
>
>      // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections
> to
>      // describe address ranges.
> +    StringRef RangeSectionName = ".debug_ranges";
>      if (getVersion() >= 5) {
> -      if (IsDWO)
> +      if (IsDWO) {
> +        RangeSectionName = ".debug_rnglists.dwo";
>          setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(),
> 0);
> -      else
> +      } else {
> +        RangeSectionName = ".debug_rnglists";
>          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,
> -
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20181106/61a187dd/attachment.html>


More information about the llvm-commits mailing list