forked from OSchip/llvm-project
[llvm-objdump] Display locations of variables alongside disassembly
This adds the --debug-vars option to llvm-objdump, which prints locations (registers/memory) of source-level variables alongside the disassembly based on DWARF info. A vertical line is printed for each live-range, with a label at the top giving the variable name and location, and the position and length of the line indicating the program counter range in which it is valid. Differential revision: https://reviews.llvm.org/D70720
This commit is contained in:
parent
1c7c5019a7
commit
dc4a6f5db4
|
@ -123,6 +123,17 @@ OPTIONS
|
|||
|
||||
Demangle symbol names in the output.
|
||||
|
||||
.. option:: --debug-vars=<format>
|
||||
|
||||
Print the locations (in registers or memory) of source-level variables
|
||||
alongside disassembly. ``format`` may be ``unicode`` or ``ascii``, defaulting
|
||||
to ``unicode`` if omitted.
|
||||
|
||||
.. option:: --debug-vars-indent=<width>
|
||||
|
||||
Distance to indent the source-level variable display, relative to the start
|
||||
of the disassembly. Defaults to 40 characters.
|
||||
|
||||
.. option:: -j, --section=<section1[,section2,...]>
|
||||
|
||||
Perform commands on the specified sections only. For Mach-O use
|
||||
|
|
|
@ -142,6 +142,12 @@ public:
|
|||
void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U,
|
||||
bool IsEH = false) const;
|
||||
|
||||
/// Print the expression in a format intended to be compact and useful to a
|
||||
/// user, but not perfectly unambiguous, or capable of representing every
|
||||
/// valid DWARF expression. Returns true if the expression was sucessfully
|
||||
/// printed.
|
||||
bool printCompact(raw_ostream &OS, const MCRegisterInfo &RegInfo);
|
||||
|
||||
bool verify(DWARFUnit *U);
|
||||
|
||||
private:
|
||||
|
|
|
@ -374,4 +374,74 @@ bool DWARFExpression::verify(DWARFUnit *U) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// A user-facing string representation of a DWARF expression. This might be an
|
||||
/// Address expression, in which case it will be implicitly dereferenced, or a
|
||||
/// Value expression.
|
||||
struct PrintedExpr {
|
||||
enum ExprKind {
|
||||
Address,
|
||||
Value,
|
||||
};
|
||||
ExprKind Kind;
|
||||
SmallString<16> String;
|
||||
|
||||
PrintedExpr(ExprKind K = Address) : Kind(K) {}
|
||||
};
|
||||
|
||||
static bool printCompactDWARFExpr(raw_ostream &OS, DWARFExpression::iterator I,
|
||||
const DWARFExpression::iterator E,
|
||||
const MCRegisterInfo &MRI) {
|
||||
SmallVector<PrintedExpr, 4> Stack;
|
||||
|
||||
while (I != E) {
|
||||
DWARFExpression::Operation &Op = *I;
|
||||
uint8_t Opcode = Op.getCode();
|
||||
switch (Opcode) {
|
||||
case dwarf::DW_OP_regx: {
|
||||
// DW_OP_regx: A register, with the register num given as an operand.
|
||||
// Printed as the plain register name.
|
||||
uint64_t DwarfRegNum = Op.getRawOperand(0);
|
||||
Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
|
||||
if (!LLVMRegNum) {
|
||||
OS << "<unknown register " << DwarfRegNum << ">";
|
||||
return false;
|
||||
}
|
||||
raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
|
||||
S << MRI.getName(*LLVMRegNum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
|
||||
// DW_OP_reg<N>: A register, with the register num implied by the
|
||||
// opcode. Printed as the plain register name.
|
||||
uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
|
||||
Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
|
||||
if (!LLVMRegNum) {
|
||||
OS << "<unknown register " << DwarfRegNum << ">";
|
||||
return 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 its effect on the stack,
|
||||
// so bail out on the whole expression.
|
||||
OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("
|
||||
<< (int)Opcode << ")>";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++I;
|
||||
}
|
||||
|
||||
assert(Stack.size() == 1 && "expected one value on stack");
|
||||
OS << Stack.front().String;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) {
|
||||
return printCompactDWARFExpr(OS, begin(), end(), MRI);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
int foo(int *喵) {
|
||||
return *喵;
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
## Check that the --debug-vars option works for simple register locations, when
|
||||
## using DWARF4 debug info, with functions in 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
|
||||
|
||||
# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars --no-show-raw-insn | \
|
||||
# RUN: FileCheck %s
|
||||
|
||||
# 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:
|
|
@ -0,0 +1,454 @@
|
|||
## 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. These do not affect the DWARF parsing
|
||||
## used by --debug-vars, but do add extra lines or columns to the output, so we
|
||||
## test to make sure the live ranges are still displayed correctly.
|
||||
|
||||
## 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 -
|
||||
|
||||
# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars | \
|
||||
# RUN: FileCheck %s --check-prefix=RAW --strict-whitespace
|
||||
|
||||
## Check that passing the default value for --debug-vars-indent (40) makes no
|
||||
## change to the output.
|
||||
# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars --debug-vars-indent=40 | \
|
||||
# RUN: FileCheck %s --check-prefix=RAW --strict-whitespace
|
||||
|
||||
# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars --debug-vars-indent=30 | \
|
||||
# RUN: FileCheck %s --check-prefix=INDENT --strict-whitespace
|
||||
|
||||
# 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 --strict-whitespace
|
||||
|
||||
# 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 --strict-whitespace
|
||||
|
||||
# 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 --strict-whitespace
|
||||
|
||||
## An optional argument to the --debug-vars= option can be used to switch
|
||||
## between unicode and ascii output (with unicode being the default).
|
||||
# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars=unicode | \
|
||||
# RUN: FileCheck %s --check-prefix=RAW --strict-whitespace
|
||||
# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars=ascii | \
|
||||
# RUN: FileCheck %s --check-prefix=ASCII --strict-whitespace
|
||||
|
||||
## Note that llvm-objdump emits tab characters in the disassembly, assuming an
|
||||
## 8-byte tab stop, so these might not look aligned in a text editor.
|
||||
|
||||
# RAW: 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 ┻
|
||||
|
||||
|
||||
# INDENT: 00000000 <foo>:
|
||||
# INDENT-NEXT: ┠─ a = R0
|
||||
# INDENT-NEXT: ┃ ┠─ b = R1
|
||||
# INDENT-NEXT: ┃ ┃ ┠─ c = R2
|
||||
# INDENT-NEXT: ┃ ┃ ┃ ┌─ x = R0
|
||||
# INDENT-NEXT: 0: 00 00 81 e0 add r0, r1, r0 ┻ ┃ ┃ ╈
|
||||
# INDENT-NEXT: ┌─ y = R0
|
||||
# INDENT-NEXT: 4: 02 00 80 e0 add r0, r0, r2 ╈ ┃ ┃ ┻
|
||||
# INDENT-NEXT: 8: 1e ff 2f e1 bx lr ┻ ┻ ┻
|
||||
# INDENT-EMPTY:
|
||||
# INDENT-NEXT: 0000000c <bar>:
|
||||
# INDENT-NEXT: ┠─ a = R0
|
||||
# INDENT-NEXT: c: 01 00 80 e2 add r0, r0, #1 ┃
|
||||
# INDENT-NEXT: 10: 1e ff 2f e1 bx lr ┻
|
||||
|
||||
# NO-RAW: 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: 00000000 <foo>:
|
||||
# LINE-NUMS-NEXT: ; 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: ; 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: 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 ┻
|
||||
|
||||
# ASCII: 00000000 <foo>:
|
||||
# ASCII-NEXT: |- a = R0
|
||||
# ASCII-NEXT: | |- b = R1
|
||||
# ASCII-NEXT: | | |- c = R2
|
||||
# ASCII-NEXT: | | | /- x = R0
|
||||
# ASCII-NEXT: 0: 00 00 81 e0 add r0, r1, r0 v | | ^
|
||||
# ASCII-NEXT: /- y = R0
|
||||
# ASCII-NEXT: 4: 02 00 80 e0 add r0, r0, r2 ^ | | v
|
||||
# ASCII-NEXT: 8: 1e ff 2f e1 bx lr v v v
|
||||
# ASCII-EMPTY:
|
||||
# ASCII-NEXT: 0000000c <bar>:
|
||||
# ASCII-NEXT: |- a = R0
|
||||
# ASCII-NEXT: c: 01 00 80 e2 add r0, r0, #1 |
|
||||
# ASCII-NEXT: 10: 1e ff 2f e1 bx lr v
|
||||
|
||||
.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:
|
|
@ -0,0 +1,411 @@
|
|||
## Check that the --debug-vars option works for simple register locations, when
|
||||
## using DWARF4 debug info, with functions in 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
|
||||
|
||||
# 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: 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:
|
|
@ -0,0 +1,382 @@
|
|||
## 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 -
|
||||
|
||||
# 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: 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:
|
|
@ -0,0 +1,232 @@
|
|||
# RUN: mkdir -p %t/a
|
||||
# RUN: cp %p/Inputs/wide-char.c %t/a/wide-char.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 --source | \
|
||||
# RUN: FileCheck %s --strict-whitespace
|
||||
|
||||
## The Chinese character in the source does not print correctly on Windows.
|
||||
# UNSUPPORTED: system-windows
|
||||
|
||||
## Check that the --debug-vars option correctly aligns the variable display when
|
||||
## the source code (printed by the -S option) includes East Asian wide
|
||||
## characters.
|
||||
|
||||
# CHECK: 00000000 <foo>:
|
||||
# CHECK-NEXT: ; return *喵; ┠─ 喵 = R0
|
||||
# CHECK-NEXT: 0: 00 00 90 e5 ldr r0, [r0] ┻
|
||||
# CHECK-NEXT: 4: 1e ff 2f e1 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 vfpv3
|
||||
.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 "wide.c"
|
||||
.globl foo
|
||||
.p2align 2
|
||||
.type foo,%function
|
||||
.code 32
|
||||
foo:
|
||||
.Lfunc_begin0:
|
||||
.file 1 "SRC_COMPDIR/wide-char.c"
|
||||
.loc 1 1 0
|
||||
.fnstart
|
||||
.cfi_sections .debug_frame
|
||||
.cfi_startproc
|
||||
.loc 1 2 10 prologue_end
|
||||
ldr r0, [r0]
|
||||
.Ltmp0:
|
||||
.loc 1 2 3 is_stmt 0
|
||||
bx lr
|
||||
.Ltmp1:
|
||||
.Lfunc_end0:
|
||||
.size foo, .Lfunc_end0-foo
|
||||
.cfi_endproc
|
||||
.cantunwind
|
||||
.fnend
|
||||
|
||||
.section .debug_str,"MS",%progbits,1
|
||||
.Linfo_string0:
|
||||
.asciz "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)"
|
||||
.Linfo_string1:
|
||||
.asciz "wide-char.c"
|
||||
.Linfo_string2:
|
||||
.asciz "SRC_COMPDIR"
|
||||
.Linfo_string3:
|
||||
.asciz "foo"
|
||||
.Linfo_string4:
|
||||
.asciz "int"
|
||||
.Linfo_string5:
|
||||
.asciz "\345\226\265"
|
||||
.section .debug_loc,"",%progbits
|
||||
.Ldebug_loc0:
|
||||
.long .Lfunc_begin0-.Lfunc_begin0
|
||||
.long .Ltmp0-.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
|
||||
.ascii "\264B"
|
||||
.byte 25
|
||||
.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
|
||||
.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 36
|
||||
.byte 0
|
||||
.byte 3
|
||||
.byte 14
|
||||
.byte 62
|
||||
.byte 11
|
||||
.byte 11
|
||||
.byte 11
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 5
|
||||
.byte 15
|
||||
.byte 0
|
||||
.byte 73
|
||||
.byte 19
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.section .debug_info,"",%progbits
|
||||
.Lcu_begin0:
|
||||
.long 84
|
||||
.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_end0-.Lfunc_begin0
|
||||
.byte 2
|
||||
.long .Lfunc_begin0
|
||||
.long .Lfunc_end0-.Lfunc_begin0
|
||||
.byte 1
|
||||
.byte 91
|
||||
.long .Linfo_string3
|
||||
.byte 1
|
||||
.byte 1
|
||||
|
||||
.long 75
|
||||
|
||||
.byte 3
|
||||
.long .Ldebug_loc0
|
||||
.long .Linfo_string5
|
||||
.byte 1
|
||||
.byte 1
|
||||
.long 82
|
||||
.byte 0
|
||||
.byte 4
|
||||
.long .Linfo_string4
|
||||
.byte 5
|
||||
.byte 4
|
||||
.byte 5
|
||||
.long 75
|
||||
.byte 0
|
||||
.section .debug_ranges,"",%progbits
|
||||
.section .debug_macinfo,"",%progbits
|
||||
.Lcu_macro_begin0:
|
||||
.byte 0
|
||||
.section .debug_pubnames,"",%progbits
|
||||
.long .LpubNames_end0-.LpubNames_begin0
|
||||
.LpubNames_begin0:
|
||||
.short 2
|
||||
.long .Lcu_begin0
|
||||
.long 88
|
||||
.long 38
|
||||
.asciz "foo"
|
||||
.long 0
|
||||
.LpubNames_end0:
|
||||
.section .debug_pubtypes,"",%progbits
|
||||
.long .LpubTypes_end0-.LpubTypes_begin0
|
||||
.LpubTypes_begin0:
|
||||
.short 2
|
||||
.long .Lcu_begin0
|
||||
.long 88
|
||||
.long 75
|
||||
.asciz "int"
|
||||
.long 0
|
||||
.LpubTypes_end0:
|
||||
|
||||
.ident "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)"
|
||||
.section ".note.GNU-stack","",%progbits
|
||||
.eabi_attribute 30, 1
|
||||
.section .debug_line,"",%progbits
|
||||
.Lline_table_start0:
|
|
@ -0,0 +1,372 @@
|
|||
## 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;
|
||||
## }
|
||||
|
||||
# RUN: llvm-mc -triple powerpc64-unknown-linux < %s -filetype=obj | \
|
||||
# RUN: llvm-objdump - -d --debug-vars --no-show-raw-insn | \
|
||||
# RUN: FileCheck %s
|
||||
|
||||
# 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:
|
|
@ -21,7 +21,9 @@
|
|||
#include "MachODump.h"
|
||||
#include "WasmDump.h"
|
||||
#include "XCOFFDump.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"
|
||||
|
@ -79,6 +81,8 @@ using namespace llvm;
|
|||
using namespace llvm::object;
|
||||
using namespace llvm::objdump;
|
||||
|
||||
#define DEBUG_TYPE "objdump"
|
||||
|
||||
static cl::OptionCategory ObjdumpCat("llvm-objdump Options");
|
||||
|
||||
static cl::opt<uint64_t> AdjustVMA(
|
||||
|
@ -344,6 +348,28 @@ static cl::opt<bool>
|
|||
cl::cat(ObjdumpCat));
|
||||
static cl::alias WideShort("w", cl::Grouping, cl::aliasopt(Wide));
|
||||
|
||||
enum DebugVarsFormat {
|
||||
DVDisabled,
|
||||
DVUnicode,
|
||||
DVASCII,
|
||||
};
|
||||
|
||||
static cl::opt<DebugVarsFormat> DbgVariables(
|
||||
"debug-vars", cl::init(DVDisabled),
|
||||
cl::desc("Print the locations (in registers or memory) of "
|
||||
"source-level variables alongside disassembly"),
|
||||
cl::ValueOptional,
|
||||
cl::values(clEnumValN(DVUnicode, "", "unicode"),
|
||||
clEnumValN(DVUnicode, "unicode", "unicode"),
|
||||
clEnumValN(DVASCII, "ascii", "unicode")),
|
||||
cl::cat(ObjdumpCat));
|
||||
|
||||
static cl::opt<int>
|
||||
DbgIndent("debug-vars-indent", cl::init(40),
|
||||
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");
|
||||
|
||||
|
@ -548,6 +574,357 @@ static bool getHidden(RelocationRef RelRef) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// Get the column at which we want to start printing the instruction
|
||||
/// disassembly, taking into account anything which appears to the left of it.
|
||||
unsigned getInstStartColumn(const MCSubtargetInfo &STI) {
|
||||
return NoShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24;
|
||||
}
|
||||
|
||||
/// 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(const 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) const {
|
||||
DataExtractor Data({LocExpr.Expr.data(), LocExpr.Expr.size()},
|
||||
Unit->getContext().isLittleEndian(), 0);
|
||||
DWARFExpression Expression(Data, Unit->getAddressByteSize());
|
||||
Expression.printCompact(OS, MRI);
|
||||
}
|
||||
};
|
||||
|
||||
/// 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 = NullVarIdx;
|
||||
bool LiveIn = false;
|
||||
bool LiveOut = false;
|
||||
bool MustDrawLabel = false;
|
||||
|
||||
bool isActive() const { return VarIdx != NullVarIdx; }
|
||||
|
||||
static constexpr unsigned NullVarIdx = std::numeric_limits<unsigned>::max();
|
||||
};
|
||||
|
||||
// All live variables we know about in the object/image file.
|
||||
std::vector<LiveVariable> LiveVariables;
|
||||
|
||||
// The columns we are currently drawing.
|
||||
IndexedMap<Column> ActiveCols;
|
||||
|
||||
const MCRegisterInfo &MRI;
|
||||
const MCSubtargetInfo &STI;
|
||||
|
||||
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<DWARFLocationExpressionsVector> Locs =
|
||||
VarDie.getLocations(dwarf::DW_AT_location);
|
||||
if (!Locs) {
|
||||
// If the variable doesn't have any locations, just ignore it. We don't
|
||||
// report an error or warning here as that could be noisy on optimised
|
||||
// code.
|
||||
consumeError(Locs.takeError());
|
||||
return;
|
||||
}
|
||||
|
||||
for (const DWARFLocationExpression &LocExpr : *Locs) {
|
||||
if (LocExpr.Range) {
|
||||
LiveVariables.emplace_back(LocExpr, 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 (const DWARFDie &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 + getInstStartColumn(STI);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Logical column number: column zero is the first column we print in, each
|
||||
// logical column is 2 physical columns wide.
|
||||
unsigned FirstUnprintedLogicalColumn =
|
||||
std::max((int)(OS.getColumn() - getIndentLevel() + 1) / 2, 0);
|
||||
// Physical column number: the actual column number in characters, with
|
||||
// zero being the left-most side of the screen.
|
||||
unsigned FirstUnprintedPhysicalColumn =
|
||||
getIndentLevel() + FirstUnprintedLogicalColumn * 2;
|
||||
|
||||
if (FirstUnprintedPhysicalColumn > OS.getColumn())
|
||||
OS.PadToColumn(FirstUnprintedPhysicalColumn);
|
||||
|
||||
return FirstUnprintedLogicalColumn;
|
||||
}
|
||||
|
||||
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<size_t>(OldSize * 2, 1));
|
||||
return OldSize;
|
||||
}
|
||||
|
||||
public:
|
||||
LiveVariablePrinter(const MCRegisterInfo &MRI, const MCSubtargetInfo &STI)
|
||||
: LiveVariables(), ActiveCols(Column()), MRI(MRI), STI(STI) {}
|
||||
|
||||
void dump() const {
|
||||
for (const LiveVariable &LV : LiveVariables) {
|
||||
dbgs() << LV.VarName << " @ " << LV.LocExpr.Range << ": ";
|
||||
LV.print(dbgs(), MRI);
|
||||
dbgs() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void addCompileUnit(DWARFDie D) {
|
||||
if (D.getTag() == dwarf::DW_TAG_subprogram)
|
||||
addFunction(D);
|
||||
else
|
||||
for (const DWARFDie &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 IncludeDefinedVars is false, then live
|
||||
/// ranges starting at NextAddr will be ignored.
|
||||
void update(object::SectionedAddress ThisAddr,
|
||||
object::SectionedAddress NextAddr, bool IncludeDefinedVars) {
|
||||
// First, check variables which have already been assigned a column, so
|
||||
// that we don't change their order.
|
||||
SmallSet<unsigned, 8> CheckedVarIdxs;
|
||||
for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++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 = Column::NullVarIdx;
|
||||
}
|
||||
|
||||
// Next, look for variables which don't already have a column, but which
|
||||
// are now live.
|
||||
if (IncludeDefinedVars) {
|
||||
for (unsigned VarIdx = 0, End = LiveVariables.size(); VarIdx < End;
|
||||
++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 = VarIdx;
|
||||
ActiveCols[ColIdx].LiveIn = LiveIn;
|
||||
ActiveCols[ColIdx].LiveOut = LiveOut;
|
||||
ActiveCols[ColIdx].MustDrawLabel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class LineChar {
|
||||
RangeStart,
|
||||
RangeMid,
|
||||
RangeEnd,
|
||||
LabelVert,
|
||||
LabelCornerNew,
|
||||
LabelCornerActive,
|
||||
LabelHoriz,
|
||||
};
|
||||
const char *getLineChar(LineChar C) const {
|
||||
bool IsASCII = DbgVariables == DVASCII;
|
||||
switch (C) {
|
||||
case LineChar::RangeStart:
|
||||
return IsASCII ? "^" : u8"\u2548";
|
||||
case LineChar::RangeMid:
|
||||
return IsASCII ? "|" : u8"\u2503";
|
||||
case LineChar::RangeEnd:
|
||||
return IsASCII ? "v" : u8"\u253b";
|
||||
case LineChar::LabelVert:
|
||||
return IsASCII ? "|" : u8"\u2502";
|
||||
case LineChar::LabelCornerNew:
|
||||
return IsASCII ? "/" : u8"\u250c";
|
||||
case LineChar::LabelCornerActive:
|
||||
return IsASCII ? "|" : u8"\u2520";
|
||||
case LineChar::LabelHoriz:
|
||||
return IsASCII ? "-" : u8"\u2500";
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, End = ActiveCols.size();
|
||||
ColIdx < End; ++ColIdx) {
|
||||
if (ActiveCols[ColIdx].isActive()) {
|
||||
if ((AfterInst && ActiveCols[ColIdx].LiveOut) ||
|
||||
(!AfterInst && ActiveCols[ColIdx].LiveIn))
|
||||
OS << getLineChar(LineChar::RangeMid);
|
||||
else if (!AfterInst && ActiveCols[ColIdx].LiveOut)
|
||||
OS << getLineChar(LineChar::LabelVert);
|
||||
else
|
||||
OS << " ";
|
||||
}
|
||||
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, End = ActiveCols.size(); ColIdx < End; ++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()) {
|
||||
if (ActiveCols[ColIdx2].MustDrawLabel &&
|
||||
!ActiveCols[ColIdx2].LiveIn)
|
||||
OS << getLineChar(LineChar::LabelVert) << " ";
|
||||
else
|
||||
OS << getLineChar(LineChar::RangeMid) << " ";
|
||||
} 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 << getLineChar(ActiveCols[ColIdx].LiveIn
|
||||
? LineChar::LabelCornerActive
|
||||
: LineChar::LabelCornerNew)
|
||||
<< getLineChar(LineChar::LabelHoriz) << " ";
|
||||
WithColor(OS, raw_ostream::GREEN)
|
||||
<< LiveVariables[ActiveCols[ColIdx].VarIdx].VarName;
|
||||
OS << " = ";
|
||||
{
|
||||
WithColor ExprColor(OS, raw_ostream::CYAN);
|
||||
LiveVariables[ActiveCols[ColIdx].VarIdx].print(OS, MRI);
|
||||
}
|
||||
|
||||
// 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, End = ActiveCols.size();
|
||||
ColIdx2 < End; ++ColIdx2) {
|
||||
if (ActiveCols[ColIdx2].isActive() && ActiveCols[ColIdx2].LiveIn)
|
||||
OS << getLineChar(LineChar::RangeMid) << " ";
|
||||
else
|
||||
OS << " ";
|
||||
}
|
||||
|
||||
OS << "\n";
|
||||
PrintedSomething = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++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, End = ActiveCols.size();
|
||||
ColIdx < End; ++ColIdx) {
|
||||
if (!ActiveCols[ColIdx].isActive())
|
||||
OS << " ";
|
||||
else if (ActiveCols[ColIdx].LiveIn && ActiveCols[ColIdx].LiveOut)
|
||||
OS << getLineChar(LineChar::RangeMid) << " ";
|
||||
else if (ActiveCols[ColIdx].LiveOut)
|
||||
OS << getLineChar(LineChar::RangeStart) << " ";
|
||||
else if (ActiveCols[ColIdx].LiveIn)
|
||||
OS << getLineChar(LineChar::RangeEnd) << " ";
|
||||
else
|
||||
llvm_unreachable("var must be live in or out!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SourcePrinter {
|
||||
protected:
|
||||
DILineInfo OldLineInfo;
|
||||
|
@ -565,11 +942,12 @@ protected:
|
|||
private:
|
||||
bool cacheSource(const DILineInfo& LineInfoFile);
|
||||
|
||||
void printLines(raw_ostream &OS, const DILineInfo &LineInfo,
|
||||
StringRef Delimiter);
|
||||
void printLines(formatted_raw_ostream &OS, const DILineInfo &LineInfo,
|
||||
StringRef Delimiter, LiveVariablePrinter &LVP);
|
||||
|
||||
void printSources(raw_ostream &OS, const DILineInfo &LineInfo,
|
||||
StringRef ObjectFilename, StringRef Delimiter);
|
||||
void printSources(formatted_raw_ostream &OS, const DILineInfo &LineInfo,
|
||||
StringRef ObjectFilename, StringRef Delimiter,
|
||||
LiveVariablePrinter &LVP);
|
||||
|
||||
public:
|
||||
SourcePrinter() = default;
|
||||
|
@ -583,9 +961,10 @@ public:
|
|||
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 = "; ");
|
||||
};
|
||||
|
||||
|
@ -619,9 +998,10 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
|
|||
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;
|
||||
|
@ -646,14 +1026,15 @@ void SourcePrinter::printSourceLine(raw_ostream &OS,
|
|||
}
|
||||
|
||||
if (PrintLines)
|
||||
printLines(OS, LineInfo, Delimiter);
|
||||
printLines(OS, LineInfo, Delimiter, LVP);
|
||||
if (PrintSource)
|
||||
printSources(OS, LineInfo, ObjectFilename, Delimiter);
|
||||
printSources(OS, LineInfo, ObjectFilename, Delimiter, LVP);
|
||||
OldLineInfo = LineInfo;
|
||||
}
|
||||
|
||||
void SourcePrinter::printLines(raw_ostream &OS, const DILineInfo &LineInfo,
|
||||
StringRef Delimiter) {
|
||||
void SourcePrinter::printLines(formatted_raw_ostream &OS,
|
||||
const DILineInfo &LineInfo, StringRef Delimiter,
|
||||
LiveVariablePrinter &LVP) {
|
||||
bool PrintFunctionName = LineInfo.FunctionName != DILineInfo::BadString &&
|
||||
LineInfo.FunctionName != OldLineInfo.FunctionName;
|
||||
if (PrintFunctionName) {
|
||||
|
@ -666,13 +1047,16 @@ void SourcePrinter::printLines(raw_ostream &OS, const DILineInfo &LineInfo,
|
|||
}
|
||||
if (LineInfo.FileName != DILineInfo::BadString && LineInfo.Line != 0 &&
|
||||
(OldLineInfo.Line != LineInfo.Line ||
|
||||
OldLineInfo.FileName != LineInfo.FileName || PrintFunctionName))
|
||||
OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line << "\n";
|
||||
OldLineInfo.FileName != LineInfo.FileName || PrintFunctionName)) {
|
||||
OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line;
|
||||
LVP.printBetweenInsts(OS, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SourcePrinter::printSources(raw_ostream &OS, const DILineInfo &LineInfo,
|
||||
StringRef ObjectFilename,
|
||||
StringRef Delimiter) {
|
||||
void SourcePrinter::printSources(formatted_raw_ostream &OS,
|
||||
const DILineInfo &LineInfo,
|
||||
StringRef ObjectFilename, StringRef Delimiter,
|
||||
LiveVariablePrinter &LVP) {
|
||||
if (LineInfo.FileName == DILineInfo::BadString || LineInfo.Line == 0 ||
|
||||
(OldLineInfo.Line == LineInfo.Line &&
|
||||
OldLineInfo.FileName == LineInfo.FileName))
|
||||
|
@ -692,7 +1076,8 @@ void SourcePrinter::printSources(raw_ostream &OS, const DILineInfo &LineInfo,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,28 +1095,30 @@ static bool hasMappingSymbols(const ObjectFile *Obj) {
|
|||
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<uint8_t> Bytes,
|
||||
object::SectionedAddress Address, raw_ostream &OS,
|
||||
StringRef Annot, MCSubtargetInfo const &STI,
|
||||
SourcePrinter *SP, StringRef ObjectFilename,
|
||||
std::vector<RelocationRef> *Rels = nullptr) {
|
||||
virtual void
|
||||
printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
|
||||
object::SectionedAddress Address, formatted_raw_ostream &OS,
|
||||
StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
|
||||
StringRef ObjectFilename, std::vector<RelocationRef> *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)
|
||||
|
@ -741,11 +1128,9 @@ public:
|
|||
dumpBytes(Bytes, OS);
|
||||
}
|
||||
|
||||
// The output of printInst starts with a tab. Print some spaces so that the
|
||||
// tab has 1 column and advances to the target tab stop. Give more columns
|
||||
// to x86 which may encode an instruction with many bytes.
|
||||
unsigned TabStop =
|
||||
NoShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24;
|
||||
// The output of printInst starts with a tab. Print some spaces so that
|
||||
// the tab has 1 column and advances to the target tab stop.
|
||||
unsigned TabStop = getInstStartColumn(STI);
|
||||
unsigned Column = OS.tell() - Start;
|
||||
OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);
|
||||
|
||||
|
@ -766,7 +1151,7 @@ PrettyPrinter PrettyPrinterInst;
|
|||
class HexagonPrettyPrinter : public PrettyPrinter {
|
||||
public:
|
||||
void printLead(ArrayRef<uint8_t> 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)
|
||||
|
@ -778,12 +1163,12 @@ public:
|
|||
}
|
||||
}
|
||||
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> 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<RelocationRef> *Rels) override {
|
||||
StringRef ObjectFilename, std::vector<RelocationRef> *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 << " <unknown>";
|
||||
|
@ -809,7 +1194,7 @@ public:
|
|||
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;
|
||||
|
@ -820,7 +1205,7 @@ public:
|
|||
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 = " ";
|
||||
|
@ -848,12 +1233,12 @@ HexagonPrettyPrinter HexagonPrettyPrinterInst;
|
|||
class AMDGCNPrettyPrinter : public PrettyPrinter {
|
||||
public:
|
||||
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> 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<RelocationRef> *Rels) override {
|
||||
StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
|
||||
LiveVariablePrinter &LVP) override {
|
||||
if (SP && (PrintSource || PrintLines))
|
||||
SP->printSourceLine(OS, Address, ObjectFilename);
|
||||
SP->printSourceLine(OS, Address, ObjectFilename, LVP);
|
||||
|
||||
if (MI) {
|
||||
SmallString<40> InstStr;
|
||||
|
@ -900,12 +1285,12 @@ AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
|
|||
class BPFPrettyPrinter : public PrettyPrinter {
|
||||
public:
|
||||
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> 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<RelocationRef> *Rels) override {
|
||||
StringRef ObjectFilename, std::vector<RelocationRef> *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) {
|
||||
|
@ -1094,26 +1479,27 @@ static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols,
|
|||
static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index,
|
||||
uint64_t End, const ObjectFile *Obj,
|
||||
ArrayRef<uint8_t> Bytes,
|
||||
ArrayRef<MappingSymbolPair> MappingSymbols) {
|
||||
ArrayRef<MappingSymbolPair> MappingSymbols,
|
||||
raw_ostream &OS) {
|
||||
support::endianness Endian =
|
||||
Obj->isLittleEndian() ? support::little : support::big;
|
||||
outs() << format("%8" PRIx64 ":\t", SectionAddr + Index);
|
||||
OS << format("%8" PRIx64 ":\t", SectionAddr + Index);
|
||||
if (Index + 4 <= End) {
|
||||
dumpBytes(Bytes.slice(Index, 4), outs());
|
||||
outs() << "\t.word\t"
|
||||
dumpBytes(Bytes.slice(Index, 4), OS);
|
||||
OS << "\t.word\t"
|
||||
<< format_hex(support::endian::read32(Bytes.data() + Index, Endian),
|
||||
10);
|
||||
return 4;
|
||||
}
|
||||
if (Index + 2 <= End) {
|
||||
dumpBytes(Bytes.slice(Index, 2), outs());
|
||||
outs() << "\t\t.short\t"
|
||||
dumpBytes(Bytes.slice(Index, 2), OS);
|
||||
OS << "\t\t.short\t"
|
||||
<< format_hex(support::endian::read16(Bytes.data() + Index, Endian),
|
||||
6);
|
||||
return 2;
|
||||
}
|
||||
dumpBytes(Bytes.slice(Index, 1), outs());
|
||||
outs() << "\t\t.byte\t" << format_hex(Bytes[0], 4);
|
||||
dumpBytes(Bytes.slice(Index, 1), OS);
|
||||
OS << "\t\t.byte\t" << format_hex(Bytes[0], 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1288,6 +1674,17 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
stable_sort(SecSyms.second);
|
||||
stable_sort(AbsoluteSymbols);
|
||||
|
||||
std::unique_ptr<DWARFContext> DICtx;
|
||||
LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI);
|
||||
|
||||
if (DbgVariables != DVDisabled) {
|
||||
DICtx = DWARFContext::create(*Obj);
|
||||
for (const std::unique_ptr<DWARFUnit> &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()))
|
||||
|
@ -1481,6 +1878,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
Symbols[SI].Type != ELF::STT_OBJECT &&
|
||||
!DisassembleAll;
|
||||
bool DumpARMELFData = false;
|
||||
formatted_raw_ostream FOS(outs());
|
||||
while (Index < End) {
|
||||
// ARM and AArch64 ELF binaries can interleave data and text in the
|
||||
// same section. We rely on the markers introduced to understand what
|
||||
|
@ -1502,7 +1900,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
|
||||
if (DumpARMELFData) {
|
||||
Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
|
||||
MappingSymbols);
|
||||
MappingSymbols, FOS);
|
||||
} else {
|
||||
// When -z or --disassemble-zeroes are given we always dissasemble
|
||||
// them. Otherwise we might want to skip zero bytes we see.
|
||||
|
@ -1515,7 +1913,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
|
||||
if (size_t N =
|
||||
countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) {
|
||||
outs() << "\t\t..." << '\n';
|
||||
FOS << "\t\t..." << '\n';
|
||||
Index += N;
|
||||
continue;
|
||||
}
|
||||
|
@ -1530,11 +1928,14 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
if (Size == 0)
|
||||
Size = 1;
|
||||
|
||||
LVP.update({Index, Section.getIndex()},
|
||||
{Index + Size, Section.getIndex()}, Index + Size != End);
|
||||
|
||||
PIP.printInst(
|
||||
*IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
|
||||
{SectionAddr + Index + VMAAdjustment, Section.getIndex()}, outs(),
|
||||
"", *STI, &SP, Obj->getFileName(), &Rels);
|
||||
outs() << CommentStream.str();
|
||||
{SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS,
|
||||
"", *STI, &SP, Obj->getFileName(), &Rels, LVP);
|
||||
FOS << CommentStream.str();
|
||||
Comments.clear();
|
||||
|
||||
// If disassembly has failed, avoid analysing invalid/incomplete
|
||||
|
@ -1551,7 +1952,7 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
Inst, SectionAddr + Index, Size)) {
|
||||
Target = *MaybeTarget;
|
||||
PrintTarget = true;
|
||||
outs() << " # " << Twine::utohexstr(Target);
|
||||
FOS << " # " << Twine::utohexstr(Target);
|
||||
}
|
||||
if (PrintTarget) {
|
||||
// In a relocatable object, the target's section must reside in
|
||||
|
@ -1607,16 +2008,18 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
if (Demangle)
|
||||
TargetName = demangle(TargetName);
|
||||
|
||||
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) {
|
||||
|
@ -1646,8 +2049,9 @@ static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
|
|||
Offset += AdjustVMA;
|
||||
}
|
||||
|
||||
printRelocation(Obj->getFileName(), *RelCur, SectionAddr + Offset,
|
||||
Is64Bits);
|
||||
printRelocation(FOS, Obj->getFileName(), *RelCur,
|
||||
SectionAddr + Offset, Is64Bits);
|
||||
LVP.printAfterOtherLine(FOS, true);
|
||||
++RelCur;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue