Я играю с CPython и пытаюсь понять, как работает отладчик. В частности, я пытаюсь получить местоположение последнего PyFrameObject
, чтобы я мог пройти его и получить Python обратную трассировку.
В файле ceval.c
строка 689 содержит определение функции. :
PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
Меня интересует расположение f
в стеке. При выгрузке двоичного файла с помощью dwarfdump
я получаю, что f
находится на $rbp-824
, но если я выгружаю двоичный файл с помощью objdump
, я получаю, что местоположение равно $rbp-808
- несоответствие 16. Кроме того, при отладке с ГБД, я понимаю, что правильный ответ $rbp-808
, как objdump
дает мне. Почему расхождение и почему dwarfdump
неверно? Что я не понимаю?
Как технически воссоздать проблему: Загрузите python-2.7.17.tgz
с Python веб-сайта. Извлечение.
Я скомпилировал python -2.7.17 из источника с символами отладки (./configure --enable-pydebug && make
). Выполните следующие команды в результирующем двоичном файле 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
Я знаю, что это правильный 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
Отладка этот вывод покажет вам, что соответствующая строка: f758b: 48 89 bd d8 fc ff ff mov %rdi,-0x328(%rbp)
, где вы можете ясно видеть, что f
загружается из -0x328(%rbp)
, что составляет $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
В соответствии с ответом ниже, 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
Как указано выше, я уже знаю, что %rbp-808
работает. Как правильно сделать это с моими регистрами?
Редактировать: Я наконец понял ответ. Мне нужно было развернуть еще одну функцию и найти место, где была вызвана моя функция. Там переменная, которую я искал, действительно была в $rsp
и $rsp-824
была правильной