Dwarf DW_AT_location objdump 和 dwarfdump 不一致

Mei*_*eir 3 gdb reverse-engineering

我在玩 CPython 并试图了解调试器的工作原理。具体来说,我正在尝试获取最后一个的位置PyFrameObject以便我可以遍历它并获得 Python 回溯。

在文件中ceval.c,第 689 行有函数的定义:

PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)

我感兴趣的是f堆栈上的位置。当我转储二进制文件时,dwarfdump我得到的f$rbp-824,但如果我转储二进制文件,objdump我得到的位置是$rbp-808- 16 的差异。此外,当使用 GDB 调试时,我得到正确的答案$rbp-808就像objdump给了我。为什么有差异,为什么dwarfdump不正确?我不明白什么?

如何在技术上重现问题:python-2.7.17.tgz从 Python 网站下载。提炼。

我使用调试符号 ( ./configure --enable-pydebug && make)从源代码编译了 python-2.7.17 。在生成的python二进制文件上运行以下命令:

dwarfdump Python-2.7.17/python 有以下输出:

                        DW_AT_name                  f           
                        DW_AT_decl_file             0x00000001 /home/meir/code/python/Python-2.7.17/Python/ceval.c
                        DW_AT_decl_line             0x000002b1                         
                        DW_AT_type                  <0x00002916>
                        DW_AT_location              len 0x0003: 91c879: DW_OP_fbreg -824
Run Code Online (Sandbox Code Playgroud)

我知道这是正确的,f因为声明变量的行是689 (0x2b1). 如您所见,位置是:

DW_AT_location len 0x0003: 91c879: DW_OP_fbreg -824: 意思$rbp-824

运行命令objdump -S Python-2.7.17/python有以下输出:

PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{
   f7577:       55                      push   %rbp
   f7578:       48 89 e5                mov    %rsp,%rbp
   f757b:       41 57                   push   %r15
   f757d:       41 56                   push   %r14
   f757f:       41 55                   push   %r13
   f7581:       41 54                   push   %r12
   f7583:       53                      push   %rbx
   f7584:       48 81 ec 38 03 00 00    sub    $0x338,%rsp
   f758b:       48 89 bd d8 fc ff ff    mov    %rdi,-0x328(%rbp)
   f7592:       89 b5 d4 fc ff ff       mov    %esi,-0x32c(%rbp)
   f7598:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
   f759f:       00 00 
   f75a1:       48 89 45 c8             mov    %rax,-0x38(%rbp)
   f75a5:       31 c0                   xor    %eax,%eax
Run Code Online (Sandbox Code Playgroud)

调试此输出将向您显示相关行是: f758b: 48 89 bd d8 fc ff ff mov %rdi,-0x328(%rbp)where 您可以清楚地看到f正在加载的是-0x328(%rbp)which is $rbp-808。此外,GDB 支持这一发现。

所以,问题是,我错过了什么,为什么 16 字节dwarfdump与现实之间存在差异?

谢谢

编辑:dwarfdump包括上面的功能是:

< 1><0x00004519>    DW_TAG_subprogram
                      DW_AT_external              yes(1)
                      DW_AT_name                  PyEval_EvalFrameEx
                      DW_AT_decl_file             0x00000001 /home/meir/code/python/Python-2.7.17/Python/ceval.c
                      DW_AT_decl_line             0x000002b1
                      DW_AT_prototyped            yes(1)
                      DW_AT_type                  <0x00000817>
                      DW_AT_low_pc                0x000f7577
                      DW_AT_high_pc               <offset-from-lowpc>53969
                      DW_AT_frame_base            len 0x0001: 9c: DW_OP_call_frame_cfa
                      DW_AT_GNU_all_tail_call_sites yes(1)
                      DW_AT_sibling               <0x00005bbe>
< 2><0x0000453b>      DW_TAG_formal_parameter
                        DW_AT_name                  f
                        DW_AT_decl_file             0x00000001 /home/meir/code/python/Python-2.7.17/Python/ceval.c
                        DW_AT_decl_line             0x000002b1
                        DW_AT_type                  <0x00002916>
                        DW_AT_location              len 0x0003: 91c879: DW_OP_fbreg -824
Run Code Online (Sandbox Code Playgroud)

根据下面的答案,DW_OP_fbreg从框架基础偏移 - 在我的情况下DW_OP_call_frame_cfa。我在识别框架底座时遇到问题。我的寄存器如下:

(gdb) info registers
rax            0xfffffffffffffdfe       -514
rbx            0x7f6a4887d040   140094460121152
rcx            0x7f6a48e83ff7   140094466441207
rdx            0x0      0
rsi            0x0      0
rdi            0x0      0
rbp            0x7ffd24bcef00   0x7ffd24bcef00
rsp            0x7ffd24bceba0   0x7ffd24bceba0
r8             0x7ffd24bcea50   140725219813968
r9             0x0      0
r10            0x0      0
r11            0x246    582
r12            0x7f6a48870df0   140094460071408
r13            0x7f6a48874b58   140094460087128
r14            0x1      1
r15            0x7f6a48873794   140094460082068
rip            0x5559834e99c0   0x5559834e99c0 <PyEval_EvalFrameEx+46153>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
Run Code Online (Sandbox Code Playgroud)

如上所述,我已经知道这是%rbp-808有效的。使用我拥有的寄存器进行操作的正确方法是什么?

编辑:我终于明白了答案。我需要再展开一个函数,并找到我的函数被调用的地方。在那里,我正在寻找的变量确实存在$rsp并且$rsp-824是正确的

Emp*_*ian 5

DW_OP_fbreg -824: 意义 $rbp-824

不是那个意思。这意味着,-824帧基(虚拟)寄存器的偏移量,不一定(也不通常)等于$rbp.

您需要查找DW_AT_frame_base以了解当前函数中的框架基础是什么。

很可能它被定义为DW_OP_call_frame_cfa,这是调用当前函数$RSP 之前的值,并且等于$RBP-16CALL指令保存的返回地址为 8 个字节,$RBP函数的第一条指令保存的返回地址为 8 个字节)。