Index: include/llvm/BinaryFormat/Dwarf.def =================================================================== --- include/llvm/BinaryFormat/Dwarf.def +++ include/llvm/BinaryFormat/Dwarf.def @@ -844,11 +844,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/DWARFDebugRnglists.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -0,0 +1,61 @@ +//===- 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 +#include + +namespace llvm { + +class raw_ostream; + +class DWARFDebugRnglists { +public: + struct BoundedRange { + uint64_t Start; + uint64_t End; + + BoundedRange(uint64_t S, uint64_t E) : Start(S), End(E) {} + }; + using RangeList = std::vector; + +private: + struct Header { + /// The total length of the entries for this table, not including the length + /// field itself. + uint32_t Length; + /// 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(); + bool extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); + void dump(raw_ostream &OS) const; +}; + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H Index: include/llvm/DebugInfo/DWARF/DWARFObject.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFObject.h +++ include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -44,6 +44,7 @@ virtual const DWARFSection &getLineSection() const { return Dummy; } 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: lib/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- lib/DebugInfo/DWARF/CMakeLists.txt +++ lib/DebugInfo/DWARF/CMakeLists.txt @@ -14,6 +14,7 @@ DWARFDebugMacro.cpp DWARFDebugPubTable.cpp DWARFDebugRangeList.cpp + DWARFDebugRnglists.cpp DWARFDie.cpp DWARFExpression.cpp DWARFFormValue.cpp 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" @@ -480,6 +481,16 @@ rangeList.dump(OS); } + if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists, + DObj->getRnglistsSection().Data)) { + DWARFDataExtractor rnglistData(*DObj, DObj->getRnglistsSection(), + isLittleEndian(), 0); + DWARFDebugRnglists Set; + uint32_t Offset = 0; + while (Set.extract(rnglistData, &Offset)) + Set.dump(OS); + } + if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, DObj->getPubNamesSection())) DWARFDebugPubTable(DObj->getPubNamesSection(), isLittleEndian(), false) @@ -1146,6 +1157,7 @@ DWARFSectionMap LocSection; DWARFSectionMap LineSection; DWARFSectionMap RangeSection; + DWARFSectionMap RnglistsSection; DWARFSectionMap StringOffsetSection; DWARFSectionMap InfoDWOSection; DWARFSectionMap LineDWOSection; @@ -1165,6 +1177,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) @@ -1452,6 +1465,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/DWARFDebugRnglists.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -0,0 +1,124 @@ +//===- 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/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void DWARFDebugRnglists::clear() { + std::memset(&HeaderData, 0, sizeof(Header)); + Offsets.clear(); + Ranges.clear(); +} + +bool DWARFDebugRnglists::extract(DWARFDataExtractor Data, uint32_t *OffsetPtr) { + clear(); + if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(Header))) { + return false; + } + + uint32_t TableOffset = *OffsetPtr; + + // TODO: Add support for DWARF64. + HeaderData.Length = Data.getU32(OffsetPtr); + HeaderData.Version = Data.getU16(OffsetPtr); + HeaderData.AddrSize = Data.getU8(OffsetPtr); + HeaderData.SegSize = Data.getU8(OffsetPtr); + HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); + + uint64_t End = TableOffset + HeaderData.Length + sizeof(uint32_t); + + // Perform basic validation of the header fields. + if (!Data.isValidOffsetForDataOfSize(TableOffset, End - TableOffset) || + (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)) { + clear(); + return false; + } + if (End < TableOffset + sizeof(HeaderData) + + HeaderData.OffsetEntryCount * sizeof(uint32_t)) { + clear(); + return false; + } + + Data.setAddressSize(HeaderData.AddrSize); + + for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) + Offsets.push_back(Data.getU32(OffsetPtr)); + + std::vector CurrentRanges; + while (Data.isValidOffset(*OffsetPtr) && *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: + case dwarf::DW_RLE_startx_endx: + case dwarf::DW_RLE_startx_length: + case dwarf::DW_RLE_offset_pair: + case dwarf::DW_RLE_base_address: + llvm_unreachable("unimplemented rnglists encoding"); + break; + case dwarf::DW_RLE_start_end: { + uint64_t Start = Data.getAddress(OffsetPtr); + uint64_t End = Data.getAddress(OffsetPtr); + CurrentRanges.emplace_back(Start, End); + break; + } + case dwarf::DW_RLE_start_length: { + uint64_t Start = Data.getAddress(OffsetPtr); + uint64_t Length = Data.getULEB128(OffsetPtr); + CurrentRanges.emplace_back(Start, Start + Length); + break; + } + default: + errs() << "Unknown rnglists encoding " << uint32_t(Encoding) << "\n"; + Ranges.insert(Ranges.end(), CurrentRanges); + return false; + } + } + + // 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 OffsetPtr does not indicate the End offset, we must have reached the end + // of the buffer before we got to the end of the section, or read past the end + // of the section. + return CurrentRanges.empty() && *OffsetPtr == End; +} + +void DWARFDebugRnglists::dump(raw_ostream &OS) const { + 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.Start, HexWidth, HexWidth, Entry.End); + } + OS << "\n"; + } +} Index: test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_invalid_header.s =================================================================== --- test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_invalid_header.s +++ test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_invalid_header.s @@ -0,0 +1,6 @@ +.section .debug_rnglists,"",@progbits +.long 7 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.byte 0, 0, 0 # Offset entry count Index: test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_invalid_offset_entries.s =================================================================== --- test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_invalid_offset_entries.s +++ test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_invalid_offset_entries.s @@ -0,0 +1,11 @@ +.section .debug_rnglists,"",@progbits +.long 26 # Table length +.short 5 # Version +.byte 8 # Address size +.byte 0 # Segment selector size +.long 0x12345678 # 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 Index: test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_long_length.s =================================================================== --- test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_long_length.s +++ test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_long_length.s @@ -0,0 +1,11 @@ +.section .debug_rnglists,"",@progbits +.long 27 # Table length - 1 greater than actual section 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 Index: test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_short_length.s =================================================================== --- test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_short_length.s +++ test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_short_length.s @@ -0,0 +1,11 @@ +.section .debug_rnglists,"",@progbits +.long 25 # Table length - 1 smaller than actual section 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 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,60 @@ +# 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 = 0x0000002b, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# CHECK-NEXT: Ranges: +# CHECK-NEXT: [0x0000000000000000, 0x0000000000000000) +# CHECK-NEXT: [0x0000000000000002, 0x0000000000000006) +# CHECK-NEXT: + +.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 43 # 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 0, 0 # Start, end address +.byte 6 # DW_RLE_start_end +.quad 0x2, 0x6 # Start, end address +.byte 0 # DW_RLE_end_of_list 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,16 @@ +# 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 = 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 +.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_invalid.test =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.test +++ test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.test @@ -0,0 +1,11 @@ +# RUN: llvm-mc %S/Inputs/debug_rnglists_invalid_header.s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - | FileCheck %s +# RUN: llvm-mc %S/Inputs/debug_rnglists_invalid_offset_entries.s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - | FileCheck %s +# RUN: llvm-mc %S/Inputs/debug_rnglists_long_length.s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - | FileCheck %s +# RUN: llvm-mc %S/Inputs/debug_rnglists_short_length.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 Index: test/tools/llvm-dwarfdump/X86/debug_rnglists_unknown_encoding.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_rnglists_unknown_encoding.s +++ test/tools/llvm-dwarfdump/X86/debug_rnglists_unknown_encoding.s @@ -0,0 +1,22 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - 2> %t.err | FileCheck %s +# RUN: FileCheck %s --input-file=%t.err --check-prefix=ERROR + +# CHECK: .debug_rnglists contents: +# CHECK-NOT: Range List Header + +# ERROR: Unknown rnglists encoding 42 + +.section .debug_rnglists,"",@progbits + +# First table +.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