问题描述
如何使用dtrace访问函数局部变量?
How do I access variables local to a function using dtrace?
例如,在以下代码段中,我想使用dtrace知道变量x的值.
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);
}
推荐答案
对于内核代码来说,跟踪局部变量是不可能的,因为没有机制可以检测任意内核指令.甚至在用户领域,跟踪局部变量也有些复杂,因此,对于您给出的特定示例,改为跟踪some_fun()
的返回值会更有意义.
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.
如果必须跟踪任意局部变量,则需要确定其在特定兴趣点的位置(通常是寄存器或内存中的位置).对于简单的情况,您可以通过反汇编功能并检查输出来执行此操作.对于更复杂的情况,使用DWARF构建对象,然后找到局部变量的DIE的DW_AT_location
属性可能会有所帮助.
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.
您会发现需要用D表示变量的位置;请注意,寄存器通过uregs[]
数组公开.此外,由于dtrace(1)
无法理解行号,因此您需要使用函数内的偏移量来描述探针.请参见 Oracle Solaris Dynamic跟踪指南以获取更多信息.
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 DynamicTracing 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;
并使用DWARF将其构建为amd64可执行文件...
and built it, as an amd64 executable, with DWARF...
cc -m64 -g -o demo demo.c
...在输出中查找foo()
及其定义x
之前的dwarfdump demo
:
...before looking for foo()
and its definition of x
in the outputof 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
被描述为DW_OP_fbreg -24
,但DW_OP_fbreg
本身必须是由父函数的DW_AT_frame_base
的结果替换属性,即DW_OP_reg6
. DWARF使用自己的架构不可知寄存器编号以及到单个寄存器的映射最多适当的标准机构.在这种情况下, AMD64 ABI 告诉我们知道DWARF寄存器6对应于%rbp
.因此x
存储在%rbp - 0x18
. (有关DWARF本身的更多信息,我推荐Michael Eager的DWARF调试格式简介.)
x
is described as DW_OP_fbreg -24
but DW_OP_fbreg
itself must besubstituted by the result of the parent function's DW_AT_frame_base
attribute, i.e. DW_OP_reg6
. DWARF uses its own architecture-agnosticnumbering for registers and the mapping to individual registers is up tothe appropriate standards body. In this case, the AMD64 ABI tellsus that DWARF register 6 corresponds to %rbp
. Thus x
is stored at%rbp - 0x18
. (For more about DWARF itself I recommend Michael Eager'sIntroduction to the DWARF Debugging Format.)
因此,如果您发现您所在的源代码行感兴趣的是偏移量0x32(也许通过检查DWARF行表),那么您可以编写类似以下内容的探针:
Thus, if you had found that the line of source in which you'reinterested is at offset 0x32 (perhaps by inspecting the DWARFline 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
#
这篇关于Dtrace中的局部变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!