diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -119,6 +119,16 @@ Demangle symbol names in the output. +.. option:: --debug-vars + + Print the locations (in registers or memory) of source-level variables + alongside disassembly. + +.. option:: --debug-vars-indent= + + Distance to indent the source-level variable display, relative to the start + of the disassembly. + .. option:: -j, --section= Perform commands on the specified sections only. For Mach-O use diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h @@ -119,6 +119,10 @@ return Op; } + iterator skip_bytes(uint32_t Add) { + return iterator(Expr, Op.EndOffset + Add); + } + class Operation &operator*() { return Op; } diff --git a/llvm/include/llvm/Support/FormattedStream.h b/llvm/include/llvm/Support/FormattedStream.h --- a/llvm/include/llvm/Support/FormattedStream.h +++ b/llvm/include/llvm/Support/FormattedStream.h @@ -105,11 +105,17 @@ /// \param NewCol - The column to move to. formatted_raw_ostream &PadToColumn(unsigned NewCol); - /// getColumn - Return the column number - unsigned getColumn() { return Position.first; } + /// Return the column number. + unsigned getColumn() { + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); + return Position.first; + } - /// getLine - Return the line number - unsigned getLine() { return Position.second; } + /// Return the line number. + unsigned getLine() { + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); + return Position.second; + } raw_ostream &resetColor() override { TheStream->resetColor(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1062,33 +1062,6 @@ return None; } -static Optional -getLocationFrameOffset(DWARFCompileUnit *CU, DWARFFormValue &FormValue, - Optional FrameBaseReg) { - if (Optional> Location = FormValue.getAsBlock()) { - return getExpressionFrameOffset(*Location, FrameBaseReg); - } else if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { - uint64_t Offset = *FormValue.getAsSectionOffset(); - const DWARFLocationTable &LocTable = CU->getLocationTable(); - Optional FrameOffset; - Error E = LocTable.visitLocationList( - &Offset, [&](const DWARFLocationEntry &Entry) { - if (Entry.Kind == dwarf::DW_LLE_base_address || - Entry.Kind == dwarf::DW_LLE_base_addressx || - Entry.Kind == dwarf::DW_LLE_end_of_list) { - return true; - } - if ((FrameOffset = getExpressionFrameOffset(Entry.Loc, FrameBaseReg))) - return false; - return true; - }); - if (E) - return None; - return FrameOffset; - } - return None; -} - void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, std::vector &Result) { if (Die.getTag() == DW_TAG_variable || @@ -1104,8 +1077,17 @@ (*Expr)[0] <= DW_OP_reg31) { FrameBaseReg = (*Expr)[0] - DW_OP_reg0; } - if (auto LocationAttr = Die.find(DW_AT_location)) - Local.FrameOffset = getLocationFrameOffset(CU, *LocationAttr, FrameBaseReg); + + if (Expected> Loc = + Die.getLocations(DW_AT_location)) { + for (const auto &Entry : *Loc) { + if (Optional FrameOffset = + getExpressionFrameOffset(Entry.Expr, FrameBaseReg)) { + Local.FrameOffset = *FrameOffset; + break; + } + } + } if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset)) Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant(); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -494,8 +494,18 @@ return createStringError(inconvertibleErrorCode(), "No %s", dwarf::AttributeString(Attr).data()); - if (Optional Off = Location->getAsSectionOffset()) - return U->findLoclistFromOffset(*Off); + if (Optional Off = Location->getAsSectionOffset()) { + uint64_t Offset = *Off; + + if (Location->getForm() == DW_FORM_loclistx) { + if (auto LoclistOffset = U->getLoclistOffset(Offset)) + Offset = *LoclistOffset + getDwarfUnit()->getLocSectionBase(); + else + return createStringError(inconvertibleErrorCode(), + "Loclist table not found"); + } + return U->findLoclistFromOffset(Offset); + } if (Optional> Expr = Location->getAsBlock()) { return DWARFLocationExpressionsVector{ diff --git a/llvm/lib/Support/FormattedStream.cpp b/llvm/lib/Support/FormattedStream.cpp --- a/llvm/lib/Support/FormattedStream.cpp +++ b/llvm/lib/Support/FormattedStream.cpp @@ -27,7 +27,28 @@ // Keep track of the current column and line by scanning the string for // special characters for (const char *End = Ptr + Size; Ptr != End; ++Ptr) { + // If this is a multi-byte sequence, skip the extra bytes, and don't check + // for special whitespace characters. + bool MultiByte = true; + if ((*Ptr & 0b11100000) == 0b11000000) + Ptr += 1; + else if ((*Ptr & 0b11110000) == 0b11100000) + Ptr += 2; + else if ((*Ptr & 0b11111000) == 0b11110000) + Ptr += 3; + else + MultiByte = false; + + // The string should never end part way through a multi-byte sequence. + assert(Ptr < End && "Malformed multi-byte sequence"); + ++Column; + + // If this is the final byte of a multi-byte sequence, it can't be any of + // the special whitespace characters below. + if (MultiByte) + continue; + switch (*Ptr) { case '\n': Line += 1; diff --git a/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c b/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c @@ -0,0 +1,10 @@ +int foo(int a, int b, int c) { + int x = a + b; + int y = x + c; + return y; +} + +int bar(int a) { + a++; + return a; +} diff --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4-sections.s @@ -0,0 +1,351 @@ +## RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +## RUN: FileCheck %s + +# Check that the -debug-vars option works for simple register locations, when +# using DWARF4 debug info, with functions im multiple sections. + +# Generated with this compile command, with the source code in Inputs/debug.c: +# clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-4 -S -o - -ffunction-sections + +# CHECK: Disassembly of section .text.foo: +# CHECK-EMPTY: +# CHECK-NEXT: 00000000 foo: +# CHECK-NEXT: ┠─ a = R0 +# CHECK-NEXT: ┃ ┠─ b = R1 +# CHECK-NEXT: ┃ ┃ ┠─ c = R2 +# CHECK-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# CHECK-NEXT: 0: add r0, r1, r0 ┻ ┃ ┃ ╈ +# CHECK-NEXT: ┌─ y = R0 +# CHECK-NEXT: 4: add r0, r0, r2 ╈ ┃ ┃ ┻ +# CHECK-NEXT: 8: bx lr ┻ ┻ ┻ +# CHECK-EMPTY: +# CHECK-NEXT: Disassembly of section .text.bar: +# CHECK-EMPTY: +# CHECK-NEXT: 00000000 bar: +# CHECK-NEXT: ┠─ a = R0 +# CHECK-NEXT: 0: add r0, r0, #1 ┃ +# CHECK-NEXT: 4: bx lr ┻ + + .text + .syntax unified + .eabi_attribute 67, "2.09" + .eabi_attribute 6, 10 + .eabi_attribute 7, 65 + .eabi_attribute 8, 1 + .eabi_attribute 9, 2 + .fpu neon + .eabi_attribute 34, 0 + .eabi_attribute 17, 1 + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 38, 1 + .eabi_attribute 18, 4 + .eabi_attribute 26, 2 + .eabi_attribute 14, 0 + .file "debug.c" + .section .text.foo,"ax",%progbits + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin0: + .file 1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" + .loc 1 1 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .loc 1 2 13 prologue_end + add r0, r1, r0 +.Ltmp0: + .loc 1 3 13 + add r0, r0, r2 +.Ltmp1: + .loc 1 4 3 + bx lr +.Ltmp2: +.Lfunc_end0: + .size foo, .Lfunc_end0-foo + .cfi_endproc + .cantunwind + .fnend + + .section .text.bar,"ax",%progbits + .globl bar + .p2align 2 + .type bar,%function + .code 32 +bar: +.Lfunc_begin1: + .loc 1 7 0 + .fnstart + .cfi_startproc + .loc 1 8 4 prologue_end + add r0, r0, #1 +.Ltmp3: + .loc 1 9 3 + bx lr +.Ltmp4: +.Lfunc_end1: + .size bar, .Lfunc_end1-bar + .cfi_endproc + .cantunwind + .fnend + + .section .debug_str,"MS",%progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" +.Linfo_string1: + .asciz "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" +.Linfo_string2: + .asciz "/work/scratch" +.Linfo_string3: + .asciz "foo" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "bar" +.Linfo_string6: + .asciz "a" +.Linfo_string7: + .asciz "b" +.Linfo_string8: + .asciz "c" +.Linfo_string9: + .asciz "x" +.Linfo_string10: + .asciz "y" + .section .debug_loc,"",%progbits +.Ldebug_loc0: + .long -1 + .long .Lfunc_begin0 + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp0-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc1: + .long -1 + .long .Lfunc_begin0 + .long .Ltmp0-.Lfunc_begin0 + .long .Ltmp1-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc2: + .long -1 + .long .Lfunc_begin0 + .long .Ltmp1-.Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 + .section .debug_abbrev,"",%progbits + .byte 1 + .byte 17 + .byte 1 + .byte 37 + .byte 14 + .byte 19 + .byte 5 + .byte 3 + .byte 14 + .byte 16 + .byte 23 + .byte 27 + .byte 14 + .byte 17 + .byte 1 + .byte 85 + .byte 23 + .byte 0 + .byte 0 + .byte 2 + .byte 46 + .byte 1 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 64 + .byte 24 + .ascii "\227B" + .byte 25 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 73 + .byte 19 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 2 + .byte 23 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 5 + .byte 0 + .byte 2 + .byte 24 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 52 + .byte 0 + .byte 2 + .byte 23 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 6 + .byte 36 + .byte 0 + .byte 3 + .byte 14 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 0 + .section .debug_info,"",%progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 +.Ldebug_info_start0: + .short 4 + .long .debug_abbrev + .byte 4 + .byte 1 + .long .Linfo_string0 + .short 12 + .long .Linfo_string1 + .long .Lline_table_start0 + .long .Linfo_string2 + .long 0 + .long .Ldebug_ranges0 + .byte 2 + .long .Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .long .Linfo_string3 + .byte 1 + .byte 1 + + .long 166 + + .byte 3 + .long .Ldebug_loc0 + .long .Linfo_string6 + .byte 1 + .byte 1 + .long 166 + .byte 4 + .byte 1 + .byte 81 + .long .Linfo_string7 + .byte 1 + .byte 1 + .long 166 + .byte 4 + .byte 1 + .byte 82 + .long .Linfo_string8 + .byte 1 + .byte 1 + .long 166 + .byte 5 + .long .Ldebug_loc1 + .long .Linfo_string9 + .byte 1 + .byte 2 + .long 166 + .byte 5 + .long .Ldebug_loc2 + .long .Linfo_string10 + .byte 1 + .byte 3 + .long 166 + .byte 0 + .byte 2 + .long .Lfunc_begin1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .long .Linfo_string5 + .byte 1 + .byte 7 + + .long 166 + + .byte 4 + .byte 1 + .byte 80 + .long .Linfo_string6 + .byte 1 + .byte 7 + .long 166 + .byte 0 + .byte 6 + .long .Linfo_string4 + .byte 5 + .byte 4 + .byte 0 +.Ldebug_info_end0: + .section .debug_ranges,"",%progbits +.Ldebug_ranges0: + .long .Lfunc_begin0 + .long .Lfunc_end0 + .long .Lfunc_begin1 + .long .Lfunc_end1 + .long 0 + .long 0 + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" + .section ".note.GNU-stack","",%progbits + .addrsig + .eabi_attribute 30, 1 + .section .debug_line,"",%progbits +.Lline_table_start0: diff --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf4.s @@ -0,0 +1,406 @@ +## RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \ +## RUN: llvm-objdump - -d -debug-vars | \ +## RUN: FileCheck %s --check-prefix=RAW + +## RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +## RUN: FileCheck %s --check-prefix=NO-RAW + +## RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn -line-numbers | \ +## RUN: FileCheck %s --check-prefix=LINE-NUMS + +## RUN: mkdir -p %t/a +## RUN: cp %p/Inputs/debug.c %t/a/debug.c +## RUN: sed -e "s,SRC_COMPDIR,%t/a,g" %s > %t.s +## RUN: llvm-mc -triple armv8a--none-eabi < %t.s -filetype=obj | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn -source | \ +## RUN: FileCheck %s --check-prefix=SOURCE + +# Check that the -debug-vars option works for simple register locations, when +# using DWARF4 debug info, with multiple functions in one section. Check that +# the live-range lines are rendered correctly when using the -no-show-raw-insn, +# -line-numbers and -source options. + +# Generated with this compile command, with the source code in Inputs/debug.c: +# clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-4 -S -o - + + +# RAW: Disassembly of section .text: +# RAW-EMPTY: +# RAW-NEXT: 00000000 foo: +# RAW-NEXT: ┠─ a = R0 +# RAW-NEXT: ┃ ┠─ b = R1 +# RAW-NEXT: ┃ ┃ ┠─ c = R2 +# RAW-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# RAW-NEXT: 0: 00 00 81 e0 add r0, r1, r0 ┻ ┃ ┃ ╈ +# RAW-NEXT: ┌─ y = R0 +# RAW-NEXT: 4: 02 00 80 e0 add r0, r0, r2 ╈ ┃ ┃ ┻ +# RAW-NEXT: 8: 1e ff 2f e1 bx lr ┻ ┻ ┻ +# RAW-EMPTY: +# RAW-NEXT: 0000000c bar: +# RAW-NEXT: ┠─ a = R0 +# RAW-NEXT: c: 01 00 80 e2 add r0, r0, #1 ┃ +# RAW-NEXT: 10: 1e ff 2f e1 bx lr ┻ + +# NO-RAW: Disassembly of section .text: +# NO-RAW-EMPTY: +# NO-RAW-NEXT: 00000000 foo: +# NO-RAW-NEXT: ┠─ a = R0 +# NO-RAW-NEXT: ┃ ┠─ b = R1 +# NO-RAW-NEXT: ┃ ┃ ┠─ c = R2 +# NO-RAW-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# NO-RAW-NEXT: 0: add r0, r1, r0 ┻ ┃ ┃ ╈ +# NO-RAW-NEXT: ┌─ y = R0 +# NO-RAW-NEXT: 4: add r0, r0, r2 ╈ ┃ ┃ ┻ +# NO-RAW-NEXT: 8: bx lr ┻ ┻ ┻ +# NO-RAW-EMPTY: +# NO-RAW-NEXT: 0000000c bar: +# NO-RAW-NEXT: ┠─ a = R0 +# NO-RAW-NEXT: c: add r0, r0, #1 ┃ +# NO-RAW-NEXT: 10: bx lr ┻ + +# LINE-NUMS: Disassembly of section .text: +# LINE-NUMS-EMPTY: +# LINE-NUMS-NEXT: 00000000 foo: +# LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:2 ┠─ a = R0 +# LINE-NUMS-NEXT: ┃ ┠─ b = R1 +# LINE-NUMS-NEXT: ┃ ┃ ┠─ c = R2 +# LINE-NUMS-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# LINE-NUMS-NEXT: 0: add r0, r1, r0 ┻ ┃ ┃ ╈ +# LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:3 ┌─ y = R0 +# LINE-NUMS-NEXT: 4: add r0, r0, r2 ╈ ┃ ┃ ┻ +# LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:4 ┃ ┃ ┃ +# LINE-NUMS-NEXT: 8: bx lr ┻ ┻ ┻ +# LINE-NUMS-EMPTY: +# LINE-NUMS-NEXT: 0000000c bar: +# LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:8 ┠─ a = R0 +# LINE-NUMS-NEXT: c: add r0, r0, #1 ┃ +# LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:9 ┃ +# LINE-NUMS-NEXT: 10: bx lr ┻ + +# SOURCE: Disassembly of section .text: +# SOURCE-EMPTY: +# SOURCE-NEXT: 00000000 foo: +# SOURCE-NEXT: ; int x = a + b; ┠─ a = R0 +# SOURCE-NEXT: ┃ ┠─ b = R1 +# SOURCE-NEXT: ┃ ┃ ┠─ c = R2 +# SOURCE-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# SOURCE-NEXT: 0: add r0, r1, r0 ┻ ┃ ┃ ╈ +# SOURCE-NEXT: ; int y = x + c; ┌─ y = R0 +# SOURCE-NEXT: 4: add r0, r0, r2 ╈ ┃ ┃ ┻ +# SOURCE-NEXT: ; return y; ┃ ┃ ┃ +# SOURCE-NEXT: 8: bx lr ┻ ┻ ┻ +# SOURCE-EMPTY: +# SOURCE-NEXT: 0000000c bar: +# SOURCE-NEXT: ; a++; ┠─ a = R0 +# SOURCE-NEXT: c: add r0, r0, #1 ┃ +# SOURCE-NEXT: ; return a; ┃ +# SOURCE-NEXT: 10: bx lr ┻ + + .text + .syntax unified + .eabi_attribute 67, "2.09" + .eabi_attribute 6, 10 + .eabi_attribute 7, 65 + .eabi_attribute 8, 1 + .eabi_attribute 9, 2 + .fpu neon + .eabi_attribute 34, 0 + .eabi_attribute 17, 1 + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 38, 1 + .eabi_attribute 18, 4 + .eabi_attribute 26, 2 + .eabi_attribute 14, 0 + .file "debug.c" + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin0: + .file 1 "" "SRC_COMPDIR/debug.c" + .loc 1 1 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .loc 1 2 13 prologue_end + add r0, r1, r0 +.Ltmp0: + .loc 1 3 13 + add r0, r0, r2 +.Ltmp1: + .loc 1 4 3 + bx lr +.Ltmp2: +.Lfunc_end0: + .size foo, .Lfunc_end0-foo + .cfi_endproc + .cantunwind + .fnend + + .globl bar + .p2align 2 + .type bar,%function + .code 32 +bar: +.Lfunc_begin1: + .loc 1 7 0 + .fnstart + .cfi_startproc + .loc 1 8 4 prologue_end + add r0, r0, #1 +.Ltmp3: + .loc 1 9 3 + bx lr +.Ltmp4: +.Lfunc_end1: + .size bar, .Lfunc_end1-bar + .cfi_endproc + .cantunwind + .fnend + + .section .debug_str,"MS",%progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" +.Linfo_string1: + .asciz "SRC_COMPDIR/debug.c" +.Linfo_string2: + .asciz "" +.Linfo_string3: + .asciz "foo" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "bar" +.Linfo_string6: + .asciz "a" +.Linfo_string7: + .asciz "b" +.Linfo_string8: + .asciz "c" +.Linfo_string9: + .asciz "x" +.Linfo_string10: + .asciz "y" + .section .debug_loc,"",%progbits +.Ldebug_loc0: + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp0-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc1: + .long .Ltmp0-.Lfunc_begin0 + .long .Ltmp1-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc2: + .long .Ltmp1-.Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 + .section .debug_abbrev,"",%progbits + .byte 1 + .byte 17 + .byte 1 + .byte 37 + .byte 14 + .byte 19 + .byte 5 + .byte 3 + .byte 14 + .byte 16 + .byte 23 + .byte 27 + .byte 14 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 0 + .byte 0 + .byte 2 + .byte 46 + .byte 1 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 64 + .byte 24 + .ascii "\227B" + .byte 25 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 73 + .byte 19 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 2 + .byte 23 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 5 + .byte 0 + .byte 2 + .byte 24 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 52 + .byte 0 + .byte 2 + .byte 23 + .byte 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 6 + .byte 36 + .byte 0 + .byte 3 + .byte 14 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 0 + .section .debug_info,"",%progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 +.Ldebug_info_start0: + .short 4 + .long .debug_abbrev + .byte 4 + .byte 1 + .long .Linfo_string0 + .short 12 + .long .Linfo_string1 + .long .Lline_table_start0 + .long .Linfo_string2 + .long .Lfunc_begin0 + .long .Lfunc_end1-.Lfunc_begin0 + .byte 2 + .long .Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .long .Linfo_string3 + .byte 1 + .byte 1 + + .long 166 + + .byte 3 + .long .Ldebug_loc0 + .long .Linfo_string6 + .byte 1 + .byte 1 + .long 166 + .byte 4 + .byte 1 + .byte 81 + .long .Linfo_string7 + .byte 1 + .byte 1 + .long 166 + .byte 4 + .byte 1 + .byte 82 + .long .Linfo_string8 + .byte 1 + .byte 1 + .long 166 + .byte 5 + .long .Ldebug_loc1 + .long .Linfo_string9 + .byte 1 + .byte 2 + .long 166 + .byte 5 + .long .Ldebug_loc2 + .long .Linfo_string10 + .byte 1 + .byte 3 + .long 166 + .byte 0 + .byte 2 + .long .Lfunc_begin1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .long .Linfo_string5 + .byte 1 + .byte 7 + + .long 166 + + .byte 4 + .byte 1 + .byte 80 + .long .Linfo_string6 + .byte 1 + .byte 7 + .long 166 + .byte 0 + .byte 6 + .long .Linfo_string4 + .byte 5 + .byte 4 + .byte 0 +.Ldebug_info_end0: + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" + .section ".note.GNU-stack","",%progbits + .addrsig + .eabi_attribute 30, 1 + .section .debug_line,"",%progbits +.Lline_table_start0: diff --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5-sections.s @@ -0,0 +1,411 @@ +## RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj --dwarf-version=5 | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +## RUN: FileCheck %s + +# Check that the -debug-vars option works for simple register locations, when +# using DWARF4 debug info, with functions im multiple sections. + +# Generated with this compile command, with the source code in Inputs/debug.c: +# clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-5 -S -o - -ffunction-sections + +# CHECK: Disassembly of section .text.foo: +# CHECK-EMPTY: +# CHECK-NEXT: 00000000 foo: +# CHECK-NEXT: ┠─ a = R0 +# CHECK-NEXT: ┃ ┠─ b = R1 +# CHECK-NEXT: ┃ ┃ ┠─ c = R2 +# CHECK-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# CHECK-NEXT: 0: add r0, r1, r0 ┻ ┃ ┃ ╈ +# CHECK-NEXT: ┌─ y = R0 +# CHECK-NEXT: 4: add r0, r0, r2 ╈ ┃ ┃ ┻ +# CHECK-NEXT: 8: bx lr ┻ ┻ ┻ +# CHECK-EMPTY: +# CHECK-NEXT: Disassembly of section .text.bar: +# CHECK-EMPTY: +# CHECK-NEXT: 00000000 bar: +# CHECK-NEXT: ┠─ a = R0 +# CHECK-NEXT: 0: add r0, r0, #1 ┃ +# CHECK-NEXT: 4: bx lr ┻ + + .text + .syntax unified + .eabi_attribute 67, "2.09" + .eabi_attribute 6, 10 + .eabi_attribute 7, 65 + .eabi_attribute 8, 1 + .eabi_attribute 9, 2 + .fpu neon + .eabi_attribute 34, 0 + .eabi_attribute 17, 1 + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 38, 1 + .eabi_attribute 18, 4 + .eabi_attribute 26, 2 + .eabi_attribute 14, 0 + .file "debug.c" + .section .text.foo,"ax",%progbits + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin0: + .file 0 "/work/scratch" "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e + .file 1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e + .loc 1 1 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .loc 1 2 13 prologue_end + add r0, r1, r0 +.Ltmp0: + .loc 1 3 13 + add r0, r0, r2 +.Ltmp1: + .loc 1 4 3 + bx lr +.Ltmp2: +.Lfunc_end0: + .size foo, .Lfunc_end0-foo + .cfi_endproc + .cantunwind + .fnend + + .section .text.bar,"ax",%progbits + .globl bar + .p2align 2 + .type bar,%function + .code 32 +bar: +.Lfunc_begin1: + .loc 1 7 0 + .fnstart + .cfi_startproc + .loc 1 8 4 prologue_end + add r0, r0, #1 +.Ltmp3: + .loc 1 9 3 + bx lr +.Ltmp4: +.Lfunc_end1: + .size bar, .Lfunc_end1-bar + .cfi_endproc + .cantunwind + .fnend + + .section .debug_str_offsets,"",%progbits + .long 48 + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",%progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" +.Linfo_string1: + .asciz "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" +.Linfo_string2: + .asciz "/work/scratch" +.Linfo_string3: + .asciz "foo" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "bar" +.Linfo_string6: + .asciz "a" +.Linfo_string7: + .asciz "b" +.Linfo_string8: + .asciz "c" +.Linfo_string9: + .asciz "x" +.Linfo_string10: + .asciz "y" + .section .debug_str_offsets,"",%progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .section .debug_loclists,"",%progbits + .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 +.Ldebug_loclist_table_start0: + .short 5 + .byte 4 + .byte 0 + .long 3 +.Lloclists_table_base0: + .long .Ldebug_loc0-.Lloclists_table_base0 + .long .Ldebug_loc1-.Lloclists_table_base0 + .long .Ldebug_loc2-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 3 + .byte 0 + .uleb128 .Ltmp0-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc1: + .byte 1 + .byte 0 + .byte 4 + .uleb128 .Ltmp0-.Lfunc_begin0 + .uleb128 .Ltmp1-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc2: + .byte 1 + .byte 0 + .byte 4 + .uleb128 .Ltmp1-.Lfunc_begin0 + .uleb128 .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loclist_table_end0: + .section .debug_abbrev,"",%progbits + .byte 1 + .byte 17 + .byte 1 + .byte 37 + .byte 37 + .byte 19 + .byte 5 + .byte 3 + .byte 37 + .byte 114 + .byte 23 + .byte 16 + .byte 23 + .byte 27 + .byte 37 + .byte 17 + .byte 1 + .byte 85 + .byte 35 + .byte 115 + .byte 23 + .byte 116 + .byte 23 + .ascii "\214\001" + .byte 23 + .byte 0 + .byte 0 + .byte 2 + .byte 46 + .byte 1 + .byte 17 + .byte 27 + .byte 18 + .byte 6 + .byte 64 + .byte 24 + .byte 122 + .byte 25 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 73 + .byte 19 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 2 + .byte 34 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 5 + .byte 0 + .byte 2 + .byte 24 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 52 + .byte 0 + .byte 2 + .byte 34 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 6 + .byte 36 + .byte 0 + .byte 3 + .byte 37 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 0 + .section .debug_info,"",%progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 +.Ldebug_info_start0: + .short 5 + .byte 1 + .byte 4 + .long .debug_abbrev + .byte 1 + .byte 0 + .short 12 + .byte 1 + .long .Lstr_offsets_base0 + .long .Lline_table_start0 + .byte 2 + .long 0 + .byte 0 + .long .Laddr_table_base0 + .long .Lrnglists_table_base0 + .long .Lloclists_table_base0 + .byte 2 + .byte 0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .byte 3 + .byte 1 + .byte 1 + + .long 132 + + .byte 3 + .byte 0 + .byte 6 + .byte 1 + .byte 1 + .long 132 + .byte 4 + .byte 1 + .byte 81 + .byte 7 + .byte 1 + .byte 1 + .long 132 + .byte 4 + .byte 1 + .byte 82 + .byte 8 + .byte 1 + .byte 1 + .long 132 + .byte 5 + .byte 1 + .byte 9 + .byte 1 + .byte 2 + .long 132 + .byte 5 + .byte 2 + .byte 10 + .byte 1 + .byte 3 + .long 132 + .byte 0 + .byte 2 + .byte 1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .byte 5 + .byte 1 + .byte 7 + + .long 132 + + .byte 4 + .byte 1 + .byte 80 + .byte 6 + .byte 1 + .byte 7 + .long 132 + .byte 0 + .byte 6 + .byte 4 + .byte 5 + .byte 4 + .byte 0 +.Ldebug_info_end0: + .section .debug_rnglists,"",%progbits + .long .Ldebug_rnglist_table_end0-.Ldebug_rnglist_table_start0 +.Ldebug_rnglist_table_start0: + .short 5 + .byte 4 + .byte 0 + .long 1 +.Lrnglists_table_base0: + .long .Ldebug_ranges0-.Lrnglists_table_base0 +.Ldebug_ranges0: + .byte 3 + .byte 0 + .uleb128 .Lfunc_end0-.Lfunc_begin0 + .byte 3 + .byte 1 + .uleb128 .Lfunc_end1-.Lfunc_begin1 + .byte 0 +.Ldebug_rnglist_table_end0: + .section .debug_addr,"",%progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 +.Ldebug_addr_start0: + .short 5 + .byte 4 + .byte 0 +.Laddr_table_base0: + .long .Lfunc_begin0 + .long .Lfunc_begin1 +.Ldebug_addr_end0: + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" + .section ".note.GNU-stack","",%progbits + .addrsig + .eabi_attribute 30, 1 + .section .debug_line,"",%progbits +.Lline_table_start0: diff --git a/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-dwarf5.s @@ -0,0 +1,382 @@ +## RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj --dwarf-version=5 | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +## RUN: FileCheck %s + +# Check that the -debug-vars option works for simple register locations, when +# using DWARF5 debug info, with multiple functions in one section. + +# Generated with this compile command, with the source code in Inputs/debug.c: +# clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-3 -S -o - + +# CHECK: Disassembly of section .text: +# CHECK-EMPTY: +# CHECK-NEXT: 00000000 foo: +# CHECK-NEXT: ┠─ a = R0 +# CHECK-NEXT: ┃ ┠─ b = R1 +# CHECK-NEXT: ┃ ┃ ┠─ c = R2 +# CHECK-NEXT: ┃ ┃ ┃ ┌─ x = R0 +# CHECK-NEXT: 0: add r0, r1, r0 ┻ ┃ ┃ ╈ +# CHECK-NEXT: ┌─ y = R0 +# CHECK-NEXT: 4: add r0, r0, r2 ╈ ┃ ┃ ┻ +# CHECK-NEXT: 8: bx lr ┻ ┻ ┻ +# CHECK-EMPTY: +# CHECK-NEXT: 0000000c bar: +# CHECK-NEXT: ┠─ a = R0 +# CHECK-NEXT: c: add r0, r0, #1 ┃ +# CHECK-NEXT: 10: bx lr ┻ + + .text + .syntax unified + .eabi_attribute 67, "2.09" + .eabi_attribute 6, 10 + .eabi_attribute 7, 65 + .eabi_attribute 8, 1 + .eabi_attribute 9, 2 + .fpu neon + .eabi_attribute 34, 0 + .eabi_attribute 17, 1 + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 38, 1 + .eabi_attribute 18, 4 + .eabi_attribute 26, 2 + .eabi_attribute 14, 0 + .file "debug.c" + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin0: + .file 0 "/work/scratch" "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e + .file 1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" md5 0x07374f01ab24ec7c07db73bc13bd778e + .loc 1 1 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .loc 1 2 13 prologue_end + add r0, r1, r0 +.Ltmp0: + .loc 1 3 13 + add r0, r0, r2 +.Ltmp1: + .loc 1 4 3 + bx lr +.Ltmp2: +.Lfunc_end0: + .size foo, .Lfunc_end0-foo + .cfi_endproc + .cantunwind + .fnend + + .globl bar + .p2align 2 + .type bar,%function + .code 32 +bar: +.Lfunc_begin1: + .loc 1 7 0 + .fnstart + .cfi_startproc + .loc 1 8 4 prologue_end + add r0, r0, #1 +.Ltmp3: + .loc 1 9 3 + bx lr +.Ltmp4: +.Lfunc_end1: + .size bar, .Lfunc_end1-bar + .cfi_endproc + .cantunwind + .fnend + + .section .debug_str_offsets,"",%progbits + .long 48 + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",%progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" +.Linfo_string1: + .asciz "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" +.Linfo_string2: + .asciz "/work/scratch" +.Linfo_string3: + .asciz "foo" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "bar" +.Linfo_string6: + .asciz "a" +.Linfo_string7: + .asciz "b" +.Linfo_string8: + .asciz "c" +.Linfo_string9: + .asciz "x" +.Linfo_string10: + .asciz "y" + .section .debug_str_offsets,"",%progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .section .debug_loclists,"",%progbits + .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 +.Ldebug_loclist_table_start0: + .short 5 + .byte 4 + .byte 0 + .long 3 +.Lloclists_table_base0: + .long .Ldebug_loc0-.Lloclists_table_base0 + .long .Ldebug_loc1-.Lloclists_table_base0 + .long .Ldebug_loc2-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 4 + .uleb128 .Lfunc_begin0-.Lfunc_begin0 + .uleb128 .Ltmp0-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc1: + .byte 4 + .uleb128 .Ltmp0-.Lfunc_begin0 + .uleb128 .Ltmp1-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc2: + .byte 4 + .uleb128 .Ltmp1-.Lfunc_begin0 + .uleb128 .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loclist_table_end0: + .section .debug_abbrev,"",%progbits + .byte 1 + .byte 17 + .byte 1 + .byte 37 + .byte 37 + .byte 19 + .byte 5 + .byte 3 + .byte 37 + .byte 114 + .byte 23 + .byte 16 + .byte 23 + .byte 27 + .byte 37 + .byte 17 + .byte 27 + .byte 18 + .byte 6 + .byte 115 + .byte 23 + .ascii "\214\001" + .byte 23 + .byte 0 + .byte 0 + .byte 2 + .byte 46 + .byte 1 + .byte 17 + .byte 27 + .byte 18 + .byte 6 + .byte 64 + .byte 24 + .byte 122 + .byte 25 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 73 + .byte 19 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 2 + .byte 34 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 5 + .byte 0 + .byte 2 + .byte 24 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 52 + .byte 0 + .byte 2 + .byte 34 + .byte 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 6 + .byte 36 + .byte 0 + .byte 3 + .byte 37 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 0 + .section .debug_info,"",%progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 +.Ldebug_info_start0: + .short 5 + .byte 1 + .byte 4 + .long .debug_abbrev + .byte 1 + .byte 0 + .short 12 + .byte 1 + .long .Lstr_offsets_base0 + .long .Lline_table_start0 + .byte 2 + .byte 0 + .long .Lfunc_end1-.Lfunc_begin0 + .long .Laddr_table_base0 + .long .Lloclists_table_base0 + .byte 2 + .byte 0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .byte 3 + .byte 1 + .byte 1 + + .long 128 + + .byte 3 + .byte 0 + .byte 6 + .byte 1 + .byte 1 + .long 128 + .byte 4 + .byte 1 + .byte 81 + .byte 7 + .byte 1 + .byte 1 + .long 128 + .byte 4 + .byte 1 + .byte 82 + .byte 8 + .byte 1 + .byte 1 + .long 128 + .byte 5 + .byte 1 + .byte 9 + .byte 1 + .byte 2 + .long 128 + .byte 5 + .byte 2 + .byte 10 + .byte 1 + .byte 3 + .long 128 + .byte 0 + .byte 2 + .byte 1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .byte 5 + .byte 1 + .byte 7 + + .long 128 + + .byte 4 + .byte 1 + .byte 80 + .byte 6 + .byte 1 + .byte 7 + .long 128 + .byte 0 + .byte 6 + .byte 4 + .byte 5 + .byte 4 + .byte 0 +.Ldebug_info_end0: + .section .debug_addr,"",%progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 +.Ldebug_addr_start0: + .short 5 + .byte 4 + .byte 0 +.Laddr_table_base0: + .long .Lfunc_begin0 + .long .Lfunc_begin1 +.Ldebug_addr_end0: + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" + .section ".note.GNU-stack","",%progbits + .addrsig + .eabi_attribute 30, 1 + .section .debug_line,"",%progbits +.Lline_table_start0: diff --git a/llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s b/llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/PowerPC/debug-vars.s @@ -0,0 +1,372 @@ +## RUN: llvm-mc -triple powerpc64-unknown-linux < %s -filetype=obj | \ +## RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +## RUN: FileCheck %s + +# Check that the -debug-vars option works for simple register locations, when +# using DWARF4 debug info, with multiple functions in one section. + +# Generated with this compile command and source code: +# clang --target=arm--none-eabi -march=armv7-a -c debug.c -O1 -gdwarf-3 -S -o - + +# clang --target=powerpc64-unknown-linux -c debug.c -O1 -S -o - +# +# int foo(int a, int b, int c) { +# int x = a + b; +# int y = x + c; +# return y; +# } +# +# int bar(int a) { +# a++; +# return a; +# } + +# CHECK: Disassembly of section .text: +# CHECK-EMPTY: +# CHECK-NEXT: 0000000000000000 .text: +# CHECK-NEXT: ┠─ a = S3 +# CHECK-NEXT: ┃ ┠─ b = S4 +# CHECK-NEXT: ┃ ┃ ┠─ c = S5 +# CHECK-NEXT: ┃ ┃ ┃ ┌─ x = S3 +# CHECK-NEXT: 0: add 3, 4, 3 ┻ ┃ ┃ ╈ +# CHECK-NEXT: ┌─ y = S3 +# CHECK-NEXT: 4: add 3, 3, 5 ╈ ┃ ┃ ┻ +# CHECK-NEXT: 8: extsw 3, 3 ┻ ┃ ┃ +# CHECK-NEXT: c: blr ┃ ┃ +# CHECK-NEXT: ... +# CHECK-NEXT: ┠─ a = S3 +# CHECK-NEXT: 1c: addi 3, 3, 1 ┃ +# CHECK-NEXT: 20: extsw 3, 3 ┻ +# CHECK-NEXT: 24: blr +# CHECK-NEXT: ... + + .text + .file "debug.c" + .globl foo # -- Begin function foo + .p2align 2 + .type foo,@function + .section .opd,"aw",@progbits +foo: # @foo + .p2align 3 + .quad .Lfunc_begin0 + .quad .TOC.@tocbase + .quad 0 + .text +.Lfunc_begin0: + .file 1 "/work" "llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" + .loc 1 1 0 # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:1:0 + .cfi_sections .debug_frame + .cfi_startproc +# %bb.0: # %entry + #DEBUG_VALUE: foo:a <- $x3 + #DEBUG_VALUE: foo:a <- $r3 + #DEBUG_VALUE: foo:b <- $x4 + #DEBUG_VALUE: foo:b <- $x4 + #DEBUG_VALUE: foo:b <- $r4 + #DEBUG_VALUE: foo:c <- $x5 + #DEBUG_VALUE: foo:c <- $x5 + #DEBUG_VALUE: foo:c <- $r5 + .loc 1 2 13 prologue_end # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:2:13 + add 3, 4, 3 +.Ltmp0: + #DEBUG_VALUE: foo:x <- $r3 + .loc 1 3 13 # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:3:13 + add 3, 3, 5 +.Ltmp1: + #DEBUG_VALUE: foo:y <- $r3 + .loc 1 4 3 # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:4:3 + extsw 3, 3 +.Ltmp2: + blr +.Ltmp3: + .long 0 + .quad 0 +.Lfunc_end0: + .size foo, .Lfunc_end0-.Lfunc_begin0 + .cfi_endproc + # -- End function + .globl bar # -- Begin function bar + .p2align 2 + .type bar,@function + .section .opd,"aw",@progbits +bar: # @bar + .p2align 3 + .quad .Lfunc_begin1 + .quad .TOC.@tocbase + .quad 0 + .text +.Lfunc_begin1: + .loc 1 7 0 # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:7:0 + .cfi_startproc +# %bb.0: # %entry + #DEBUG_VALUE: bar:a <- $x3 + #DEBUG_VALUE: bar:a <- $r3 + .loc 1 8 4 prologue_end # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:8:4 + addi 3, 3, 1 +.Ltmp4: + #DEBUG_VALUE: bar:a <- $r3 + .loc 1 9 3 # llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c:9:3 + extsw 3, 3 +.Ltmp5: + blr +.Ltmp6: + .long 0 + .quad 0 +.Lfunc_end1: + .size bar, .Lfunc_end1-.Lfunc_begin1 + .cfi_endproc + # -- End function + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" # string offset=0 +.Linfo_string1: + .asciz "/work/llvm/src/llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c" # string offset=101 +.Linfo_string2: + .asciz "/work/scratch" # string offset=164 +.Linfo_string3: + .asciz "foo" # string offset=178 +.Linfo_string4: + .asciz "int" # string offset=182 +.Linfo_string5: + .asciz "bar" # string offset=186 +.Linfo_string6: + .asciz "a" # string offset=190 +.Linfo_string7: + .asciz "b" # string offset=192 +.Linfo_string8: + .asciz "c" # string offset=194 +.Linfo_string9: + .asciz "x" # string offset=196 +.Linfo_string10: + .asciz "y" # string offset=198 + .section .debug_loc,"",@progbits +.Ldebug_loc0: + .quad .Lfunc_begin0-.Lfunc_begin0 + .quad .Ltmp0-.Lfunc_begin0 + .short 3 # Loc expr size + .byte 144 # super-register DW_OP_regx + .byte 179 # 1203 + .byte 9 # + .quad 0 + .quad 0 +.Ldebug_loc1: + .quad .Ltmp0-.Lfunc_begin0 + .quad .Ltmp1-.Lfunc_begin0 + .short 3 # Loc expr size + .byte 144 # super-register DW_OP_regx + .byte 179 # 1203 + .byte 9 # + .quad 0 + .quad 0 +.Ldebug_loc2: + .quad .Ltmp1-.Lfunc_begin0 + .quad .Ltmp2-.Lfunc_begin0 + .short 3 # Loc expr size + .byte 144 # super-register DW_OP_regx + .byte 179 # 1203 + .byte 9 # + .quad 0 + .quad 0 +.Ldebug_loc3: + .quad .Lfunc_begin1-.Lfunc_begin0 + .quad .Ltmp5-.Lfunc_begin0 + .short 3 # Loc expr size + .byte 144 # super-register DW_OP_regx + .byte 179 # 1203 + .byte 9 # + .quad 0 + .quad 0 + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .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 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .ascii "\227B" # DW_AT_GNU_all_call_sites + .byte 25 # DW_FORM_flag_present + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 39 # DW_AT_prototyped + .byte 25 # DW_FORM_flag_present + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .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 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .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 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0xb5 DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 12 # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc + .byte 2 # Abbrev [2] 0x2a:0x65 DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 81 + # DW_AT_GNU_all_call_sites + .long .Linfo_string3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + # DW_AT_prototyped + .long 184 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x43:0xf DW_TAG_formal_parameter + .long .Ldebug_loc0 # DW_AT_location + .long .Linfo_string6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 184 # DW_AT_type + .byte 4 # Abbrev [4] 0x52:0xf DW_TAG_formal_parameter + .byte 3 # DW_AT_location + .byte 144 + .ascii "\264\t" + .long .Linfo_string7 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 184 # DW_AT_type + .byte 4 # Abbrev [4] 0x61:0xf DW_TAG_formal_parameter + .byte 3 # DW_AT_location + .byte 144 + .ascii "\265\t" + .long .Linfo_string8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 184 # DW_AT_type + .byte 5 # Abbrev [5] 0x70:0xf DW_TAG_variable + .long .Ldebug_loc1 # DW_AT_location + .long .Linfo_string9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 184 # DW_AT_type + .byte 5 # Abbrev [5] 0x7f:0xf DW_TAG_variable + .long .Ldebug_loc2 # DW_AT_location + .long .Linfo_string10 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .long 184 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 2 # Abbrev [2] 0x8f:0x29 DW_TAG_subprogram + .quad .Lfunc_begin1 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 81 + # DW_AT_GNU_all_call_sites + .long .Linfo_string5 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + # DW_AT_prototyped + .long 184 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0xa8:0xf DW_TAG_formal_parameter + .long .Ldebug_loc3 # DW_AT_location + .long .Linfo_string6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .long 184 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0xb8:0x7 DW_TAG_base_type + .long .Linfo_string4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git e73f78acd34360f7450b81167d9dc858ccddc262)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/llvm/test/tools/llvm-symbolizer/frame-loclistx.s b/llvm/test/tools/llvm-symbolizer/frame-loclistx.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/frame-loclistx.s @@ -0,0 +1,284 @@ +// Test dwarf-5 DW_AT_location [DW_FORM_loclistx]. +// REQUIRES: aarch64-registered-target + +// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android -o %t.o %s +// RUN: echo 'FRAME %t.o 0x4' | llvm-symbolizer | FileCheck %s + +// DW_AT_location (indexed (0x0) loclist = 0x00000010: +// [0x0000000000000010, 0x0000000000000018): DW_OP_consts +1, DW_OP_stack_value +// [0x0000000000000018, 0x0000000000000028): DW_OP_breg29 W29-4) +// CHECK: f +// CHECK-NEXT: x +// CHECK-NEXT: {{.*}}dbg.cc:5 +// CHECK-NEXT: -4 4 ?? + + .text + .file "dbg.cc" + .file 0 "/tmp" "/tmp/dbg.cc" md5 0xb9e2d9cf63655505d60c734686e688fd + .file 1 "dbg.cc" md5 0xb9e2d9cf63655505d60c734686e688fd + .globl f // -- Begin function f + .p2align 2 + .type f,@function +f: // @f +.Lfunc_begin0: + .loc 1 4 0 // dbg.cc:4:0 + .cfi_startproc +// %bb.0: + sub sp, sp, #32 // =32 + stp x29, x30, [sp, #16] // 16-byte Folded Spill + add x29, sp, #16 // =16 + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + mov w8, #1 +.Ltmp0: + //DEBUG_VALUE: f:x <- 1 + .loc 1 6 3 prologue_end // dbg.cc:6:3 + sub x0, x29, #4 // =4 + .loc 1 5 7 // dbg.cc:5:7 + stur w8, [x29, #-4] +.Ltmp1: + //DEBUG_VALUE: f:x <- [DW_OP_constu 4, DW_OP_minus, DW_OP_deref] $fp + .loc 1 6 3 // dbg.cc:6:3 + bl use +.Ltmp2: + .loc 1 7 1 // dbg.cc:7:1 + ldp x29, x30, [sp, #16] // 16-byte Folded Reload + add sp, sp, #32 // =32 + ret +.Ltmp3: +.Lfunc_end0: + .size f, .Lfunc_end0-f + .cfi_endproc + // -- End function + .section .debug_str_offsets,"",@progbits + .word 32 + .hword 5 + .hword 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 10.0.0 (git@github.com:llvm/llvm-project.git 57e2b50509793c72f562e8a08523f7ab664adfcd)" // string offset=0 +.Linfo_string1: + .asciz "/tmp/dbg.cc" // string offset=101 +.Linfo_string2: + .asciz "/tmp" // string offset=113 +.Linfo_string3: + .asciz "use" // string offset=118 +.Linfo_string4: + .asciz "f" // string offset=122 +.Linfo_string5: + .asciz "x" // string offset=124 +.Linfo_string6: + .asciz "int" // string offset=126 + .section .debug_str_offsets,"",@progbits + .word .Linfo_string0 + .word .Linfo_string1 + .word .Linfo_string2 + .word .Linfo_string3 + .word .Linfo_string4 + .word .Linfo_string5 + .word .Linfo_string6 + .section .debug_loclists,"",@progbits + .word .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 // Length +.Ldebug_loclist_table_start0: + .hword 5 // Version + .byte 8 // Address size + .byte 0 // Segment selector size + .word 1 // Offset entry count +.Lloclists_table_base0: + .word .Ldebug_loc0-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 4 // DW_LLE_offset_pair + .uleb128 .Ltmp0-.Lfunc_begin0 // starting offset + .uleb128 .Ltmp1-.Lfunc_begin0 // ending offset + .byte 3 // Loc expr size + .byte 17 // DW_OP_consts + .byte 1 // 1 + .byte 159 // DW_OP_stack_value + .byte 4 // DW_LLE_offset_pair + .uleb128 .Ltmp1-.Lfunc_begin0 // starting offset + .uleb128 .Lfunc_end0-.Lfunc_begin0 // ending offset + .byte 2 // Loc expr size + .byte 141 // DW_OP_breg29 + .byte 124 // -4 + .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 37 // DW_AT_producer + .byte 37 // DW_FORM_strx1 + .byte 19 // DW_AT_language + .byte 5 // DW_FORM_data2 + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 114 // DW_AT_str_offsets_base + .byte 23 // DW_FORM_sec_offset + .byte 16 // DW_AT_stmt_list + .byte 23 // DW_FORM_sec_offset + .byte 27 // DW_AT_comp_dir + .byte 37 // DW_FORM_strx1 + .byte 17 // DW_AT_low_pc + .byte 27 // DW_FORM_addrx + .byte 18 // DW_AT_high_pc + .byte 6 // DW_FORM_data4 + .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 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 58 // DW_AT_decl_file + .byte 11 // DW_FORM_data1 + .byte 59 // DW_AT_decl_line + .byte 11 // DW_FORM_data1 + .byte 60 // DW_AT_declaration + .byte 25 // DW_FORM_flag_present + .byte 63 // DW_AT_external + .byte 25 // DW_FORM_flag_present + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 3 // Abbreviation Code + .byte 5 // DW_TAG_formal_parameter + .byte 0 // DW_CHILDREN_no + .byte 73 // DW_AT_type + .byte 19 // DW_FORM_ref4 + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 4 // Abbreviation Code + .byte 15 // DW_TAG_pointer_type + .byte 0 // DW_CHILDREN_no + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 5 // 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 64 // DW_AT_frame_base + .byte 24 // DW_FORM_exprloc + .byte 122 // DW_AT_call_all_calls + .byte 25 // DW_FORM_flag_present + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 58 // DW_AT_decl_file + .byte 11 // DW_FORM_data1 + .byte 59 // DW_AT_decl_line + .byte 11 // DW_FORM_data1 + .byte 63 // DW_AT_external + .byte 25 // DW_FORM_flag_present + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 6 // Abbreviation Code + .byte 52 // DW_TAG_variable + .byte 0 // DW_CHILDREN_no + .byte 2 // DW_AT_location + .byte 34 // DW_FORM_loclistx + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 58 // DW_AT_decl_file + .byte 11 // DW_FORM_data1 + .byte 59 // DW_AT_decl_line + .byte 11 // DW_FORM_data1 + .byte 73 // DW_AT_type + .byte 19 // DW_FORM_ref4 + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 7 // Abbreviation Code + .byte 72 // DW_TAG_call_site + .byte 0 // DW_CHILDREN_no + .byte 127 // DW_AT_call_origin + .byte 19 // DW_FORM_ref4 + .byte 125 // DW_AT_call_return_pc + .byte 1 // DW_FORM_addr + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 8 // Abbreviation Code + .byte 36 // DW_TAG_base_type + .byte 0 // DW_CHILDREN_no + .byte 3 // DW_AT_name + .byte 37 // DW_FORM_strx1 + .byte 62 // DW_AT_encoding + .byte 11 // DW_FORM_data1 + .byte 11 // DW_AT_byte_size + .byte 11 // DW_FORM_data1 + .byte 0 // EOM(1) + .byte 0 // EOM(2) + .byte 0 // EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .word .Ldebug_info_end0-.Ldebug_info_start0 // Length of Unit +.Ldebug_info_start0: + .hword 5 // DWARF version number + .byte 1 // DWARF Unit Type + .byte 8 // Address Size (in bytes) + .word .debug_abbrev // Offset Into Abbrev. Section + .byte 1 // Abbrev [1] 0xc:0x4d DW_TAG_compile_unit + .byte 0 // DW_AT_producer + .hword 33 // DW_AT_language + .byte 1 // DW_AT_name + .word .Lstr_offsets_base0 // DW_AT_str_offsets_base + .word .Lline_table_start0 // DW_AT_stmt_list + .byte 2 // DW_AT_comp_dir + .byte 0 // DW_AT_low_pc + .word .Lfunc_end0-.Lfunc_begin0 // DW_AT_high_pc + .word .Laddr_table_base0 // DW_AT_addr_base + .word .Lloclists_table_base0 // DW_AT_loclists_base + .byte 2 // Abbrev [2] 0x27:0xa DW_TAG_subprogram + .byte 3 // DW_AT_name + .byte 1 // DW_AT_decl_file + .byte 2 // DW_AT_decl_line + // DW_AT_declaration + // DW_AT_external + .byte 3 // Abbrev [3] 0x2b:0x5 DW_TAG_formal_parameter + .word 49 // DW_AT_type + .byte 0 // End Of Children Mark + .byte 4 // Abbrev [4] 0x31:0x1 DW_TAG_pointer_type + .byte 5 // Abbrev [5] 0x32:0x22 DW_TAG_subprogram + .byte 0 // DW_AT_low_pc + .word .Lfunc_end0-.Lfunc_begin0 // DW_AT_high_pc + .byte 1 // DW_AT_frame_base + .byte 109 + // DW_AT_call_all_calls + .byte 4 // DW_AT_name + .byte 1 // DW_AT_decl_file + .byte 4 // DW_AT_decl_line + // DW_AT_external + .byte 6 // Abbrev [6] 0x3d:0x9 DW_TAG_variable + .byte 0 // DW_AT_location + .byte 5 // DW_AT_name + .byte 1 // DW_AT_decl_file + .byte 5 // DW_AT_decl_line + .word 84 // DW_AT_type + .byte 7 // Abbrev [7] 0x46:0xd DW_TAG_call_site + .word 39 // DW_AT_call_origin + .xword .Ltmp2-.Lfunc_begin0 // DW_AT_call_return_pc + .byte 0 // End Of Children Mark + .byte 8 // Abbrev [8] 0x54:0x4 DW_TAG_base_type + .byte 6 // DW_AT_name + .byte 5 // DW_AT_encoding + .byte 4 // DW_AT_byte_size + .byte 0 // End Of Children Mark +.Ldebug_info_end0: + .section .debug_addr,"",@progbits + .word .Ldebug_addr_end0-.Ldebug_addr_start0 // Length of contribution +.Ldebug_addr_start0: + .hword 5 // DWARF version number + .byte 8 // Address size + .byte 0 // Segment selector size +.Laddr_table_base0: + .xword .Lfunc_begin0 +.Ldebug_addr_end0: + .ident "clang version 10.0.0 (git@github.com:llvm/llvm-project.git 57e2b50509793c72f562e8a08523f7ab664adfcd)" + .section ".note.GNU-stack","",@progbits + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -16,7 +16,9 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" +#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/StringExtras.h" @@ -70,6 +72,8 @@ #include #include +#define DEBUG_TYPE "objdump" + using namespace llvm::object; namespace llvm { @@ -334,6 +338,17 @@ cl::cat(ObjdumpCat)); static cl::alias WideShort("w", cl::Grouping, cl::aliasopt(Wide)); +static cl::opt + DbgVariables("debug-vars", cl::init(false), + cl::desc("Print the locations (in registers or memory) of " + "source-level variables alongside disassembly"), + cl::cat(ObjdumpCat)); +static cl::opt + DbgIndent("debug-vars-indent", cl::init(50), + cl::desc("Distance to indent the source-level variable display, " + "relative to the start of the disassembly"), + cl::cat(ObjdumpCat)); + static cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); @@ -538,6 +553,370 @@ } namespace { + +/// A user-facing string representation of a DWARF expression. This might be an +/// Address expression, in which case it will get an implicit dereference, or a +/// Value expression, which does not. +struct PrintedExpr { + enum ExprKind { + Address, + Value, + }; + ExprKind Kind; + SmallString<20> String; + + PrintedExpr(ExprKind K = Address) : Kind(K) {} +}; + +static void PrettyPrintDWARFOps(raw_ostream &OS, DWARFExpression::iterator I, + const DWARFExpression::iterator E, + const MCRegisterInfo *MRI) { + SmallVector Stack; + + while (I != E) { + auto &Op = *I; + unsigned Opcode = Op.getCode(); + if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) { + int DwarfRegNum = Opcode - dwarf::DW_OP_reg0; + int LLVMRegNum = *MRI->getLLVMRegNum(DwarfRegNum, false); + raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); + S << MRI->getName(LLVMRegNum); + } else if (Opcode == dwarf::DW_OP_regx) { + int DwarfRegNum = Op.getRawOperand(0); + int LLVMRegNum = *MRI->getLLVMRegNum(DwarfRegNum, false); + raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); + S << MRI->getName(LLVMRegNum); + } else { + // If we hit an unknown operand, we don't know it's effect on the stack, + // so bail out on the whole expression. + OS << ""; + return; + } + ++I; + } + + assert(Stack.size() == 1 && "expected one value on stack"); + OS << Stack.front().String; +} + +static void PrettyPrintDWARFExpr(raw_ostream &OS, const DWARFExpression *Expr, + const MCRegisterInfo *MRI, + const DWARFDie FuncDie, bool LittleEndian) { + // TODO: render the DW_AT_frame_base expression for the function, if it has + // one. + + // Render the actual expression. + PrettyPrintDWARFOps(OS, Expr->begin(), Expr->end(), MRI); +} + +/// Stores a single expression representing the location of a source-level +/// variable, along with the PC range for which that expression is valid. +struct LiveVariable { + DWARFLocationExpression LocExpr; + const char *VarName; + DWARFUnit *Unit; + const DWARFDie FuncDie; + + LiveVariable(DWARFLocationExpression &LocExpr, const char *VarName, + DWARFUnit *Unit, const DWARFDie FuncDie) + : LocExpr(LocExpr), VarName(VarName), Unit(Unit), FuncDie(FuncDie) {} + + bool liveAtAddress(object::SectionedAddress Addr) { + if (LocExpr.Range == None) + return false; + return LocExpr.Range->SectionIndex == Addr.SectionIndex && + LocExpr.Range->LowPC <= Addr.Address && + LocExpr.Range->HighPC > Addr.Address; + } + + void print(raw_ostream &OS, const MCRegisterInfo *MRI, + bool LittleEndian) const { + DataExtractor Data({LocExpr.Expr.data(), LocExpr.Expr.size()}, LittleEndian, + 0); + DWARFExpression Expression(Data, Unit->getVersion(), + Unit->getAddressByteSize()); + PrettyPrintDWARFExpr(OS, &Expression, MRI, FuncDie, LittleEndian); + } +}; + +/// Helper class for printing source variable locations alongside disassembly. +class LiveVariablePrinter { + // Information we want to track about one column in which we are printing a + // variable live range. + struct Column { + unsigned VarIdx; + bool LiveIn; + bool LiveOut; + bool MustDrawLabel; + + bool isActive() const { return VarIdx != ~0U; } + }; + + // All live variables we know about in the object/image file. + std::vector LiveVariables; + + // Coulmns which we are currently drawing. + IndexedMap ActiveCols; + + const MCRegisterInfo *MRI; + bool LittleEndian; + + void AddVariable(DWARFDie FuncDie, DWARFDie VarDie) { + uint64_t FuncLowPC, FuncHighPC, SectionIndex; + FuncDie.getLowAndHighPC(FuncLowPC, FuncHighPC, SectionIndex); + const char *VarName = VarDie.getName(DINameKind::ShortName); + DWARFUnit *U = VarDie.getDwarfUnit(); + + Expected Locs = + VarDie.getLocations(dwarf::DW_AT_location); + if (!Locs) { + consumeError(Locs.takeError()); + return; + } + + for (auto &LocExpr : *Locs) { + if (LocExpr.Range) { + // FIXME: getLocations seems to get the section index wrong for + // objects built with -ffunction-sections, for now we just fix it up + // here. + DWARFLocationExpression FixedExpr{ + DWARFAddressRange(LocExpr.Range->LowPC, LocExpr.Range->HighPC, + SectionIndex), + LocExpr.Expr}; + LiveVariables.emplace_back(FixedExpr, VarName, U, FuncDie); + } else { + // If the LocExpr does not have an associated range, it is valid for + // the whole of the function. + // TODO: technically it is not valid for any range covered by another + // LocExpr, does that happen in reality? + DWARFLocationExpression WholeFuncExpr{ + DWARFAddressRange(FuncLowPC, FuncHighPC, SectionIndex), + LocExpr.Expr}; + LiveVariables.emplace_back(WholeFuncExpr, VarName, U, FuncDie); + } + } + } + + void AddFunction(DWARFDie D) { + for (auto Child : D.children()) { + if (Child.getTag() == dwarf::DW_TAG_variable || + Child.getTag() == dwarf::DW_TAG_formal_parameter) + AddVariable(D, Child); + else + AddFunction(Child); + } + } + + // Get the column number (in characters) at which the first live variable + // line should be printed. + unsigned getIndentLevel() const { + return DbgIndent + (NoShowRawInsn ? 16 : 40); + } + + // Indent to the first live-range column to the right of the currently + // printed line, and return the index of that column. + // TODO: formatted_raw_ostream uses "column" to mean a number of characters + // since the last \n, and we use it to mean the number of slots in which we + // put live variable lines. Pick a less overloaded word. + unsigned MoveToFirstVarColumn(formatted_raw_ostream &OS) { + unsigned FirstUnprintedColumn = + std::max((int)(OS.getColumn() - getIndentLevel() + 1) / 2, 0); + if ((getIndentLevel() + FirstUnprintedColumn * 2) > OS.getColumn()) + OS.PadToColumn(getIndentLevel() + FirstUnprintedColumn * 2); + return FirstUnprintedColumn; + } + + unsigned findFreeColumn() { + for (unsigned ColIdx = 0; ColIdx < ActiveCols.size(); ++ColIdx) + if (!ActiveCols[ColIdx].isActive()) + return ColIdx; + + size_t OldSize = ActiveCols.size(); + ActiveCols.grow(std::max(OldSize * 2, 1)); + return OldSize; + } + + +public: + + LiveVariablePrinter(const MCRegisterInfo *MRI, bool LittleEndian) + : LiveVariables(), ActiveCols({~0U, false, false, false}), MRI(MRI), + LittleEndian(LittleEndian) {} + + void dump() const { + for (const LiveVariable &LV : LiveVariables) { + dbgs() << LV.VarName << " @ " << LV.LocExpr.Range << ": "; + LV.print(dbgs(), MRI, LittleEndian); + dbgs() << "\n"; + } + } + + void AddCompileUnit(DWARFDie D) { + if (D.getTag() == dwarf::DW_TAG_subprogram) + AddFunction(D); + else + for (auto Child : D.children()) + AddFunction(Child); + } + + /// Update to match the state of the instruction between ThisAddr and + /// NextAddr. In the common case, any live range active at ThisAddr is + /// live-in to the instruction, and any live range active at NextAddr is + /// live-out of the instruction. If EndFunction is true, then ThisAddr and + /// NextAddr are in different functions, so live ranges starting at NextAddr + /// will be ignored, because they belong to the next function. + void update(object::SectionedAddress ThisAddr, + object::SectionedAddress NextAddr, bool EndFunction) { + // First, check variables which have already been assigned a column, so + // that we don't change their order. + SmallSet CheckedVarIdxs; + for (unsigned ColIdx = 0; ColIdx < ActiveCols.size(); ++ColIdx) { + if (!ActiveCols[ColIdx].isActive()) + continue; + CheckedVarIdxs.insert(ActiveCols[ColIdx].VarIdx); + LiveVariable &LV = LiveVariables[ActiveCols[ColIdx].VarIdx]; + ActiveCols[ColIdx].LiveIn = LV.liveAtAddress(ThisAddr); + ActiveCols[ColIdx].LiveOut = LV.liveAtAddress(NextAddr); + LLVM_DEBUG(dbgs() << "pass 1, " << ThisAddr.Address << "-" + << NextAddr.Address << ", " << LV.VarName << ", Col " + << ColIdx << ": LiveIn=" << ActiveCols[ColIdx].LiveIn + << ", LiveOut=" << ActiveCols[ColIdx].LiveOut << "\n"); + + if (!ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut) + ActiveCols[ColIdx].VarIdx = ~0U; + } + + // Next, look for variables which don't already have a column, but which + // are now live. + if (!EndFunction) { + for (unsigned VarIdx = 0; VarIdx < LiveVariables.size(); ++VarIdx) { + if (CheckedVarIdxs.count(VarIdx)) + continue; + LiveVariable &LV = LiveVariables[VarIdx]; + bool LiveIn = LV.liveAtAddress(ThisAddr); + bool LiveOut = LV.liveAtAddress(NextAddr); + if (!LiveIn && !LiveOut) + continue; + + unsigned ColIdx = findFreeColumn(); + LLVM_DEBUG(dbgs() << "pass 2, " << ThisAddr.Address << "-" + << NextAddr.Address << ", " << LV.VarName << ", Col " + << ColIdx << ": LiveIn=" << LiveIn + << ", LiveOut=" << LiveOut << "\n"); + ActiveCols[ColIdx] = {VarIdx, LiveIn, LiveOut, true}; + } + } + } + + /// Print live ranges to the right of an existing line. This assumes the + /// line is not an instruction, so doesn't start or end any live ranges, so + /// we only need to print active ranges or empty columns. If AfterInst is + /// true, this is being printed after the last instruction fed to update(), + /// otherwise this is being printed before it. + void printAfterOtherLine(formatted_raw_ostream &OS, bool AfterInst) { + if (ActiveCols.size()) { + unsigned FirstUnprintedColumn = MoveToFirstVarColumn(OS); + for (size_t ColIdx = FirstUnprintedColumn; ColIdx < ActiveCols.size(); + ++ColIdx) { + if (ActiveCols[ColIdx].isActive()) { + if ((AfterInst && ActiveCols[ColIdx].LiveOut) || + (!AfterInst && ActiveCols[ColIdx].LiveIn)) + OS << "┃ "; + else if (!AfterInst && ActiveCols[ColIdx].LiveOut) + OS << "│ "; + else + OS << " "; + } else { + OS << " "; + } + } + } + OS << "\n"; + } + + /// Print any live variable range info needed to the right of a + /// non-instruction line of disassembly. This is where we print the variable + /// names and expressions, with thin line-drawing characters connecting them + /// to the live range which starts at the next instruction. If MustPrint is + /// true, we have to print at least one line (with the continuation of any + /// already-active live ranges) because something has already been printed + /// earlier on this line. + void printBetweenInsts(formatted_raw_ostream &OS, bool MustPrint) { + bool PrintedSomething = false; + for (unsigned ColIdx = 0; ColIdx < ActiveCols.size(); ++ColIdx) { + if (ActiveCols[ColIdx].isActive() && ActiveCols[ColIdx].MustDrawLabel) { + // First we need to print the live range markers for any active + // columns to the left of this one. + OS.PadToColumn(getIndentLevel()); + for (unsigned ColIdx2 = 0; ColIdx2 < ColIdx; ++ColIdx2) { + if (ActiveCols[ColIdx2].isActive()) + OS << (ActiveCols[ColIdx2].MustDrawLabel && + !ActiveCols[ColIdx2].LiveIn + ? "│ " + : "┃ "); + else + OS << " "; + } + + // Then print the variable name and location of the new live range, + // with box drawing characters joining it to the live range line. + OS << (ActiveCols[ColIdx].LiveIn ? "┠─ " : "┌─ "); + WithColor(OS, raw_ostream::GREEN) + << LiveVariables[ActiveCols[ColIdx].VarIdx].VarName; + OS << " = "; + { + WithColor ExprColor(OS, raw_ostream::CYAN); + LiveVariables[ActiveCols[ColIdx].VarIdx].print(OS, MRI, LittleEndian); + } + + // If there are any columns to the right of the expression we just + // printed, then continue their live range lines. + unsigned FirstUnprintedColumn = MoveToFirstVarColumn(OS); + for (unsigned ColIdx2 = FirstUnprintedColumn; + ColIdx2 < ActiveCols.size(); ++ColIdx2) { + if (ActiveCols[ColIdx2].isActive() && ActiveCols[ColIdx2].LiveIn) + OS << "┃ "; + else + OS << " "; + } + + OS << "\n"; + PrintedSomething = true; + } + } + + for (unsigned ColIdx = 0; ColIdx < ActiveCols.size(); ++ColIdx) + if (ActiveCols[ColIdx].isActive()) + ActiveCols[ColIdx].MustDrawLabel = false; + + // If we must print something (because we printed a line/column number), + // but don't have any new variables to print, then print a line which + // just continues any existing live ranges. + if (MustPrint && !PrintedSomething) + printAfterOtherLine(OS, false); + } + + /// Print the live variable ranges to the right of a disassembled instruction. + void printAfterInst(formatted_raw_ostream &OS) { + if (!ActiveCols.size()) + return; + unsigned FirstUnprintedColumn = MoveToFirstVarColumn(OS); + for (unsigned ColIdx = FirstUnprintedColumn; ColIdx < ActiveCols.size(); + ++ColIdx) { + if (!ActiveCols[ColIdx].isActive()) + OS << " "; + else if (ActiveCols[ColIdx].LiveIn && ActiveCols[ColIdx].LiveOut) + OS << "┃ "; + else if (ActiveCols[ColIdx].LiveOut) + OS << "╈ "; + else if (ActiveCols[ColIdx].LiveIn) + OS << "┻ "; + else + llvm_unreachable("var must be live in or out!"); + } + } +}; + class SourcePrinter { protected: DILineInfo OldLineInfo; @@ -566,9 +945,10 @@ Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts)); } virtual ~SourcePrinter() = default; - virtual void printSourceLine(raw_ostream &OS, + virtual void printSourceLine(formatted_raw_ostream &OS, object::SectionedAddress Address, StringRef ObjectFilename, + LiveVariablePrinter &LVP, StringRef Delimiter = "; "); }; @@ -602,9 +982,10 @@ return true; } -void SourcePrinter::printSourceLine(raw_ostream &OS, +void SourcePrinter::printSourceLine(formatted_raw_ostream &OS, object::SectionedAddress Address, StringRef ObjectFilename, + LiveVariablePrinter &LVP, StringRef Delimiter) { if (!Symbolizer) return; @@ -633,8 +1014,10 @@ (OldLineInfo.FileName == LineInfo.FileName))) return; - if (PrintLines) - OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line << "\n"; + if (PrintLines) { + OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line; + LVP.printBetweenInsts(OS, true); + } if (PrintSource) { if (SourceCache.find(LineInfo.FileName) == SourceCache.end()) if (!cacheSource(LineInfo)) @@ -650,7 +1033,8 @@ return; } // Vector begins at 0, line numbers are non-zero - OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n'; + OS << Delimiter << LineBuffer->second[LineInfo.Line - 1]; + LVP.printBetweenInsts(OS, true); } } OldLineInfo = LineInfo; @@ -670,28 +1054,31 @@ return isArmElf(Obj) || isAArch64Elf(Obj); } -static void printRelocation(StringRef FileName, const RelocationRef &Rel, - uint64_t Address, bool Is64Bits) { +static void printRelocation(formatted_raw_ostream &OS, StringRef FileName, + const RelocationRef &Rel, uint64_t Address, + bool Is64Bits) { StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": "; SmallString<16> Name; SmallString<32> Val; Rel.getTypeName(Name); if (Error E = getRelocationValueString(Rel, Val)) reportError(std::move(E), FileName); - outs() << format(Fmt.data(), Address) << Name << "\t" << Val << "\n"; + OS << format(Fmt.data(), Address) << Name << "\t" << Val; } + class PrettyPrinter { public: virtual ~PrettyPrinter() = default; - virtual void printInst(MCInstPrinter &IP, const MCInst *MI, - ArrayRef Bytes, - object::SectionedAddress Address, raw_ostream &OS, - StringRef Annot, MCSubtargetInfo const &STI, - SourcePrinter *SP, StringRef ObjectFilename, - std::vector *Rels = nullptr) { + virtual void + printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes, + object::SectionedAddress Address, formatted_raw_ostream &OS, + StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, + StringRef ObjectFilename, std::vector *Rels, + LiveVariablePrinter &LVP) { if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename); + SP->printSourceLine(OS, Address, ObjectFilename, LVP); + LVP.printBetweenInsts(OS, false); size_t Start = OS.tell(); if (!NoLeadingAddr) @@ -718,7 +1105,7 @@ class HexagonPrettyPrinter : public PrettyPrinter { public: void printLead(ArrayRef Bytes, uint64_t Address, - raw_ostream &OS) { + formatted_raw_ostream &OS) { uint32_t opcode = (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0]; if (!NoLeadingAddr) @@ -730,12 +1117,12 @@ } } void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes, - object::SectionedAddress Address, raw_ostream &OS, + object::SectionedAddress Address, formatted_raw_ostream &OS, StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, - StringRef ObjectFilename, - std::vector *Rels) override { + StringRef ObjectFilename, std::vector *Rels, + LiveVariablePrinter &LVP) override { if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename, ""); + SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); if (!MI) { printLead(Bytes, Address.Address, OS); OS << " "; @@ -761,7 +1148,7 @@ auto PrintReloc = [&]() -> void { while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { if (RelCur->getOffset() == Address.Address) { - printRelocation(ObjectFilename, *RelCur, Address.Address, false); + printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false); return; } ++RelCur; @@ -772,7 +1159,7 @@ OS << Separator; Separator = "\n"; if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename, ""); + SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); printLead(Bytes, Address.Address, OS); OS << Preamble; Preamble = " "; @@ -800,12 +1187,12 @@ class AMDGCNPrettyPrinter : public PrettyPrinter { public: void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes, - object::SectionedAddress Address, raw_ostream &OS, + object::SectionedAddress Address, formatted_raw_ostream &OS, StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, - StringRef ObjectFilename, - std::vector *Rels) override { + StringRef ObjectFilename, std::vector *Rels, + LiveVariablePrinter &LVP) override { if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename); + SP->printSourceLine(OS, Address, ObjectFilename, LVP); if (MI) { SmallString<40> InstStr; @@ -852,12 +1239,12 @@ class BPFPrettyPrinter : public PrettyPrinter { public: void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef Bytes, - object::SectionedAddress Address, raw_ostream &OS, + object::SectionedAddress Address, formatted_raw_ostream &OS, StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, - StringRef ObjectFilename, - std::vector *Rels) override { + StringRef ObjectFilename, std::vector *Rels, + LiveVariablePrinter &LVP) override { if (SP && (PrintSource || PrintLines)) - SP->printSourceLine(OS, Address, ObjectFilename); + SP->printSourceLine(OS, Address, ObjectFilename, LVP); if (!NoLeadingAddr) OS << format("%8" PRId64 ":", Address.Address / 8); if (!NoShowRawInsn) { @@ -1201,6 +1588,17 @@ array_pod_sort(SecSyms.second.begin(), SecSyms.second.end()); array_pod_sort(AbsoluteSymbols.begin(), AbsoluteSymbols.end()); + std::unique_ptr DICtx; + LiveVariablePrinter LVP(Ctx.getRegisterInfo(), Obj->isLittleEndian()); + + if (DbgVariables) { + DICtx = DWARFContext::create(*Obj); + for (const auto &CU : DICtx->compile_units()) + LVP.AddCompileUnit(CU->getUnitDIE(false)); + } + + LLVM_DEBUG(LVP.dump()); + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { if (FilterSections.empty() && !DisassembleAll && (!Section.isText() || Section.isVirtual())) @@ -1418,11 +1816,15 @@ if (Size == 0) Size = 1; + LVP.update({Index, Section.getIndex()}, + {Index + Size, Section.getIndex()}, Index + Size == End); + + formatted_raw_ostream FOS(outs()); PIP.printInst(*IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size), {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, - outs(), "", *STI, &SP, Obj->getFileName(), &Rels); - outs() << CommentStream.str(); + FOS, "", *STI, &SP, Obj->getFileName(), &Rels, LVP); + FOS << CommentStream.str(); Comments.clear(); // Try to resolve the target of a call, tail call, etc. to a specific @@ -1473,15 +1875,17 @@ --TargetSym; uint64_t TargetAddress = std::get<0>(*TargetSym); StringRef TargetName = std::get<1>(*TargetSym); - outs() << " <" << TargetName; + FOS << " <" << TargetName; uint64_t Disp = Target - TargetAddress; if (Disp) - outs() << "+0x" << Twine::utohexstr(Disp); - outs() << '>'; + FOS << "+0x" << Twine::utohexstr(Disp); + FOS << '>'; } } } - outs() << "\n"; + + LVP.printAfterInst(FOS); + FOS << "\n"; // Hexagon does this in pretty printer if (Obj->getArch() != Triple::hexagon) { @@ -1507,8 +1911,9 @@ Offset += AdjustVMA; } - printRelocation(Obj->getFileName(), *RelCur, SectionAddr + Offset, - Is64Bits); + printRelocation(FOS, Obj->getFileName(), *RelCur, + SectionAddr + Offset, Is64Bits); + LVP.printAfterOtherLine(FOS, true); ++RelCur; } }