How do I print each line executed in GDB automatically until the set breakpoint is reached?

I would like to be able to set a breakpoint in GDB and run it to that point - and in the process print the lines that it has "crossed".

Here is an example based on this simple file with main and function, and two breakpoints for each:

 $ cat > test.c <<EOF #include "stdio.h" int count=0; void doFunction(void) { // two steps forward count += 2; // one step back count--; } int main(void) { // some pointless init commands; count = 1; count += 2; count = 0; //main loop while(1) { doFunction(); printf("%d\n", count); } } EOF $ gcc -g -Wall test.c -o test.exe $ chmod +x test.exe $ gdb -se test.exe ... Reading symbols from /path/to/test.exe...done. (gdb) b main Breakpoint 1 at 0x80483ec: file test.c, line 14. (gdb) b doFunction Breakpoint 2 at 0x80483c7: file test.c, line 7. 

To start a session, I need to run the ( r ) program, which then stops at the first breakpoint ( main ):

 (gdb) r Starting program: /path/to/test.exe Breakpoint 1, main () at test.c:14 14 count = 1; (gdb) 

At this point, I can, for example, click continue ( c ); and the process will go through, does not output anything, and is interrupted by the requested line:

 (gdb) c Continuing. Breakpoint 2, doFunction () at test.c:7 7 count += 2; (gdb) 

On the other hand, instead of continuing - I can go line by line using step ( s ) or next ( n ); eg:

 14 count = 1; (gdb) n 15 count += 2; (gdb) s 16 count = 0; (gdb) s 19 doFunction(); (gdb) s Breakpoint 2, doFunction () at test.c:7 7 count += 2; (gdb) s 9 count--; (gdb) s 10 } (gdb) s main () at test.c:20 20 printf("%d\n", count); (gdb) s ... (gdb) s _IO_vfprintf_internal (s=Cannot access memory at address 0xe5853361 ) at vfprintf.c:210 210 vfprintf.c: No such file or directory. in vfprintf.c (gdb) s 245 in vfprintf.c (gdb) s 210 in vfprintf.c (gdb) n 245 in vfprintf.c ... (gdb) n 2006 in vfprintf.c (gdb) n __printf (format=0x80484f0 "%d\n") at printf.c:39 39 printf.c: No such file or directory. in printf.c (gdb) n main () at test.c:21 21 } (gdb) n 19 doFunction(); (gdb) n Breakpoint 2, doFunction () at test.c:7 7 count += 2; (gdb) 

In any case, I know that I can keep Enter pressed and the last entered command (step or next) will be repeated (the remaining bit is a longer session in the second case, to show that the "next" remains at the same level, steps " step "inside the called functions). However, as you can see, depending on whether there will be a step or the next start, it may take some time until the result is achieved - and therefore I do not want to sit for 10 minutes when my hand is stuck on the Enter button :)

So my question is: can I somehow instruct gdb to work with “breakpoint 2” without additional user intervention - when printing lines through which it passes, as if a button (or the next one) were pressed?

+21
c debugging automation gdb
Aug 04 '11 at 19:24
source share
4 answers

Well, it wasn’t easy, but I think I understood it a little :) I went through a bunch of unsuccessful attempts (published here ); corresponding code below.

Basically the problem of the “next / step to breakpoint” is how to determine if you are “on” a breakpoint or not if the debugger is stopped (in step). Notice that I am using GDB 7.2-1ubuntu11 (current for Ubuntu 11.04). So it was like this:

  • For the first time I found about "Convenience Variables" , and given that there are program counters and such available, there must be some convenient GDB variable that gives the status of a "breakpoint" and can be used directly in the GDB script. Looking through the GDB link index , I just cannot find such variables (my attempts are in nub.gdb )
  • In the absence of such an internal variable "breakpoint status" - the only thing left to do is to capture the output of the command line ("stdout") GDB (in response to commands) as a string and analyze it (looking for a "breakpoint")
  • Then I learned about the Python API for GDB and the gdb.execute("CMDSTR", toString=True) command gdb.execute("CMDSTR", toString=True) , which, apparently, is exactly what is needed to capture the output: "By default, any output created by the command is sent to standard gdb output. If the to_string parameter is True, the output will be compiled by gdb.execute and returned as string [ 1 ] "!

And finally, the approach that worked: temporarily redirects GDB output from gdb.execute to a log file in RAM (Linux: /dev/shm ); and then by reading it, smoothing it and printing it from python - python also handles a simple while loop, which until the breakpoint is reached.

The irony is that most of these errors that caused this decision by redirecting the log file are actually recently recorded in SVN; that they will be distributed on distributions in the near future, and it will be possible to use gdb.execute("CMDSTR", toString=True) directly gdb.execute("CMDSTR", toString=True) : / Nevertheless, since I cannot risk building GDB from the source right now (and, possibly, with possible new incompatible ones), this is good enough for me as well :)

Here are the relevant files (partially also in pygdb-fork.gdb , pygdb-fork.py ):

