Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to loop in a GDB script till program is finished?

define traverse
    while(CONDITION)
        if $start == 0
            set $start = 1
            print_node
            print_rss_item
        else
            continue
            print_node
            print_rss_item
        end
    end
end

What condition do I need to stop the loop if the program is finished?

like image 382
user3084621 Avatar asked Dec 09 '13 22:12

user3084621


1 Answers

Looking at your gdb script:

define traverse
    while(CONDITION)
        if $start == 0
            set $start = 1
            print_node
            print_rss_item
        else
            continue
            print_node
            print_rss_item
        end
    end
end

Several things to note:

  1. The gdb script (so called "debugger") and debuggee are always operating in a toggling mode: WHENEVER THE GDB SCRIPT RUN, the debuggee is paused and NOT running, and whenever the DEBUGGEE is running, the gdb script is paused and NOT RUNNING.

  2. Why is this so? This is because whenever the debuggee is in paused mode (read up "ptrace()" API and its various option: PEEKUSER, POKEUSER, PTRACE_CONT) the debugger actually can cleanly (and memory-consistently) read the memory of the debuggee without fear of corruption, and thus all its variables values etc.

When debugger is not running, ie, it executed the "continue" operation, where control is passed to the debuggee, the debuggee can thus continue to run and change its own memory, without fear of wrongly being read by another process - because it cannot happened.

So how do we know when the debuggee has ended? When "continue" failed and thus the gdbscript will not continue running. But if you setup a debuggee without any breakpoints, then executing the gdb "run" command you will find the the debuggee run continuously, without the gdb script having a chance to execute.

So effectively if your script is running, then debuggee is in STOP mode, and vice versa. And if the debuggee has ended by calling exit(), the gdb script will not be running as well.

eg:

defining the macro (inside .gdbinit file):

define myloop_print
set $total = $arg0
set $i = 0
   while($i<$total)
     set $i = $i + 1
     print $i, $i
     cont
   end
end

And then running "gdb /bin/ls" and followed by "break write" and "run -al" and then "myloop_print 10000" (the sequence or order is important), we can see that every "write" it will break and gdbscript will print out the counter.

And last few lines executed are:

Breakpoint 1, write () at ../sysdeps/unix/syscall-template.S:81
81  in ../sysdeps/unix/syscall-template.S
$40571 = 285
drwxrwxr-x   2 tthtlc tthtlc    4096 Feb 18 00:00 yocto_slide
[Inferior 1 (process 7395) exited normally]
$40572 = 286
The program is not being run.
(gdb) 

Which clearly shows that the last counter printed is 286, even though I had specified 10000 as the limit.

Running the macro without the debuggee running:

(gdb) myloop_print 10000
$40573 = 1
The program is not being run.
(gdb) 

We can see that the gdbscript will not run.

And if you do "gdb /bin/ls" and followed by "myloop_print 10000" (assuming the macro is defined inside .gdbinit) then you will get gdbscript running to completion 10000 loops - without the debuggee ever running.

like image 168
Peter Teoh Avatar answered Oct 20 '22 13:10

Peter Teoh