Replay Debugger User Manual


Overview

Replay debugger is a debugging tool that allows the user to go to any state of a program execution i.e it allows the user to execute the code line by line forwards or backwards. To allow this interaction , it has two stages:

1. Tracing :

In this stage the program is executed and enough information is generated to exactly reproduce the same execution of the program. A number of files are generated that store the program state. This dump of process state is called a checkpoint. This stage also stores rhat the program reads from the files and standard input, in order to replay it during the next stage.

2. Debugging session :

A read-only interactive debugging session allows the user to locate the bug by executing the program in forward and reverse direction.

The GDB-5.3 back-end and Insight-5.3 as a front-end have been extended to include replay features, and better code navigation facility.

One of the features, namely reverse watchpoints, allows the user to query the past execution of the program.

Scope

The Replay debugger is a source level debugger for single - threaded C programs.

It runs on Linux-i386 platform and allows the user only a read-only interaction , i.e user is not allowed to set program variable values as it could lead to change of program flow.

Breakpoints and watchpoints can be set as in GDB, and their forward semantics remain as they are. The semantics of breakpoints and watchpoints in reverse execution have been defined above.

Run

This node describes how to run and start debugging your program.

Suppose your program is "foo.c". Then, run the following commands.

  $ mkdir scratch
  $ cp foo.c scratch
  $ cd scratch
  $ export CHECKPOINT_INTERVAL=120   # in microseconds; you can change this number
  $ ~/replaydebugger/bin/run.sh
  $ ~/replaydebugger/bin/rd.sh

(Some sample programs can be found in the test-cases/ subdirectory of the distribution.)

The first three commands setup a new directory for running the program because many files are generated by the tracer etc. After debugging is over you can safely remove this directory.

The CHECKPOINT_INTERVAL environment variable controls how often the tracer checkpoints. A smaller interval makes tracing slower but replaying faster, and vice versa. Reverse watchpoints only work when this interval is set to zero.

The run.sh command analyses and traces the program.

The last command invokes the insight GUI. On the menubar, click Plugins -> Activation Tree to see the activation tree.

You can run any commands such as "jump_forward", "jump_backward", "fs", "bs", etc. These commands are documented in See section Commands.

Commands

The following commands can be executed at the GDB prompt.

bs : Back Step
This command takes the program to the previous line executed. If the previous line is a function call, it steps back into the function i.e it steps back to the closing brace of the that function. If any breakpoints, conditional or unconditional, are set, then they can be hit. This is analogous to the "step" command, the only differece being that it executes in the reverse direction.
prev : Previous
This command takes the program to the previous line in the current function activation. If the previous line is a function call, it steps across the function call without stepping back into it. If any breakpoints, conditional or unconditional , are set, then they can be hit. Breakpoints set inside function(s) called on the previous line will also be hit. This is analogous to the "next" command.
fs : Forward Step
This is a replacement for the GDB step command. On execution of this command the program goes to the next line executed. If the current line contains a function call, the program steps into the function , i.e to the opening brace of the function. If any breakpoints , conditional or conditional , or watchpoints are set in the system, they can be hit. The semantics of similar GDB command "step" have been preserved in this replacement command.
fn : Next
This is a replacement for the GDB next command. If the current line contains a function call(s), it steps across them. (The program remains in the current "stack frame" or activation.) If any breakpoints (conditional or unconditional) are set, they can be hit. Breakpoints set in the function(s) called on the current line will also be hit. The semantics of similar GDB command "next" have been preserved in this replacement command.
jump_forward LINESPEC : Direct jump Forward
This takes the program to the state of the program when it next executes that line. It is equivalent to setting a temporary breakpoint at that point and continuing, except that jump_forward does not hit any breakpoints or watchpoints that may be set by the user. If control never reaches that line number after this point, then a message is printed and the program state remains as it is. LINESPEC may simply be a line number, or it can be an offset such as +1, or a function name.
jump_backward LINESPEC : Direct Jump Backward
This takes the program to the state it was in when that line number was last executed. It is like to setting a temporary breakpoint at that line number and "reverse executing" the program, except that jump_forward does not hit any breakpoints or watchpoints that may be set by the user. If control had never reached that line number before this point, then a message is printed and the program state remains as it is.
reverse_watchpoint VARIABLE_NAME : Reverse Watchpoints
Takes you to the last place where VARIABLE_NAME was changed. This lets the user make a query such as 'when last was the value of variable x made different from what it is now'.

Activation Tree

By clicking on the menubar Plugin -> Activation Tree, a tree of the function activations can be displayed.

The activation tree of the debuggee's execution shows the nested structure of functions executed, where functions at the same level are ordered on time. When one function calls another, the callee becomes a child of the caller in the tree.

At every node of the tree, the name of the corresponding function is shown.