pygdb-logg.gdb :

 # gdb script: pygdb-logg.gdb # easier interface for pygdb-logg.py stuff # from within gdb: (gdb) source -v pygdb-logg.gdb # from cdmline: gdb -x pygdb-logg.gdb -se test.exe # first, "include" the python file: source -v pygdb-logg.py # define shorthand for nextUntilBreakpoint(): define nub python nextUntilBreakpoint() end # set up breakpoints for test.exe: b main b doFunction # go to main breakpoint run 

pygdb-logg.py :

 # gdb will 'recognize' this as python # upon 'source pygdb-logg.py' # however, from gdb functions still have # to be called like: # (gdb) python print logExecCapture("bt") import sys import gdb import os def logExecCapture(instr): # /dev/shm - save file in RAM ltxname="/dev/shm/c.log" gdb.execute("set logging file "+ltxname) # lpfname gdb.execute("set logging redirect on") gdb.execute("set logging overwrite on") gdb.execute("set logging on") gdb.execute(instr) gdb.execute("set logging off") replyContents = open(ltxname, 'r').read() # read entire file return replyContents # next until breakpoint def nextUntilBreakpoint(): isInBreakpoint = -1; # as long as we don't find "Breakpoint" in report: while isInBreakpoint == -1: REP=logExecCapture("n") isInBreakpoint = REP.find("Breakpoint") print "LOOP:: ", isInBreakpoint, "\n", REP 

Basically, pygdb-logg.gdb loads the pygdb-logg.py python script, sets the alias nub for nextUntilBreakpoint and initializes the session - everything else is handled by the python script. And here is an example session - regarding the test source in the OP:

 $ gdb -x pygdb-logg.gdb -se test.exe ... Reading symbols from /path/to/test.exe...done. Breakpoint 1 at 0x80483ec: file test.c, line 14. Breakpoint 2 at 0x80483c7: file test.c, line 7. Breakpoint 1, main () at test.c:14 14 count = 1; (gdb) nub LOOP:: -1 15 count += 2; LOOP:: -1 16 count = 0; LOOP:: -1 19 doFunction(); LOOP:: 1 Breakpoint 2, doFunction () at test.c:7 7 count += 2; (gdb) nub LOOP:: -1 9 count--; LOOP:: -1 10 } LOOP:: -1 main () at test.c:20 20 printf("%d\n", count); 1 LOOP:: -1 21 } LOOP:: -1 19 doFunction(); LOOP:: 1 Breakpoint 2, doFunction () at test.c:7 7 count += 2; (gdb) 

... just like I wanted it: P I just don’t know how reliable it is (and whether it can be used in avr-gdb , for which I need it :) EDIT: the version of avr -gdb in Ubuntu 11.04 is currently 6.4 that the python command does not recognize :()

Ok, hope this helps someone
Hurrah!

Here are some links:

+16
Aug 6 2018-11-11T00:
source share

Based on the link in @sdaau's answer ( http://www.mail-archive.com/gdb@gnu.org/msg00031.html ), I created my own script to just keep sending 'and reading gdb output constantly while printing output to a text file and terminal, of course, my script can be modified to fit any other needs, however I hope that the modification you made should meet most of the needs of people.

http://www.codeground.net/coding/gdb-step-into-all-lines-to-get-full-application-flow/

 wget http://www.codeground.net/downloads/gdbwalkthrough.c gcc gdbwalkthrough.c -o gdbwalkthrough ./gdbwalkthrough <application full path> [application arguments] 
+3
Oct 20 '14 at 1:48
source share

How to do this in gdb using a batch file. Change the file argument and number of loops as needed.

 gdb -x run.gdb 

run.gdb:

 set pagination off set logging file gdb.log set logging on set $i = 0 file main break main break WriteData # sadly, commands not getting executed on reaching breakpoint 2 commands 2 set $i=1000 print "commands 2 : %d",$i end run while ( $i < 1000 ) step # next # continue set $i = $i + 1 end 
+2
Aug 09 '15 at 14:10
source share

As a new answer, since the previous one is already confused :) In principle, if the goal is to monitor the execution of lines of source code (and / or assembly), because the program works, because the motivation is often for me to search for "automatic listing" - then, in In principle, a very quick way is to use the GDB TUI mode; I quote:

c - gdb behavior: optimized value - stack overflow # 1354762

Use TUI GDB mode. My copy of GDB allows this when I type minus and Enter. Then enter Cx 2 (hold down the Control key and press X, release both and then press 2). This will place it in the separation source and demo display. Then use stepi and nexti to move one machine command at a time. Use Cx o to switch between TUI windows.

The trick is that even if you click continue , this time source will be shown and indicated in the TUI; and after program execution:

GDB TUI Screenshot

... and this for me avoids many situations where I should have a script breakpoint in the "auto-step context" (although there are still such situations). TUI Docs: TUI - Debugging with GDB

Hurrah!

+1
Aug 07 2018-11-18T00:
source share



All Articles