Skip to content

Commit

Permalink
[llvm-objdump] Display locations of variables alongside disassembly
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ostannard committed Jul 9, 2020
1 parent 1c7c501 commit dc4a6f5
Show file tree
Hide file tree
Showing 12 changed files with 2,772 additions and 66 deletions.
11 changes: 11 additions & 0 deletions llvm/docs/CommandGuide/llvm-objdump.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ class DWARFExpression {
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:
Expand Down
70 changes: 70 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 10 additions & 0 deletions llvm/test/tools/llvm-objdump/ARM/Inputs/debug.c
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions llvm/test/tools/llvm-objdump/ARM/Inputs/wide-char.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int foo(int *) {
return *;
}
Loading

0 comments on commit dc4a6f5

Please sign in to comment.