【发布时间】:2012-01-29 06:26:53
【问题描述】:
我的代码中似乎存在某种多线程错误,导致其测试套件每运行 30 次就会崩溃一次。测试套件是非交互式的。我想在 gdb 中运行我的测试套件,如果程序正常退出,则 gdb 正常退出,如果崩溃则中断(并显示调试提示)。这样我就可以让测试套件重复运行,去喝杯咖啡,回来,并得到一个很好的调试提示。如何使用 gdb 做到这一点?
【问题讨论】:
标签: gdb
我的代码中似乎存在某种多线程错误,导致其测试套件每运行 30 次就会崩溃一次。测试套件是非交互式的。我想在 gdb 中运行我的测试套件,如果程序正常退出,则 gdb 正常退出,如果崩溃则中断(并显示调试提示)。这样我就可以让测试套件重复运行,去喝杯咖啡,回来,并得到一个很好的调试提示。如何使用 gdb 做到这一点?
【问题讨论】:
标签: gdb
最简单的方法是使用gdb提供的Python API:
def exit_handler(event):
gdb.execute("quit")
gdb.events.exited.connect(exit_handler)
你甚至可以用一行来完成:
(gdb) python gdb.events.exited.connect(lambda x : gdb.execute("quit"))
您还可以检查返回代码,以确保它是您对 event.exit_code 期望的“正常”代码。
您可以将它与@acm 提到的--eval-command 或--command 结合使用,以从命令行或.gdbinit 文件注册事件处理程序。
【讨论】:
这有点老套,但你可以这样做:
gdb -ex='set confirm on' -ex=run -ex=quit --args ./a.out
如果 a.out 正常终止,它只会让你退出 GDB。但是如果你崩溃了,程序仍然是活动的,所以如果你真的想用一个活动的下级退出,GDB 通常会提示:
Program received signal SIGABRT, Aborted.
0x00007ffff72dad05 in raise (sig=...) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
in ../nptl/sysdeps/unix/sysv/linux/raise.c
A debugging session is active.
Inferior 1 [process 15126] will be killed.
Quit anyway? (y or n)
就像我说的那样,不是很漂亮,但是只要您没有关闭提示以退出活动进程,它就可以工作。也可能有一种方法可以使用 gdb 的 quit 命令:它接受一个数字参数,即调试会话的退出代码。所以也许你可以使用 --eval-command="quit stuff",其中的 stuff 是一些 GDB 表达式,它反映了下级是否正在运行。
这个程序可以用来测试一下:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
if (time(NULL) % 2) {
raise(SIGINT);
}
puts("no crash");
return EXIT_SUCCESS;
}
【讨论】:
set confirm off 文件中有set confirm off,这将不起作用,GDB 将始终返回...
如果您在~/.gdbinit 文件中加入以下行,gdb 将在您的程序以状态码 0 退出时退出。
python
def exit_handler ( event ):
if event .exit_code == 0:
gdb .execute ( "quit" )
gdb .events .exited .connect ( exit_handler )
end
以上是凯文的回答的改进。
【讨论】:
创建一个名为.gdbinit的文件,它将在gdb启动时使用。
run
quit
不带选项运行:
gdb --args prog arg1...
您告诉 gdb 运行并退出,但如果发生错误,它应该停止处理文件。
【讨论】:
你也可以在程序崩溃时触发回溯,让gdb以子进程的返回码退出:
gdb -return-child-result -ex run -ex "thread apply all bt" -ex "quit" --args myProgram -myProgramArg
【讨论】:
-return-child-result
当它崩溃时你没有得到核心文件吗?像这样 'gdb -c core' 启动 gdb 并进行堆栈回溯。
您更有可能想要使用 Valgrind。
【讨论】:
让它崩溃时转储核心。如果您使用的是 linux,请阅读 man core 手册页以及运行 bash 的 ulimit 内置函数。
这样,当它崩溃时,您会找到一个不错的核心文件,您可以将其提供给 gdb:
$ ulimit -c unlimited
$ ... run program ..., gopher coffee (or reddit ;)
$ gdb progname corefile
【讨论】: