gdb断点调试python代码
📅 2026/8/1 14:32:15
👁️ 阅读次数
📝 编程学习
最近在解程序cordump的问题,代码是C/C++与python混合部署的,gdb的bt命令只能看到C/C++的调用栈,看不到python的调用栈。踩了一些坑,这里记录下最终的结果。
下面都是在Python-3.11.12版本上实现的。
python调用栈打印
网上搜到的一些教程,是让下载对应python版本的libpython.py文件,然后在gdb里source一下,就有py-bt命令了,但是我执行了之后,py-bt命令并不生效。
我在这里卡了几个小时,最后发现py-bt命令要生效有个大前提,就是python命令需要是debug版本!!!
源码编译python debug版本
创建build_python.sh:
#!/bin/bashset-ewget--no-check-certificate https://www.python.org/ftp/python/3.11.12/Python-3.11.12.tgztar-xzfPython-3.11.12.tgzcdPython-3.11.12 ./configure --with-pydebug\--enable-shared\--prefix=/usr/local\CFLAGS="-g -O0 -fno-omit-frame-pointer"\LDFLAGS="-Wl,-rpath=/usr/local/lib"# --prefix= 这里要注意下,由于我这里是临时容器,所以我直接替换掉系统的python了。建议你安装到其他的目录,方便回退到系统自带的python。make-jmakeinstallldconfig使用py-bt打印python的调用栈
写个简单的测试脚本test.py:
importtime a=10deffunc_c():globala a=a+1b=5print("now in func_c")whileTrue:print("func_c is running")time.sleep(3)b=b+1print("func_c done")deffunc_b():globala a=a+1b=4print("now in func_b")func_c()print("func_b done")deffunc_a():globala a=a+1print("now in func_a")func_b()if__name__=="__main__":func_a()运行上面的脚本python test.py,使用gdb -p </pid/of/python test.py>,然后在gdb命令窗口执行py-bt就能看到调用栈了。
其中/workspace/python_gdb/libpython.py文件是从Python-3.11.12/Tools/gdb/libpython.py目录拷过来的。
(gdb)source/workspace/python_gdb/libpython.py(gdb)py-bt Traceback(most recent call first): File"/workspace/test.py", line12,infunc_c time.sleep(3)File"/workspace/test.py", line21,infunc_b func_c()File"/workspace/test.py", line28,infunc_a func_b()File"/workspace/test.py", line31,in<module>func_a()(gdb)py-list8b=59print("now in func_c")10whileTrue:11print("func_c is running")>12time.sleep(3)13b=b +114print("func_c done")1516def func_b():17global a18a=a +1(gdb)py-print blocal'b'=8libpython.py中的命令
| 命令 | 作用 |
|---|---|
| py-bt | 打印python调用栈 |
| py-bt-full | 打印所有线程python调用栈 |
| py-up | 调转到上一层python调用栈 |
| py-down | 调转到下一层python调用栈 |
| py-list | 打印当前python frame附近的代码行 |
| py-print | 打印变量值 |
| py-locals | 打印当前python frame的所有局部变量 |
运行中的python代码打断点调试
py-bt能成功运行后,我就想能动态调试正在运行中的python代码。这个功能对多进程、多机场景就特别有用,尤其那种拉起个服务耗时很久的场景,能节约调试时间。
原来是有个py-break命令的PR合入请求的,但是最终社区没有合入这个PR,py-break这个命令就没有很好维护的地方,提到py-break命令的blog多是10年前的了,和当前python版本不匹配。
最终我参照libpython.py写了个gdb自定义命令py-break,后面又加了py-next命令,都保存在py_break.py文件中:
#!/usr/bin/env python3# -*- coding: utf-8 -*-""" GDB commands for Python source-level debugging (pydebug CPython): py-break <file>:<lineno> — break on a Python source line py-next — step to next Python line (step over calls) IMPORTANT --------- These hooks use `maybe_call_line_trace`, which only runs when line tracing is on. Start the inferior with: PYTHON_GDB_LINEBREAK=1 gdb --args /usr/local/bin/python3.11d your.py (sitecustomize installs a no-op sys.settrace when that env var is set.) Usage: (gdb) py-break test.py:13 (gdb) run (gdb) py-next """from__future__importprint_functionimportosimportreimportsysimportgdb _GDB_PYTHON_DIR="/workspace/python_gdb"if_GDB_PYTHON_DIRnotinsys.path:sys.path.insert(0,_GDB_PYTHON_DIR)def_filename_match(expected,actual):ifnotactual:returnFalseifexpected==actual:returnTrueifos.path.basename(actual)==os
编程学习
技术分享
实战经验