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,11 @@ Demangle symbol names in the output. +.. option:: --debug-vars + + Print the locations (in registers or memory) of source-level variables + alongside 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 @@ -106,10 +106,16 @@ formatted_raw_ostream &PadToColumn(unsigned NewCol); /// getColumn - Return the column number - unsigned getColumn() { return Position.first; } + unsigned getColumn() { + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); + return Position.first; + } /// getLine - Return the line number - unsigned getLine() { return Position.second; } + unsigned getLine() { + ComputePosition(getBufferStart(), GetNumBytesInBuffer()); + return Position.second; + } raw_ostream &resetColor() override { TheStream->resetColor(); 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 @@ -26,8 +26,33 @@ // Keep track of the current column and line by scanning the string for // special characters + bool MultiByte = false; 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. + if ((*Ptr & 0b11100000) == 0b11000000) { + Ptr += 1; + MultiByte = true; + } else if ((*Ptr & 0b11110000) == 0b11100000) { + Ptr += 2; + MultiByte = true; + } else if ((*Ptr & 0b11111000) == 0b11110000) { + Ptr += 3; + MultiByte = true; + } + + // 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) { + MultiByte = false; + 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,21 @@ +void bar(int*); +int baz(long a, int b, int c) { + int d = a + b; + bar(&d); + int e = d * c; + return e; +} + +struct S { + int a; + int b; +}; +int foo(struct S x) { + int y = x.a + x.b; + return y; +} + +int quxx(int a, int b, int c, int d, int x, int y) { + int z = x + y; + return z; +} 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,729 @@ +// RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \ +// RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +// RUN: FileCheck %s + +// Generated with this compile command and source: +// +// clang --target=arm--none-eabi -march=armv7-a -c debug.c -O2 -gdwarf-4 -S -o - -ffunction-sections +// +// void bar(int*); +// int baz(long a, int b, int c) { +// int d = a + b; +// bar(&d); +// int e = d * c; +// return e; +// } +// +// struct S { +// int a; +// int b; +// }; +// int foo(struct S x) { +// int y = x.a + x.b; +// return y; +// } +// +// int quxx(int a, int b, int c, int d, int x, int y) { +// int z = x + y; +// return z; +// } + +// CHECK: Disassembly of section .text.baz: +// CHECK-EMPTY: +// CHECK: 00000000 baz: +// CHECK: ┠─ a = R0 +// CHECK: ┃ ┠─ b = R1 +// CHECK: ┃ ┃ ┠─ c = R2 +// CHECK: 0: push {r4, r10, r11, lr} ┃ ┃ ┃ +// CHECK: 4: add r11, sp, #8 ┃ ┃ ┃ +// CHECK: 8: sub sp, sp, #8 ┃ ┃ ┃ +// CHECK: ┃ ┃ ┃ ┌─ d = R0 +// CHECK: c: add r0, r1, r0 ┻ ┃ ┃ ╈ +// CHECK: ┌─ d = [SP+4] +// CHECK: 10: str r0, [sp, #4] ╈ ┃ ┃ ┻ +// CHECK: 14: add r0, sp, #4 ┃ ┃ ┃ +// CHECK: ┃ ┃ ┃ ┌─ a = R0 +// CHECK: ┃ ┃ ┃ │ ┌─ c = R4 +// CHECK: 18: mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// CHECK: 1c: bl #-8 ┃ ┻ ┻ ┃ +// CHECK: ┃ ┌─ d = R0 +// CHECK: 20: ldr r0, [sp, #4] ┻ ╈ ┃ +// CHECK: ┌─ e = R0 +// CHECK: 24: mul r0, r0, r4 ╈ ┻ ┃ +// CHECK: 28: sub sp, r11, #8 ┃ ┃ +// CHECK: 2c: pop {r4, r10, r11, pc} ┻ ┻ +// CHECK-EMPTY: +// CHECK: Disassembly of section .text.foo: +// CHECK-EMPTY: +// CHECK: 00000000 foo: +// CHECK: ┠─ x = [0,4): R0 [4,8): R1 +// CHECK: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// CHECK: ┃ │ ┌─ y = R0 +// CHECK: 0: add r0, r0, r1 ┻ ╈ ╈ +// CHECK: 4: bx lr ┻ ┻ +// CHECK-EMPTY: +// CHECK: Disassembly of section .text.quxx: +// CHECK-EMPTY: +// CHECK: 00000000 quxx: +// CHECK: ┠─ a = R0 ┃ +// CHECK: ┃ ┠─ b = R1 +// CHECK: ┃ ┃ ┠─ c = R2 +// CHECK: ┃ ┃ ┃ ┠─ d = R3 +// CHECK: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// CHECK: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// CHECK: 0: ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// CHECK: ┌─ z = R0 ┃ +// CHECK: 4: add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// CHECK: 8: 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" + .file 1 "/work/scratch" "debug.c" + .section .text.baz,"ax",%progbits + .globl baz + .p2align 2 + .type baz,%function + .code 32 +baz: +.Lfunc_begin0: + .loc 1 2 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .save {r4, r10, r11, lr} + push {r4, r10, r11, lr} + .cfi_def_cfa_offset 16 + .cfi_offset lr, -4 + .cfi_offset r11, -8 + .cfi_offset r10, -12 + .cfi_offset r4, -16 + .setfp r11, sp, #8 + add r11, sp, #8 + .cfi_def_cfa r11, 8 + .pad #8 + sub sp, sp, #8 +.Ltmp0: + .loc 1 3 13 prologue_end + add r0, r1, r0 +.Ltmp1: + .loc 1 3 7 is_stmt 0 + str r0, [sp, #4] +.Ltmp2: + .loc 1 0 7 + add r0, sp, #4 + mov r4, r2 +.Ltmp3: + .loc 1 4 3 is_stmt 1 + bl bar +.Ltmp4: + .loc 1 5 11 + ldr r0, [sp, #4] +.Ltmp5: + .loc 1 5 13 is_stmt 0 + mul r0, r0, r4 +.Ltmp6: + .loc 1 6 3 is_stmt 1 + sub sp, r11, #8 + pop {r4, r10, r11, pc} +.Ltmp7: +.Lfunc_end0: + .size baz, .Lfunc_end0-baz + .cfi_endproc + .cantunwind + .fnend + + .section .text.foo,"ax",%progbits + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin1: + .loc 1 13 0 + .fnstart + .cfi_startproc + .loc 1 14 15 prologue_end + add r0, r0, r1 +.Ltmp8: + .loc 1 15 3 + bx lr +.Ltmp9: +.Lfunc_end1: + .size foo, .Lfunc_end1-foo + .cfi_endproc + .cantunwind + .fnend + + .section .text.quxx,"ax",%progbits + .globl quxx + .p2align 2 + .type quxx,%function + .code 32 +quxx: +.Lfunc_begin2: + .loc 1 18 0 + .fnstart + .cfi_startproc + ldm sp, {r0, r1} +.Ltmp10: + .loc 1 19 13 prologue_end + add r0, r1, r0 +.Ltmp11: + .loc 1 20 3 + bx lr +.Ltmp12: +.Lfunc_end2: + .size quxx, .Lfunc_end2-quxx + .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 "debug.c" +.Linfo_string2: + .asciz "/work/scratch" +.Linfo_string3: + .asciz "bar" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "baz" +.Linfo_string6: + .asciz "foo" +.Linfo_string7: + .asciz "quxx" +.Linfo_string8: + .asciz "a" +.Linfo_string9: + .asciz "long int" +.Linfo_string10: + .asciz "b" +.Linfo_string11: + .asciz "c" +.Linfo_string12: + .asciz "d" +.Linfo_string13: + .asciz "e" +.Linfo_string14: + .asciz "x" +.Linfo_string15: + .asciz "S" +.Linfo_string16: + .asciz "y" +.Linfo_string17: + .asciz "z" + .section .debug_loc,"",%progbits +.Ldebug_loc0: + .long -1 + .long .Lfunc_begin0 + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp1-.Lfunc_begin0 + .short 1 + .byte 80 + .long .Ltmp3-.Lfunc_begin0 + .long .Ltmp4-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc1: + .long -1 + .long .Lfunc_begin0 + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp4-.Lfunc_begin0 + .short 1 + .byte 81 + .long 0 + .long 0 +.Ldebug_loc2: + .long -1 + .long .Lfunc_begin0 + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp3-.Lfunc_begin0 + .short 1 + .byte 82 + .long .Ltmp3-.Lfunc_begin0 + .long .Ltmp7-.Lfunc_begin0 + .short 1 + .byte 84 + .long 0 + .long 0 +.Ldebug_loc3: + .long -1 + .long .Lfunc_begin0 + .long .Ltmp1-.Lfunc_begin0 + .long .Ltmp2-.Lfunc_begin0 + .short 1 + .byte 80 + .long .Ltmp2-.Lfunc_begin0 + .long .Ltmp5-.Lfunc_begin0 + .short 2 + .byte 125 + .byte 4 + .long .Ltmp5-.Lfunc_begin0 + .long .Ltmp6-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc4: + .long -1 + .long .Lfunc_begin0 + .long .Ltmp6-.Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc5: + .long -1 + .long .Lfunc_begin1 + .long .Lfunc_begin1-.Lfunc_begin1 + .long .Ltmp8-.Lfunc_begin1 + .short 6 + .byte 80 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .long .Ltmp8-.Lfunc_begin1 + .long .Lfunc_end1-.Lfunc_begin1 + .short 5 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .long 0 + .long 0 +.Ldebug_loc6: + .long -1 + .long .Lfunc_begin1 + .long .Ltmp8-.Lfunc_begin1 + .long .Lfunc_end1-.Lfunc_begin1 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc7: + .long -1 + .long .Lfunc_begin2 + .long .Lfunc_begin2-.Lfunc_begin2 + .long .Ltmp10-.Lfunc_begin2 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc8: + .long -1 + .long .Lfunc_begin2 + .long .Lfunc_begin2-.Lfunc_begin2 + .long .Ltmp10-.Lfunc_begin2 + .short 1 + .byte 81 + .long 0 + .long 0 +.Ldebug_loc9: + .long -1 + .long .Lfunc_begin2 + .long .Ltmp11-.Lfunc_begin2 + .long .Lfunc_end2-.Lfunc_begin2 + .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 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 60 + .byte 25 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 15 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 36 + .byte 0 + .byte 3 + .byte 14 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 6 + .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 7 + .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 8 + .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 9 + .ascii "\211\202\001" + .byte 0 + .byte 49 + .byte 19 + .byte 17 + .byte 1 + .byte 0 + .byte 0 + .byte 10 + .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 11 + .byte 19 + .byte 1 + .byte 3 + .byte 14 + .byte 11 + .byte 11 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 0 + .byte 0 + .byte 12 + .byte 13 + .byte 0 + .byte 3 + .byte 14 + .byte 73 + .byte 19 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 56 + .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 .Linfo_string3 + .byte 1 + .byte 1 + + + + .byte 3 + .long 51 + .byte 0 + .byte 4 + .long 56 + .byte 5 + .long .Linfo_string4 + .byte 5 + .byte 4 + .byte 6 + .long .Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .long .Linfo_string5 + .byte 1 + .byte 2 + + .long 56 + + .byte 7 + .long .Ldebug_loc0 + .long .Linfo_string8 + .byte 1 + .byte 2 + .long 342 + .byte 7 + .long .Ldebug_loc1 + .long .Linfo_string10 + .byte 1 + .byte 2 + .long 56 + .byte 7 + .long .Ldebug_loc2 + .long .Linfo_string11 + .byte 1 + .byte 2 + .long 56 + .byte 8 + .long .Ldebug_loc3 + .long .Linfo_string12 + .byte 1 + .byte 3 + .long 56 + .byte 8 + .long .Ldebug_loc4 + .long .Linfo_string13 + .byte 1 + .byte 5 + .long 56 + .byte 9 + .long 38 + .long .Ltmp4 + .byte 0 + .byte 6 + .long .Lfunc_begin1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .long .Linfo_string6 + .byte 1 + .byte 13 + + .long 56 + + .byte 7 + .long .Ldebug_loc5 + .long .Linfo_string14 + .byte 1 + .byte 13 + .long 349 + .byte 8 + .long .Ldebug_loc6 + .long .Linfo_string16 + .byte 1 + .byte 14 + .long 56 + .byte 0 + .byte 6 + .long .Lfunc_begin2 + .long .Lfunc_end2-.Lfunc_begin2 + .byte 1 + .byte 91 + + .long .Linfo_string7 + .byte 1 + .byte 18 + + .long 56 + + .byte 7 + .long .Ldebug_loc7 + .long .Linfo_string8 + .byte 1 + .byte 18 + .long 56 + .byte 7 + .long .Ldebug_loc8 + .long .Linfo_string10 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 1 + .byte 82 + .long .Linfo_string11 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 1 + .byte 83 + .long .Linfo_string12 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 2 + .byte 125 + .byte 0 + .long .Linfo_string14 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 2 + .byte 125 + .byte 4 + .long .Linfo_string16 + .byte 1 + .byte 18 + .long 56 + .byte 8 + .long .Ldebug_loc9 + .long .Linfo_string17 + .byte 1 + .byte 19 + .long 56 + .byte 0 + .byte 5 + .long .Linfo_string9 + .byte 5 + .byte 4 + .byte 11 + .long .Linfo_string15 + .byte 8 + .byte 1 + .byte 9 + .byte 12 + .long .Linfo_string8 + .long 56 + .byte 1 + .byte 10 + .byte 0 + .byte 12 + .long .Linfo_string10 + .long 56 + .byte 1 + .byte 11 + .byte 4 + .byte 0 + .byte 0 +.Ldebug_info_end0: + .section .debug_ranges,"",%progbits +.Ldebug_ranges0: + .long .Lfunc_begin0 + .long .Lfunc_end0 + .long .Lfunc_begin1 + .long .Lfunc_end1 + .long .Lfunc_begin2 + .long .Lfunc_end2 + .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,847 @@ +// 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 + +// Generated with this compile command and source: +// +// clang --target=arm--none-eabi -march=armv7-a -c debug.c -O2 -gdwarf-4 -S -o - +// +// void bar(int*); +// int baz(long a, int b, int c) { +// int d = a + b; +// bar(&d); +// int e = d * c; +// return e; +// } +// +// struct S { +// int a; +// int b; +// }; +// int foo(struct S x) { +// int y = x.a + x.b; +// return y; +// } +// +// int quxx(int a, int b, int c, int d, int x, int y) { +// int z = x + y; +// return z; +// } + +// RAW: Disassembly of section .text: +// RAW-EMPTY: +// RAW-NEXT: 00000000 baz: +// RAW-NEXT: ┠─ a = R0 +// RAW-NEXT: ┃ ┠─ b = R1 +// RAW-NEXT: ┃ ┃ ┠─ c = R2 +// RAW-NEXT: 0: 10 4c 2d e9 push {r4, r10, r11, lr} ┃ ┃ ┃ +// RAW-NEXT: 4: 08 b0 8d e2 add r11, sp, #8 ┃ ┃ ┃ +// RAW-NEXT: 8: 08 d0 4d e2 sub sp, sp, #8 ┃ ┃ ┃ +// RAW-NEXT: ┃ ┃ ┃ ┌─ d = R0 +// RAW-NEXT: c: 00 00 81 e0 add r0, r1, r0 ┻ ┃ ┃ ╈ +// RAW-NEXT: ┌─ d = [SP+4] +// RAW-NEXT: 10: 04 00 8d e5 str r0, [sp, #4] ╈ ┃ ┃ ┻ +// RAW-NEXT: 14: 04 00 8d e2 add r0, sp, #4 ┃ ┃ ┃ +// RAW-NEXT: ┃ ┃ ┃ ┌─ a = R0 +// RAW-NEXT: ┃ ┃ ┃ │ ┌─ c = R4 +// RAW-NEXT: 18: 02 40 a0 e1 mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// RAW-NEXT: 1c: fe ff ff eb bl #-8 ┃ ┻ ┻ ┃ +// RAW-NEXT: ┃ ┌─ d = R0 +// RAW-NEXT: 20: 04 00 9d e5 ldr r0, [sp, #4] ┻ ╈ ┃ +// RAW-NEXT: ┌─ e = R0 +// RAW-NEXT: 24: 90 04 00 e0 mul r0, r0, r4 ╈ ┻ ┃ +// RAW-NEXT: 28: 08 d0 4b e2 sub sp, r11, #8 ┃ ┃ +// RAW-NEXT: 2c: 10 8c bd e8 pop {r4, r10, r11, pc} ┻ ┻ +// RAW-EMPTY: +// RAW-NEXT: 00000030 foo: +// RAW-NEXT: ┠─ x = [0,4): R0 [4,8): R1 +// RAW-NEXT: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// RAW-NEXT: ┃ │ ┌─ y = R0 +// RAW-NEXT: 30: 01 00 80 e0 add r0, r0, r1 ┻ ╈ ╈ +// RAW-NEXT: 34: 1e ff 2f e1 bx lr ┻ ┻ +// RAW-EMPTY: +// RAW-NEXT: 00000038 quxx: +// RAW-NEXT: ┠─ a = R0 ┃ +// RAW-NEXT: ┃ ┠─ b = R1 +// RAW-NEXT: ┃ ┃ ┠─ c = R2 +// RAW-NEXT: ┃ ┃ ┃ ┠─ d = R3 +// RAW-NEXT: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// RAW-NEXT: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// RAW-NEXT: 38: 03 00 9d e8 ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// RAW-NEXT: ┌─ z = R0 ┃ +// RAW-NEXT: 3c: 00 00 81 e0 add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// RAW-NEXT: 40: 1e ff 2f e1 bx lr ┻ ┻ ┻ ┻ ┻ + +// NO-RAW: Disassembly of section .text: +// NO-RAW-EMPTY: +// NO-RAW-NEXT: 00000000 baz: +// NO-RAW-NEXT: ┠─ a = R0 +// NO-RAW-NEXT: ┃ ┠─ b = R1 +// NO-RAW-NEXT: ┃ ┃ ┠─ c = R2 +// NO-RAW-NEXT: 0: push {r4, r10, r11, lr} ┃ ┃ ┃ +// NO-RAW-NEXT: 4: add r11, sp, #8 ┃ ┃ ┃ +// NO-RAW-NEXT: 8: sub sp, sp, #8 ┃ ┃ ┃ +// NO-RAW-NEXT: ┃ ┃ ┃ ┌─ d = R0 +// NO-RAW-NEXT: c: add r0, r1, r0 ┻ ┃ ┃ ╈ +// NO-RAW-NEXT: ┌─ d = [SP+4] +// NO-RAW-NEXT: 10: str r0, [sp, #4] ╈ ┃ ┃ ┻ +// NO-RAW-NEXT: 14: add r0, sp, #4 ┃ ┃ ┃ +// NO-RAW-NEXT: ┃ ┃ ┃ ┌─ a = R0 +// NO-RAW-NEXT: ┃ ┃ ┃ │ ┌─ c = R4 +// NO-RAW-NEXT: 18: mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// NO-RAW-NEXT: 1c: bl #-8 ┃ ┻ ┻ ┃ +// NO-RAW-NEXT: ┃ ┌─ d = R0 +// NO-RAW-NEXT: 20: ldr r0, [sp, #4] ┻ ╈ ┃ +// NO-RAW-NEXT: ┌─ e = R0 +// NO-RAW-NEXT: 24: mul r0, r0, r4 ╈ ┻ ┃ +// NO-RAW-NEXT: 28: sub sp, r11, #8 ┃ ┃ +// NO-RAW-NEXT: 2c: pop {r4, r10, r11, pc} ┻ ┻ +// NO-RAW-EMPTY: +// NO-RAW-NEXT: 00000030 foo: +// NO-RAW-NEXT: ┠─ x = [0,4): R0 [4,8): R1 +// NO-RAW-NEXT: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// NO-RAW-NEXT: ┃ │ ┌─ y = R0 +// NO-RAW-NEXT: 30: add r0, r0, r1 ┻ ╈ ╈ +// NO-RAW-NEXT: 34: bx lr ┻ ┻ +// NO-RAW-EMPTY: +// NO-RAW-NEXT: 00000038 quxx: +// NO-RAW-NEXT: ┠─ a = R0 ┃ +// NO-RAW-NEXT: ┃ ┠─ b = R1 +// NO-RAW-NEXT: ┃ ┃ ┠─ c = R2 +// NO-RAW-NEXT: ┃ ┃ ┃ ┠─ d = R3 +// NO-RAW-NEXT: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// NO-RAW-NEXT: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// NO-RAW-NEXT: 38: ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// NO-RAW-NEXT: ┌─ z = R0 ┃ +// NO-RAW-NEXT: 3c: add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// NO-RAW-NEXT: 40: bx lr ┻ ┻ ┻ ┻ ┻ + +// LINE-NUMS: Disassembly of section .text: +// LINE-NUMS-EMPTY: +// LINE-NUMS-NEXT: 00000000 baz: +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:2 ┠─ a = R0 +// LINE-NUMS-NEXT: ┃ ┠─ b = R1 +// LINE-NUMS-NEXT: ┃ ┃ ┠─ c = R2 +// LINE-NUMS-NEXT: 0: push {r4, r10, r11, lr} ┃ ┃ ┃ +// LINE-NUMS-NEXT: 4: add r11, sp, #8 ┃ ┃ ┃ +// LINE-NUMS-NEXT: 8: sub sp, sp, #8 ┃ ┃ ┃ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:3 ┃ ┃ ┃ ┌─ d = R0 +// LINE-NUMS-NEXT: c: add r0, r1, r0 ┻ ┃ ┃ ╈ +// LINE-NUMS-NEXT: ┌─ d = [SP+4] +// LINE-NUMS-NEXT: 10: str r0, [sp, #4] ╈ ┃ ┃ ┻ +// LINE-NUMS-NEXT: 14: add r0, sp, #4 ┃ ┃ ┃ +// LINE-NUMS-NEXT: ┃ ┃ ┃ ┌─ a = R0 +// LINE-NUMS-NEXT: ┃ ┃ ┃ │ ┌─ c = R4 +// LINE-NUMS-NEXT: 18: mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:4 ┃ ┃ ┃ ┃ +// LINE-NUMS-NEXT: 1c: bl #-8 ┃ ┻ ┻ ┃ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:5 ┃ ┌─ d = R0 +// LINE-NUMS-NEXT: 20: ldr r0, [sp, #4] ┻ ╈ ┃ +// LINE-NUMS-NEXT: ┌─ e = R0 +// LINE-NUMS-NEXT: 24: mul r0, r0, r4 ╈ ┻ ┃ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:6 ┃ ┃ +// LINE-NUMS-NEXT: 28: sub sp, r11, #8 ┃ ┃ +// LINE-NUMS-NEXT: 2c: pop {r4, r10, r11, pc} ┻ ┻ +// LINE-NUMS-EMPTY: +// LINE-NUMS-NEXT: 00000030 foo: +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:14 ┠─ x = [0,4): R0 [4,8): R1 +// LINE-NUMS-NEXT: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// LINE-NUMS-NEXT: ┃ │ ┌─ y = R0 +// LINE-NUMS-NEXT: 30: add r0, r0, r1 ┻ ╈ ╈ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:15 ┃ ┃ +// LINE-NUMS-NEXT: 34: bx lr ┻ ┻ +// LINE-NUMS-EMPTY: +// LINE-NUMS-NEXT: 00000038 quxx: +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:18 ┠─ a = R0 ┃ +// LINE-NUMS-NEXT: ┃ ┠─ b = R1 +// LINE-NUMS-NEXT: ┃ ┃ ┠─ c = R2 +// LINE-NUMS-NEXT: ┃ ┃ ┃ ┠─ d = R3 +// LINE-NUMS-NEXT: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// LINE-NUMS-NEXT: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// LINE-NUMS-NEXT: 38: ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:19 ┌─ z = R0 ┃ +// LINE-NUMS-NEXT: 3c: add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// LINE-NUMS-NEXT: ; SRC_COMPDIR/debug.c:20 ┃ ┃ ┃ ┃ ┃ +// LINE-NUMS-NEXT: 40: bx lr ┻ ┻ ┻ ┻ ┻ + +// SOURCE: Disassembly of section .text: +// SOURCE-EMPTY: +// SOURCE-NEXT: 00000000 baz: +// SOURCE-NEXT: ; int baz(long a, int b, int c) { ┠─ a = R0 +// SOURCE-NEXT: ┃ ┠─ b = R1 +// SOURCE-NEXT: ┃ ┃ ┠─ c = R2 +// SOURCE-NEXT: 0: push {r4, r10, r11, lr} ┃ ┃ ┃ +// SOURCE-NEXT: 4: add r11, sp, #8 ┃ ┃ ┃ +// SOURCE-NEXT: 8: sub sp, sp, #8 ┃ ┃ ┃ +// SOURCE-NEXT: ; int d = a + b; ┃ ┃ ┃ ┌─ d = R0 +// SOURCE-NEXT: c: add r0, r1, r0 ┻ ┃ ┃ ╈ +// SOURCE-NEXT: ┌─ d = [SP+4] +// SOURCE-NEXT: 10: str r0, [sp, #4] ╈ ┃ ┃ ┻ +// SOURCE-NEXT: 14: add r0, sp, #4 ┃ ┃ ┃ +// SOURCE-NEXT: ┃ ┃ ┃ ┌─ a = R0 +// SOURCE-NEXT: ┃ ┃ ┃ │ ┌─ c = R4 +// SOURCE-NEXT: 18: mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// SOURCE-NEXT: ; bar(&d); ┃ ┃ ┃ ┃ +// SOURCE-NEXT: 1c: bl #-8 ┃ ┻ ┻ ┃ +// SOURCE-NEXT: ; int e = d * c; ┃ ┌─ d = R0 +// SOURCE-NEXT: 20: ldr r0, [sp, #4] ┻ ╈ ┃ +// SOURCE-NEXT: ┌─ e = R0 +// SOURCE-NEXT: 24: mul r0, r0, r4 ╈ ┻ ┃ +// SOURCE-NEXT: ; return e; ┃ ┃ +// SOURCE-NEXT: 28: sub sp, r11, #8 ┃ ┃ +// SOURCE-NEXT: 2c: pop {r4, r10, r11, pc} ┻ ┻ +// SOURCE-EMPTY: +// SOURCE-NEXT: 00000030 foo: +// SOURCE-NEXT: ; int y = x.a + x.b; ┠─ x = [0,4): R0 [4,8): R1 +// SOURCE-NEXT: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// SOURCE-NEXT: ┃ │ ┌─ y = R0 +// SOURCE-NEXT: 30: add r0, r0, r1 ┻ ╈ ╈ +// SOURCE-NEXT: ; return y; ┃ ┃ +// SOURCE-NEXT: 34: bx lr ┻ ┻ +// SOURCE-EMPTY: +// SOURCE-NEXT: 00000038 quxx: +// SOURCE-NEXT: ; int quxx(int a, int b, int c, int d, int x, int y) { ┠─ a = R0 ┃ +// SOURCE-NEXT: ┃ ┠─ b = R1 +// SOURCE-NEXT: ┃ ┃ ┠─ c = R2 +// SOURCE-NEXT: ┃ ┃ ┃ ┠─ d = R3 +// SOURCE-NEXT: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// SOURCE-NEXT: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// SOURCE-NEXT: 38: ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// SOURCE-NEXT: ; int z = x + y; ┌─ z = R0 ┃ +// SOURCE-NEXT: 3c: add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// SOURCE-NEXT: ; return z; ┃ ┃ ┃ ┃ ┃ +// SOURCE-NEXT: 40: 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" + .file 1 "" "debug.c" + .globl baz + .p2align 2 + .type baz,%function + .code 32 +baz: +.Lfunc_begin0: + .loc 1 2 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .save {r4, r10, r11, lr} + push {r4, r10, r11, lr} + .cfi_def_cfa_offset 16 + .cfi_offset lr, -4 + .cfi_offset r11, -8 + .cfi_offset r10, -12 + .cfi_offset r4, -16 + .setfp r11, sp, #8 + add r11, sp, #8 + .cfi_def_cfa r11, 8 + .pad #8 + sub sp, sp, #8 +.Ltmp0: + .loc 1 3 13 prologue_end + add r0, r1, r0 +.Ltmp1: + .loc 1 3 7 is_stmt 0 + str r0, [sp, #4] +.Ltmp2: + .loc 1 0 7 + add r0, sp, #4 + mov r4, r2 +.Ltmp3: + .loc 1 4 3 is_stmt 1 + bl bar +.Ltmp4: + .loc 1 5 11 + ldr r0, [sp, #4] +.Ltmp5: + .loc 1 5 13 is_stmt 0 + mul r0, r0, r4 +.Ltmp6: + .loc 1 6 3 is_stmt 1 + sub sp, r11, #8 + pop {r4, r10, r11, pc} +.Ltmp7: +.Lfunc_end0: + .size baz, .Lfunc_end0-baz + .cfi_endproc + .cantunwind + .fnend + + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin1: + .loc 1 13 0 + .fnstart + .cfi_startproc + .loc 1 14 15 prologue_end + add r0, r0, r1 +.Ltmp8: + .loc 1 15 3 + bx lr +.Ltmp9: +.Lfunc_end1: + .size foo, .Lfunc_end1-foo + .cfi_endproc + .cantunwind + .fnend + + .globl quxx + .p2align 2 + .type quxx,%function + .code 32 +quxx: +.Lfunc_begin2: + .loc 1 18 0 + .fnstart + .cfi_startproc + ldm sp, {r0, r1} +.Ltmp10: + .loc 1 19 13 prologue_end + add r0, r1, r0 +.Ltmp11: + .loc 1 20 3 + bx lr +.Ltmp12: +.Lfunc_end2: + .size quxx, .Lfunc_end2-quxx + .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 "debug.c" +.Linfo_string2: + .asciz "SRC_COMPDIR" +.Linfo_string3: + .asciz "bar" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "baz" +.Linfo_string6: + .asciz "foo" +.Linfo_string7: + .asciz "quxx" +.Linfo_string8: + .asciz "a" +.Linfo_string9: + .asciz "long int" +.Linfo_string10: + .asciz "b" +.Linfo_string11: + .asciz "c" +.Linfo_string12: + .asciz "d" +.Linfo_string13: + .asciz "e" +.Linfo_string14: + .asciz "x" +.Linfo_string15: + .asciz "S" +.Linfo_string16: + .asciz "y" +.Linfo_string17: + .asciz "z" + .section .debug_loc,"",%progbits +.Ldebug_loc0: + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp1-.Lfunc_begin0 + .short 1 + .byte 80 + .long .Ltmp3-.Lfunc_begin0 + .long .Ltmp4-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc1: + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp4-.Lfunc_begin0 + .short 1 + .byte 81 + .long 0 + .long 0 +.Ldebug_loc2: + .long .Lfunc_begin0-.Lfunc_begin0 + .long .Ltmp3-.Lfunc_begin0 + .short 1 + .byte 82 + .long .Ltmp3-.Lfunc_begin0 + .long .Ltmp7-.Lfunc_begin0 + .short 1 + .byte 84 + .long 0 + .long 0 +.Ldebug_loc3: + .long .Ltmp1-.Lfunc_begin0 + .long .Ltmp2-.Lfunc_begin0 + .short 1 + .byte 80 + .long .Ltmp2-.Lfunc_begin0 + .long .Ltmp5-.Lfunc_begin0 + .short 2 + .byte 125 + .byte 4 + .long .Ltmp5-.Lfunc_begin0 + .long .Ltmp6-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc4: + .long .Ltmp6-.Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc5: + .long .Lfunc_begin1-.Lfunc_begin0 + .long .Ltmp8-.Lfunc_begin0 + .short 6 + .byte 80 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .long .Ltmp8-.Lfunc_begin0 + .long .Lfunc_end1-.Lfunc_begin0 + .short 5 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .long 0 + .long 0 +.Ldebug_loc6: + .long .Ltmp8-.Lfunc_begin0 + .long .Lfunc_end1-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc7: + .long .Lfunc_begin2-.Lfunc_begin0 + .long .Ltmp10-.Lfunc_begin0 + .short 1 + .byte 80 + .long 0 + .long 0 +.Ldebug_loc8: + .long .Lfunc_begin2-.Lfunc_begin0 + .long .Ltmp10-.Lfunc_begin0 + .short 1 + .byte 81 + .long 0 + .long 0 +.Ldebug_loc9: + .long .Ltmp11-.Lfunc_begin0 + .long .Lfunc_end2-.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 3 + .byte 14 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 60 + .byte 25 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 15 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 36 + .byte 0 + .byte 3 + .byte 14 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 6 + .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 7 + .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 8 + .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 9 + .ascii "\211\202\001" + .byte 0 + .byte 49 + .byte 19 + .byte 17 + .byte 1 + .byte 0 + .byte 0 + .byte 10 + .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 11 + .byte 19 + .byte 1 + .byte 3 + .byte 14 + .byte 11 + .byte 11 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 0 + .byte 0 + .byte 12 + .byte 13 + .byte 0 + .byte 3 + .byte 14 + .byte 73 + .byte 19 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 56 + .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_end2-.Lfunc_begin0 + .byte 2 + .long .Linfo_string3 + .byte 1 + .byte 1 + + + + .byte 3 + .long 51 + .byte 0 + .byte 4 + .long 56 + .byte 5 + .long .Linfo_string4 + .byte 5 + .byte 4 + .byte 6 + .long .Lfunc_begin0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .long .Linfo_string5 + .byte 1 + .byte 2 + + .long 56 + + .byte 7 + .long .Ldebug_loc0 + .long .Linfo_string8 + .byte 1 + .byte 2 + .long 342 + .byte 7 + .long .Ldebug_loc1 + .long .Linfo_string10 + .byte 1 + .byte 2 + .long 56 + .byte 7 + .long .Ldebug_loc2 + .long .Linfo_string11 + .byte 1 + .byte 2 + .long 56 + .byte 8 + .long .Ldebug_loc3 + .long .Linfo_string12 + .byte 1 + .byte 3 + .long 56 + .byte 8 + .long .Ldebug_loc4 + .long .Linfo_string13 + .byte 1 + .byte 5 + .long 56 + .byte 9 + .long 38 + .long .Ltmp4 + .byte 0 + .byte 6 + .long .Lfunc_begin1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .long .Linfo_string6 + .byte 1 + .byte 13 + + .long 56 + + .byte 7 + .long .Ldebug_loc5 + .long .Linfo_string14 + .byte 1 + .byte 13 + .long 349 + .byte 8 + .long .Ldebug_loc6 + .long .Linfo_string16 + .byte 1 + .byte 14 + .long 56 + .byte 0 + .byte 6 + .long .Lfunc_begin2 + .long .Lfunc_end2-.Lfunc_begin2 + .byte 1 + .byte 91 + + .long .Linfo_string7 + .byte 1 + .byte 18 + + .long 56 + + .byte 7 + .long .Ldebug_loc7 + .long .Linfo_string8 + .byte 1 + .byte 18 + .long 56 + .byte 7 + .long .Ldebug_loc8 + .long .Linfo_string10 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 1 + .byte 82 + .long .Linfo_string11 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 1 + .byte 83 + .long .Linfo_string12 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 2 + .byte 125 + .byte 0 + .long .Linfo_string14 + .byte 1 + .byte 18 + .long 56 + .byte 10 + .byte 2 + .byte 125 + .byte 4 + .long .Linfo_string16 + .byte 1 + .byte 18 + .long 56 + .byte 8 + .long .Ldebug_loc9 + .long .Linfo_string17 + .byte 1 + .byte 19 + .long 56 + .byte 0 + .byte 5 + .long .Linfo_string9 + .byte 5 + .byte 4 + .byte 11 + .long .Linfo_string15 + .byte 8 + .byte 1 + .byte 9 + .byte 12 + .long .Linfo_string8 + .long 56 + .byte 1 + .byte 10 + .byte 0 + .byte 12 + .long .Linfo_string10 + .long 56 + .byte 1 + .byte 11 + .byte 4 + .byte 0 + .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,805 @@ +// 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 + +// Generated with this compile command and source: +// +// clang --target=arm--none-eabi -march=armv7-a -c debug.c -O2 -gdwarf-4 -S -o - -ffunction-sections +// +// void bar(int*); +// int baz(long a, int b, int c) { +// int d = a + b; +// bar(&d); +// int e = d * c; +// return e; +// } +// +// struct S { +// int a; +// int b; +// }; +// int foo(struct S x) { +// int y = x.a + x.b; +// return y; +// } +// +// int quxx(int a, int b, int c, int d, int x, int y) { +// int z = x + y; +// return z; +// } + +// CHECK: Disassembly of section .text.baz: +// CHECK-EMPTY: +// CHECK: 00000000 baz: +// CHECK: ┠─ a = R0 +// CHECK: ┃ ┠─ b = R1 +// CHECK: ┃ ┃ ┠─ c = R2 +// CHECK: 0: push {r4, r10, r11, lr} ┃ ┃ ┃ +// CHECK: 4: add r11, sp, #8 ┃ ┃ ┃ +// CHECK: 8: sub sp, sp, #8 ┃ ┃ ┃ +// CHECK: ┃ ┃ ┃ ┌─ d = R0 +// CHECK: c: add r0, r1, r0 ┻ ┃ ┃ ╈ +// CHECK: ┌─ d = [SP+4] +// CHECK: 10: str r0, [sp, #4] ╈ ┃ ┃ ┻ +// CHECK: 14: add r0, sp, #4 ┃ ┃ ┃ +// CHECK: ┃ ┃ ┃ ┌─ a = R0 +// CHECK: ┃ ┃ ┃ │ ┌─ c = R4 +// CHECK: 18: mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// CHECK: 1c: bl #-8 ┃ ┻ ┻ ┃ +// CHECK: ┃ ┌─ d = R0 +// CHECK: 20: ldr r0, [sp, #4] ┻ ╈ ┃ +// CHECK: ┌─ e = R0 +// CHECK: 24: mul r0, r0, r4 ╈ ┻ ┃ +// CHECK: 28: sub sp, r11, #8 ┃ ┃ +// CHECK: 2c: pop {r4, r10, r11, pc} ┻ ┻ +// CHECK-EMPTY: +// CHECK: Disassembly of section .text.foo: +// CHECK-EMPTY: +// CHECK: 00000000 foo: +// CHECK: ┠─ x = [0,4): R0 [4,8): R1 +// CHECK: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// CHECK: ┃ │ ┌─ y = R0 +// CHECK: 0: add r0, r0, r1 ┻ ╈ ╈ +// CHECK: 4: bx lr ┻ ┻ +// CHECK-EMPTY: +// CHECK: Disassembly of section .text.quxx: +// CHECK-EMPTY: +// CHECK: 00000000 quxx: +// CHECK: ┠─ a = R0 ┃ +// CHECK: ┃ ┠─ b = R1 +// CHECK: ┃ ┃ ┠─ c = R2 +// CHECK: ┃ ┃ ┃ ┠─ d = R3 +// CHECK: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// CHECK: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// CHECK: 0: ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// CHECK: ┌─ z = R0 ┃ +// CHECK: 4: add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// CHECK: 8: 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" + .file 0 "/work/scratch" "debug.c" md5 0x4c6163a553bc9aedc49d96b4eb628daa + .section .text.baz,"ax",%progbits + .globl baz + .p2align 2 + .type baz,%function + .code 32 +baz: +.Lfunc_begin0: + .loc 0 2 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .save {r4, r10, r11, lr} + push {r4, r10, r11, lr} + .cfi_def_cfa_offset 16 + .cfi_offset lr, -4 + .cfi_offset r11, -8 + .cfi_offset r10, -12 + .cfi_offset r4, -16 + .setfp r11, sp, #8 + add r11, sp, #8 + .cfi_def_cfa r11, 8 + .pad #8 + sub sp, sp, #8 +.Ltmp0: + .loc 0 3 13 prologue_end + add r0, r1, r0 +.Ltmp1: + .loc 0 3 7 is_stmt 0 + str r0, [sp, #4] +.Ltmp2: + .loc 0 0 7 + add r0, sp, #4 + mov r4, r2 +.Ltmp3: + .loc 0 4 3 is_stmt 1 + bl bar +.Ltmp4: + .loc 0 5 11 + ldr r0, [sp, #4] +.Ltmp5: + .loc 0 5 13 is_stmt 0 + mul r0, r0, r4 +.Ltmp6: + .loc 0 6 3 is_stmt 1 + sub sp, r11, #8 + pop {r4, r10, r11, pc} +.Ltmp7: +.Lfunc_end0: + .size baz, .Lfunc_end0-baz + .cfi_endproc + .cantunwind + .fnend + + .section .text.foo,"ax",%progbits + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin1: + .loc 0 13 0 + .fnstart + .cfi_startproc + .loc 0 14 15 prologue_end + add r0, r0, r1 +.Ltmp8: + .loc 0 15 3 + bx lr +.Ltmp9: +.Lfunc_end1: + .size foo, .Lfunc_end1-foo + .cfi_endproc + .cantunwind + .fnend + + .section .text.quxx,"ax",%progbits + .globl quxx + .p2align 2 + .type quxx,%function + .code 32 +quxx: +.Lfunc_begin2: + .loc 0 18 0 + .fnstart + .cfi_startproc + ldm sp, {r0, r1} +.Ltmp10: + .loc 0 19 13 prologue_end + add r0, r1, r0 +.Ltmp11: + .loc 0 20 3 + bx lr +.Ltmp12: +.Lfunc_end2: + .size quxx, .Lfunc_end2-quxx + .cfi_endproc + .cantunwind + .fnend + + .section .debug_str_offsets,"",%progbits + .long 76 + .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 "debug.c" +.Linfo_string2: + .asciz "/work/scratch" +.Linfo_string3: + .asciz "bar" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "baz" +.Linfo_string6: + .asciz "foo" +.Linfo_string7: + .asciz "quxx" +.Linfo_string8: + .asciz "a" +.Linfo_string9: + .asciz "long int" +.Linfo_string10: + .asciz "b" +.Linfo_string11: + .asciz "c" +.Linfo_string12: + .asciz "d" +.Linfo_string13: + .asciz "e" +.Linfo_string14: + .asciz "x" +.Linfo_string15: + .asciz "S" +.Linfo_string16: + .asciz "y" +.Linfo_string17: + .asciz "z" + .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 + .long .Linfo_string11 + .long .Linfo_string12 + .long .Linfo_string13 + .long .Linfo_string14 + .long .Linfo_string15 + .long .Linfo_string16 + .long .Linfo_string17 + .section .debug_loclists,"",%progbits + .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 +.Ldebug_loclist_table_start0: + .short 5 + .byte 4 + .byte 0 + .long 10 +.Lloclists_table_base0: + .long .Ldebug_loc0-.Lloclists_table_base0 + .long .Ldebug_loc1-.Lloclists_table_base0 + .long .Ldebug_loc2-.Lloclists_table_base0 + .long .Ldebug_loc3-.Lloclists_table_base0 + .long .Ldebug_loc4-.Lloclists_table_base0 + .long .Ldebug_loc5-.Lloclists_table_base0 + .long .Ldebug_loc6-.Lloclists_table_base0 + .long .Ldebug_loc7-.Lloclists_table_base0 + .long .Ldebug_loc8-.Lloclists_table_base0 + .long .Ldebug_loc9-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 1 + .byte 0 + .byte 4 + .uleb128 .Lfunc_begin0-.Lfunc_begin0 + .uleb128 .Ltmp1-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 4 + .uleb128 .Ltmp3-.Lfunc_begin0 + .uleb128 .Ltmp4-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc1: + .byte 3 + .byte 0 + .uleb128 .Ltmp4-.Lfunc_begin0 + .byte 1 + .byte 81 + .byte 0 +.Ldebug_loc2: + .byte 1 + .byte 0 + .byte 4 + .uleb128 .Lfunc_begin0-.Lfunc_begin0 + .uleb128 .Ltmp3-.Lfunc_begin0 + .byte 1 + .byte 82 + .byte 4 + .uleb128 .Ltmp3-.Lfunc_begin0 + .uleb128 .Ltmp7-.Lfunc_begin0 + .byte 1 + .byte 84 + .byte 0 +.Ldebug_loc3: + .byte 1 + .byte 0 + .byte 4 + .uleb128 .Ltmp1-.Lfunc_begin0 + .uleb128 .Ltmp2-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 4 + .uleb128 .Ltmp2-.Lfunc_begin0 + .uleb128 .Ltmp5-.Lfunc_begin0 + .byte 2 + .byte 125 + .byte 4 + .byte 4 + .uleb128 .Ltmp5-.Lfunc_begin0 + .uleb128 .Ltmp6-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc4: + .byte 1 + .byte 0 + .byte 4 + .uleb128 .Ltmp6-.Lfunc_begin0 + .uleb128 .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc5: + .byte 1 + .byte 1 + .byte 4 + .uleb128 .Lfunc_begin1-.Lfunc_begin1 + .uleb128 .Ltmp8-.Lfunc_begin1 + .byte 6 + .byte 80 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .byte 4 + .uleb128 .Ltmp8-.Lfunc_begin1 + .uleb128 .Lfunc_end1-.Lfunc_begin1 + .byte 5 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .byte 0 +.Ldebug_loc6: + .byte 1 + .byte 1 + .byte 4 + .uleb128 .Ltmp8-.Lfunc_begin1 + .uleb128 .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc7: + .byte 3 + .byte 2 + .uleb128 .Ltmp10-.Lfunc_begin2 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc8: + .byte 3 + .byte 2 + .uleb128 .Ltmp10-.Lfunc_begin2 + .byte 1 + .byte 81 + .byte 0 +.Ldebug_loc9: + .byte 1 + .byte 2 + .byte 4 + .uleb128 .Ltmp11-.Lfunc_begin2 + .uleb128 .Lfunc_end2-.Lfunc_begin2 + .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 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 60 + .byte 25 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 15 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 36 + .byte 0 + .byte 3 + .byte 37 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 6 + .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 7 + .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 8 + .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 9 + .byte 72 + .byte 0 + .byte 127 + .byte 19 + .byte 125 + .byte 1 + .byte 0 + .byte 0 + .byte 10 + .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 11 + .byte 19 + .byte 1 + .byte 3 + .byte 37 + .byte 11 + .byte 11 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 0 + .byte 0 + .byte 12 + .byte 13 + .byte 0 + .byte 3 + .byte 37 + .byte 73 + .byte 19 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 56 + .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 3 + .byte 0 + .byte 1 + + + + .byte 3 + .long 53 + .byte 0 + .byte 4 + .long 58 + .byte 5 + .byte 4 + .byte 5 + .byte 4 + .byte 6 + .byte 0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .byte 5 + .byte 0 + .byte 2 + + .long 58 + + .byte 7 + .byte 0 + .byte 8 + .byte 0 + .byte 2 + .long 251 + .byte 7 + .byte 1 + .byte 10 + .byte 0 + .byte 2 + .long 58 + .byte 7 + .byte 2 + .byte 11 + .byte 0 + .byte 2 + .long 58 + .byte 8 + .byte 3 + .byte 12 + .byte 0 + .byte 3 + .long 58 + .byte 8 + .byte 4 + .byte 13 + .byte 0 + .byte 5 + .long 58 + .byte 9 + .long 43 + .long .Ltmp4-.Lfunc_begin0 + .byte 0 + .byte 6 + .byte 1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .byte 6 + .byte 0 + .byte 13 + + .long 58 + + .byte 7 + .byte 5 + .byte 14 + .byte 0 + .byte 13 + .long 255 + .byte 8 + .byte 6 + .byte 16 + .byte 0 + .byte 14 + .long 58 + .byte 0 + .byte 6 + .byte 2 + .long .Lfunc_end2-.Lfunc_begin2 + .byte 1 + .byte 91 + + .byte 7 + .byte 0 + .byte 18 + + .long 58 + + .byte 7 + .byte 7 + .byte 8 + .byte 0 + .byte 18 + .long 58 + .byte 7 + .byte 8 + .byte 10 + .byte 0 + .byte 18 + .long 58 + .byte 10 + .byte 1 + .byte 82 + .byte 11 + .byte 0 + .byte 18 + .long 58 + .byte 10 + .byte 1 + .byte 83 + .byte 12 + .byte 0 + .byte 18 + .long 58 + .byte 10 + .byte 2 + .byte 125 + .byte 0 + .byte 14 + .byte 0 + .byte 18 + .long 58 + .byte 10 + .byte 2 + .byte 125 + .byte 4 + .byte 16 + .byte 0 + .byte 18 + .long 58 + .byte 8 + .byte 9 + .byte 17 + .byte 0 + .byte 19 + .long 58 + .byte 0 + .byte 5 + .byte 9 + .byte 5 + .byte 4 + .byte 11 + .byte 15 + .byte 8 + .byte 0 + .byte 9 + .byte 12 + .byte 8 + .long 58 + .byte 0 + .byte 10 + .byte 0 + .byte 12 + .byte 10 + .long 58 + .byte 0 + .byte 11 + .byte 4 + .byte 0 + .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 3 + .byte 2 + .uleb128 .Lfunc_end2-.Lfunc_begin2 + .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 + .long .Lfunc_begin2 +.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,760 @@ +// 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 + +// Generated with this compile command and source: +// +// clang --target=arm--none-eabi -march=armv7-a -c debug.c -O2 -gdwarf-5 -S -o - +// +// void bar(int*); +// int baz(long a, int b, int c) { +// int d = a + b; +// bar(&d); +// int e = d * c; +// return e; +// } +// +// struct S { +// int a; +// int b; +// }; +// int foo(struct S x) { +// int y = x.a + x.b; +// return y; +// } +// +// int quxx(int a, int b, int c, int d, int x, int y) { +// int z = x + y; +// return z; +// } + +// CHECK: Disassembly of section .text: +// CHECK-EMPTY: +// CHECK: 00000000 baz: +// CHECK: ┠─ a = R0 +// CHECK: ┃ ┠─ b = R1 +// CHECK: ┃ ┃ ┠─ c = R2 +// CHECK: 0: push {r4, r10, r11, lr} ┃ ┃ ┃ +// CHECK: 4: add r11, sp, #8 ┃ ┃ ┃ +// CHECK: 8: sub sp, sp, #8 ┃ ┃ ┃ +// CHECK: ┃ ┃ ┃ ┌─ d = R0 +// CHECK: c: add r0, r1, r0 ┻ ┃ ┃ ╈ +// CHECK: ┌─ d = [SP+4] +// CHECK: 10: str r0, [sp, #4] ╈ ┃ ┃ ┻ +// CHECK: 14: add r0, sp, #4 ┃ ┃ ┃ +// CHECK: ┃ ┃ ┃ ┌─ a = R0 +// CHECK: ┃ ┃ ┃ │ ┌─ c = R4 +// CHECK: 18: mov r4, r2 ┃ ┃ ┻ ╈ ╈ +// CHECK: 1c: bl #-8 ┃ ┻ ┻ ┃ +// CHECK: ┃ ┌─ d = R0 +// CHECK: 20: ldr r0, [sp, #4] ┻ ╈ ┃ +// CHECK: ┌─ e = R0 +// CHECK: 24: mul r0, r0, r4 ╈ ┻ ┃ +// CHECK: 28: sub sp, r11, #8 ┃ ┃ +// CHECK: 2c: pop {r4, r10, r11, pc} ┻ ┻ +// CHECK-EMPTY: +// CHECK: 00000030 foo: +// CHECK: ┠─ x = [0,4): R0 [4,8): R1 +// CHECK: ┃ ┌─ x = [0,4): ??? [4,8): R1 +// CHECK: ┃ │ ┌─ y = R0 +// CHECK: 30: add r0, r0, r1 ┻ ╈ ╈ +// CHECK: 34: bx lr ┻ ┻ +// CHECK-EMPTY: +// CHECK: 00000038 quxx: +// CHECK: ┠─ a = R0 ┃ +// CHECK: ┃ ┠─ b = R1 +// CHECK: ┃ ┃ ┠─ c = R2 +// CHECK: ┃ ┃ ┃ ┠─ d = R3 +// CHECK: ┃ ┃ ┃ ┃ ┠─ x = [SP] +// CHECK: ┃ ┃ ┃ ┃ ┃ ┠─ y = [SP+4] +// CHECK: 38: ldm sp, {r0, r1} ┻ ┻ ┃ ┃ ┃ ┃ +// CHECK: ┌─ z = R0 ┃ +// CHECK: 3c: add r0, r1, r0 ╈ ┃ ┃ ┃ ┃ +// CHECK: 40: 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" + .file 0 "/work/scratch" "debug.c" md5 0x4c6163a553bc9aedc49d96b4eb628daa + .globl baz + .p2align 2 + .type baz,%function + .code 32 +baz: +.Lfunc_begin0: + .loc 0 2 0 + .fnstart + .cfi_sections .debug_frame + .cfi_startproc + .save {r4, r10, r11, lr} + push {r4, r10, r11, lr} + .cfi_def_cfa_offset 16 + .cfi_offset lr, -4 + .cfi_offset r11, -8 + .cfi_offset r10, -12 + .cfi_offset r4, -16 + .setfp r11, sp, #8 + add r11, sp, #8 + .cfi_def_cfa r11, 8 + .pad #8 + sub sp, sp, #8 +.Ltmp0: + .loc 0 3 13 prologue_end + add r0, r1, r0 +.Ltmp1: + .loc 0 3 7 is_stmt 0 + str r0, [sp, #4] +.Ltmp2: + .loc 0 0 7 + add r0, sp, #4 + mov r4, r2 +.Ltmp3: + .loc 0 4 3 is_stmt 1 + bl bar +.Ltmp4: + .loc 0 5 11 + ldr r0, [sp, #4] +.Ltmp5: + .loc 0 5 13 is_stmt 0 + mul r0, r0, r4 +.Ltmp6: + .loc 0 6 3 is_stmt 1 + sub sp, r11, #8 + pop {r4, r10, r11, pc} +.Ltmp7: +.Lfunc_end0: + .size baz, .Lfunc_end0-baz + .cfi_endproc + .cantunwind + .fnend + + .globl foo + .p2align 2 + .type foo,%function + .code 32 +foo: +.Lfunc_begin1: + .loc 0 13 0 + .fnstart + .cfi_startproc + .loc 0 14 15 prologue_end + add r0, r0, r1 +.Ltmp8: + .loc 0 15 3 + bx lr +.Ltmp9: +.Lfunc_end1: + .size foo, .Lfunc_end1-foo + .cfi_endproc + .cantunwind + .fnend + + .globl quxx + .p2align 2 + .type quxx,%function + .code 32 +quxx: +.Lfunc_begin2: + .loc 0 18 0 + .fnstart + .cfi_startproc + ldm sp, {r0, r1} +.Ltmp10: + .loc 0 19 13 prologue_end + add r0, r1, r0 +.Ltmp11: + .loc 0 20 3 + bx lr +.Ltmp12: +.Lfunc_end2: + .size quxx, .Lfunc_end2-quxx + .cfi_endproc + .cantunwind + .fnend + + .section .debug_str_offsets,"",%progbits + .long 76 + .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 "debug.c" +.Linfo_string2: + .asciz "/work/scratch" +.Linfo_string3: + .asciz "bar" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "baz" +.Linfo_string6: + .asciz "foo" +.Linfo_string7: + .asciz "quxx" +.Linfo_string8: + .asciz "a" +.Linfo_string9: + .asciz "long int" +.Linfo_string10: + .asciz "b" +.Linfo_string11: + .asciz "c" +.Linfo_string12: + .asciz "d" +.Linfo_string13: + .asciz "e" +.Linfo_string14: + .asciz "x" +.Linfo_string15: + .asciz "S" +.Linfo_string16: + .asciz "y" +.Linfo_string17: + .asciz "z" + .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 + .long .Linfo_string11 + .long .Linfo_string12 + .long .Linfo_string13 + .long .Linfo_string14 + .long .Linfo_string15 + .long .Linfo_string16 + .long .Linfo_string17 + .section .debug_loclists,"",%progbits + .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 +.Ldebug_loclist_table_start0: + .short 5 + .byte 4 + .byte 0 + .long 10 +.Lloclists_table_base0: + .long .Ldebug_loc0-.Lloclists_table_base0 + .long .Ldebug_loc1-.Lloclists_table_base0 + .long .Ldebug_loc2-.Lloclists_table_base0 + .long .Ldebug_loc3-.Lloclists_table_base0 + .long .Ldebug_loc4-.Lloclists_table_base0 + .long .Ldebug_loc5-.Lloclists_table_base0 + .long .Ldebug_loc6-.Lloclists_table_base0 + .long .Ldebug_loc7-.Lloclists_table_base0 + .long .Ldebug_loc8-.Lloclists_table_base0 + .long .Ldebug_loc9-.Lloclists_table_base0 +.Ldebug_loc0: + .byte 4 + .uleb128 .Lfunc_begin0-.Lfunc_begin0 + .uleb128 .Ltmp1-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 4 + .uleb128 .Ltmp3-.Lfunc_begin0 + .uleb128 .Ltmp4-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc1: + .byte 4 + .uleb128 .Lfunc_begin0-.Lfunc_begin0 + .uleb128 .Ltmp4-.Lfunc_begin0 + .byte 1 + .byte 81 + .byte 0 +.Ldebug_loc2: + .byte 4 + .uleb128 .Lfunc_begin0-.Lfunc_begin0 + .uleb128 .Ltmp3-.Lfunc_begin0 + .byte 1 + .byte 82 + .byte 4 + .uleb128 .Ltmp3-.Lfunc_begin0 + .uleb128 .Ltmp7-.Lfunc_begin0 + .byte 1 + .byte 84 + .byte 0 +.Ldebug_loc3: + .byte 4 + .uleb128 .Ltmp1-.Lfunc_begin0 + .uleb128 .Ltmp2-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 4 + .uleb128 .Ltmp2-.Lfunc_begin0 + .uleb128 .Ltmp5-.Lfunc_begin0 + .byte 2 + .byte 125 + .byte 4 + .byte 4 + .uleb128 .Ltmp5-.Lfunc_begin0 + .uleb128 .Ltmp6-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc4: + .byte 4 + .uleb128 .Ltmp6-.Lfunc_begin0 + .uleb128 .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc5: + .byte 4 + .uleb128 .Lfunc_begin1-.Lfunc_begin0 + .uleb128 .Ltmp8-.Lfunc_begin0 + .byte 6 + .byte 80 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .byte 4 + .uleb128 .Ltmp8-.Lfunc_begin0 + .uleb128 .Lfunc_end1-.Lfunc_begin0 + .byte 5 + .byte 147 + .byte 4 + .byte 81 + .byte 147 + .byte 4 + .byte 0 +.Ldebug_loc6: + .byte 4 + .uleb128 .Ltmp8-.Lfunc_begin0 + .uleb128 .Lfunc_end1-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc7: + .byte 4 + .uleb128 .Lfunc_begin2-.Lfunc_begin0 + .uleb128 .Ltmp10-.Lfunc_begin0 + .byte 1 + .byte 80 + .byte 0 +.Ldebug_loc8: + .byte 4 + .uleb128 .Lfunc_begin2-.Lfunc_begin0 + .uleb128 .Ltmp10-.Lfunc_begin0 + .byte 1 + .byte 81 + .byte 0 +.Ldebug_loc9: + .byte 4 + .uleb128 .Ltmp11-.Lfunc_begin0 + .uleb128 .Lfunc_end2-.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 3 + .byte 37 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 39 + .byte 25 + .byte 60 + .byte 25 + .byte 63 + .byte 25 + .byte 0 + .byte 0 + .byte 3 + .byte 5 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 4 + .byte 15 + .byte 0 + .byte 73 + .byte 19 + .byte 0 + .byte 0 + .byte 5 + .byte 36 + .byte 0 + .byte 3 + .byte 37 + .byte 62 + .byte 11 + .byte 11 + .byte 11 + .byte 0 + .byte 0 + .byte 6 + .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 7 + .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 8 + .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 9 + .byte 72 + .byte 0 + .byte 127 + .byte 19 + .byte 125 + .byte 1 + .byte 0 + .byte 0 + .byte 10 + .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 11 + .byte 19 + .byte 1 + .byte 3 + .byte 37 + .byte 11 + .byte 11 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 0 + .byte 0 + .byte 12 + .byte 13 + .byte 0 + .byte 3 + .byte 37 + .byte 73 + .byte 19 + .byte 58 + .byte 11 + .byte 59 + .byte 11 + .byte 56 + .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_end2-.Lfunc_begin0 + .long .Laddr_table_base0 + .long .Lloclists_table_base0 + .byte 2 + .byte 3 + .byte 0 + .byte 1 + + + + .byte 3 + .long 49 + .byte 0 + .byte 4 + .long 54 + .byte 5 + .byte 4 + .byte 5 + .byte 4 + .byte 6 + .byte 0 + .long .Lfunc_end0-.Lfunc_begin0 + .byte 1 + .byte 91 + + .byte 5 + .byte 0 + .byte 2 + + .long 54 + + .byte 7 + .byte 0 + .byte 8 + .byte 0 + .byte 2 + .long 247 + .byte 7 + .byte 1 + .byte 10 + .byte 0 + .byte 2 + .long 54 + .byte 7 + .byte 2 + .byte 11 + .byte 0 + .byte 2 + .long 54 + .byte 8 + .byte 3 + .byte 12 + .byte 0 + .byte 3 + .long 54 + .byte 8 + .byte 4 + .byte 13 + .byte 0 + .byte 5 + .long 54 + .byte 9 + .long 39 + .long .Ltmp4-.Lfunc_begin0 + .byte 0 + .byte 6 + .byte 1 + .long .Lfunc_end1-.Lfunc_begin1 + .byte 1 + .byte 91 + + .byte 6 + .byte 0 + .byte 13 + + .long 54 + + .byte 7 + .byte 5 + .byte 14 + .byte 0 + .byte 13 + .long 251 + .byte 8 + .byte 6 + .byte 16 + .byte 0 + .byte 14 + .long 54 + .byte 0 + .byte 6 + .byte 2 + .long .Lfunc_end2-.Lfunc_begin2 + .byte 1 + .byte 91 + + .byte 7 + .byte 0 + .byte 18 + + .long 54 + + .byte 7 + .byte 7 + .byte 8 + .byte 0 + .byte 18 + .long 54 + .byte 7 + .byte 8 + .byte 10 + .byte 0 + .byte 18 + .long 54 + .byte 10 + .byte 1 + .byte 82 + .byte 11 + .byte 0 + .byte 18 + .long 54 + .byte 10 + .byte 1 + .byte 83 + .byte 12 + .byte 0 + .byte 18 + .long 54 + .byte 10 + .byte 2 + .byte 125 + .byte 0 + .byte 14 + .byte 0 + .byte 18 + .long 54 + .byte 10 + .byte 2 + .byte 125 + .byte 4 + .byte 16 + .byte 0 + .byte 18 + .long 54 + .byte 8 + .byte 9 + .byte 17 + .byte 0 + .byte 19 + .long 54 + .byte 0 + .byte 5 + .byte 9 + .byte 5 + .byte 4 + .byte 11 + .byte 15 + .byte 8 + .byte 0 + .byte 9 + .byte 12 + .byte 8 + .long 54 + .byte 0 + .byte 10 + .byte 0 + .byte 12 + .byte 10 + .long 54 + .byte 0 + .byte 11 + .byte 4 + .byte 0 + .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 + .long .Lfunc_begin2 +.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-precedence.s b/llvm/test/tools/llvm-objdump/ARM/debug-vars-precedence.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ARM/debug-vars-precedence.s @@ -0,0 +1,456 @@ +// RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \ +// RUN: llvm-objdump - -d -debug-vars -no-show-raw-insn | \ +// RUN: FileCheck %s + +// Generated with this compile command and source (using GCC, clang doesn't +// emit complex DWARF expressions like this): +// +// arm-none-eabi-gcc -march=armv7-a -c test.c -O1 -g -o - -S -gno-as-locview-support +// +// void bar(); +// int foo(int a, int b, int c) { +// int z = a + b << c; +// return z; +// } +// int baz(int a, int b, int c) { +// int z = a + (b << c); +// return z; +// } + +// CHECK: Disassembly of section .text: +// CHECK-EMPTY: +// CHECK-NEXT: 00000000 foo: +// CHECK-NEXT: ┠─ a = R0 +// CHECK-NEXT: ┃ ┌─ a = entry(R0) +// CHECK-NEXT: ┃ │ ┠─ b = R1 +// CHECK-NEXT: ┃ │ ┃ ┠─ c = R2 +// CHECK-NEXT: ┃ │ ┃ ┃ ┠─ z = R2< #include #include +#include #include #include #include +#define DEBUG_TYPE "objdump" + using namespace llvm::object; namespace llvm { @@ -334,6 +341,9 @@ cl::cat(ObjdumpCat)); static cl::alias WideShort("w", cl::Grouping, cl::aliasopt(Wide)); +static cl::opt DbgVariables("debug-vars", cl::init(false)); +static cl::opt DbgIndent("debug-vars-indent", cl::init(50)); + static cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); @@ -538,6 +548,579 @@ } namespace { +struct PrintedExpr { + enum ExprKind { + Address, + Value, + }; + ExprKind Kind; + unsigned Precedence; + SmallString<20> String; + + PrintedExpr(unsigned Precedence = 0, ExprKind K = Address) + : Kind(K), Precedence(Precedence) {} + + // Add parentheses around this expression if they are needed when this is an + // operand to an operator with NewPrecedence. We use the same operator + // precedence as C, with numbers taken from the table at + // https://en.cppreference.com/w/c/language/operator_precedence. + void AddParens(unsigned NewPrecedence) { + if (NewPrecedence < Precedence) { + SmallString<20> NewString; + raw_svector_ostream S(NewString); + S << "(" << String << ")"; + String = NewString; + Precedence = 0; + } + } +}; + +static void PrettyPrintDWARFOps(raw_ostream &OS, DWARFExpression::iterator I, + const DWARFExpression::iterator E, + const MCRegisterInfo *MRI, + SmallString<20> FrameBase, + bool ForFrameBase = false) { + SmallVector Stack; + unsigned PieceStart = 0; + + while (I != E) { + auto &Op = *I; + unsigned Opcode = Op.getCode(); + if (Opcode == dwarf::DW_OP_piece) { + // DW_OP_piece - record piece of larger object. + assert(Stack.size() <= 1 && "too many values on stack"); + uint64_t PieceSize = Op.getRawOperand(0); + if (PieceStart != 0) + OS << " "; + if (OS.has_colors()) + OS.changeColor(raw_ostream::YELLOW); + OS << "[" << PieceStart << "," << (PieceStart + PieceSize) << "): "; + if (OS.has_colors()) + OS.changeColor(raw_ostream::CYAN); + if (Stack.empty()) + OS << "???"; + else if (Stack.front().Kind == PrintedExpr::Address && !ForFrameBase) + OS << "[" << Stack.front().String << "]"; + else + OS << Stack.front().String; + Stack.clear(); + PieceStart += PieceSize; + } else 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(0, 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(0, PrintedExpr::Value).String); + S << MRI->getName(LLVMRegNum); + } else if (Opcode >= dwarf::DW_OP_breg0 && Opcode <= dwarf::DW_OP_breg31) { + int DwarfRegNum = Opcode - dwarf::DW_OP_breg0; + int LLVMRegNum = *MRI->getLLVMRegNum(DwarfRegNum, false); + int64_t Offset = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back().String); + S << MRI->getName(LLVMRegNum); + if (Offset) { + S << format("%+" PRId64, Offset); + Stack.back().Precedence = 4; + } + } else if (Opcode == dwarf::DW_OP_bregx) { + int DwarfRegNum = Op.getRawOperand(0); + int LLVMRegNum = *MRI->getLLVMRegNum(DwarfRegNum, false); + int64_t Offset = Op.getRawOperand(1); + raw_svector_ostream S(Stack.emplace_back().String); + S << MRI->getName(LLVMRegNum); + if (Offset) { + S << format("%+" PRId64, Offset); + Stack.back().Precedence = 4; + } + } else if (Opcode == dwarf::DW_OP_fbreg) { + int64_t Offset = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back().String); + S << FrameBase; + if (Offset) { + S << format("%+" PRId64, Offset); + Stack.back().Precedence = 4; + } + } else if (Opcode >= dwarf::DW_OP_lit0 && Opcode <= dwarf::DW_OP_lit31) { + unsigned Val = Opcode - dwarf::DW_OP_lit0; + raw_svector_ostream S(Stack.emplace_back().String); + S << Val; + } else if (Opcode == dwarf::DW_OP_consts || + Opcode == dwarf::DW_OP_const1s || + Opcode == dwarf::DW_OP_const2s || + Opcode == dwarf::DW_OP_const4s || + Opcode == dwarf::DW_OP_const8s) { + // Signed constant + int64_t Val = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back().String); + S << Val; + } else if (Opcode == dwarf::DW_OP_constu || + Opcode == dwarf::DW_OP_const1u || + Opcode == dwarf::DW_OP_const2u || + Opcode == dwarf::DW_OP_const4u || + Opcode == dwarf::DW_OP_const8u) { + // Unsigned constant + uint64_t Val = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back().String); + S << Val; + } else if (Opcode == dwarf::DW_OP_implicit_value) { + uint64_t Len = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); + S << ""; + // TODO: Print the actual value, if it is not too big. + } else if (Opcode == dwarf::DW_OP_stack_value) { + assert(!Stack.empty()); + Stack.back().Kind = PrintedExpr::Value; + } else if (Opcode == dwarf::DW_OP_entry_value || + Opcode == dwarf::DW_OP_GNU_entry_value) { + int64_t SubExprLength = Op.getRawOperand(0); + DWARFExpression::iterator SubExprEnd = I.skip_bytes(SubExprLength); + ++I; + raw_svector_ostream S(Stack.emplace_back().String); + S << "entry("; + PrettyPrintDWARFOps(S, I, SubExprEnd, MRI, FrameBase); + S << ")"; + I = SubExprEnd; + continue; + } else if (Opcode == dwarf::DW_OP_deref || + Opcode == dwarf::DW_OP_deref_size) { + // We use square brackets to show memory access, which is a departure + // from our otherise C-like syntax, but makes common cases like '[R0]' + // and '[SP+16]' concise. We also ignore the memory access width, which + // loses detail, but most real debug locations are simple enough that it + // can be inferred by the user, so we prefer to avoid bloating the + // syntax. + PrintedExpr PoppedVal = Stack.pop_back_val(); + raw_svector_ostream S(Stack.emplace_back().String); + S << "[" << PoppedVal.String << "]"; + } else if (Opcode == dwarf::DW_OP_neg || + Opcode == dwarf::DW_OP_not) { + PrintedExpr ExprOp = Stack.pop_back_val(); + ExprOp.AddParens(2); + raw_svector_ostream S(Stack.emplace_back(2).String); + switch (Opcode) { + case dwarf::DW_OP_neg: S << "-" << ExprOp.String; break; + case dwarf::DW_OP_not: S << "~" << ExprOp.String; break; + default: llvm_unreachable("unexpected opcode"); + } + } else if (Opcode == dwarf::DW_OP_abs) { + PrintedExpr ExprOp = Stack.pop_back_val(); + raw_svector_ostream S(Stack.emplace_back().String); + S << "abs(" << ExprOp.String << ")"; + } else if (Opcode == dwarf::DW_OP_plus_uconst) { + PrintedExpr LHS = Stack.pop_back_val(); + LHS.AddParens(4); + uint64_t RHS = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back(4).String); + S << LHS.String << "+" << RHS; + } else if (Opcode == dwarf::DW_OP_and || Opcode == dwarf::DW_OP_div || + Opcode == dwarf::DW_OP_minus || Opcode == dwarf::DW_OP_mod || + Opcode == dwarf::DW_OP_mul || Opcode == dwarf::DW_OP_or || + Opcode == dwarf::DW_OP_plus || Opcode == dwarf::DW_OP_shl || + Opcode == dwarf::DW_OP_shr || Opcode == dwarf::DW_OP_shra || + Opcode == dwarf::DW_OP_xor) { + // Binary operations + unsigned Precedence; + const char * Op; + switch (Opcode) { + case dwarf::DW_OP_and: Precedence = 8; Op = "&"; break; + case dwarf::DW_OP_div: Precedence = 3; Op = "/"; break; + case dwarf::DW_OP_minus: Precedence = 4; Op = "-"; break; + case dwarf::DW_OP_mod: Precedence = 3; Op = "%"; break; + case dwarf::DW_OP_mul: Precedence = 3; Op = "*"; break; + case dwarf::DW_OP_or: Precedence = 8; Op = "|"; break; + case dwarf::DW_OP_plus: Precedence = 4; Op = "+"; break; + case dwarf::DW_OP_xor: Precedence = 9; Op = "^"; break; + case dwarf::DW_OP_shl : Precedence = 5; Op = "<<"; break; + case dwarf::DW_OP_shr: Precedence = 5; Op = ">>"; break; + case dwarf::DW_OP_shra: Precedence = 5; Op = ">>>"; break; + default: llvm_unreachable("unexpected opcode"); + } + PrintedExpr LHS = Stack.pop_back_val(); + PrintedExpr RHS = Stack.pop_back_val(); + LHS.AddParens(Precedence); + RHS.AddParens(Precedence); + raw_svector_ostream S(Stack.emplace_back(Precedence).String); + S << LHS.String << Op << RHS.String; + } else if (Opcode == dwarf::DW_OP_call_frame_cfa) { + raw_svector_ostream S(Stack.emplace_back().String); + S << "CFA"; + } else if (Opcode == dwarf::DW_OP_regval_type) { + // Register contents with type (we ignore the type for now) + int LLVMRegNum = *MRI->getLLVMRegNum(Op.getRawOperand(0), false); + raw_svector_ostream S(Stack.emplace_back(0, PrintedExpr::Value).String); + S << MRI->getName(LLVMRegNum); + } else if (Opcode == dwarf::DW_OP_addr) { + // TODO: For relocatable object files, we should check for relocations on + // the DWARF section, and print the actual symbol name. + uint64_t Addr = Op.getRawOperand(0); + raw_svector_ostream S(Stack.emplace_back().String); + S << format("%#" PRIx64, Addr); + } else if (Opcode == dwarf::DW_OP_implicit_pointer) { + // TODO: Operand 0 is a reference to the DIE for a variable or parameter, + // we should follow that and print the name. + raw_svector_ostream S(Stack.emplace_back(0, PrintedExpr::Value).String); + S << ""; + } 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((PieceStart != 0 && Stack.size() == 0) || + (PieceStart == 0 && Stack.size() == 1) && + "expected pieces and an empty stack, or one value on stack"); + if (!Stack.empty()) { + if (Stack.front().Kind == PrintedExpr::Address && !ForFrameBase) + OS << "[" << Stack.front().String << "]"; + else + OS << Stack.front().String; + } +} + +static void PrettyPrintDWARFExpr(raw_ostream &OS, const DWARFExpression *Expr, + const MCRegisterInfo *MRI, + const DWARFDie FuncDie, bool LittleEndian) { + // First, render the DW_AT_frame_base expression for the function, if it has + // one. + // TODO: Only do this once per function, not once per expression (it's + // typically a small expression though, so this isn't too bad). + // TODO: If this is an expression like 'SP+16', we might want to simplify + // expressions which use it, so we print 'SP+8' instead of 'SP+16-8'. I've + // not seen any code which uses anything other than DW_OP_call_frame_cfa + // here, so might not be worth the extra complexity. + SmallString<20> FrameBase; + auto FrameBaseAttr = FuncDie.find(dwarf::DW_AT_frame_base); + if (FrameBaseAttr) { + StringRef FrameBaseStr((const char *)FrameBaseAttr->getAsBlock()->data(), + FrameBaseAttr->getAsBlock()->size()); + DataExtractor FrameBaseData(FrameBaseStr, LittleEndian, 0); + DWARFExpression FrameBaseExpr(FrameBaseData, + FuncDie.getDwarfUnit()->getVersion(), + FuncDie.getDwarfUnit()->getAddressByteSize()); + raw_svector_ostream S(FrameBase); + PrettyPrintDWARFOps(S, FrameBaseExpr.begin(), FrameBaseExpr.end(), MRI, + FrameBase, true); + } + + // Render the actual expression. + PrettyPrintDWARFOps(OS, Expr->begin(), Expr->end(), MRI, FrameBase); +} + +// 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); + } +}; + +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(); + + auto Locs = VarDie.getLocations(dwarf::DW_AT_location); + if (Locs) { + 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); + } + } + } else { + consumeError(Locs.takeError()); + } + } + + 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()) { + 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!"); + } else { + OS << " "; + } + } + } +}; + class SourcePrinter { protected: DILineInfo OldLineInfo; @@ -566,9 +1149,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 +1186,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 +1218,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 +1237,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 +1258,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 +1309,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 +1321,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 +1352,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 +1363,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 +1391,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 +1443,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) { @@ -1110,6 +1701,7 @@ } } + static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, MCContext &Ctx, MCDisassembler *PrimaryDisAsm, MCDisassembler *SecondaryDisAsm, @@ -1201,6 +1793,18 @@ 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 +2022,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 +2081,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 +2117,9 @@ Offset += AdjustVMA; } - printRelocation(Obj->getFileName(), *RelCur, SectionAddr + Offset, - Is64Bits); + printRelocation(FOS, Obj->getFileName(), *RelCur, + SectionAddr + Offset, Is64Bits); + LVP.printAfterOtherLine(FOS, true); ++RelCur; } }