views:

77

answers:

2

I use a debugging script that runs several related processes in succession with the debugger. I'm currently using -x to execute several commands automatically (such as run). How can I make gdb quit automatically when the debugged process successfully terminates? Adding a quit command to the command file will cause that command to be handled not just on successful termination, but when errors occur also (when I'd rather take over at that point).

Here's an extract of what's going on:

+ 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)

Contents of gdbbatch:

start
b cpfs_log if level >= WARNING
+2  A: 

GDB has a different "language" for interacting with automated programs called GDB/MI (detailed here), but unfortunately, it doesn't look like it supports conditionals, and is expected to run from other programs with parsing and branching. So, it looks like Expect is the easiest (or at least a working) solution:

$ 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 }
}

I tested this with the simple programs:

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

With the following results:

$ ./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)

Essentially, you have to parse the output and branch using something else. This would of course work with any other program capable of handling input/output of another process, but the above expect script should get you started, if you don't mind Tcl. It should be a little better, and expect the first (gdb) prompt, but works due to stdin buffering.

You can also modify it to use that GDB/MI interface with the -i command-line argument to GDB; its commands and output are a bit more readily parsable, if you will expand to need more advanced features, as you can see in the previously linked documentation.

Simon
+2  A: 

gdb sets $_exitcode when the program successfully terminates. You can make use of that - set it to an unlikely value at the start of your script, and only quit at the end if it has changed:

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

(Setting $_exitcode to an unlikely value is a bit ugly, but it will otherwise not be defined at all if the program doesn't terminate, and there doesn't seem to be any obvious way of asking "is this variable defined?" in a conditional.)

Matthew Slattery