This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] Reverse debugging, part 3/3: user interface / docs


Here is the user interface part of the reverse debugging patch.

As discussed previously, it starts with the simplest interface,
exporting control of the "execution direction" state to the user,
and then shows how that functionality can be trivially extended
to provide user commands such as reverse-step and reverse-continue.

To avoid confusion as to what "reverse-step" means if you are
already in "reverse" mode, I've just rejected the combination.
You can say "set exec-direction reverse" and then "step",
or you can say "reverse-step", but you can't use reverse-step
if you're already in reverse mode.  So, you have the choice of
going backward once, or going backward until you say otherwise.

If people hate that combination, one or the other can be
un-exported, or a completely different user interface can be
"dropped in" to replace this one.

All reverse-xxx commands have 2 or 3 letter abbreviations.

Command documentation is included in this part of the patch.

2006-03-31  Michael Snyder  <msnyder@redhat.com>

	User interface for reverse execution.
	* Makefile.in (reverse.c): New file.
	* reverse.c: New file.  User interface for reverse execution.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.800
diff -p -r1.800 Makefile.in
*** Makefile.in	30 Mar 2006 16:34:23 -0000	1.800
--- Makefile.in	31 Mar 2006 21:48:40 -0000
*************** SFILES = ada-exp.y ada-lang.c ada-typepr
*** 543,549 ****
  	objfiles.c osabi.c observer.c \
  	p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
  	prologue-value.c \
! 	regcache.c reggroups.c remote.c remote-fileio.c \
  	scm-exp.c scm-lang.c scm-valprint.c \
  	sentinel-frame.c \
  	serial.c ser-base.c ser-unix.c \
--- 543,549 ----
  	objfiles.c osabi.c observer.c \
  	p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
  	prologue-value.c \
! 	regcache.c reggroups.c remote.c remote-fileio.c reverse.c \
  	scm-exp.c scm-lang.c scm-valprint.c \
  	sentinel-frame.c \
  	serial.c ser-base.c ser-unix.c \
*************** COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
*** 927,933 ****
  	signals.o \
  	kod.o kod-cisco.o \
  	gdb-events.o \
! 	exec.o bcache.o objfiles.o observer.o minsyms.o maint.o demangle.o \
  	dbxread.o coffread.o coff-pe-read.o elfread.o \
  	dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
  	dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
--- 927,934 ----
  	signals.o \
  	kod.o kod-cisco.o \
  	gdb-events.o \
! 	exec.o reverse.o \
! 	bcache.o objfiles.o observer.o minsyms.o maint.o demangle.o \
  	dbxread.o coffread.o coff-pe-read.o elfread.o \
  	dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
  	dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
*************** remote-st.o: remote-st.c $(defs_h) $(gdb
*** 2493,2498 ****
--- 2494,2501 ----
  remote-utils.o: remote-utils.c $(defs_h) $(gdb_string_h) $(gdbcmd_h) \
  	$(target_h) $(serial_h) $(gdbcore_h) $(inferior_h) $(remote_utils_h) \
  	$(regcache_h)
+ reverse.o: reverse.c $(defs_h) $(gdb_string_h) $(target_h) $(cli_cmds_h) \
+ 	$(cli_decode_h) $(top_h)
  rom68k-rom.o: rom68k-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \
  	$(serial_h) $(regcache_h) $(value_h) $(m68k_tdep_h)
  rs6000-nat.o: rs6000-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdbcore_h) \
