如何在调试cpython时逐步了解Python操作码?

问题描述 投票:2回答:1

我想了解Python解释器的功能。我了解操作码上的生成过程,并希望更好地了解解释器部分。为此,我在互联网上阅读了很多,并了解了python解释器(Cpython)中for (;;)文件中的ceval.c循环。

现在我想解释以下python代码a.py

a = 4
b = 5
c = a + b

当我做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

现在我将调试点放在switch(opcode)ceval.c行中。现在,当我启动调试器时,它到达该位置的时间超过2000次。我认为这是因为python在开始之前还必须做一些其他的解释工作。因此,我的问题是如何仅调试相关的操作码指令?

基本上,我怎么知道我正在调试的指令实际上来自我创建的程序?

请同样帮助我。预先感谢。

python c++ c gdb cpython
1个回答
0
投票

我做了很多CPython调试,以更好地了解其工作方式。通过编写C扩展模块解决了在Python源文件中设置gdb断点的可能性。

The ideaCPython是一个用C语言编写的大程序。我们可以像任何C程序一样轻松调试它-没问题。如果要在启动_PyType_Lookup功能时停止执行,则只需运行break _PyType_Lookup命令。因此,如果将自己的C函数添加到CPython程序中,例如cbreakpoint,则可以在每次调用cbreakpoint时停止执行。而且,如果我们找到将cbreakpoint函数插入source.py的方法,我们将获得所需的功能-每次解释器看到cbreakpoint时,它都会停止运行(如果我们在之前将break cbreakpoint设置为)。问题是:我们该怎么做?答案:“通过编写C扩展名”。

我如何做到的(我会错过一些事情,因为我是从记忆中复制出来的::

  1. CPython源下载到~/learning_python/cpython-master目录中。
  2. 本身创建了一个模块-my_breakpoint.c
  3. 创建设置文件-my_breakpoint_setup.py
  4. 运行~/learning_python/cpython-master/python my_breakpoint_setup.py build命令。它创建了一个my_breakpoint.cpython-38dm-x86_64-linux-gnu.so文件。
  5. 将上一步中的共享库文件复制到CPython's Lib目录:

    cp -iv my_breakpoint.cpython-38dm-x86_64-linux-gnu.so ~/learning_python/cpython-master/Lib/
    

    为了方便起见,需要复制,否则,我们应该在要使用(导入)此模块的任何目录中都有此.so文件。

  6. 现在,我们可以创建以下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,因为系统的python没有my_breakpoint模块:

    ~/learning_python/cpython-master/python source.py
    
  7. 要调试此文件,请执行以下操作:

    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时,gdbcbreakpoint函数的开始处停止,您需要执行许多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
    

    现在,您像第7步一样开始gdb并执行:

    (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])

P.S。

过去我问过同样的问题,对您可能有用:The optimal way to set a breakpoint in the Python source code while debugging CPython by GDB

© www.soinside.com 2019 - 2024. All rights reserved.