如何在GDB加载CPython核心转储后访问进程上下文执行Python代码?
在CPython Core Dump上下文中执行Python代码的方法
首先得明确:GDB的python-interactive命令启动的是全新的Python解释器实例,完全和core dump里的进程上下文隔离,所以看不到原进程的模块、变量是正常的。要访问core里的上下文,得直接操作core中的CPython解释器状态,或者调用CPython的C API函数来执行代码。
方法一:通过GDB Python API直接访问解释器状态
GDB自带Python扩展,可以直接解析core中的CPython内部结构,不需要执行代码就能查看上下文:
- 获取主解释器状态:
py import gdb py interp = gdb.parse_and_eval("_PyRuntime.interpreters.main") - 获取当前执行帧(如果进程在Python代码处崩溃):
py frame = interp.frame # 打印帧的函数名和文件名 py print(frame.f_code.co_name.string(), frame.f_code.co_filename.string()) - 查看
sys.modules字典:py sys_mods = gdb.parse_and_eval("PyImport_GetModuleDict()") # 遍历所有模块名 py for key in sys_mods: py print(key.string())
方法二:调用CPython C API执行代码并获取上下文
如果需要执行自定义Python代码(比如打印变量、调用函数),可以通过GDB调用CPython的C API函数,直接在core的解释器上下文中执行:
前提条件
确保你用来加载core的Python二进制文件带有调试符号(编译时加--with-debug,或者安装对应发行版的调试包),否则会找不到CPython的内部函数符号。
步骤示例
- 切换到崩溃的线程(如果是多线程程序):
thread apply all bt # 查看所有线程的调用栈,找到Python线程 thread <线程编号> - 调用
PyRun_String执行代码并获取结果:# 执行"sys.modules"表达式,返回对应的PyObject*,存到$1 call PyRun_String("import sys; sys.modules", Py_eval_input, PyImport_GetModuleDict(), PyImport_GetModuleDict()) # 将PyObject转为可读的字符串表示,存到$2 call PyObject_Repr($1) # 将Unicode对象转为C字符串,存到$3 call PyUnicode_AsUTF8($2) # 打印结果 print $3 # 释放引用(避免不必要的内存占用,虽然core进程已终止) call Py_DECREF($1) call Py_DECREF($2) - 如果要执行多行代码,可以用
PyRun_SimpleString,但注意输出不会直接显示(因为core进程的stdout已经关闭),可以将结果写入文件:
之后在主机上查看call PyRun_SimpleString("import sys; f = open('/tmp/core_dump_output.txt', 'w'); f.write(str(sys.modules)); f.close()")/tmp/core_dump_output.txt即可。
注意事项
- 如果调用C API时出现
Cannot access memory at address XXX,可能是解释器状态不一致(比如进程崩溃时处于C扩展的代码中,Python线程状态未正确设置),可以尝试先设置线程状态:call _PyThreadState_SetCurrent(interp.tstate) # 这里的interp是之前获取的主解释器 - 对于Python 3.10+,解释器结构有变化,
_PyRuntime.interpreters.main是正确的;旧版本可能需要用PyInterpreterState_Head()来获取解释器链表。
内容的提问来源于stack exchange,提问作者styrofoam fly
相关产品推荐
相关产品推荐

