Local Variables in Dtrace

感情迁移 提交于 2019-12-11 03:39:21

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!