The activations on the current stack are colored with red dots, and the current activation is colored blue in the activation tree.

The user can click at any function activation, and the program state is restored to the beginning of that activation of the function, with the corresponding code appearing in the code browser window.

The data display window and stack window also get updated when you click on an activation.

Sample session

A sample debugging session is as shown below.

The graphical front end is not shown. This session is shown to explain the use and semantics of the core commands provided by the debugger.

The code is ::


1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

///////////////////////////////////////////

(gdb) start

1  int main()
2  {
=>  int x=2;
4   int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

///////////////////////////////////////////

(gdb) jump_forward 8		/* This takes the control to the line no 8 as shown */

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
=>  read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

/////////////////////////////////////////////

(gdb) bs			/* This causes the program to be
				   executed backwards and so we stop
				   at the previous line executed,
				    which is inside the the function
				   "sub", at the '}' */

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
=> }

////////////////////////////////////////////////

(gdb) fs			/* This causes the program to be
				   executed forwards and so we stop
				   at the previous line executed,
				    which is inside the the function
				   "main", at the line no. 8 */

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
=>  read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

/////////////////////////////////////////////////////

(gdb) previous			/* This causes the program to be
				   executed backwards and so we stop
				   at the previous line executed , but
				   the previous function call is not
				   stepped into.It steps across the
				   function, back to line 7
				     */	   

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
=>   sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

/////////////////////////////////////////////////////////////

(gdb) fn			/* This causes the program to be
				   executed forwards and so we stop
				   at the next line executed , but
				   the next function call is not
				   stepped into.It steps across the
				   function, to line 8
				     */	   

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
=>  read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

////////////////////////////////////////////////////////////////////

(gdb) jump_backward 6		/* This causes the program to be
				   executed backwards and so we stop
				   at line no. 6 . Line numbers any
				   where in the programs could have
				   been given. Any breakpoints or
				   watches set by user would be
				   ignored.	  
				      */	   

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
=>  x++;
7   sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

/////////////////

(gdb) fs

1  int main()
2  {
3   int x=2;
4   int y=5;
5   char buf[6];
6   x++;
=>  sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }

////////////////

(gdb) reverse_watchpoint x	 /* The program is executed backwards and	
				    the state of program is restored
				    to the one instruction after the
				    last time value of expression "x"
				    had changed from current value. 
				    Current value is "x=3".After
				    command executes, state is
				    restored to line 4, which is one
				    instruction after  the
				    value of x was made 2.

1  int main()
2  {
3   int x=2;
=>  int y=5;
5   char buf[6];
6   x++;
7   sub(3,5);
8   read(0 , buf , 5);
9  }

10 int sub(int x , int y)
11 {
12   return x-y;
13 }
 

///////////////////////////////////////////////

(gdb) q                        /* Quit the debugger */

//////////////////////////////////////////////

Bugs

  1. The Code Browser window does not get updated when the user attempts to jump to certain instructions. The problem arises when the user tries to jump to the very next instruction after a checkpoint is taken.
  2. Reverse watchpoints can only be used when the checkpoint interval is set to 0. This problem is mainly due to the fact that GDB-5.3 internally deletes a watchpoint when a watched variable is no longer in scope.
  3. Programs that contain system calls other than "read" are not fully supported. The "write" system call is supported only for standard output. This implies that programs that have 'malloc' or 'printf' cannot be debugged yet. However, a "write" to stdout is an alternative to 'printf', and as mentioned this is supported. (There may be many system calls before and after the execution of main. All these are executed unimpeded.)
  4. Events such as signals are not traced and replayed yet.
  5. Only single threaded programs can be debugged.
  6. Although the replay debugger has extended the functionality of GDB, not all the features of GDB are usable during the replay debugging session. The current implementation doesnot support the execution of the following commands, hence the user must not execute these during debugging. Appropriate replacements for essential commands have been provided as explained above. These commands will also be supported in the next version. Do NOT use the following commands:
    1.  step
    2.  next
    3.  return
    4.  run 
    5.  continue
    6.  finish
    7.  until
    8.  stepi
    9.  nexti
    10. stop
    

Improvements in the next Release

In addition to mending all above mentioned bugs , we intend to do the following in the immediate next release :

1. Support replaying of system calls :: "brk" and "write" . This would enable programs to contain 'malloc' and 'printf' like functions.

2. Support replaying of signals :: Since we can trace the signals that a program recieves, we will be able to replay the signal at the exact place where that it was recieved.

Index

Jump to: a - b - f - j - m - o - p - r - t

a

  • analysis
  • b

  • bs
  • f

  • fn
  • fs
  • j

  • jump_backward
  • jump_forward
  • m

  • modules
  • o

  • overview
  • p

  • prev
  • r

  • reverse_watchpoint
  • t

  • tracing

  • This document was generated on 28 February 2004 using texi2html 1.56k.