使用gdb 7调试Python程序需要什么?

16 投票
2 回答
13124 浏览
提问于 2025-04-17 15:56

我想使用gdb 7来调试Python的“子进程”。

我需要做些什么才能实现这个呢?

比如说:

  • 子进程的Python在配置时需要加什么选项吗?

  • 这个子进程的Python必须是2.7版本或更新的吗?我看到gdb对这个功能的支持是在Python源代码中提交的那时候开始的。还是说2.7版本只是gdb本身需要的?

  • 有没有什么文件是必须安装的,但并不是所有的发行版都有打包?比如在packages.ubuntu.com上,我没有找到python-gdb.py这个文件,我觉得这个是需要的。

知道在特定的发行版上需要什么会很有帮助。我特别想了解在Ubuntu和Centos上需要什么。

2 个回答

0

对于Centos 6,你只需要这样做:

yum install gdb python-debuginfo
debuginfo-install python

然后你可以通过用gdb连接到正在运行的python进程来进行调试:

gdb python [process id]

一旦连接上了,只需输入:

py-bt
21

在Ubuntu 12.04上,Python似乎需要用--with-pydebug这个选项编译过。这里的python-dbg包就包含了一个合适的Python可执行文件,名字也是python-dbg。而且,使用的Python版本不一定要是2.7,2.6也能成功加载2.7的gdb扩展(下面会有调试的例子)。至少在Ubuntu 12.04上,安装的定义gdb扩展的文件叫libpython.py,而不是python-gdb.py(奇怪的是,编译Python时会生成一个包含这两个文件的目录,它们是一样的)。

不过,我觉得现在还不可能用生产环境的核心文件进行调试。因为Python的gdb扩展在处理Python进程时,试图获取一些在生产版本中被优化掉的变量(比如在PyEval_EvalFrameEx中的f变量)。看起来Linux/gdb和Python还没有达到Bryan Cantrill在这里提到的那种水平,能够在Illumos上调试生产环境的核心转储:

http://www.infoq.com/presentations/Debugging-Production-Systems

下面是Ubuntu 12.04上的调试会话,展示了gdb如何运行一个Python 2.6的进程来调试一个段错误,使用的是Python 2.7的gdb扩展。首先是导致段错误的代码:

~/Downloads/Python-2.6.4$ cat ~/bin/dumpcore.py
class Foo:

    def bar(self):
        from ctypes import string_at
        string_at(0xDEADBEEF) # this code will cause Python to segfault


def main():
    f = Foo()
    f.someattr = 42
    f.someotherattr = {'one':1, 'two':2L, 'three':[(), (None,), (None, None)]}
    f.bar()


if __name__ == "__main__":
    main()

接下来是调试会话:

~/Downloads/Python-2.6.4$ gdb --args ./python ~/bin/dumpcore.py
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/john/Downloads/Python-2.6.4/python...done.
(gdb) run
Starting program: /home/john/Downloads/Python-2.6.4/python /home/john/bin/dumpcore.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000468d67 in PyString_FromString (str=0xdeadbeef <Address 0xdeadbeef out of bounds>) at Objects/stringobject.c:116
116             size = strlen(str);
(gdb) py-bt
Undefined command: "py-bt".  Try "help".
(gdb) python
>import sys
>sys.path.insert(0, "/home/john/Downloads/Python-2.7/Tools/gdb")
>import libpython
>(gdb) py-bt
#10 Frame 0x8f0f90, for file /home/john/Downloads/Python-2.6.4/Lib/ctypes/__init__.py, line 496, in string_at (ptr=3735928559, size=-1)
    return _string_at(ptr, size)
#14 Frame 0x8ebf90, for file /home/john/bin/dumpcore.py, line 5, in bar (self=<Foo(someattr=42, someotherattr={'three': [(), (None,), (None, None)], 'two': 2L, 'one': 1}) at remote 0x7ffff6e03240>, string_at=<function at remote 0x7ffff6e1c990>)
        string_at(0xDEADBEEF) # this code will cause Python to segfault
#17 Frame 0x8ebd80, for file /home/john/bin/dumpcore.py, line 12, in main (f=<Foo(someattr=42, someotherattr={'three': [(), (None,), (None, None)], 'two': 2L, 'one': 1}) at remote 0x7ffff6e03240>)
    f.bar()
#20 Frame 0x8eb680, for file /home/john/bin/dumpcore.py, line 16, in <module> ()
    main()
(gdb) 

撰写回答