Index: include/llvm/BinaryFormat/Dwarf.h =================================================================== --- include/llvm/BinaryFormat/Dwarf.h +++ 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: include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ 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,41 @@ uint32_t OffsetEntryCount; }; +public: + struct RangeListEntry { + /// The offset at which the entry is located in the section. + uint32_t Offset; + /// The DWARF encoding (DW_RLE_*). + uint8_t EntryKind; + /// The range list entry. When EntryKind == DW_RLE_base_address, the + /// BaseAddress field is active, otherwise the AddressRange field is. + union { + uint64_t BaseAddress; + DWARFAddressRange AddressRange; + }; + + RangeListEntry() = delete; + + RangeListEntry(uint32_t Offset, uint8_t EntryKind, uint64_t LowPC, + uint64_t HighPC) + : Offset(Offset), EntryKind(EntryKind), AddressRange(LowPC, HighPC) {} + RangeListEntry(uint32_t Offset, uint8_t EntryKind, uint64_t Address) + : Offset(Offset), EntryKind(EntryKind), BaseAddress(Address) {} + }; + + using DWARFRangeList = std::vector; + +private: + uint32_t HeaderOffset; Header HeaderData; std::vector Offsets; - std::vector Ranges; + std::vector Ranges; 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: lib/BinaryFormat/Dwarf.cpp =================================================================== --- lib/BinaryFormat/Dwarf.cpp +++ 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: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -508,7 +508,7 @@ break; Offset = TableOffset + Length; } else - Rnglists.dump(OS); + Rnglists.dump(OS, DumpOpts); } } Index: lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ 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,20 @@ *OffsetPtr); // TODO: Add support for DWARF64. HeaderData.Length = Data.getU32(OffsetPtr); + if (HeaderData.Length == 0xffffffffu) + return make_error("DWARF64 is not supported in .dbg_rnglists", + inconvertibleErrorCode()); 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 +66,35 @@ 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; + // DWARFAddressRangesVector CurrentRanges; + DWARFRangeList CurrentRanges; while (*OffsetPtr < End) { + uint32_t EntryOffset = *OffsetPtr; uint8_t Encoding = Data.getU8(OffsetPtr); switch (Encoding) { case dwarf::DW_RLE_end_of_list: + CurrentRanges.emplace_back(EntryOffset, Encoding, 0); Ranges.insert(Ranges.end(), CurrentRanges); CurrentRanges.clear(); break; @@ -121,7 +127,7 @@ *OffsetPtr - 1); uint64_t Start = Data.getAddress(OffsetPtr); uint64_t End = Data.getAddress(OffsetPtr); - CurrentRanges.emplace_back(Start, End); + CurrentRanges.emplace_back(EntryOffset, Encoding, Start, End); break; } case dwarf::DW_RLE_start_length: { @@ -132,7 +138,7 @@ 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.emplace_back(EntryOffset, Encoding, Start, Start + Length); break; } default: @@ -155,12 +161,65 @@ 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, + uint32_t HexWidth) { + switch (Entry.EntryKind) { + case dwarf::DW_RLE_end_of_list: + OS << ""; + break; + case dwarf::DW_RLE_start_length: + case dwarf::DW_RLE_start_end: + OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 ")", HexWidth, HexWidth, + Entry.AddressRange.LowPC, HexWidth, HexWidth, + Entry.AddressRange.HighPC); + break; + default: + llvm_unreachable("Unsupported range list encoding"); + } + OS << "\n"; +} + +static void dumpRangeEntryVerbose(raw_ostream &OS, + DWARFDebugRnglists::RangeListEntry Entry, + uint32_t HexWidth) { + 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 << " [" << EncodingString << "]"; + + switch (Entry.EntryKind) { + case dwarf::DW_RLE_end_of_list: + break; + case dwarf::DW_RLE_start_end: + OS << format(": 0x%*.*" PRIx64 ", 0x%*.*" PRIx64, HexWidth, HexWidth, + Entry.AddressRange.LowPC, HexWidth, HexWidth, + Entry.AddressRange.HighPC); + break; + case dwarf::DW_RLE_start_length: + OS << format(": 0x%*.*" PRIx64 ", 0x%*.*" PRIx64 " => ", HexWidth, HexWidth, + Entry.AddressRange.LowPC, HexWidth, HexWidth, + Entry.AddressRange.HighPC - Entry.AddressRange.LowPC); + OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 ")", HexWidth, HexWidth, + Entry.AddressRange.LowPC, HexWidth, HexWidth, + Entry.AddressRange.HighPC); + break; + + default: + // Any unhandled encodings should have been filtered out during parsing. + llvm_unreachable("Unknown range linst entry 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,8 +230,12 @@ 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"; @@ -180,9 +243,10 @@ 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"; + if (DumpOpts.Verbose) + dumpRangeEntryVerbose(OS, Entry, HexWidth); + else + dumpRangeEntry(OS, Entry, HexWidth); } } 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 @@ -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=DEFAULT,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: +# DEFAULT-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: +# DEFAULT-NEXT: [0x0000000000000010, 0x0000000000000020) +# DEFAULT-NEXT: [0x0000000000000025, 0x00000000000000a5) +# DEFAULT-NEXT: +# DEFAULT-NEXT: [0x0000000000000100, 0x0000000000000200) +# DEFAULT-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] + +# DEFAULT-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: + +# DEFAULT-NEXT: [0x00000000, 0x00000000) +# DEFAULT-NEXT: [0x00000002, 0x00000006) +# DEFAULT-NEXT: +# DEFAULT-NEXT: [0x00000036, 0x00000136) +# DEFAULT-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] + +# DEFAULT-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