所以这是交易。我正在使用pin工具调试一个调试器,以及我附加的进程中的矮信息。 Pin是一个框架,允许您为已经运行的进程创建检测工具,我附加到进程,然后从中解析DWARF信息。
很明显,pin让我在我附加到程序的精确时刻抓住寄存器。我可以获得ebp
,esp
和eip
。但是堆栈中的信息与DWARF信息中的信息不匹配。
例如:
Pin告诉我ebp
是:bfe0abe8
我假设这是寄存器的实际地址,而不是它内部的值。
如果我去堆栈,我有这个:
bfe0abb5 -> 00000020 \\this is esp
bfe0abb6 -> 0804855d
bfe0abb7 -> 08048720
bfe0abb8 -> 0000000a
bfe0abb9 -> bfe0abe8 \\this is what I think is ebp, but according to pin is not
bfe0abba -> 0015711f
bfe0abbb -> bfe0ac28
bfe0abbc -> 4236b852 \\this is a local float variable named jos
bfe0abbd -> 42c0947b \\this is a local float variable named tib
bfe0abbe -> 0000000a
bfe0abbf -> 08048724
bfe0abc0 -> bfe0abf8
bfe0abc1 -> bfe0ac28
bfe0abc2 -> 08048612
bfe0abc3 -> 00000000
bfe0abc4 -> 0000000a
bfe0abc5 -> 00006680
bfe0abc6 -> 08048689
bfe0abc7 -> 00266324
bfe0abc8 -> 00265ff4
bfe0abc9 -> 936498a8
bfe0abca -> 4072464d
bfe0abcb -> 0013f4a5
bfe0abcc -> 424ab852 \\this is another local variable
bfe0abcd -> 42bc947b \\this is another local variable
bfe0abce -> 0000000a
bfe0abcf -> 08048670
bfe0abd0 -> 00000000
bfe0abd1 -> bfe0aca8
还有更多,我不知道实际上堆栈的底部是什么,所以我只是展示了它。
如果我转到DWARF信息,这是堆栈顶部当前所在的函数,以及应该指向哪个ebp:
<1>< 962> DW_TAG_subprogram
DW_AT_external yes(1)
DW_AT_name add
DW_AT_decl_line 36
DW_AT_prototyped yes(1)
DW_AT_low_pc 0x8048513
DW_AT_high_pc 0x804855f
DW_AT_frame_base <loclist with 3 entries follows>
[ 0]<lowpc=0x2f><highpc=0x30>DW_OP_breg4+4
[ 1]<lowpc=0x30><highpc=0x32>DW_OP_breg4+8
[ 2]<lowpc=0x32><highpc=0x7b>DW_OP_breg5+8
我知道这是因为我在堆栈上看到的局部变量都在这个函数中。这些局部变量是:
<2>< 1029> DW_TAG_variable
DW_AT_name tib
DW_AT_decl_line 38
DW_AT_type <837>
DW_AT_location DW_OP_fbreg -24
<2>< 1043> DW_TAG_variable
DW_AT_name jos
DW_AT_decl_line 39
DW_AT_type <837>
DW_AT_location DW_OP_fbreg -28
我知道根据DWARF(和这个:How to see variables stored on the stack with GDB),此函数中的ebp应该是当前的ebp + 8(因为我使用DWORD应该是+2)。然后我应该减去-24到8,使它成为ebp-16(实际上是ebp-4)。在纸上这应该有用,但是当我进入堆栈时,我遇到了很多问题:
bfe0abb9
是当前的ebp,并且该引脚实际上返回寄存器的值而不是地址,如果我从该寄存器中减去4,则不会得到tib的值,因为as我对堆栈的理解,我会不会下降。即使我试图获得jos(ebp-28+8 = ebp -20 = ebp -5
)时我会失败,但我绝对不会得到jos而是000000a
。我在这里遗漏了什么吗?我对堆栈和/或寄存器或DWARF信息有错误的理解吗?或者是Pin搞砸了我并提供了错误的信息?
有什么建议吗?
答案 0 :(得分:1)
我会忽略堆栈转储,因为我不确定你要在那里展示什么。
您引用的DWARF表示该函数的框架基础最初为$esp + 4
,然后更改为$esp + 8
,然后更改为$ebp + 8
。这是打开大多数i386功能的标准“push $ebp; mov $esp, $ebp
”指令序列。在函数入口处,帧基是esp
加上4的值。一旦我们在堆栈上保存了调用者的ebp
寄存器,帧基现为esp
加8,因为{{ 1}}由于esp
而发生了变化。最后,push
中的值被复制到esp
中,并且该值的其余部分将保持不变(通常会进一步调整ebp
。)
您在此处看到的内容 - “frame base” - 在debug_frame部分中也称为Canonical Frame Address或CFA。 CFA是堆栈上的地址,在整个功能期间是相同的。在i386上,CFA地址是调用者的esp
值,然后执行esp
指令来调用您正在查看的函数。
DWARF表示变量call
位于帧基-24处。您的函数的框架基础是tib
所以是的,ebp + 8
寄存器的值减去16是堆栈上的地址。变量存储在该地址。
如果DWARF不清楚,假设您对汇编语言有一个合理的理解,我经常发现阅读函数的实际汇编代码很有帮助。您还可以单步执行程序,检查寄存器和堆栈地址。对真实代码进行少量动手实验几乎总能回答任何问题。
答案 1 :(得分:0)
这很奇怪,因为它不像堆栈寻址,bfe0abb5
,bfe0abb6
,bfe0abb7
,bfe0abb8
,bfe0abb9
,bfe0abba
,....
它应该在32位机器中以4字节对齐。根据您提供的堆栈地址,即使您提供了正确的DWARF信息,我也无法计算实际地址。