Index: reverse.c
===================================================================
RCS file: reverse.c
diff -N reverse.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- reverse.c	31 Mar 2006 21:48:40 -0000
***************
*** 0 ****
--- 1,197 ----
+ /* Reverse execution and reverse debugging.
+ 
+    Copyright (C) 2006 Free Software Foundation, Inc.
+ 
+    This file is part of GDB.
+ 
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.  */
+ 
+ #include "defs.h"
+ #include "gdb_string.h"
+ #include "target.h"
+ #include "top.h"
+ #include "cli/cli-cmds.h"
+ #include "cli/cli-decode.h"
+ 
+ /* User interface for reverse debugging:
+    Set exec-direction / show exec-direction commands
+    (returns error unles target implements to_set_execdir method).  */
+ 
+ static const char exec_forward[] = "forward";
+ static const char exec_reverse[] = "reverse";
+ static const char *exec_direction = exec_forward;
+ static const char *exec_direction_names[] = {
+   exec_forward,
+   exec_reverse,
+   NULL
+ };
+ 
+ static void
+ set_exec_direction_func (char *args, int from_tty, 
+ 			 struct cmd_list_element *cmd)
+ {
+   if (target_get_execution_direction () != EXEC_ERROR)
+     {
+       enum exec_direction_kind dir = EXEC_ERROR;
+ 
+       if (!strcmp (exec_direction, exec_forward))
+ 	dir = EXEC_FORWARD;
+       else if (!strcmp (exec_direction, exec_reverse))
+ 	dir = EXEC_REVERSE;
+ 
+       if (target_set_execution_direction (dir) != EXEC_ERROR)
+ 	return;
+     }
+   error (_("Target `%s' does not support execution-direction."),
+ 	 target_shortname);
+ }
+ 
+ static void
+ show_exec_direction_func (struct ui_file *out, int from_tty, 
+ 			  struct cmd_list_element *cmd, const char *value)
+ {
+   enum exec_direction_kind dir = target_get_execution_direction ();
+ 
+   switch (dir) {
+   case EXEC_FORWARD:
+     fprintf_filtered (out, "Forward.\n");
+     break;
+   case EXEC_REVERSE:
+     fprintf_filtered (out, "Reverse.\n");
+     break;
+   case EXEC_ERROR:
+   default:
+     error (_("Target `%s' does not support execution-direction."),
+ 	   target_shortname);
+     break;
+   }
+ }
+ 
+ /* User interface:
+    reverse-step, reverse-next etc.
+    (returns error unles target implements to_set_execdir method).  */
+ 
+ static void execdir_default (void *notused)
+ {
+   /* Return execution direction to default state.  */
+   target_set_execution_direction (EXEC_FORWARD);
+ }
+ 
+ static void
+ exec_reverse_once (char *cmd, char *args, int from_tty)
+ {
+   /* String buffer for command consing.  */
+   char reverse_command[512];
+   enum exec_direction_kind dir = target_get_execution_direction ();
+ 
+   if (dir == EXEC_ERROR)
+     error (_("Target %s does not support this command."), target_shortname);
+ 
+   if (dir == EXEC_REVERSE)
+     error (_("Already in reverse mode.  Use '%s' or 'set exec-dir forward'."),
+ 	   cmd);
+ 
+   if (target_set_execution_direction (EXEC_REVERSE) == EXEC_ERROR)
+     error (_("Target %s does not support this command."), target_shortname);
+ 
+   make_cleanup (execdir_default, NULL);
+   sprintf (reverse_command, "%s %s", cmd, args ? args : "");
+   execute_command (reverse_command, from_tty);
+ }
+ 
+ static void
+ reverse_step (char *args, int from_tty)
+ {
+   exec_reverse_once ("step", args, from_tty);
+ }
+ 
+ static void
+ reverse_stepi (char *args, int from_tty)
+ {
+   exec_reverse_once ("stepi", args, from_tty);
+ }
+ 
+ static void
+ reverse_next (char *args, int from_tty)
+ {
+   exec_reverse_once ("next", args, from_tty);
+ }
+ 
+ static void
+ reverse_nexti (char *args, int from_tty)
+ {
+   exec_reverse_once ("nexti", args, from_tty);
+ }
+ 
+ static void
+ reverse_continue (char *args, int from_tty)
+ {
+   exec_reverse_once ("continue", args, from_tty);
+ }
+ 
+ static void
+ reverse_finish (char *args, int from_tty)
+ {
+   exec_reverse_once ("finish", args, from_tty);
+ }
+ 
+ void
+ _initialize_reverse (void)
+ {
+   add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names,
+ 			&exec_direction, "Set direction of execution.\n\
+ Options are 'forward' or 'reverse'.",
+ 			"Show direction of execution (forward/reverse).",
+ 			"Tells gdb whether to execute forward or backward.",
+ 			set_exec_direction_func, show_exec_direction_func,
+ 			&setlist, &showlist);
+ 
+   add_com ("reverse-step", class_run, reverse_step, _("\
+ Step program backward until it reaches the beginning of another source line.\n\
+ Argument N means do this N times (or till program stops for another reason).")
+ 	   );
+   add_com_alias ("rs", "reverse-step", class_alias, 1);
+ 
+   add_com ("reverse-next", class_run, reverse_next, _("\
+ Step program backward, proceeding through subroutine calls.\n\
+ Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\
+ when they do, the call is treated as one instruction.\n\
+ Argument N means do this N times (or till program stops for another reason).")
+ 	   );
+   add_com_alias ("rn", "reverse-next", class_alias, 1);
+ 
+   add_com ("reverse-stepi", class_run, reverse_stepi, _("\
+ Step backward exactly one instruction.\n\
+ Argument N means do this N times (or till program stops for another reason).")
+ 	   );
+   add_com_alias ("rsi", "reverse-stepi", class_alias, 0);
+ 
+   add_com ("reverse-nexti", class_run, reverse_nexti, _("\
+ Step backward one instruction, but proceed through called subroutines.\n\
+ Argument N means do this N times (or till program stops for another reason).")
+ 	   );
+   add_com_alias ("rni", "reverse-nexti", class_alias, 0);
+ 
+   add_com ("reverse-continue", class_run, reverse_continue, _("\
+ Continue program being debugged, running in reverse.\n\
+ If proceeding from breakpoint, a number N may be used as an argument,\n\
+ which means to set the ignore count of that breakpoint to N - 1 (so that\n\
+ the breakpoint won't break until the Nth time it is reached)."));
+   add_com_alias ("rc", "reverse-continue", class_alias, 0);
+ 
+   add_com ("reverse-finish", class_run, reverse_finish, _("\
+ Execute backward until just before selected stack frame is called."));
+ }
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.321
diff -p -r1.321 gdb.texinfo
*** doc/gdb.texinfo	31 Mar 2006 19:47:11 -0000	1.321
--- doc/gdb.texinfo	31 Mar 2006 21:48:51 -0000
*************** Copyright (C) 1988-2006 Free Software Fo
*** 127,132 ****
--- 127,133 ----
  * Commands::                    @value{GDBN} commands
  * Running::                     Running programs under @value{GDBN}
  * Stopping::                    Stopping and continuing
