Я много отлаживаю CPython , чтобы лучше понять, как это работает. Отсутствие возможности установить точку останова gdb в исходных файлах Python Я решил, написав модуль расширения C .
Идея : CPython - большая программа, написанная на языке C . Мы можем легко отладить его как любую C программу - здесь никаких проблем. Если мы хотим остановить выполнение при запуске функции _PyType_Lookup
, мы просто запускаем команду break _PyType_Lookup
. Таким образом, если мы добавим нашу собственную функцию C в программу CPython , например cbreakpoint
, мы можем остановить выполнение при каждом вызове cbreakpoint
. И если мы найдем способ вставить эту cbreakpoint
функцию в source.py
, мы получим требуемую функциональность - каждый раз, когда интерпретатор увидит cbreakpoint
, она будет остановлена (если мы установим break cbreakpoint
до того, как). Мы можем сделать это, написав расширение C .
Как я это сделал (я могу что-то упустить, потому что я воспроизводлю по памяти):
- Загрузил исходный код CPython в каталог
~/learning_python/cpython-master
и скомпилировал его. Были некоторые сложности - Не удалось избавиться от «значения были оптимизированы» в GDB . - Создание самого модуля -
my_breakpoint.c
. - Создание файла установки -
my_breakpoint_setup.py
. Выполнение команды
~/learning_python/cpython-master/python my_breakpoint_setup.py build
. создал файл my_breakpoint.cpython-38dm-x86_64-linux-gnu.so
.
Скопировал файл общего объекта из предыдущего шага в CPython's Lib
каталог:
cp -iv my_breakpoint.cpython-38dm-x86_64-linux-gnu.so ~/learning_python/cpython-master/Lib/
копирование необходимо для удобства, в противном случае мы должны иметь этот файл .so
в любом каталоге, в котором мы хотим использовать (импортировать) этот модуль.
Теперь мы можем сделать следующее source.py
:
#!/usr/bin/python3
from my_breakpoint import cbreakpoint
cbreakpoint(1)
a = 4
cbreakpoint(2)
b = 5
cbreakpoint(3)
c = a + b
Чтобы выполнить этот файл, мы должны использовать наш интерпретатор ~/learning_python/cpython-master
, а не системный python3
, потому что системный питон не имеет модуля my_breakpoint
le:
~/learning_python/cpython-master/python source.py
Для отладки этого файла выполните:
gdb --args ~/learning_python/cpython-master/python -B source.py
Затем внутри gdb
:
(gdb) start
(gdb) break cbreakpoint
Function "cbreakpoint" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (cbreakpoint) pending.
(gdb) cont
Естьодна проблема. Когда вы нажимаете cont
, gdb
останавливается в начале функции cbreakpoint
, и вам нужно выполнить много команд next
, чтобы пропустить эту функцию, и код CPython , вызывающий функцию длядобиться начала желаемого выполнения кода Python. Или вы можете установить новую точку останова после нажатия cbreakpoint
, например:
(gdb) break ceval.c:1080 ### The LOAD_CONST case beginning
(gdb) cont
Но, после этого я автоматизировал эти действия, так что вы можете просто добавить эти строки в ~ / .gdbinit :
set breakpoint pending on
break cbreakpoint
command $bpnum
tbreak ceval.c:1098
command $bpnum
n
end
cont
end
set breakpoint pending off
Теперь вы просто запускаете gdb , как в 7 шаге, и делаете:
(gdb) start
(gdb) cont
и вы прыгаетек началу выполнения кода source.py
.
my_breakpoint.c
#include <Python.h>
static PyObject* cbreakpoint(PyObject *self, PyObject *args){
int breakpoint_id;
if(!PyArg_ParseTuple(args, "i", &breakpoint_id))
return NULL;
return Py_BuildValue("i", breakpoint_id);
}
static PyMethodDef my_methods[] = {
{"cbreakpoint", cbreakpoint, METH_VARARGS, "breakpoint function"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef my_breakpoint = {
PyModuleDef_HEAD_INIT,
"my_breakpoint",
"the module for setting C breakpoint in the Python source",
-1,
my_methods
};
PyMODINIT_FUNC PyInit_my_breakpoint(void){
return PyModule_Create(&my_breakpoint);
}
my_breakpoint_setup.py
from distutils.core import setup, Extension
module = Extension('my_breakpoint', sources = ['my_breakpoint.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a package for my_breakpoint module',
ext_modules = [module])
PS
В прошлом я задавал один и тот же вопрос, он может быть полезен для вас: Оптимальный способ установки точки останова в исходном коде Python при отладке CPythonпо ГБД .