har*_*k24 5 c python gdb cpython
我想了解Python解释器的功能。我了解操作码的生成过程,并希望更好地理解解释器部分。为此,我在互联网上阅读了很多内容,并了解了python 解释器(Cpython)中的文件for (;;)
循环ceval.c
。
现在我想解释以下Python代码a.py
:
a = 4
b = 5
c = a + b
Run Code Online (Sandbox Code Playgroud)
当我做python -m dis a.py
1 0 LOAD_CONST 0 (4)
2 STORE_NAME 0 (a)
2 4 LOAD_CONST 1 (5)
6 STORE_NAME 1 (b)
3 8 LOAD_NAME 0 (a)
10 LOAD_NAME 1 (b)
12 BINARY_ADD
14 STORE_NAME 2 (c)
16 LOAD_CONST 2 (None)
18 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
现在我已将调试点switch(opcode)
放入ceval.c
. 现在,当我启动调试器时,它会出现这个位置 2000 多次。我认为这是因为在开始之前,Python 还必须做一些其他的解释工作。所以,我的问题是如何仅调试相关的操作码指令?
基本上,我如何知道我正在调试的指令实际上来自我创建的程序?
请帮我解决同样的问题。提前致谢。
我进行了大量的CPython调试,以便更好地理解它的工作方式。我通过编写C解决了无法在Python源文件中设置gdb断点的问题断点的问题。
\n\n想法:CPython是一个用C语言编写的大程序。我们可以像任何C程序一样轻松地调试它- 这里没有问题。如果我们想在_PyType_Lookup
函数启动时停止执行,我们只需运行一个break _PyType_Lookup
命令即可。因此,如果我们将自己的C函数添加到CPython程序中,例如cbreakpoint
,我们可以在每次cbreakpoint
调用时停止执行。cbreakpoint
如果我们找到将该函数插入到 中的方法source.py
,我们将获得所需的功能 - 每次解释器看到 时cbreakpoint
,它都会停止(如果我们break cbreakpoint
之前设置过)。我们可以通过编写C来做到这一点扩展来做到这一点”。
我是如何做到的(我可能会错过一些东西,因为我是从记忆中复制的):
\n\n~/learning_python/cpython-master
目录中并编译它。有一些错综复杂的问题 -无法摆脱 \xe2\x80\x9c 值已在 GDB 中优化出 \xe2\x80\x9d。my_breakpoint.c
.my_breakpoint_setup.py
.运行一个
\n\n~/learning_python/cpython-master/python my_breakpoint_setup.py build\n
Run Code Online (Sandbox Code Playgroud)\n\n命令。它创建了一个my_breakpoint.cpython-38dm-x86_64-linux-gnu.so
文件。
将上一步中的共享对象文件复制到CPython中 Lib
目录中:
cp -iv my_breakpoint.cpython-38dm-x86_64-linux-gnu.so ~/learning_python/cpython-master/Lib/\n
Run Code Online (Sandbox Code Playgroud)\n\n为了方便起见,需要进行复制,否则我们应该将此.so
文件放在我们想要使用(导入)此模块的任何目录中。
现在,我们可以做如下source.py
:
#!/usr/bin/python3\n\nfrom my_breakpoint import cbreakpoint\n\ncbreakpoint(1)\na = 4\n\ncbreakpoint(2)\nb = 5\n\ncbreakpoint(3)\nc = a + b\n
Run Code Online (Sandbox Code Playgroud)\n\n要执行这个文件,我们必须使用我们的~/learning_python/cpython-master
解释器,而不是系统的解释器python3
,因为系统的 python 没有my_breakpoint
模块:
~/learning_python/cpython-master/python source.py\n
Run Code Online (Sandbox Code Playgroud)要调试此文件,请执行以下操作:
\n\ngdb --args ~/learning_python/cpython-master/python -B source.py\n
Run Code Online (Sandbox Code Playgroud)\n\n然后,里面gdb
:
(gdb) start\n\n(gdb) break cbreakpoint\nFunction "cbreakpoint" not defined.\nMake breakpoint pending on future shared library load? (y or [n]) y\nBreakpoint 2 (cbreakpoint) pending.\n\n(gdb) cont\n
Run Code Online (Sandbox Code Playgroud)\n\n有一个问题。当您按下, 时cont
,gdb
会停止在函数的开头cbreakpoint
,并且您需要执行许多next
命令来跳过此函数以及CPython函数调用代码以实现所需的 Python 代码执行的开始。或者你可以在之后设置一个新的断点cbreakpoint
或者你可以在被击中
(gdb) break ceval.c:1080 ### The LOAD_CONST case beginning\n(gdb) cont\n
Run Code Online (Sandbox Code Playgroud)\n\n但是,在多次执行此操作后,我将这些操作自动化,因此您只需将这些行添加到~/.gdbinit中即可中即可:
\n\nset breakpoint pending on\nbreak cbreakpoint\n command $bpnum\n tbreak ceval.c:1098\n command $bpnum\n n\n end\n cont\n end\nset breakpoint pending off\n
Run Code Online (Sandbox Code Playgroud)\n\n现在,您只需像第 7 步中那样启动gdb并执行以下操作:
\n\n(gdb) start\n(gdb) cont\n
Run Code Online (Sandbox Code Playgroud)\n\n然后您将跳转到代码执行的开头source.py
。
my_breakpoint.c
\n\n#include <Python.h>\n\nstatic PyObject* cbreakpoint(PyObject *self, PyObject *args){\n int breakpoint_id;\n\n if(!PyArg_ParseTuple(args, "i", &breakpoint_id))\n return NULL;\n\n return Py_BuildValue("i", breakpoint_id);\n}\n\nstatic PyMethodDef my_methods[] = { \n {"cbreakpoint", cbreakpoint, METH_VARARGS, "breakpoint function"}, \n {NULL, NULL, 0, NULL}\n};\n\nstatic struct PyModuleDef my_breakpoint = { \n PyModuleDef_HEAD_INIT, \n "my_breakpoint",\n "the module for setting C breakpoint in the Python source",\n -1, \n my_methods\n};\n\nPyMODINIT_FUNC PyInit_my_breakpoint(void){\n return PyModule_Create(&my_breakpoint);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\nmy_breakpoint_setup.py
\n\nfrom distutils.core import setup, Extension\n\nmodule = Extension(\'my_breakpoint\', sources = [\'my_breakpoint.c\'])\n\nsetup (name = \'PackageName\',\n version = \'1.0\',\n description = \'This is a package for my_breakpoint module\',\n ext_modules = [module])\n
Run Code Online (Sandbox Code Playgroud)\n\n我过去问过同样的问题,它对你可能有用:The best way to set a Breakpoint in the Python source code while debug CPython by GDB。
\n