问题
How do I access variables local to a function using dtrace?
For example, in the following snippet I would like to know the value of variable x using dtrace.
void foo(int a){
int x=some_fun(a);
}
回答1:
Tracing local variables is impossible for kernel code because there is no mechanism to instrument arbitrary kernel instructions. Even in user-land, tracing local variables is somewhat convoluted and so, for the specific example you give, it would make a lot more sense to trace the return value of some_fun()
instead.
If you must trace an arbitrary local variable then you will need to determine its location (typically a register or a location in memory) at the specific point of interest. For simple cases you may be able to do this by disassembling the function and inspecting the output. For more complex cases it may be helpful to build the object with DWARF and then find the DW_AT_location
attribute of the local variable's DIE.
One you find the variable's location you'll need to express it in D; note that registers are exposed through the uregs[]
array. Furthermore, you'll need to describe your probe using the offset within the function since dtrace(1)
has no way of understanding line numbers. See the section on "User Process Tracing" in the Oracle Solaris Dynamic
Tracing Guide for more.
As an example, I wrote a trivial program containing
int
foo(int i)
{
int x;
...
for (x = 0; x < 10; x++)
i += 2;
and built it, as an amd64 executable, with DWARF...
cc -m64 -g -o demo demo.c
...before looking for foo()
and its definition of x
in the output
of dwarfdump demo
:
< 1><0x000000e4> DW_TAG_subprogram
DW_AT_name "foo"
...
DW_AT_frame_base DW_OP_reg6
< 2><0x00000121> DW_TAG_variable
DW_AT_name "x"
...
DW_AT_location DW_OP_fbreg -24
x
is described as DW_OP_fbreg -24
but DW_OP_fbreg
itself must be
substituted by the result of the parent function's DW_AT_frame_base
attribute, i.e. DW_OP_reg6
. DWARF uses its own architecture-agnostic
numbering for registers and the mapping to individual registers is up to
the appropriate standards body. In this case, the AMD64 ABI tells
us that DWARF register 6 corresponds to %rbp
. Thus x
is stored at
%rbp - 0x18
. (For more about DWARF itself I recommend Michael Eager's
Introduction to the DWARF Debugging Format.)
Thus, if you had found that the line of source in which you're interested is at offset 0x32 (perhaps by inspecting the DWARF line table) then you might write a probe like:
pid$target:a.out:foo:32
{
self->up = (uintptr_t)(uregs[R_RBP] - 0x18);
self->kp = (int *)copyin(self->up, sizeof (int));
printf("x = %d\n", *self->kp);
self->up = 0;
self->kp = 0;
}
This is what I see when I run the demo program:
# dtrace -q -s test.d -c /tmp/demo
x = 1
x = 2
x = 3
x = 4
x = 5
x = 6
x = 7
x = 8
x = 9
x = 10
#
来源:https://stackoverflow.com/questions/43066579/local-variables-in-dtrace