Index: include/llvm/BinaryFormat/Dwarf.h =================================================================== --- include/llvm/BinaryFormat/Dwarf.h +++ include/llvm/BinaryFormat/Dwarf.h @@ -428,6 +428,7 @@ StringRef AtomTypeString(unsigned Atom); StringRef GDBIndexEntryKindString(GDBIndexEntryKind Kind); StringRef GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage); +StringRef LocationListEntryString(unsigned Entry); StringRef IndexString(unsigned Idx); /// @} Index: include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -20,6 +20,17 @@ class MCRegisterInfo; class raw_ostream; +class IsBaseAddressError : public ErrorInfo { +public: + static char ID; + + void log(raw_ostream &OS) const override { OS << "Is base address"; } + + std::error_code convertToErrorCode() const override { + return inconvertibleErrorCode(); + } +}; + class DWARFDebugLoc { public: /// A single location within a location list. @@ -79,6 +90,22 @@ uint64_t Value0; uint64_t Value1; SmallVector Loc; + + /// Return the half-open range of addresses covered by this entry. + /// DW_LLE_offset_pair entries are resolved using the given base address, + /// and the supplied DWARFUnit is used to look up any pooled (debug_addr) + /// addresses. In case of failure, an error is returned. If we could not get + /// an address range because this is a base address selection entry + /// (DW_LLE_base_address), then the error is of type IsBaseAddressError, and + /// the BaseAddr argument is updated accordingly. + Expected> getRange(DWARFUnit *U, + uint64_t &BaseAddr) const; + + /// Same as above, but uses a callback to resolve any address pool + /// references. + Expected> + getRange(function_ref(uint32_t)> AddrOffsetResolver, + uint64_t &BaseAddr) const; }; struct LocationList { Index: lib/BinaryFormat/Dwarf.cpp =================================================================== --- lib/BinaryFormat/Dwarf.cpp +++ lib/BinaryFormat/Dwarf.cpp @@ -617,6 +617,31 @@ return StringRef(); } +StringRef llvm::dwarf::LocationListEntryString(unsigned Entry) { + switch(Entry) { + default: + return StringRef(); + case DW_LLE_end_of_list: + return "DW_LLE_end_of_list"; + case DW_LLE_base_addressx: + return "DW_LLE_base_addressx"; + case DW_LLE_startx_endx: + return "DW_LLE_startx_endx"; + case DW_LLE_startx_length: + return "DW_LLE_startx_length"; + case DW_LLE_offset_pair: + return "DW_LLE_offset_pair"; + case DW_LLE_default_location: + return "DW_LLE_default_location"; + case DW_LLE_base_address: + return "DW_LLE_base_address"; + case DW_LLE_start_end: + return "DW_LLE_start_end"; + case DW_LLE_start_length: + return "DW_LLE_start_length"; + } +} + StringRef llvm::dwarf::IndexString(unsigned Idx) { switch (Idx) { default: Index: lib/DebugInfo/DWARF/DWARFDebugLoc.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -23,6 +23,8 @@ using namespace llvm; +char IsBaseAddressError::ID; + // When directly dumping the .debug_loc without a compile unit, we have to guess // at the DWARF version. This only affects DW_OP_call_ref, which is a rare // expression that LLVM doesn't produce. Guessing the wrong version means we @@ -153,6 +155,7 @@ E.Value1 = Data.getULEB128(C); break; case dwarf::DW_LLE_start_length: + // TODO: Read this as a relocated address. E.Value0 = Data.getAddress(C); E.Value1 = Data.getULEB128(C); break; @@ -207,6 +210,43 @@ return nullptr; } +Expected> DWARFDebugLoclists::Entry::getRange( + function_ref(uint32_t)> AddrOffsetResolver, + uint64_t &BaseAddr) const { + switch (Kind) { + case dwarf::DW_LLE_startx_length: + if (Optional Start = AddrOffsetResolver(Value0)) + return std::make_pair(*Start, *Start + Value1); + else + return createStringError(inconvertibleErrorCode(), + "Reading debug_addr failed"); + + case dwarf::DW_LLE_start_length: + return std::make_pair(Value0, Value0 + Value1); + case dwarf::DW_LLE_offset_pair: + return std::make_pair(BaseAddr + Value0, BaseAddr + Value1); + case dwarf::DW_LLE_base_address: + BaseAddr = Value0; + return make_error(); + default: + llvm_unreachable("Unsupported locations list kind"); + } +} + +Expected> +DWARFDebugLoclists::Entry::getRange(DWARFUnit *U, uint64_t &BaseAddr) const { + return getRange( + [U](uint32_t Index) -> Optional { + if (!U) + return llvm::None; + if (Optional Addr = + U->getAddrOffsetSectionItem(Index)) + return Addr->Address; + return llvm::None; + }, + BaseAddr); +} + void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr, bool IsLittleEndian, unsigned AddressSize, @@ -214,32 +254,24 @@ DWARFUnit *U, unsigned Indent) const { for (const Entry &E : Entries) { - switch (E.Kind) { - case dwarf::DW_LLE_startx_length: + if (Expected> Range = + E.getRange(U, BaseAddr)) { OS << '\n'; OS.indent(Indent); - OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): "; - break; - case dwarf::DW_LLE_start_length: + OS << format("[0x%.*" PRIx64 ", 0x%.*" PRIx64 ")", AddressSize * 2, + Range->first, AddressSize * 2, Range->second); + } else { + bool IsBaseAddress = Range.errorIsA(); + consumeError(Range.takeError()); + if (IsBaseAddress) + continue; OS << '\n'; OS.indent(Indent); - OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2, - AddressSize * 2, E.Value0, AddressSize * 2, AddressSize * 2, - E.Value0 + E.Value1); - break; - case dwarf::DW_LLE_offset_pair: - OS << '\n'; - OS.indent(Indent); - OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2, - AddressSize * 2, BaseAddr + E.Value0, AddressSize * 2, - AddressSize * 2, BaseAddr + E.Value1); - break; - case dwarf::DW_LLE_base_address: - BaseAddr = E.Value0; - break; - default: - llvm_unreachable("unreachable locations list kind"); + OS << "{" << dwarf::LocationListEntryString(E.Kind) + << format(", 0x%.*" PRIx64 ", 0x%.*" PRIx64 "}", AddressSize * 2, + E.Value0, AddressSize * 2, E.Value1); } + OS << ": "; dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U); } Index: test/DebugInfo/X86/fission-ranges.ll =================================================================== --- test/DebugInfo/X86/fission-ranges.ll +++ test/DebugInfo/X86/fission-ranges.ll @@ -45,18 +45,19 @@ ; if they've changed due to a bugfix, change in register allocation, etc. ; CHECK: [[A]]: -; CHECK-NEXT: Addr idx 2 (w/ length 15): DW_OP_consts +0, DW_OP_stack_value -; CHECK-NEXT: Addr idx 3 (w/ length 15): DW_OP_reg0 RAX -; CHECK-NEXT: Addr idx 4 (w/ length 18): DW_OP_breg7 RSP-8 +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000002, 0x0000000f}: DW_OP_consts +0, DW_OP_stack_value +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000003, 0x0000000f}: DW_OP_reg0 RAX +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000004, 0x00000012}: DW_OP_breg7 RSP-8 ; CHECK: [[E]]: -; CHECK-NEXT: Addr idx 5 (w/ length 9): DW_OP_reg0 RAX -; CHECK-NEXT: Addr idx 6 (w/ length 98): DW_OP_breg7 RSP-44 +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000005, 0x00000009}: DW_OP_reg0 RAX +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000006, 0x00000062}: DW_OP_breg7 RSP-44 + ; CHECK: [[B]]: -; CHECK-NEXT: Addr idx 7 (w/ length 15): DW_OP_reg0 RAX -; CHECK-NEXT: Addr idx 8 (w/ length 66): DW_OP_breg7 RSP-32 +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000007, 0x0000000f}: DW_OP_reg0 RAX +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000008, 0x00000042}: DW_OP_breg7 RSP-32 ; CHECK: [[D]]: -; CHECK-NEXT: Addr idx 9 (w/ length 15): DW_OP_reg0 RAX -; CHECK-NEXT: Addr idx 10 (w/ length 42): DW_OP_breg7 RSP-20 +; CHECK-NEXT: {DW_LLE_startx_length, 0x00000009, 0x0000000f}: DW_OP_reg0 RAX +; CHECK-NEXT: {DW_LLE_startx_length, 0x0000000a, 0x0000002a}: DW_OP_breg7 RSP-20 ; Make sure we don't produce any relocations in any .dwo section (though in particular, debug_info.dwo) ; HDR-NOT: .rela.{{.*}}.dwo Index: test/DebugInfo/X86/loclists-dwp.ll =================================================================== --- test/DebugInfo/X86/loclists-dwp.ll +++ test/DebugInfo/X86/loclists-dwp.ll @@ -19,10 +19,10 @@ ; void b(int i) { asm("" : : : "rdi"); } ; CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000000 -; CHECK-NEXT: Addr idx 0 (w/ length 6): DW_OP_reg5 RDI) +; CHECK-NEXT: {DW_LLE_startx_length, 0x0000000000000000, 0x0000000000000006}: DW_OP_reg5 RDI) ; CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000000 -; CHECK-NEXT: Addr idx 0 (w/ length 0): DW_OP_reg5 RDI) +; CHECK-NEXT: {DW_LLE_startx_length, 0x0000000000000000, 0x0000000000000000}: DW_OP_reg5 RDI) target triple = "x86_64-unknown-linux-gnu" Index: test/tools/llvm-dwarfdump/X86/debug_loc_dwo.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_loc_dwo.s +++ test/tools/llvm-dwarfdump/X86/debug_loc_dwo.s @@ -6,7 +6,7 @@ # CHECK: .debug_loc.dwo contents: # CHECK-NEXT: 0x00000000: -# CHECK-NEXT: Addr idx 1 (w/ length 16): DW_OP_reg5 RDI +# CHECK-NEXT: {DW_LLE_startx_length, 0x00000001, 0x00000010}: DW_OP_reg5 RDI .section .debug_loc.dwo,"",@progbits # One location list. The pre-DWARF v5 implementation only recognizes Index: test/tools/llvm-dwarfdump/X86/debug_loclists.s =================================================================== --- /dev/null +++ test/tools/llvm-dwarfdump/X86/debug_loclists.s @@ -0,0 +1,122 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o %t +# RUN: llvm-dwarfdump %t | FileCheck %s + + +# CHECK: DW_AT_location (0x0000000c +# CHECK-NEXT: [0x0000000000000000, 0x0000000000000001): DW_OP_reg0 RAX +# CHECK-NEXT: [0x0000000000000001, 0x0000000000000002): DW_OP_reg1 RDX +# CHECK-NEXT: [0x0000000000000002, 0x0000000000000003): DW_OP_reg2 RCX +# CHECK-NEXT: [0x0000000000000003, 0x0000000000000004): DW_OP_reg3 RBX +# CHECK-NEXT: {DW_LLE_startx_length, 0x000000000000dead, 0x0000000000000001}: DW_OP_reg4 RSI) + + + .text +f: # @f +.Lf0: + nop +.Lf1: + nop +.Lf2: + nop +.Lf3: + nop +.Lf4: +.Lfend: + # -- End function + .section .debug_loclists,"",@progbits + .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 # Length +.Ldebug_loclist_table_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 0 # Offset entry count +.Lloclists_table_base0: +.Ldebug_loc0: + .byte 3 # DW_LLE_startx_length + .uleb128 0 # start idx + .uleb128 .Lf1-.Lf0 # length + .byte 1 # Loc expr size + .byte 80 # super-register DW_OP_reg0 + .byte 4 # DW_LLE_offset_pair + .uleb128 .Lf1-.Lf0 # starting offset + .uleb128 .Lf2-.Lf0 # ending offset + .byte 1 # Loc expr size + .byte 81 # super-register DW_OP_reg1 + .byte 8 # DW_LLE_start_length + # TODO: Make it possible to use .Lf2 here. + .quad 2 # starting offset + .uleb128 .Lf3-.Lf2 # length + .byte 1 # Loc expr size + .byte 82 # super-register DW_OP_reg2 + .byte 6 # DW_LLE_base_address + # TODO: Make it possible to use .Lf3 here. + .quad 3 # base address + .byte 4 # DW_LLE_offset_pair + .uleb128 .Lf3-.Lf3 # starting offset + .uleb128 .Lf4-.Lf3 # ending offset + .byte 1 # Loc expr size + .byte 83 # super-register DW_OP_reg3 + .byte 3 # DW_LLE_startx_length + .uleb128 0xdead # start idx + .uleb128 .Lf1-.Lf0 # length + .byte 1 # Loc expr size + .byte 84 # super-register DW_OP_reg4 + .byte 0 # DW_LLE_end_of_list +.Ldebug_loclist_table_end0: + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .ascii "\214\001" # DW_AT_loclists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x3c DW_TAG_compile_unit + .long .Laddr_table_base0 # DW_AT_addr_base + .long .Lloclists_table_base0 # DW_AT_loclists_base + .byte 2 # Abbrev [2] 0x27:0x1c DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfend-.Lf0 # DW_AT_high_pc + .byte 3 # Abbrev [3] 0x36:0xc DW_TAG_formal_parameter + .long .Ldebug_loc0 # DW_AT_location + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lf0 +.Ldebug_addr_end0: Index: test/tools/llvm-dwarfdump/X86/debug_loclists_startx_length.s =================================================================== --- test/tools/llvm-dwarfdump/X86/debug_loclists_startx_length.s +++ test/tools/llvm-dwarfdump/X86/debug_loclists_startx_length.s @@ -8,7 +8,7 @@ # CHECK: .debug_loclists contents: # CHECK-NEXT: 0x00000000: locations list header: length = 0x0000000e, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 # CHECK-NEXT: 0x00000000: -# CHECK-NEXT: Addr idx 1 (w/ length 16): DW_OP_reg5 RDI +# CHECK-NEXT: {DW_LLE_startx_length, 0x0000000000000001, 0x0000000000000010}: DW_OP_reg5 RDI .section .debug_loclists,"",@progbits .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0