Index: llvm/trunk/include/llvm/BinaryFormat/Dwarf.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/Dwarf.h +++ llvm/trunk/include/llvm/BinaryFormat/Dwarf.h @@ -423,6 +423,7 @@ StringRef LNStandardString(unsigned Standard); StringRef LNExtendedString(unsigned Encoding); StringRef MacinfoString(unsigned Encoding); +StringRef RangeListEncodingString(unsigned Encoding); StringRef CallFrameString(unsigned Encoding); StringRef ApplePropertyString(unsigned); StringRef UnitTypeString(unsigned); Index: llvm/trunk/include/llvm/DebugInfo/DIContext.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DIContext.h +++ llvm/trunk/include/llvm/DebugInfo/DIContext.h @@ -160,6 +160,7 @@ bool ShowForm = false; bool SummarizeTypes = false; bool Verbose = false; + bool DisplayRawContents = false; /// Return default option set for printing a single DIE without children. static DIDumpOptions getForSingleDIE() { Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H #define LLVM_DEBUGINFO_DWARF_DWARFADDRESSRANGE_H +#include "llvm/DebugInfo/DIContext.h" #include #include #include @@ -48,7 +49,8 @@ return false; } - void dump(raw_ostream &OS, uint32_t AddressSize) const; + void dump(raw_ostream &OS, uint32_t AddressSize, + DIDumpOptions DumpOpts = {}) const; }; static inline bool operator<(const DWARFAddressRange &LHS, Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -10,6 +10,7 @@ #ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H #define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H +#include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include @@ -39,14 +40,35 @@ uint32_t OffsetEntryCount; }; +public: + struct RangeListEntry { + /// The offset at which the entry is located in the section. + const uint32_t Offset; + /// The DWARF encoding (DW_RLE_*). + const uint8_t EntryKind; + /// The values making up the range list entry. Most represent a range with + /// a start and end address or a start address and a length. Others are + /// single value base addresses or end-of-list with no values. The unneeded + /// values are semantically undefined, but initialized to 0. + const uint64_t Value0; + const uint64_t Value1; + }; + + using DWARFRangeList = std::vector; + +private: + uint32_t HeaderOffset; Header HeaderData; std::vector Offsets; - std::vector Ranges; + std::vector Ranges; + // The length of the longest encoding string we encountered during parsing. + uint8_t MaxEncodingStringLength = 0; public: void clear(); Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr); - void dump(raw_ostream &OS) const; + uint32_t getHeaderOffset() const { return HeaderOffset; } + void dump(raw_ostream &OS, DIDumpOptions DumpOpts) 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 Index: llvm/trunk/lib/BinaryFormat/Dwarf.cpp =================================================================== --- llvm/trunk/lib/BinaryFormat/Dwarf.cpp +++ llvm/trunk/lib/BinaryFormat/Dwarf.cpp @@ -444,6 +444,17 @@ .Default(DW_MACINFO_invalid); } +StringRef llvm::dwarf::RangeListEncodingString(unsigned Encoding) { + switch (Encoding) { + default: + return StringRef(); +#define HANDLE_DW_RLE(ID, NAME) \ + case DW_RLE_##NAME: \ + return "DW_RLE_" #NAME; +#include "llvm/BinaryFormat/Dwarf.def" + } +} + StringRef llvm::dwarf::CallFrameString(unsigned Encoding) { switch (Encoding) { default: Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFAddressRange.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFAddressRange.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFAddressRange.cpp @@ -14,10 +14,13 @@ using namespace llvm; -void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize) const { +void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize, + DIDumpOptions DumpOpts) const { - OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC) - << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2, HighPC); + OS << (DumpOpts.DisplayRawContents ? " " : "["); + OS << format("0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC) + << format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2, HighPC); + OS << (DumpOpts.DisplayRawContents ? "" : ")"); } raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) { Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -509,8 +509,9 @@ if (Length == 0) break; Offset = TableOffset + Length; - } else - Rnglists.dump(OS); + } else { + Rnglists.dump(OS, DumpOpts); + } } } Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -33,7 +33,7 @@ Error DWARFDebugRnglists::extract(DWARFDataExtractor Data, uint32_t *OffsetPtr) { clear(); - uint32_t TableOffset = *OffsetPtr; + HeaderOffset = *OffsetPtr; // Read and verify the length field. if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) @@ -42,17 +42,21 @@ *OffsetPtr); // TODO: Add support for DWARF64. HeaderData.Length = Data.getU32(OffsetPtr); + if (HeaderData.Length == 0xffffffffu) + return createError( + "DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32, + HeaderOffset); 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()); - uint32_t End = TableOffset + length(); - if (!Data.isValidOffsetForDataOfSize(TableOffset, End - TableOffset)) + HeaderOffset, length()); + uint32_t End = HeaderOffset + length(); + if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) return createError( "section is not large enough to contain a .debug_rnglists table " "of length 0x%" PRIx32 " at offset 0x%" PRIx32, - length(), TableOffset); + length(), HeaderOffset); HeaderData.Version = Data.getU16(OffsetPtr); HeaderData.AddrSize = Data.getU8(OffsetPtr); @@ -63,32 +67,37 @@ if (HeaderData.Version != 5) return createError("unrecognised .debug_rnglists table version %" PRIu16 " in table at offset 0x%" PRIx32, - HeaderData.Version, TableOffset); + HeaderData.Version, HeaderOffset); if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) return createError(".debug_rnglists table at offset 0x%" PRIx32 " has unsupported address size %hhu", - TableOffset, HeaderData.AddrSize); + HeaderOffset, 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) + + HeaderOffset, HeaderData.SegSize); + if (End < HeaderOffset + sizeof(HeaderData) + HeaderData.OffsetEntryCount * sizeof(uint32_t)) return createError(".debug_rnglists table at offset 0x%" PRIx32 " has more offset entries (%" PRIu32 ") than there is space for", - TableOffset, HeaderData.OffsetEntryCount); + HeaderOffset, HeaderData.OffsetEntryCount); Data.setAddressSize(HeaderData.AddrSize); for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) Offsets.push_back(Data.getU32(OffsetPtr)); - DWARFAddressRangesVector CurrentRanges; + DWARFRangeList CurrentRanges; while (*OffsetPtr < End) { + uint32_t EntryOffset = *OffsetPtr; uint8_t Encoding = Data.getU8(OffsetPtr); + MaxEncodingStringLength = + std::max(MaxEncodingStringLength, + (uint8_t)dwarf::RangeListEncodingString(Encoding).size()); switch (Encoding) { case dwarf::DW_RLE_end_of_list: + CurrentRanges.push_back(RangeListEntry{EntryOffset, Encoding}); Ranges.insert(Ranges.end(), CurrentRanges); CurrentRanges.clear(); break; @@ -121,7 +130,8 @@ *OffsetPtr - 1); uint64_t Start = Data.getAddress(OffsetPtr); uint64_t End = Data.getAddress(OffsetPtr); - CurrentRanges.emplace_back(Start, End); + CurrentRanges.push_back( + RangeListEntry{EntryOffset, Encoding, Start, End}); break; } case dwarf::DW_RLE_start_length: { @@ -132,7 +142,8 @@ 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); + CurrentRanges.push_back( + RangeListEntry{EntryOffset, Encoding, Start, Length}); break; } default: @@ -155,12 +166,55 @@ return createError( "no end of list marker detected at end of .debug_rnglists table " "starting at offset 0x%" PRIx32, - TableOffset); + HeaderOffset); return Error::success(); } -void DWARFDebugRnglists::dump(raw_ostream &OS) const { - // TODO: Add verbose printing of the raw encodings. +static void dumpRangeEntry(raw_ostream &OS, + DWARFDebugRnglists::RangeListEntry Entry, + uint8_t AddrSize, uint8_t MaxEncodingStringLength, + DIDumpOptions DumpOpts) { + if (DumpOpts.Verbose) { + // Print the section offset in verbose mode. + OS << format("0x%8.8" PRIx32 ":", Entry.Offset); + auto EncodingString = dwarf::RangeListEncodingString(Entry.EntryKind); + // Unsupported encodings should have been reported during parsing. + assert(!EncodingString.empty() && "Unknown range entry encoding"); + OS << format(" [%s%*c", EncodingString.data(), + MaxEncodingStringLength - EncodingString.size() + 1, ']'); + if (Entry.EntryKind != dwarf::DW_RLE_end_of_list) + OS << ": "; + } + + switch (Entry.EntryKind) { + case dwarf::DW_RLE_end_of_list: + OS << (DumpOpts.Verbose ? "" : ""); + break; + case dwarf::DW_RLE_start_length: + if (DumpOpts.Verbose) { + // Make the address range display its contents in raw form rather than + // as an interval (i.e. without brackets). + DumpOpts.DisplayRawContents = true; + DWARFAddressRange(Entry.Value0, Entry.Value1) + .dump(OS, AddrSize, DumpOpts); + OS << " => "; + } + DumpOpts.DisplayRawContents = false; + DWARFAddressRange(Entry.Value0, Entry.Value0 + Entry.Value1) + .dump(OS, AddrSize, DumpOpts); + break; + case dwarf::DW_RLE_start_end: + DWARFAddressRange(Entry.Value0, Entry.Value1).dump(OS, AddrSize, DumpOpts); + break; + default: + llvm_unreachable("Unsupported range list encoding"); + } + OS << "\n"; +} + +void DWARFDebugRnglists::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { + if (DumpOpts.Verbose) + OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); OS << format("Range List Header: length = 0x%8.8" PRIx32 ", version = 0x%4.4" PRIx16 ", " "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 @@ -171,19 +225,20 @@ if (HeaderData.OffsetEntryCount > 0) { OS << "Offsets: ["; - for (const auto &Off : Offsets) + for (const auto &Off : Offsets) { OS << format("\n0x%8.8" PRIx32, Off); + if (DumpOpts.Verbose) + OS << format(" => 0x%8.8" PRIx32, + Off + HeaderOffset + sizeof(HeaderData)); + } OS << "\n]\n"; } OS << "Ranges:\n"; - const uint32_t HexWidth = HeaderData.AddrSize * 2; - for (const auto &List : Ranges) { + 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"; - } + dumpRangeEntry(OS, Entry, HeaderData.AddrSize, MaxEncodingStringLength, + DumpOpts); } uint32_t DWARFDebugRnglists::length() const { Index: llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_DWARF64.s =================================================================== --- llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_DWARF64.s +++ llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_rnglists_DWARF64.s @@ -0,0 +1,2 @@ +.section .debug_rnglists,"",@progbits +.long 0xffffffff # Unsupported DWARF64 format Index: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_rnglists.s =================================================================== --- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_rnglists.s +++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_rnglists.s @@ -1,50 +1,79 @@ -# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \ -# RUN: llvm-dwarfdump --debug-rnglists - 2> %t.err | FileCheck %s +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o %t.o +# RUN: llvm-dwarfdump --debug-rnglists %t.o 2> %t.err | FileCheck %s --check-prefixes=TERSE,BOTH # RUN: FileCheck %s --input-file %t.err --check-prefix=ERR +# RUN: llvm-dwarfdump -v --debug-rnglists %t.o 2> %t.err | FileCheck %s --check-prefixes=VERBOSE,BOTH -# 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: +# BOTH: .debug_rnglists contents: +# TERSE-NEXT: Range List Header: length = 0x00000037, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 + +# VERBOSE-NEXT: 0x{{[0-9a-f]*}}: +# VERBOSE-SAME: Range List Header: length = 0x00000037, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 + +# BOTH-NEXT: Ranges: +# TERSE-NEXT: [0x0000000000000010, 0x0000000000000020) +# TERSE-NEXT: [0x0000000000000025, 0x00000000000000a5) +# TERSE-NEXT: +# TERSE-NEXT: [0x0000000000000100, 0x0000000000000200) +# TERSE-NEXT: + +# VERBOSE-NEXT: 0x0000000c: [DW_RLE_start_end ]: [0x0000000000000010, 0x0000000000000020) +# VERBOSE-NEXT: 0x0000001d: [DW_RLE_start_length]: 0x0000000000000025, 0x0000000000000080 +# VERBOSE-SAME: => [0x0000000000000025, 0x00000000000000a5) +# VERBOSE-NEXT: 0x00000028: [DW_RLE_end_of_list ] +# VERBOSE-NEXT: 0x00000029: [DW_RLE_start_end ]: [0x0000000000000100, 0x0000000000000200) +# VERBOSE-NEXT: 0x0000003a: [DW_RLE_end_of_list ] + +# TERSE-NEXT: Range List Header: length = 0x0000002b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000002 + +# VERBOSE-NEXT: 0x{{[0-9a-f]*}}: +# VERBOSE-SAME: Range List Header: length = 0x0000002b, version = 0x0005, addr_size = 0x04, seg_size = 0x00, offset_entry_count = 0x00000002 + +# BOTH-NEXT: Offsets: [ +# BOTH-NEXT: 0x00000008 +# VERBOSE-SAME: => 0x0000004f +# BOTH-NEXT: 0x0000001b +# VERBOSE-SAME: => 0x00000062 +# BOTH-NEXT: ] +# BOTH-NEXT: Ranges: + +# TERSE-NEXT: [0x00000000, 0x00000000) +# TERSE-NEXT: [0x00000002, 0x00000006) +# TERSE-NEXT: +# TERSE-NEXT: [0x00000036, 0x00000136) +# TERSE-NEXT: + +# VERBOSE-NEXT: 0x0000004f: [DW_RLE_start_end ]: [0x00000000, 0x00000000) +# VERBOSE-NEXT: 0x00000058: [DW_RLE_start_end ]: [0x00000002, 0x00000006) +# VERBOSE-NEXT: 0x00000061: [DW_RLE_end_of_list ] +# VERBOSE-NEXT: 0x00000062: [DW_RLE_start_length]: 0x00000036, 0x00000100 => [0x00000036, 0x00000136) +# VERBOSE-NEXT: 0x00000069: [DW_RLE_end_of_list ] + +# TERSE-NEXT: Range List Header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 + +# VERBOSE-NEXT: 0x{{[0-9a-f]*}}: +# VERBOSE-SAME: Range List Header: length = 0x00000008, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 + +# BOTH-NOT: Offsets: +# BOTH: Ranges: +# BOTH-NOT: [ +# BOTH-NOT: Range List Header: # ERR-NOT: error: -# ERR: error: unsupported rnglists encoding DW_RLE_base_addressx at offset 0x7a -# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_startx_endx at offset 0x89 -# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_startx_length at offset 0x99 -# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_offset_pair at offset 0xa9 -# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_base_address at offset 0xb9 +# ERR: error: unsupported rnglists encoding DW_RLE_base_addressx at offset 0x82 +# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_startx_endx at offset 0x91 +# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_startx_length at offset 0xa1 +# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_offset_pair at offset 0xb1 +# ERR-NEXT: error: unsupported rnglists encoding DW_RLE_base_address at offset 0xc # ERR-NOT: error: .section .debug_rnglists,"",@progbits # First table (tests DW_RLE_end_of_list, start_end, and start_length encodings) -.long 63 # Table length +.long 55 # 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 +.long 0 # Offset entry count # First range list .byte 6 # DW_RLE_start_end @@ -60,11 +89,15 @@ .byte 0 # DW_RLE_end_of_list # Second table (shows support for size 4 addresses) -.long 27 # Table length +.long 43 # Table length .short 5 # Version .byte 4 # Address size .byte 0 # Segment selector size -.long 0 # Offset entry count +.long 2 # Offset entry count + +# Offset array +.long 8 # Offset Entry 0 +.long 27 # Offset Entry 1 # First range list .byte 6 # DW_RLE_start_end @@ -73,6 +106,12 @@ .long 0x2, 0x6 # Start, end address .byte 0 # DW_RLE_end_of_list +# Second range list +.byte 7 # DW_RLE_start_length +.long 0x36 # Start address +.byte 0x80, 0x02 # Length +.byte 0 # DW_RLE_end_of_list + # Third (empty) table .long 8 # Table length .short 5 # Version Index: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s =================================================================== --- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s +++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s @@ -37,6 +37,11 @@ # CHECK-NEXT: error: section is not large enough to contain a .debug_rnglists table of length 0x1f at offset 0xe5 # CHECK-NOT: error: +# RUN: llvm-mc %S/Inputs/debug_rnglists_DWARF64.s -filetype obj -triple x86_64-pc-linux -o - | \ +# RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | FileCheck %s --check-prefix=DWARF64 + +# DWARF64: DWARF64 is not supported in .debug_rnglists at offset 0x0 + .section .debug_rnglists,"",@progbits # Table 1 (good)