GDB之4调试Python代码
GDB之(4)调试Python代码
GDB之(4)调试Python代码
Author:Once Day Date:2023年3月22日/2024年2月26日
漫漫长路,才刚刚开始…
全系列文章请查看专栏:
推荐参考文档:
文章目录
1. 概述
如果Python程序挂住了,想查看Python代码的栈,但是用GDB看到的是C栈,本文介绍使用gdb的python扩展来查看python代码栈。
一般而言,现在的ubuntu设备上,安装gdb时都会自带装上python的扩展工具:
onceday->~:# find /usr/ -name "gdb"
/usr/include/gdb
/usr/share/doc/gdb
/usr/share/gdb
/usr/share/gdb/python/gdb
/usr/share/bash-completion/completions/gdb
/usr/bin/gdb
如上面,搜索一下目录,看看是否有
/usr/share/gdb/python/gdb
,如果没有需要安装对应的工具,这里自带的是python3的调试扩展
。
对于Python2,需要安装对应的包扩展才行。
onceday->~:# apt search python-gdb
Sorting... Done
Full Text Search... Done
python-gdbm/jammy 2.7.18-1build1 amd64
GNU dbm database support for Python2
python-gdbm-dbg/jammy 2.7.18-1build1 amd64
GNU dbm database support for Python2 (debug extension)
如上所示,安装对应的python2-gdb扩展即可 。
2. 加载libpython文件
下载地址为:
下载文件需要在仓库分支那里选择对应当前版本的分支下载该文件,然后操作如下:
- 下载到本地文件夹中。 可以放到系统路径去,这样后面不需要额外添加系统路径了 。
首先找到目标进程ID,或者coredump文件,皆可以:
onceday->~:# ps aux |grep gdb
ubuntu 1588276 0.0 0.1 16288 8844 pts/8 S+ 21:58 0:00 python3 gdb_test.py
root 1588710 0.0 0.0 6476 2448 pts/9 S+ 22:00 0:00 grep --color=auto gdb
然后使用
gdb python3 1588276
,便可以attach到运行的进程上:
......
#10 0x000056527606a005 in _PyEval_EvalFrameDefault ()
No symbol table info available.
#11 0x00005652760813ac in _PyFunction_Vectorcall ()
No symbol table info available.
#12 0x000056527606a005 in _PyEval_EvalFrameDefault ()
No symbol table info available.
#13 0x00005652760813ac in _PyFunction_Vectorcall ()
No symbol table info available.
#14 0x000056527606a005 in _PyEval_EvalFrameDefault ()
No symbol table info available.
#15 0x0000565276066766 in ?? ()
......
直接使用bt full打出来的是上面的栈,(忽略符号表,重点是栈形式),这是基于C代码的角度 。
这个时候,可以手动加在python扩展, 部分发行版Linux的GDB集成了python扩展功能,那就无需手动导入了 。
(gdb) python
>import sys
>sys.path.insert(0,"/home/ubuntu/py-code")
>import libpython
>end
(gdb) py
py-bt py-down py-locals py-up python-interactive
py-bt-full py-list py-print python
sys.path.insert是把下载的libpython.py文件所在的文件夹加入系统路径中,如果已经放入系统路径,这一步就是多余的了 。
导入成功了,输入
py
然后tab,将看到下面几个命令,其含义和gdb中命令类似。
(gdb) py-bt
Traceback (most recent call first):
(unable to read python frame information)
(unable to read python frame information)
(unable to read python frame information)
py-bt
是打印栈,但是如果报出上面的错误,无需担心,这是libpython版本和当前python解释器版本没对上的问题,因此重新下载对应版本的libpython.py文件即可
。
如上图所示,选择对应的python版本即可,这里选择的应该是
3.10
版本
。
下面来看一下常见的命令效果:
py-bt打印栈的简略信息:
(gdb) py-bt
Traceback (most recent call first):
File "/home/postgres/Connect_data.py", line 44, in deal_type_value
data = (int(random.random() * 20000), int(random.random() * 1000000))
File "/home/postgres/Connect_data.py", line 159, in <module>
deal_type_value(f1, f2, start_time_sec)
py-bt-full打印栈的详细信息 :
(gdb) py-bt-full
#0 Frame 0xffffb85ed640, for file /home/postgres/Connect_data.py, line 44, in deal_type_value (f1=<_io.TextIOWrapper at remote 0xffffb8622860>, f2=<_io.TextIOWrapper at remote 0xffffb8622ee0>, now_time=1704118932, d_time=80532)
data = (int(random.random() * 20000), int(random.random() * 1000000))
#5 Frame 0x2302d680, for file /home/postgres/Connect_data.py, line 159, in <module> ()
deal_type_value
py-up和py-down上下移动栈的位置
,
py-list
显示当前附近的源码:
(gdb) py-list
39
40 def deal_type_value(f1, f2, now_time):
41 global sava_start_time
42 global data_sum
43 d_time = now_time - sava_start_time
>44 data = (int(random.random() * 20000), int(random.random() * 1000000))
45 data_sum["3s"].append(data)
46 data_sum["10s"].append(data)
47 if d_time % 3 == 0:
48 succ, conc = sum_data(data_sum["3s"])
49 f1.write(f"{now_time}, 1, {succ}, {conc}\n")
py-locals打印当前栈的局部变量信息 :
(gdb) py-locals
f1 = <_io.TextIOWrapper at remote 0xffffb8622860>
f2 = <_io.TextIOWrapper at remote 0xffffb8622ee0>
now_time = 1704118932
d_time = 80532
py-print可以打印指定的变量信息:
(gdb) py-print now_time
local 'now_time' = 1704118932
2.1 如果打印信息失败
(gdb) py-bt
Traceback (most recent call first):
(unable to read python frame information)
(unable to read python frame information)
(unable to read python frame information)
(unable to read python frame information)
上述输出表明 GDB 无法读取 Python 堆栈帧信息。这可能会出现在几种情况下:
GDB 没有正确加载 Python 插件 :需要确保在开始追踪之前已经通过
gdb
命令行加载了 Python 插件,比如:(gdb) python >>> import sys >>> sys.path.append('/path/to/python/source') >>> from Tools import gdb >>> end
这里的 ‘/path/to/python/source’ 是 Python 源代码的路径。这个路径需要替换为实际的路径。
Python 可执行文件没有包含调试符号 :要在 GDB 中调试 Python,需要一个包含调试符号的 Python 可执行文件。在构建 Python 时,需要使用
--with-pydebug
选项来包含这些符号。如果使用的 Python 没有包含这些符号,可能需要重新构建 Python。GDB 版本不兼容 :不是所有版本的 GDB 都能正确地处理 Python 堆栈帧。你可能需要尝试升级或降级 GDB 来解决这个问题。
Python 代码正在执行非 Python 代码 :如果 Python 代码正在执行一个 C 扩展或者其他非 Python 代码,GDB 可能无法显示 Python 堆栈帧。在这种情况下,可能需要等待代码回到 Python 域,或者在 C 代码中设置断点。
3.安装pip+pystack
使用下面命令安装
pip(“ensurepip” is a module in Python that provides support for bootstrapping the pip installer into an existing Python installation or virtual environment)
pip -m ensurepip
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pystack-debugger
ps -ef | grep yams
pystack <python-pid>
Once Day
也信美人终作土,不堪幽梦太匆匆……
如果这篇文章为您带来了帮助或启发,不妨点个赞👍和关注,再加上一个小小的收藏⭐!
(。◕‿◕。)感谢您的阅读与支持~~~