GDB 7+ 支持使用 Python 语言扩展 GDB 功能 - Extending GDB using Python , 比如,可以通过编写代码可视化展现某些库独有的数据结构(比如 C++ STL 类型)。
通用调试方法
以下命令不限于调试Python程序。
查看进程号:
ps auxf
查看此进程卡在哪个系统回调:
strace -p *pid*
pid替换为实际进程号。此命令会返回一个系统回调和文件操作符。
检查上一条命令系统回调的文件操作符的含义:
ls -l /proc/*pid*/fd
数字就是文件操作符。
/proc/pid 中还包含其他很多进程信息,有兴趣可自行研究。
列出此进程当前的文件操作:
lsof -p *pid*
GDB调试
安装依赖
目前来说调试python 的条件比较苛刻, 只针对特定版本的python版本 和 centos 系统。
对于 centos6.x 系统, 目前已经开发出的 debuginfo 包是针对python3.4 版本
对于 centos7.x 系统, 目前针对python3.4 和python3.6 版本
安装debuginfo包
yum install python36-debug && debuginfo-install python36-debug-3.6.3-7.el7.x86_64
或者
sudo yum install gdb
sudo yum install yum-utils
sudo debuginfo-install glibc
sudo yum install python-debuginfo
下载libpython.py脚本
地址:github.com/python/cpyt…
注:不同的系统该脚本不一样,比如有的可能是叫pythonx.x-gdb.py
进入gdb
执行以下命令
$gdb -p 1000 #使用此命令即可使gdb附加到进程
其中1000是进程号
载入libpython脚本
如果gdb是redhat或fedora等厂商修改过的,会有--python选项,使用此选项即可指定gdb启动时载入的Python扩展脚本
$ gdb --python /path/to/libpython.py -p 1000
如果安装的是GNU的gdb,就需要打开gdb后手动载入libpython.py脚本
(gdb) python
> import sys
>sys.path.insert(0, '/path/to/libpython.py' ) # 这里是libpython.py的目录,不包含该文件
> import libpython
>end
(gdb)
这时就可以使用py-bt等命令了
常用命令
bt # 当前C调用栈
py-bt # 当前Py调用栈
py-list # 当前py代码位置
info thread # 线程信息
thread <id> # 切换到某个线程
thread apply all py-list # 查看所有线程的py代码位置
ctrl-c # 中断
生成 core file
为了不影响运行中的进程,可以通过生成 core file 的方式来保存进程的当前信息:
(gdb) generate-core-file
warning: target file /proc/6489/cmdline contained unexpected null characters
Saved corefile core.6489
(gdb) quit
A debugging session is active.
Inferior 1 [process 6489] will be detached.
Quit anyway? (y or n) y
可以通过 gdb python core.PID 的方式来读取 core file:
$ gdb python core.6489
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
...
Type "apropos word" to search for commands related to "word"...
Reading symbols from python...Reading symbols from /usr/lib/debug/.build-id/90/d1300febaeb0a626baa2540d19df2416cd3361.debug...done.
done.
warning: core file may not match specified executable file.
[New LWP 6489]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
Core was generated by `python'.
#0 0xb778fc31 in __kernel_vsyscall ()
(gdb)
查看变量的值
(gdb) py-list
1 # -*- coding: utf-8 -*-
2 import time
3
4
5 def do(x):
>6 time.sleep(10)
7
8
9 def main():
10 for x in range(10000):
11 do(x)
(gdb) py-print x
local 'x' = 12
(gdb)
(gdb) py-locals
x = 12
(gdb)
查看上层调用方的信息
(gdb) py-up
#9 Frame 0xb74c0994, for file test.py, line 11, in main (x=12)
do(x)
(gdb) py-list
6 time.sleep(10)
7
8
9 def main():
10 for x in range(10000):
>11 do(x)
12
13
14 if __name__ == '__main__':
15 main()
(gdb) py-print x
local 'x' = 12
(gdb)
可以通过 py-down 回去:
(gdb) py-down
#6 Frame 0xb74926e4, for file test.py, line 6, in do (x=12)
time.sleep(10)
(gdb) py-list
1 # -*- coding: utf-8 -*-
2 import time
3
4
5 def do(x):
>6 time.sleep(10)
7
8
9 def main():
10 for x in range(10000):
11 do(x)
(gdb)
查看所有线程
(gdb) info threads
Id Target Id Frame
* 1 Thread 0xb74b9700 (LWP 11039) 0xb7711c31 in __kernel_vsyscall ()
2 Thread 0xb73b8b40 (LWP 11040) 0xb7711c31 in __kernel_vsyscall ()
3 Thread 0xb69ffb40 (LWP 11041) 0xb7711c31 in __kernel_vsyscall ()
(gdb)
可以看到这个程序当前有 3 个线程, 当前进入的是 1 号线程。
切换线程
(gdb) thread 3
[Switching to thread 3 (Thread 0xb69ffb40 (LWP 11041))]
#0 0xb7711c31 in __kernel_vsyscall ()
(gdb) info threads
Id Target Id Frame
1 Thread 0xb74b9700 (LWP 11039) 0xb7711c31 in __kernel_vsyscall ()
2 Thread 0xb73b8b40 (LWP 11040) 0xb7711c31 in __kernel_vsyscall ()
* 3 Thread 0xb69ffb40 (LWP 11041) 0xb7711c31 in __kernel_vsyscall ()
(gdb)
现在切换到了 3 号线程.
参考链接
ialloc.org/blog/python…
sourceware.org/gdb/current…
wiki.python.org/moin/Debugg…
mozillazg.com/2017/07/deb…