C++ 我是否使用仪器例程(pin)得到了错误的ebp,或者我在这里遗漏了什么?

C++ 我是否使用仪器例程(pin)得到了错误的ebp,或者我在这里遗漏了什么?,c++,debugging,elf,instrumentation,dwarf,C++,Debugging,Elf,Instrumentation,Dwarf,这就是交易。我正在使用pin工具和我所附加到的进程中的dwarf信息处理调试器。Pin是一个框架,允许您为已经运行的进程创建检测工具,我附加到该进程,然后从中解析DWARF信息 显然,pin让我在连接到程序的精确时刻获取寄存器。我能够获得ebp、esp和eip。但是堆栈中的信息与DWARF信息中的信息不匹配 例如: Pin告诉我ebp是:bfe0abe8我假设这是寄存器的实际地址,而不是寄存器中的值 如果我进入堆栈,我有以下内容: bfe0abb5 -> 00000020 \\this

这就是交易。我正在使用pin工具和我所附加到的进程中的dwarf信息处理调试器。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
<962>DW\u TAG\u子程序
DW_在_外部是(1)
DW_AT_name add
德克卢36号线的德瓦卢
DW_AT_原型是(1)
DW_在_低_pc 0x8048513
DW_在_高_pc 0x804855f
框架底部的DW_
[0]DW_OP_breg4+4
[1]DW_OP_breg4+8
[2]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
<1029>DW_标记_变量
DW_AT_name tib
德克卢线38处的德瓦卢
DW_AT_类型
DW_位置DW_OP_fbreg-24
<1043>DW_标记_变量
DW_AT_name jos
德克卢第39线的德瓦卢
DW_AT_类型
DW_位置DW_OP_fbreg-28
我知道根据DWARF(和这个:),这个函数中的ebp应该是当前的ebp+8(因为我正在使用DWORD,所以应该是+2)。然后我将-24减去8,使之成为ebp-16(实际上是ebp-4)。从理论上讲,这应该是可行的,但当我进入堆栈时,我遇到了很多问题:

  • 我甚至没有在堆栈顶部附近看到pin返回给我的当前ebp的地址
  • 假设
    bfe0abb9
    是当前ebp,并且该引脚实际上返回寄存器的值,而不是地址,如果我从寄存器中减去4,我将不会得到tib的值,因为根据我对堆栈的理解,我将向上而不是向下。即使我在试图得到jos时会倒下(
    ebp-28+8=ebp-20=ebp-5
    ),我也肯定不会得到jos,而是
    000000a
我是不是遗漏了什么?我是否对堆栈和/或寄存器或DWARF信息有错误的理解?还是别针把我搞砸了,给了我错误的信息


有什么建议吗?

我将忽略堆栈转储,因为我不确定您想在那里显示什么

您引用的侏儒函数表示,函数的帧基最初是
$esp+4
,然后变为
$esp+8
,然后变为
$ebp+8
。这是打开大多数i386函数的标准“
push$ebp;mov$esp,$ebp
”指令序列。在函数输入上,帧基是
esp
加4的值。在堆栈上保存调用方的
ebp
寄存器后,帧基现在是
esp
加8,因为
esp
由于
推送而发生了变化。最后,
esp
中的值被复制到
ebp
中,该值在函数的其余部分将保持不变(而
esp
通常会进一步调整)

您在这里看到的“帧基”在debug_frame部分中也被称为规范帧地址或CFA。CFA是堆栈上的一个地址,在函数的整个期间都是相同的。在i386上,CFA地址是调用方在执行调用您正在查看的函数的
call
指令之前的
esp

侏儒说变量
tib
位于帧底-24处。函数的帧基是
ebp+8
,因此是的,
ebp
寄存器的值减去16是堆栈上的地址。变量存储在该地址


我经常发现,如果DWARF不清楚,那么阅读函数的实际汇编代码会很有帮助,前提是您对汇编语言有合理的理解。您还可以单步执行程序,在执行过程中检查寄存器和堆栈地址。少量的实际代码实验几乎总能回答任何问题。

这很奇怪,因为它不像堆栈寻址,
bfe0abb5
bfe0abb6
bfe0abb7
bfe0abb8
bfe0abbf9
bfe0abba
,…

在32位机器中,它应该是4字节对齐的。根据您提供的堆栈地址,即使您提供了正确的DWARF信息,我也无法计算实际地址。

我认为您遗漏了什么(或者我完全误解了您)。寄存器没有地址——它们包含值(可能是地址)。每个地址实际上只涉及一个字节——当我们谈到地址X处的32位字时,实际上是指X、X+1、X+2和X+3处的字节组合成一个字。因此,您对上面堆栈的转储毫无意义……但我的理解是,每个寄存器在
bf…
空间中也有一个地址,通过对该地址的解引用,我将得到寄存器@ChrisDoddHey内的实际值