runsisi's

technical notes

使用 gdb 调试 Python 解释器

2019-08-30 runsisi#python#debug#gdb

直接使用 gdb 调试 Python 解释器 (CPython) 是一件很痛苦的事情,因为里面的变量类型基本上全部是 Python 封装的结构体,很少能看到原生的 C 内置类型,不过自从 gdb 7+ 增加了 Python 扩展支持之后,一切就都变得很简单了。

对比下面两个输出显然可以看出来区别:

Breakpoint 1, import_name (f=f@entry=0x5555557e0f18, name=name@entry=0x5555558001a0, fromlist=fromlist@entry=0x7ffff7d5aba0 <_Py_NoneStruct>, 
    level=level@entry=0x7ffff7da4ab0 <small_ints+240>) at Python/ceval.c:5228
5228    {
(gdb) p name
$1 = (PyObject *) 0x5555558001a0
Breakpoint 1, import_name (
    f=f@entry=Frame 0x5555557e0f18, for file <frozen importlib._bootstrap>, line 1159, in _install (sys_module=<module at remote 0x5555557cca38>, _imp_module=<module at remote 0x5555557df1b8>), name=name@entry='_frozen_importlib_external', fromlist=fromlist@entry=None, level=level@entry=0) at Python/ceval.c:5228
5228    {
(gdb) p name
$1 = '_frozen_importlib_external'

首先下载 Python 解释器调试支持脚本

然后让 gdb 加载该脚本,这里有两种方式:

一是临时加载:

(gdb) show cwd
You have not set the inferior's current working directory.
The inferior will inherit GDB's cwd if native debugging, or the remote
server's cwd if remote debugging.
(gdb) pwd
Working directory /home/runsisi/working/test/pyleak/build.
(gdb) set cwd /home/runsisi/working/test/pyleak/build
(gdb) cd ~/working/test/Python-3.7.4/Tools/gdb
Working directory /home/runsisi/working/test/Python-3.7.4/Tools/gdb.
(gdb) source libpython.py

二是放到 gdb 的启动脚本中(请忽略第一行,那是用于控制加载 .gdbinit 的配置,与当前需求无关):

$ cat ~/.gdbinit 
set auto-load safe-path /

python
def setup_python_gdb(event):
    import os
    import sys
    sys.path.insert(0, os.path.expanduser("~/working/test/Python-3.7.4/Tools/gdb"))
    import libpython

import gdb
gdb.events.new_objfile.connect(setup_python_gdb)
end

加载脚本之后,除了 p/disp 显示的区别外,还新增了如下一些命令(具体的帮助文档可以阅读参考链接中提供的 Python 开发者手册):

(gdb) py-
py-bt       py-bt-full  py-down     py-list     py-locals   py-print    py-up

参考资料

Internals of CPython

https://hackmd.io/@xff9N3eQTLSL4Trq-6setg/ByMHBMjFe

Your Guide to the CPython Source Code

https://realpython.com/cpython-source-code-guide/

Debugging of CPython processes with gdb

https://www.podoliaka.org/2016/04/10/debugging-cpython-gdb/

gdb Support

https://devguide.python.org/gdb/