As part of a research project, I am trying to write a gdb command file that outputs certain information on every line of code in arbitrary C source files until the program terminates. This seems easily accomplished with a while loop, outputting whatever data I want within the loop, and then calling "next" at the end of the loop. (I know I would want "step" to enter function calls; I'm not concerned about that at the moment.)
However, in addition to the data I output on every line, I also want to execute special commands at certain breakpoints. This seems easily accomplished with "command". However, I'm encountering a problem where the while loop and breakpoint commands won't both work.
Here is the extremely simple C file I'm working with for testing purposes:
int global;
int main() {
int x;
x=-1;
global = 5;
return(0);
}
I compile it with gcc -g -o simple simple.c
. Then I run gdb -x commands.txt
. If the contents of commands.txt are the following:
set confirm off
exec-file simple
file simple
set logging file gdb_output.txt
set logging on
set pagination off
#Special commands I want to execute on certain breakpoints
break 5
command
echo COMMAND 1 ACTIVATED\n
end
break 6
command
echo COMMAND 2 ACTIVATED\n
end
break 7
command
echo COMMAND 3 ACTIVATED\n
end
run
next
next
next
continue
quit
...then the contents of gdb_output.txt are the following, as expected:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
COMMAND 2 ACTIVATED
Breakpoint 3, main () at simple.c:7
7 return(0);
COMMAND 3 ACTIVATED
8 }
[Inferior 1 (process 29631) exited normally]
However, if I edit the command file to try to execute as a loop, replacing
next
next
next
continue
with
while true
next
end
but leaving the rest of the script exactly the same, then the commands I specified for the breakpoints on lines 6&7 never execute, as evidenced by the contents of gdb_output.txt after running the modified command file:
Breakpoint 1 at 0x4004da: file simple.c, line 5.
Breakpoint 2 at 0x4004e1: file simple.c, line 6.
Breakpoint 3 at 0x4004eb: file simple.c, line 7.
Breakpoint 1, main () at simple.c:5
5 x=-1;
COMMAND 1 ACTIVATED
Breakpoint 2, main () at simple.c:6
6 global = 5;
Breakpoint 3, main () at simple.c:7
7 return(0);
8 }
__libc_start_main (main=0x4004d6 <main()>, argc=1, argv=0x7fffffffe128, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe118) at ../csu/libc-start.c:325
325 ../csu/libc-start.c: No such file or directory.
[Inferior 1 (process 29652) exited normally]
commands.txt:30: Error in sourced command file:
The program is not being run.
I know that the loop in its current form is problematic in that it will just keep calling "next" until the program terminates (so it never reaches "quit" at the bottom of the script), but that doesn't seem like it should stop the breakpoint commands from being run -- yet that is what appears to be happening. (If the breakpoint commands were being executed, I could condition my while loop to terminate once it hit breakpoints set before the C program's exit points.)
Is this a bug in GDB, or am I misunderstanding something? If this construction fundamentally won't work, then is there a way to execute a canned series of GDB commands on every step of a program run until the program terminates, while also executing commands specified at certain breakpoints -- or is this fundamentally impossible with a GDB script?
(My gdb version is 7.11.1 and if it matters, my OS is Linux.)
UPDATE
I decided to give lldb a shot and ran into some more perplexing issues (using the same C file as above, compiled with the same command). Here is my lldb script:
target create --no-dependents --arch x86_64 simple
breakpoint set --file simple.c --line 5
breakpoint command add
script print "COMMAND 1 ACTIVATED"
DONE
breakpoint set --file simple.c --line 6
breakpoint command add
script print "COMMAND 2 ACTIVATED"
DONE
breakpoint set --file simple.c --line 7
breakpoint command add
script print "COMMAND 3 ACTIVATED"
DONE
run
frame variable x
continue
frame variable x
continue
frame variable x
continue
quit
This is exhibiting rather strange behavior. The above version hits the first breakpoint, executes the associated command, then ignores all the following breakpoints. If I comment out just the second breakpoint, its associated command, and the corresponding frame variable x
, continue
, then breakpoints 1 and 3 both get hit and their corresponding commands are executed. Commenting out only the 1st or 3rd breakpoint and its associated command and frame variable x
, continue
results in just the first uncommented breakpoint getting hit, and its associated command run. In short, it appears that having breakpoints on two consecutive lines of code causes all breakpoints after the first to be ignored.
Does anyone know what is going on here? Is there a way I can have a breakpoint on every line and have them all get hit? And is this problem in any way related to the gdb issues described above?
I still haven't figured out why gdb and lldb were acting the way they were, but I did devise an alternative approach to accomplish what I want. I wrote a script to communicate with lldb using two named pipes whereby the script's stdout is linked to lldb's stdin and vice-versa, so the script can send lldb commands (frame variable -L
, bt
, step
, etc.) then get lldb's output and parse it. The script can of course loop all it wants, so this bypasses the problem where I couldn't get gdb or lldb command files to loop properly.