+ * Reverse Execution::           Running programs backward
  * Stack::                       Examining the stack
  * Source::                      Examining source files
  * Data::                        Examining data
*************** Display the current scheduler locking mo
*** 4312,4317 ****
--- 4313,4421 ----
  @end table
  
  
+ @node Reverse Execution
+ @chapter Running programs backward
+ 
+ When you are debugging a program, it is not unusual to realize that
+ you have gone too far, and some event of interest has already happened.
+ If the target environment supports it, @value{GDBN} can allow you to
+ ``rewind'' the program by running it backward.
+ 
+ A target environment that supports reverse execution should be able
+ to ``undo'' the changes in machine state that have taken place as the
+ program was executing normally.  Variables, registers etc. should 
+ revert to their previous values.  Obviously this requires a great
+ deal of sophistication on the part of the target environment; not
+ all target environments can support reverse execution.
+ 
+ When a program is executed in reverse, the instructions that 
+ have most recently been executed are ``un-executed'', in reverse
+ order.  The program counter runs backward, following the previous
+ thread of execution in reverse.  As each instruction is ``un-executed'', 
+ the values of memory and/or registers that were changed by that 
+ instruction are reverted to their previous states.  After executing
+ a piece of source code in reverse, all side effects of that code
+ should be ``undone'', and all variables should be returned to their
+ prior values.
+ 
+ Assuming you are debugging in a target environment that supports
+ reverse execution, @value{GDBN} provides the following commands.
+ 
+ @table @code
+ @kindex reverse-continue
+ @kindex rc @r{(@code{reverse-continue})}
+ @item reverse-continue @r{[}@var{ignore-count}@r{]}
+ @itemx rc @r{[}@var{ignore-count}@r{]}
+ Beginning at the point where your program last stopped, start executing
+ in reverse.  Reverse execution will stop for breakpoints and synchronous
+ exceptions (signals), just like normal execution.  Behavior of 
+ asynchronous signals depends on the target environment.
+ 
+ @kindex reverse-step
+ @kindex rs @r{(@code{step})}
+ @item reverse-step @r{[}@var{count}@r{]}
+ Run the program backward until control reaches the start of a
+ different source line; then stop it, and return control to @value{GDBN}.
+ 
+ Like the @code{step} command, @code{reverse-step} will only stop
+ at the beginning of a source line.  It ``un-executes'' the previously
+ executed source line.  If the previous source line included calls to 
+ debuggable functions, @code{reverse-step} will step (backward) into
+ the called function, stopping at the beginning of the @emph{last}
+ statement in the called function (typically a return statement).
+ 
+ Also, as with the @code{step} command, if non-debuggable functions are
+ called, @code{reverse-step} will run thru them backward without stopping.
+ 
+ @kindex reverse-stepi
+ @kindex rsi @r{(@code{reverse-stepi})}
+ @item reverse-stepi @r{[}@var{count}@r{]}
+ Reverse-execute one machine instruction.  Note that the instruction
+ to be reverse-executed is @emph{not} the one pointed to by the program
+ counter, but the instruction executed prior to that one.  For instance,
+ if the last instruction was a jump, @code{reverse-stepi} will take you
+ back from the destination of the jump to the jump instruction itself.
+ 
+ @kindex reverse-next
+ @kindex rn @r{(@code{reverse-next})}
+ @item reverse-next @r{[}@var{count}@r{]}
+ Run backward to the beginning of the previous line executed in
+ the current (innermost) stack frame.  If the line contains function
+ calls, they will be ``un-executed'' without stopping.  Starting from
+ the first line of a function, @code{reverse-next} will take you back
+ to the caller of that function, @emph{before} the function was called.
+ 
+ @kindex reverse-nexti
+ @kindex rni @r{(@code{reverse-nexti})}
+ @item reverse-nexti @r{[}@var{count}@r{]}
+ Like @code{nexti}, @code{reverse-nexti} executes a single instruction
+ in reverse, except that called functions are ``un-executed'' atomically.
+ That is, if the previously executed instruction was a return from 
+ another instruction, @code{reverse-nexti} will continue to execute
+ in reverse until the call to that function (from the current stack
+ frame) is reached.
+ 
+ @kindex reverse-finish
+ @item reverse-finish
+ Just as the @code{finish} command takes you to the point where the
+ current function returns, @code{reverse-finish} takes you to the point
+ where it was called.  Instead of ending up at the end of the current
+ function invocation, you end up at the beginning.
+ 
+ @item set exec-direction 
+ Set the direction of target execution.
+ @itemx set exec-direction reverse
+ @cindex execute forward or backward in time
+ @value{GDBN} will perform all execution commands in reverse, until the 
+ exec-direction mode is changed to ``forward''.  Affected commands include
+ @code{step, stepi, next, nexti, continue, and finish}.  The @code{return}
+ command cannot be used in reverse mode.
+ @item set exec-direction forward
+ @value{GDBN} will perform all execution commands in the normal fashion.
+ This is the default.
+ @end table
+ 
+ 
  @node Stack
  @chapter Examining the Stack
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]