如何使用GDB获取Python的堆栈跟踪信息?

我正在使用GDB调试我的Python应用程序在Kubuntu 12.04上产生的段错误。据说GDB版本7内置了用于提取有关Python堆栈信息的宏(http://docs.python.org/devguide/gdb.html),但我在让它正常工作方面遇到了问题。我已经安装了python-dbg。
当我在GDB中请求Python堆栈跟踪时,结果看起来像这样:
(gdb) py-bt
#5 (unable to read python frame information)
#16 (unable to read python frame information)
#26 (unable to read python frame information)
...

我的GDB版本是7.4-2012.04-0ubuntu2,Python版本是2.7.3-0ubuntu3。
4个回答

问题在于:要在GDB中访问调试符号,您必须调用不同的二进制文件:"python-dbg"而不是"python"(在/usr/share/doc/python2.7-dbg/README.debug中找到)。

1令人惊讶的是,这在http://fedoraproject.org/wiki/Features/EasierPythonDebugging或其他任何我能找到的地方都没有提到。谢谢Luke。 - quimnuss
1这不是真的。你只需要获取与你正在使用的Python版本匹配的调试符号。如果处理虚拟环境可能会有一些问题,因为该Python版本可能与你系统上的Python版本不匹配。在https://www.podoliaka.org/2016/04/10/debugging-cpython-gdb/上有一篇很好的文章。 - aggieNick02

在Ubuntu 16.04上,我成功地通过以下步骤在Python 3.5中获取了Python堆栈跟踪:
1. 安装`python3-dbg`和`python3-dev`: ``` $ sudo apt install python3-dbg python3-dev ``` `python3-dbg`软件包附带了如何在`/usr/share/doc/python3-dbg/README.debug`中使用它的简短文档,我将在下一步中使用它。
2. 将解压缩的GDB助手脚本`/usr/share/doc/python3.5/gdbinit.gz`追加到`~/.gdbinit`文件中: ``` zcat /usr/share/doc/python3.5/gdbinit.gz >> ~/.gdbinit ```
现在,gdb将能够找到Python二进制文件的符号,并且`py-bt`命令可以在gdb中显示Python堆栈跟踪。
$ gdb -p 4762
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 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".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 4762
[New LWP 4852]
[New LWP 4853]
[New LWP 4854]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f38e43deb5d in poll () at ../sysdeps/unix/syscall-template.S:84
84      ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) py-bt
Traceback (most recent call first):
  File "/usr/bin/indicator-cpufreq", line 80, in <module>
    Gtk.main()
(gdb)

我的Ubuntu 16.04上的gdbinit.gz文件包含了许多像pystack这样的命令,但没有py-bt。你有什么想法是怎么回事吗? - Anton
为什么我已经安装了python 3.6,但为什么还是使用python 3.5 - skytree

有时候,获取调试信息是不可能的;例如,如果你使用的是 conda Python,这些包并不附带调试信息。事实证明,py-spy(https://github.com/benfred/py-spy)有一个更强大的 Python 回溯转储实现,它不依赖于准确的调试符号。然而,由于它也使用了 ptrace,你需要先分离 gdb。以下是使其工作的方法:
  • 在 gdb 中进行你的操作,达到你想要获取 Python 回溯的断点。
  • 使用 handle SIGSTOP noprint nostop pass 让 gdb 继续执行 SIGSTOP 信号。
  • 使用 signal SIGSTOP 暂停进程。
  • 使用 detach 分离 gdb。注意 PID。
  • 在另一个终端中运行 py-spy dump --pid $PID。这将给你回溯信息。
  • 你可以继续使用 attach $PID 运行 gdb。请注意,即使进程被 SIGSTOP,你仍然可以继续该进程,并且它将正常运行,如果你再次分离,它将继续暂停。

也许这对某些人有帮助:在我的Debian系统上,二进制文件名为python2.7-dbg,来自于python2.7-dbg软件包。我还安装了python2.7-dev软件包和apt-get source python2.7-dbg命令,以便gdb能够找到Python解释器的源文件。
有了这些准备工作,我成功地调试了我遇到的SIGSEGV错误:https://bugs.python.org/issue34870

如何使用Python2.7-dbg? - Nathan B
@NathanB 使用gdb /usr/bin/python2.7-dbg --args yourscript.py来启动它(注意,现在的二进制文件可能是python3-dbg,来自于python3-dbg软件包)。然后,在Python解释器中设置断点,并使用run命令以调试模式启动解释器。如需更多GDB文档,请访问https://sourceware.org/gdb/onlinedocs/gdb/。 - Per Lundberg