我的代码中似乎有某种多线程错误,每30次运行一次测试套件就会崩溃一次。测试套件是非交互式的。我想在gdb中运行我的测试套件,并且如果程序正常退出则正常退出gdb,如果崩溃则中断(并显示调试提示)。这样我可以让测试套件反复运行,去拿一杯咖啡,回来,并提供一个很好的调试提示。我怎么能用gdb做到这一点?
答案 0 :(得分:21)
这有点hacky但你可以这样做:
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”,其中的东西是一些反映下级是否正在运行的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;
}
答案 1 :(得分:8)
最简单的方法是使用gdb
提供的Python API:
def exit_handler(event):
gdb.execute("quit")
gdb.events.exited.connect(exit_handler)
您甚至可以使用一行:
(gdb) gdb.events.exited.connect(lambda x : gdb.execute("quit")
您还可以检查返回代码,以确保它是event.exit_code
所需的“正常”代码。
您可以将其与@acm所提及的--eval-command
或--command
结合使用,以从命令行或.gdbinit
文件注册事件处理程序。
答案 2 :(得分:4)
当程序崩溃时你也可以触发回溯,让gdb退出子进程的返回码:
gdb -return-child-result -ex run -ex "thread apply all bt" -ex "quit" --args myProgram -myProgramArg
答案 3 :(得分:3)
创建一个名为.gdbinit
的文件,它将在gdb启动时使用。
run
quit
无选项运行:
gdb --args prog arg1...
您告诉gdb运行并退出,但如果发生错误,它应该停止处理该文件。
答案 4 :(得分:2)
崩溃时使其转储核心。如果您使用的是Linux,请阅读man core
手册页,如果您正在运行ulimit
,请阅读内置bash
。
这种方式崩溃时你会找到一个可以提供给gdb的好的核心文件:
$ ulimit -c unlimited
$ ... run program ..., gopher coffee (or reddit ;)
$ gdb progname corefile
答案 5 :(得分:1)
如果您在~/.gdbinit
文件中添加以下行,则当您的程序以状态代码0退出时,gdb
将退出。
python
def exit_handler ( event ):
if event .exit_code == 0:
gdb .execute ( "quit" )
gdb .events .exited .connect ( exit_handler )
end
以上是凯文答案的改进。
答案 6 :(得分:-2)
崩溃时你没有收到核心文件吗?像这个'gdb -c core'一样启动gdb并进行堆栈回溯。
你更有可能想要使用Valgrind。