Index: include/llvm/BinaryFormat/Dwarf.def =================================================================== --- include/llvm/BinaryFormat/Dwarf.def +++ include/llvm/BinaryFormat/Dwarf.def @@ -845,11 +845,12 @@ HANDLE_DWARF_SECTION(DebugFrame, ".debug_frame", "debug-frame") HANDLE_DWARF_SECTION(DebugMacro, ".debug_macro", "debug-macro") HANDLE_DWARF_SECTION(DebugNames, ".debug_names", "debug-names") -HANDLE_DWARF_SECTION(DebugRanges, ".debug_ranges", "debug-ranges") HANDLE_DWARF_SECTION(DebugPubnames, ".debug_pubnames", "debug-pubnames") HANDLE_DWARF_SECTION(DebugPubtypes, ".debug_pubtypes", "debug-pubtypes") HANDLE_DWARF_SECTION(DebugGnuPubnames, ".debug_gnu_pubnames", "debug-gnu-pubnames") HANDLE_DWARF_SECTION(DebugGnuPubtypes, ".debug_gnu_pubtypes", "debug-gnu-pubtypes") +HANDLE_DWARF_SECTION(DebugRanges, ".debug_ranges", "debug-ranges") +HANDLE_DWARF_SECTION(DebugRnglists, ".debug_rnglists", "debug-rnglists") HANDLE_DWARF_SECTION(DebugStr, ".debug_str", "debug-str") HANDLE_DWARF_SECTION(DebugStrOffsets, ".debug_str_offsets", "debug-str-offsets") HANDLE_DWARF_SECTION(DebugCUIndex, ".debug_cu_index", "debug-cu-index") Index: include/llvm/DebugInfo/DWARF/DWARFAddressRange.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFAddressRange.h +++ include/llvm/DebugInfo/DWARF/DWARFAddressRange.h @@ -0,0 +1,66 @@ +//===- DWARFAddressRange.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_DWARFADDRESSRANGE_H +#define LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H + +#include +#include +#include + +namespace llvm { + +class raw_ostream; + +struct DWARFAddressRange { + uint64_t LowPC; + uint64_t HighPC; + uint64_t SectionIndex; + + DWARFAddressRange() = default; + + /// Used for unit testing. + DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) + : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} + + /// Returns true if LowPC is smaller or equal to HighPC. This accounts for + /// dead-stripped ranges. + bool valid() const { return LowPC <= HighPC; } + + /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). + bool intersects(const DWARFAddressRange &RHS) const { + // Empty ranges can't intersect. + if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) + return false; + return (LowPC < RHS.HighPC) && (HighPC > RHS.LowPC); + } + + /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). + bool contains(const DWARFAddressRange &RHS) const { + if (LowPC <= RHS.LowPC && RHS.LowPC <= HighPC) + return LowPC <= RHS.HighPC && RHS.HighPC <= HighPC; + return false; + } + + void dump(raw_ostream &OS, uint32_t AddressSize) const; +}; + +static inline bool operator<(const DWARFAddressRange &LHS, + const DWARFAddressRange &RHS) { + return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); +} + +raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); + +/// DWARFAddressRangesVector - represents a set of absolute address ranges. +using DWARFAddressRangesVector = std::vector; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H Index: include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -10,8 +10,8 @@ #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 "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include #include #include @@ -21,49 +21,6 @@ struct BaseAddress; class raw_ostream; -struct DWARFAddressRange { - uint64_t LowPC; - uint64_t HighPC; - uint64_t SectionIndex; - - DWARFAddressRange() = default; - - /// Used for unit testing. - DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) - : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} - - /// Returns true if LowPC is smaller or equal to HighPC. This accounts for - /// dead-stripped ranges. - bool valid() const { return LowPC <= HighPC; } - - /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). - bool intersects(const DWARFAddressRange &RHS) const { - // Empty ranges can't intersect. - if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) - return false; - return (LowPC < RHS.HighPC) && (HighPC > RHS.LowPC); - } - - /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). - bool contains(const DWARFAddressRange &RHS) const { - if (LowPC <= RHS.LowPC && RHS.LowPC <= HighPC) - return LowPC <= RHS.HighPC && RHS.HighPC <= HighPC; - return false; - } - - void dump(raw_ostream &OS, uint32_t AddressSize) const; -}; - -static inline bool operator<(const DWARFAddressRange &LHS, - const DWARFAddressRange &RHS) { - return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); -} - -raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); - -/// DWARFAddressRangesVector - represents a set of absolute address ranges. -using DWARFAddressRangesVector = std::vector; - class DWARFDebugRangeList { public: struct RangeListEntry { Index: include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -0,0 +1,59 @@ +//===- DWARFDebugRnglists.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_DWARFDEBUGRNGLISTS_H +#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H + +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include +#include + +namespace llvm { + +class Error; +class raw_ostream; + +class DWARFDebugRnglists { +private: + struct Header { + /// The total length of the entries for this table, not including the length + /// field itself. + uint32_t Length = 0; + /// The DWARF version number. + uint16_t Version; + /// The size in bytes of an address on the target architecture. For + /// segmented addressing, this is the size of the offset portion of the + /// address. + 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; + /// The number of offsets that follow the header before the range lists. + uint32_t OffsetEntryCount; + }; + + Header HeaderData; + std::vector Offsets; + std::vector Ranges; + +public: + void clear(); + Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); + void dump(raw_ostream &OS) const; + + /// Returns the length of this table, including the length field, or 0 if the + /// length has not been determined (e.g. because the table has not yet been + /// parsed, or there was a problem in parsing). + uint64_t length() const; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H Index: include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDie.h +++ include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -16,9 +16,9 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFAttribute.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include #include #include Index: include/llvm/DebugInfo/DWARF/DWARFObject.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFObject.h +++ include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -45,6 +45,7 @@ virtual StringRef getLineStringSection() const { return ""; } virtual StringRef getStringSection() const { return ""; } virtual const DWARFSection &getRangeSection() const { return Dummy; } + virtual const DWARFSection &getRnglistsSection() const { return Dummy; } virtual StringRef getMacinfoSection() const { return ""; } virtual StringRef getPubNamesSection() const { return ""; } virtual StringRef getPubTypesSection() const { return ""; } Index: include/llvm/DebugInfo/DWARF/DWARFVerifier.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -11,7 +11,7 @@ #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H #include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include Index: lib/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- lib/DebugInfo/DWARF/CMakeLists.txt +++ lib/DebugInfo/DWARF/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_library(LLVMDebugInfoDWARF DWARFAbbreviationDeclaration.cpp + DWARFAddressRange.cpp DWARFAcceleratorTable.cpp DWARFCompileUnit.cpp DWARFContext.cpp @@ -14,6 +15,7 @@ DWARFDebugMacro.cpp DWARFDebugPubTable.cpp DWARFDebugRangeList.cpp + DWARFDebugRnglists.cpp DWARFDie.cpp DWARFExpression.cpp DWARFFormValue.cpp Index: lib/DebugInfo/DWARF/DWARFAddressRange.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFAddressRange.cpp +++ lib/DebugInfo/DWARF/DWARFAddressRange.cpp @@ -0,0 +1,26 @@ +//===- DWARFDebugAranges.cpp ------------------------------------*- C++ -*-===// +// +// 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/DWARFAddressRange.h" + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize) const { + + OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC) + << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2, HighPC); +} + +raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) { + R.dump(OS, /* AddressSize */ 8); + return OS; +} Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -25,6 +25,7 @@ #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" #include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" @@ -490,6 +491,27 @@ rangeList.dump(OS); } + if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists, + DObj->getRnglistsSection().Data)) { + DWARFDataExtractor rnglistData(*DObj, DObj->getRnglistsSection(), + isLittleEndian(), 0); + uint32_t Offset = 0; + while (rnglistData.isValidOffset(Offset)) { + DWARFDebugRnglists Rnglists; + uint32_t TableOffset = Offset; + if (Error Err = Rnglists.extract(rnglistData, &Offset)) { + errs() << "error: " + toString(std::move(Err)) << '\n'; + uint64_t Length = Rnglists.length(); + // Keep going after an error, if we can, assuming that the length field + // could be read. If it couldn't, stop reading the section. + if (Length == 0) + break; + Offset = TableOffset + Length; + } else + Rnglists.dump(OS); + } + } + if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, DObj->getPubNamesSection())) DWARFDebugPubTable(DObj->getPubNamesSection(), isLittleEndian(), false) @@ -1164,6 +1186,7 @@ DWARFSectionMap LocSection; DWARFSectionMap LineSection; DWARFSectionMap RangeSection; + DWARFSectionMap RnglistsSection; DWARFSectionMap StringOffsetSection; DWARFSectionMap InfoDWOSection; DWARFSectionMap LineDWOSection; @@ -1184,6 +1207,7 @@ .Case("debug_line", &LineSection) .Case("debug_str_offsets", &StringOffsetSection) .Case("debug_ranges", &RangeSection) + .Case("debug_rnglists", &RnglistsSection) .Case("debug_info.dwo", &InfoDWOSection) .Case("debug_loc.dwo", &LocDWOSection) .Case("debug_line.dwo", &LineDWOSection) @@ -1475,6 +1499,9 @@ const DWARFSection &getLineSection() const override { return LineSection; } StringRef getStringSection() const override { return StringSection; } const DWARFSection &getRangeSection() const override { return RangeSection; } + const DWARFSection &getRnglistsSection() const override { + return RnglistsSection; + } StringRef getMacinfoSection() const override { return MacinfoSection; } StringRef getPubNamesSection() const override { return PubNamesSection; } StringRef getPubTypesSection() const override { return PubTypesSection; } Index: lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -13,21 +13,9 @@ #include "llvm/Support/raw_ostream.h" #include #include -#include using namespace llvm; -void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize) const { - - OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC) - << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2, HighPC); -} - -raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) { - R.dump(OS, /* AddressSize */ 8); - return OS; -} - void DWARFDebugRangeList::clear() { Offset = -1U; AddressSize = 0; Index: lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -0,0 +1,192 @@ +//===- DWARFDebugRnglists.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/DWARFDebugRnglists.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; + +void DWARFDebugRnglists::clear() { + HeaderData = {}; + Offsets.clear(); + Ranges.clear(); +} + +template +static Error createError(char const *Fmt, const Ts &... Vals) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...); + return make_error(Stream.str(), inconvertibleErrorCode()); +} + +Error DWARFDebugRnglists::extract(DWARFDataExtractor Data, + uint32_t *OffsetPtr) { + clear(); + uint32_t TableOffset = *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 + 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", + TableOffset, length()); + uint64_t End = TableOffset + length(); + if (!Data.isValidOffsetForDataOfSize(TableOffset, End - TableOffset)) + return createError( + "section is not large enough to contain a .debug_rnglists table " + "of length 0x%" PRIx32 " at offset 0x%" PRIx32, + length(), TableOffset); + + 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, TableOffset); + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + return createError(".debug_rnglists table at offset 0x%" PRIx32 + " has unsupported address size %hhu", + TableOffset, HeaderData.AddrSize); + if (HeaderData.SegSize != 0) + return createError(".debug_rnglists table at offset 0x%" PRIx32 + " has unsupported segment selector size %" PRIu8, + TableOffset, HeaderData.SegSize); + if (End < TableOffset + 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", + TableOffset, HeaderData.OffsetEntryCount); + + Data.setAddressSize(HeaderData.AddrSize); + + for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) + Offsets.push_back(Data.getU32(OffsetPtr)); + + DWARFAddressRangesVector CurrentRanges; + while (*OffsetPtr < End) { + uint8_t Encoding = Data.getU8(OffsetPtr); + switch (Encoding) { + case dwarf::DW_RLE_end_of_list: + Ranges.insert(Ranges.end(), CurrentRanges); + CurrentRanges.clear(); + break; + // TODO: Support other encodings. + case dwarf::DW_RLE_base_addressx: + return createError("unsupported rnglists encoding DW_RLE_base_addressx " + "at offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_startx_endx: + return createError("unsupported rnglists encoding DW_RLE_startx_endx at " + "offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_startx_length: + return createError("unsupported rnglists encoding DW_RLE_startx_length " + "at offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_offset_pair: + return createError("unsupported rnglists encoding DW_RLE_offset_pair at " + "offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_base_address: + return createError("unsupported rnglists encoding DW_RLE_base_address at " + "offset 0x%" PRIx32, + *OffsetPtr - 1); + case dwarf::DW_RLE_start_end: { + if (End - *OffsetPtr < HeaderData.AddrSize * 2) + return createError("insufficient space remaining in table for " + "DW_RLE_start_end encoding " + "at offset 0x%" PRIx32, + *OffsetPtr - 1); + uint64_t Start = Data.getAddress(OffsetPtr); + uint64_t End = Data.getAddress(OffsetPtr); + CurrentRanges.emplace_back(Start, End); + break; + } + case dwarf::DW_RLE_start_length: { + uint32_t PreviousOffset = *OffsetPtr - 1; + uint64_t Start = Data.getAddress(OffsetPtr); + uint64_t Length = Data.getULEB128(OffsetPtr); + if (End < *OffsetPtr) + return createError("read past end of table when reading " + "DW_RLE_start_length encoding at offset 0x%" PRIx32, + PreviousOffset); + CurrentRanges.emplace_back(Start, Start + Length); + break; + } + default: + Ranges.insert(Ranges.end(), CurrentRanges); + return createError("unknown rnglists encoding 0x%" PRIx32 + " at offset 0x%" PRIx32, + uint32_t(Encoding), *OffsetPtr - 1); + } + } + + // If OffsetPtr does not indicate the End offset, then either the above loop + // terminated prematurely, or we encountered a malformed encoding, but did not + // report an error when we should have done. + assert(*OffsetPtr == End && + "did not detect malformed data or loop ended unexpectedly"); + + // If CurrentRanges is not empty, we have a malformed section, because we did + // not find a DW_RLE_end_of_list marker at the end of the last list. + if (!CurrentRanges.empty()) + return createError( + "no end of list marker detected at end of .debug_rnglists table " + "starting at offset 0x%" PRIx32, + TableOffset); + return Error::success(); +} + +void DWARFDebugRnglists::dump(raw_ostream &OS) const { + // TODO: Add verbose printing of the raw encodings. + OS << format("Range List Header: length = 0x%8.8x, version = 0x%4.4x, " + "addr_size = 0x%2.2x, seg_size = 0x%2.2x, offset_entry_count = " + "0x%8.8x\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.8x", Off); + OS << "\n]\n"; + } + OS << "Ranges:\n"; + + const uint32_t HexWidth = HeaderData.AddrSize * 2; + for (const auto &List : Ranges) { + for (const auto &Entry : List) + OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 ")\n", HexWidth, HexWidth, + Entry.LowPC, HexWidth, HexWidth, Entry.HighPC); + OS << "\n"; + } +} + +uint64_t DWARFDebugRnglists::length() const { + if (HeaderData.Length == 0) + return 0; + // TODO: DWARF64 support. + return HeaderData.Length + sizeof(uint32_t); +} Index: test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_short_section.s =================================================================== --- test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_short_section.s +++ test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_short_section.s @@ -0,0 +1,2 @@ +.section .debug_rnglists,"",@progbits +.byte 3, 0, 0 # Short section Index: test/tools/llvm-dwarfdump/X86/debug_rnglists.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists.s +++ test/tools/llvm-dwarfdump/X86/debug_rnglists.s @@ -0,0 +1,72 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - | FileCheck %s + +# CHECK: .debug_rnglists contents: +# CHECK-NEXT: Range List Header: length = 0x0000003f, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000002 +# CHECK-NEXT: Offsets: [ +# CHECK-NEXT: 0x00000008 +# CHECK-NEXT: 0x0000002b +# CHECK-NEXT: ] +# CHECK-NEXT: Ranges: +# CHECK-NEXT: [0x0000000000000010, 0x0000000000000020) +# CHECK-NEXT: [0x0000000000000025, 0x00000000000000a5) +# CHECK-NEXT: +# CHECK-NEXT: [0x0000000000000100, 0x0000000000000200) +# CHECK-NEXT: +# CHECK-NEXT: Range List Header: length = 0x0000001b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000000 +# CHECK-NEXT: Ranges: +# CHECK-NEXT: [0x00000000, 0x00000000) +# CHECK-NEXT: [0x00000002, 0x00000006) +# CHECK-NEXT: +# CHECK-NEXT: Range List Header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# CHECK-NOT: Offsets: +# CHECK: Ranges: +# CHECK-NOT: [ +# CHECK-NOT: Range List Header: + +.section .debug_rnglists,"",@progbits + +# First table +.long 63 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 2 # Offset entry count + +# Offset array +.long 8 # Offset Entry 0 +.long 43 # Offset Entry 1 + +# First range list +.byte 6 # DW_RLE_start_end +.quad 0x10, 0x20 # Start, end address +.byte 7 # DW_RLE_start_length +.quad 0x25 # Start address +.byte 0x80, 0x01 # Length +.byte 0 # DW_RLE_end_of_list + +# Second range list +.byte 6 # DW_RLE_start_end +.quad 0x100, 0x200 # Start, end address +.byte 0 # DW_RLE_end_of_list + +# Second table +.long 27 # Table length +.short 5 # Version +.byte 4 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 6 # DW_RLE_start_end +.long 0, 0 # Start, end address +.byte 6 # DW_RLE_start_end +.long 0x2, 0x6 # Start, end address +.byte 0 # DW_RLE_end_of_list + +# Third (empty) table +.long 8 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count Index: test/tools/llvm-dwarfdump/X86/debug_rnglists_empty.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists_empty.s +++ test/tools/llvm-dwarfdump/X86/debug_rnglists_empty.s @@ -0,0 +1,7 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - | FileCheck %s +# CHECK: .debug_rnglists contents: +# CHECK-NOT: Range List Header: +# CHECK-NOT: error: + +.section .debug_rnglists,"",@progbits Index: test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s +++ test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s @@ -0,0 +1,161 @@ +# RUN: llvm-mc %S/Inputs/debug_rnglists_short_section.s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | FileCheck %s --check-prefix=SHORT +# SHORT-NOT: error: +# SHORT-NOT: Range List Header +# SHORT: error: section is not large enough to contain a .debug_rnglists table length at offset 0 +# SHORT-NOT: Range List Header +# SHORT-NOT: error: + +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - 2> %t.err | FileCheck %s --check-prefix=GOOD +# RUN: FileCheck %s --input-file %t.err + +# GOOD: .debug_rnglists contents: +# GOOD-NEXT: Range List Header: length = 0x0000001e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000001 +# GOOD-NEXT: Offsets: [ +# GOOD-NEXT: 0x00000004 +# GOOD-NEXT: ] +# GOOD-NEXT: Ranges: +# GOOD-NEXT: [0x0000000000000010, 0x0000000000000020) +# GOOD-NEXT: +# GOOD-NEXT: Range List Header: length = 0x0000001a, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# GOOD-NEXT: Ranges: +# GOOD-NEXT: [0x0000000000000030, 0x0000000000000040) +# GOOD-NEXT: +# GOOD-NOT: Range List Header + +# CHECK-NOT: error: +# CHECK: error: .debug_rnglists table at offset 0x22 has too small length (0xb) to contain a complete header +# CHECK-NEXT: error: unrecognised .debug_rnglists table version 4 in table at offset 0x2d +# CHECK-NEXT: error: .debug_rnglists table at offset 0x39 has unsupported address size 2 +# CHECK-NEXT: error: .debug_rnglists table at offset 0x45 has unsupported segment selector size 4 +# CHECK-NEXT: error: .debug_rnglists table at offset 0x51 has more offset entries (12345678) than there is space for +# CHECK-NEXT: error: insufficient space remaining in table for DW_RLE_start_end encoding at offset 0x69 +# CHECK-NEXT: error: read past end of table when reading DW_RLE_start_length encoding at offset 0x82 +# CHECK-NEXT: error: unknown rnglists encoding 0x2a at offset 0x98 +# CHECK-NEXT: error: no end of list marker detected at end of .debug_rnglists table starting at offset 0xaa +# CHECK-NEXT: error: section is not large enough to contain a .debug_rnglists table of length 0x1f at offset 0xe5 +# CHECK-NOT: error: + +.section .debug_rnglists,"",@progbits + +# Table 1 (good) +.long 30 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 1 # Offset entry count + +# Offsets +.long 4 + +# First range list +.byte 6 # DW_RLE_start_length +.quad 0x10, 0x20 # Encoding payload +.byte 0 # DW_RLE_end_of_list + +# Table 2 (length too small for header) +.long 7 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.byte 0, 0, 0 # Truncated offset entry count + +# Table 3 (unknown version) +.long 8 # Table length +.short 4 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# Table 4 (unsupported address size) +.long 8 # Table length +.short 5 # Version +.byte 2 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# Table 5 (unsupported segment selector size) +.long 8 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 4 # Segment selector size +.long 0 # Offset entry count + +# Table 6 (bad offset entry count) +.long 8 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 12345678 # Offset entry count + +# Table 7 (malformed DW_RLE_start_end) +.long 21 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 6 # DW_RLE_start_end +.quad 1 # Start address +.long 4 # Truncated end address + +# Table 8 (malformed DW_RLE_start_length) +.long 18 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 7 # DW_RLE_start_length +.quad 1 # Start address +.byte 0xFF # Length - invalid ULEB, so will continue reading past the end + +# Table 9 (unknown encoding) +.long 26 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 42 # Unknown encoding +.quad 0x10, 0x20 # Encoding payload +.byte 0 # DW_RLE_end_of_list + +# Table 10 (missing end of list marker) +.long 25 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 6 # DW_RLE_start_length +.quad 0x10, 0x20 # Encoding payload + +# Table 11 (good) +.long 26 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 6 # DW_RLE_start_length +.quad 0x30, 0x40 # Encoding payload +.byte 0 # DW_RLE_end_of_list + +# Table 12 (length too long) +.long 27 # Table length - 1 greater than actual contents +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0 # Offset entry count + +# First range list +.byte 6 # DW_RLE_start_end +.quad 1, 2 # Start, end address +.byte 0 # DW_RLE_end_of_list