如何使gdb在程序成功终止后自动退出?

13

我使用一个调试脚本,用调试器依次运行几个相关的进程。我目前使用-x自动执行几个命令(例如run)。如何在被调试的进程成功终止时使gdb自动退出?quit命令添加到命令文件中会导致该命令不仅在成功终止时处理,而且在发生错误时也会处理(此时我更愿意接管控制权)。

以下是正在进行的内容摘录:

+ gdb -return-child-result -x gdbbatch --args ./mkfs.cpfs /dev/loop0
GNU gdb (GDB) 7.1-ubuntu
Reading symbols from /home/matt/cpfs/mkfs.cpfs...done.
Program exited normally. Breakpoint 2 at 0x805224f: file log.c, line 32. (gdb)

gdbbatch的内容:

start
b cpfs_log if level >= WARNING

3
有一个重复的Stackoverflow问题,其中有一个有用的答案:https://dev59.com/rGoy5IYBdhLWcg3wScBB#8657833。 - Isaac Turner
3个回答

12
我认为我已经在寻找类似物时,与如何使gdb在接收到信号时发送外部通知?有了你问题的完整解决方案。这里没有其他人提到或发现gdb钩子

基于Matthew关于$_exitcode的提示,这是我的app/.gdbinit,可以实现所需的确切行为;成功终止时正常退出并转到gdb提示符,一切都会失效,请发送电子邮件等:

set $_exitcode = -999
set height 0
handle SIGTERM nostop print pass
handle SIGPIPE nostop
define hook-stop
    if $_exitcode != -999
        quit
    else
        shell echo | mail -s "NOTICE: app has stopped on unhandled signal" root
    end
end
echo .gdbinit: running app\n
run

这对于除了在子进程退出时显示调试提示之外的许多其他用途非常有用。如果只需要在命令行界面上执行这个操作,可以考虑使用某种形式的 gdb --return-child-result -ex r --command /dev/fd/3 3<<<$'if ! $_isvoid ($_exitcode)\nquit\nend' --args ... - undefined

11

当程序成功终止时,gdb会设置$_exitcode。您可以利用它-在脚本开始时将其设置为不太可能的值,并且仅在其发生更改时在结束时quit

set $_exitcode = -999
# ...
run
# ...
if $_exitcode != -999
  quit
end

(将 $_exitcode 设置为一个不太可能的值有点丑陋,但如果程序没有终止,否则它将根本未被定义,在条件语句中似乎没有任何明显的方式来询问“这个变量是否已定义?”)


这份文档展示了如何使用_isvoid_exitcode来避免将其设置为“不太可能的值”。此文档 - Daniel Kamil Kozar
丹尼尔,你的链接有问题 :( - Patrizio Bertoni
作为一个猜测,丹尼尔的链接可能指向https://sourceware.org/gdb/onlinedocs/gdb/Convenience-Funs.html,其中显示了示例:`print $_isvoid ($_exitcode)`。 - undefined

4

GDB有一种与自动化程序交互的不同“语言”称为GDB/MI(详见此处),但不幸的是,它似乎不支持条件,并且期望从其他程序中运行并解析和分支。因此,看起来Expect是最简单(或至少是一个有效的)解决方案:

$ cat gdbrunner
#!/usr/bin/expect -f

#spawn gdb -return-child-result --args ./mkfs.cpfs /dev/loop0
spawn gdb -return-child-result --args [lindex $argv 0]

#send "start\n"
#send "b cpfs_log if level >= WARNING"
send "run\n"

expect {
    normally\.         { send "quit\n" }
    "exited with code" { interact -nobuffer }
}

我用简单的程序进行了测试:

$ cat prog1.c
int main(void) { return 0; }
$ cat prog2.c
int main(void) { return 1; }

以下是相关结果:
$ ./gdbrunner ./prog1
spawn gdb -return-child-result --args ./prog1
run
(gdb) run
Starting program: /home/foo/prog1

Program exited normally.
(gdb) quit
$ ./gdbrunner ./prog2
spawn gdb -return-child-result --args ./prog2
run
(gdb) run
Starting program: /home/foo/prog2

Program exited with code 01.
(gdb)

基本上,你需要解析输出并使用其他方法进行分支。当然,这对于任何其他能够处理另一个进程的输入/输出的程序都可以工作,但是如果你不介意 Tcl 的话,上述 expect 脚本应该可以帮助你入门。它应该更好,并期望第一个 (gdb) 提示,但由于标准输入缓冲,它可以工作。

你也可以修改它以使用那个 GDB/MI 接口和 GDB 的-i 命令行参数;如果你需要更高级的功能,它的命令和输出会更容易被解析,正如你在之前链接的文档中看到的一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接