+2008-06-09 Michael Snyder <msnyder@specifix.com>
+ 2006-05-02 Michael Snyder <msnyder@redhat.com>
+
+ * Target interface for reverse execution.
+ * target.h (enum target_waitkind):
+ Add new wait event, TARGET_WAITKIND_NO_HISTORY.
+ (enum exec_direction_kind): New enum.
+ (struct target_ops): New methods to_set_execdir, to_get_execdir.
+ * target.c (target_get_execdir): New generic method.
+ (target_set_execdir): Ditto.
+ * remote.c (remote_get_execdir, remote_set_execdir): New methods.
+ (remote_vcont_resume): Jump out if attempting reverse execution.
+ (remote_resume): Check for reverse exec direction, and send
+ appropriate command to target.
+ (remote_wait): Check target response for NO_HISTORY status.
+ Also check for empty reply (target doesn't understand "bs" or "bc).
+ (_initialize_remote): Add new methods to remote target vector.
+
+ * breakpoint.h (breakpoint_silence): Export.
+ * breakpoint.c (breakpoint_silence): New function.
+ * infcmd.c (finish_command): Check for reverse exec direction.
+ (finish_backward): New function, handle finish cmd in reverse.
+ * infrun.c (enum inferior_stop_reason): Add NO_HISTORY reason.
+ (handle_inferior_event): Handle TARGET_WAITKIND_NO_HISTORY.
+ Handle stepping over a function call in reverse.
+ Handle stepping thru a line range in reverse.
+ Handle setting a step-resume breakpoint in reverse.
+ Handle stepping into a function in reverse.
+ Handle stepping between line ranges in reverse.
+ (print_stop_reason): Print reason for NO_HISTORY.
+
+ 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.
+
2008-06-09 Doug Evans <dje@google.com>
* remote.c (remote_wait): Include beginning of malformed packet
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 \
+ 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 \
std-regs.o \
signals.o \
gdb-events.o \
- exec.o bcache.o objfiles.o observer.o minsyms.o maint.o demangle.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 \
dwarf2read.o mipsread.o stabsread.o corefile.o \
dwarf2expr.o dwarf2loc.o dwarf2-frame.o \
$(gdb_callback_h) $(gdb_remote_sim_h) $(command_h) \
$(regcache_h) $(gdb_assert_h) $(sim_regno_h) $(arch_utils_h) \
$(readline_h)
+reverse.o: reverse.c $(defs_h) $(gdb_string_h) $(target_h) $(cli_cmds_h) \
+ $(cli_decode_h) $(top_h)
rs6000-nat.o: rs6000-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdbcore_h) \
$(xcoffsolib_h) $(symfile_h) $(objfiles_h) $(libbfd_h) $(bfd_h) \
$(exceptions_h) $(gdb_stabs_h) $(regcache_h) $(arch_utils_h) \
b->ignore_count = 0;
}
+void
+breakpoint_silence (struct breakpoint *b)
+{
+ /* Silence the breakpoint. */
+ b->silent = 1;
+}
+
/* Command to set ignore-count of breakpoint N to COUNT. */
static void
extern int breakpoints_always_inserted_mode (void);
+/* Tell a breakpoint to be quiet. */
+extern void breakpoint_silence (struct breakpoint *);
+
#endif /* !defined (BREAKPOINT_H) */
* 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
@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
/* "finish": Set a temporary breakpoint at the place the selected
frame will return to, then continue. */
+static void finish_backwards (struct symbol *);
+
static void
finish_command (char *arg, int from_tty)
{
clear_proceed_status ();
- sal = find_pc_line (get_frame_pc (frame), 0);
- sal.pc = get_frame_pc (frame);
-
- breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish);
-
- old_chain = make_cleanup_delete_breakpoint (breakpoint);
-
/* Find the function we will return from. */
function = find_pc_function (get_frame_pc (get_selected_frame (NULL)));
source. */
if (from_tty)
{
- printf_filtered (_("Run till exit from "));
+ if (target_get_execution_direction () == EXEC_REVERSE)
+ printf_filtered ("Run back to call of ");
+ else
+ printf_filtered ("Run till exit from ");
+
print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
}
+ if (target_get_execution_direction () == EXEC_REVERSE)
+ {
+ /* Split off at this point. */
+ finish_backwards (function);
+ return;
+ }
+
+ sal = find_pc_line (get_frame_pc (frame), 0);
+ sal.pc = get_frame_pc (frame);
+
+ breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish);
+
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
+
proceed_to_finish = 1; /* We want stop_registers, please... */
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
Type \"info stack\" or \"info registers\" for more information.\n"));
}
}
+
+static void
+finish_backwards (struct symbol *function)
+{
+ struct symtab_and_line sal;
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+ CORE_ADDR func_addr;
+ int back_up;
+
+ if (find_pc_partial_function (get_frame_pc (get_current_frame ()),
+ NULL, &func_addr, NULL) == 0)
+ internal_error (__FILE__, __LINE__,
+ "Finish: couldn't find function.");
+
+ sal = find_pc_line (func_addr, 0);
+
+ /* Let's cheat and not worry about async until later. */
+
+ /* We don't need a return value. */
+ proceed_to_finish = 0;
+ /* Special case: if we're sitting at the function entry point,
+ then all we need to do is take a reverse singlestep. We
+ don't need to set a breakpoint, and indeed it would do us
+ no good to do so.
+
+ Note that this can only happen at frame #0, since there's
+ no way that a function up the stack can have a return address
+ that's equal to its entry point. */
+
+ if (sal.pc != read_pc ())
+ {
+ /* Set breakpoint and continue. */
+ breakpoint =
+ set_momentary_breakpoint (sal,
+ get_frame_id (get_selected_frame (NULL)),
+ bp_breakpoint);
+ /* Tell the breakpoint to keep quiet. We won't be done
+ until we've done another reverse single-step. */
+ breakpoint_silence (breakpoint);
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ /* We will be stopped when proceed returns. */
+ do_cleanups (old_chain);
+ back_up = bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL;
+ }
+ else
+ back_up = 1;
+ if (back_up)
+ {
+ /* If in fact we hit the step-resume breakpoint (and not
+ some other breakpoint), then we're almost there --
+ we just need to back up by one more single-step. */
+ /* (Kludgy way of letting wait_for_inferior know...) */
+ step_range_start = step_range_end = 1;
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ }
+ return;
+}
+
\f
static void
environment_info (char *var, int from_tty)
/* Inferior exited. */
EXITED,
/* Inferior received signal, and user asked to be notified. */
- SIGNAL_RECEIVED
+ SIGNAL_RECEIVED,
+ /* Reverse execution -- target ran out of history info. */
+ NO_HISTORY
};
/* This structure contains what used to be local variables in
stop_signal = ecs->ws.value.sig;
break;
+ case TARGET_WAITKIND_NO_HISTORY:
+ /* Reverse execution: target ran out of history info. */
+ print_stop_reason (NO_HISTORY, 0);
+ stop_stepping (ecs);
+ return;
+
/* We had an event in the inferior, but we are not interested
in handling it at this level. The lower layers have already
done what needs to be done, if anything.
keep_going (ecs);
return;
}
+ if (stop_pc == ecs->stop_func_start &&
+ target_get_execution_direction () == EXEC_REVERSE)
+ {
+ /* We are stepping over a function call in reverse, and
+ just hit the step-resume breakpoint at the start
+ address of the function. Go back to single-stepping,
+ which should take us back to the function call. */
+ ecs->stepping_over_breakpoint = 1;
+ keep_going (ecs);
+ return;
+ }
break;
case BPSTAT_WHAT_CHECK_SHLIBS:
fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n",
paddr_nz (step_range_start),
paddr_nz (step_range_end));
- keep_going (ecs);
+
+ /* When stepping backward, stop at beginning of line range
+ (unles it's the function entry point, in which case
+ keep going back to the call point). */
+ if (stop_pc == step_range_start &&
+ stop_pc != ecs->stop_func_start &&
+ target_get_execution_direction () == EXEC_REVERSE)
+ {
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ }
+ else
+ {
+ keep_going (ecs);
+ }
return;
}
if (step_over_calls == STEP_OVER_ALL)
{
- /* We're doing a "next", set a breakpoint at callee's return
- address (the address at which the caller will
- resume). */
- insert_step_resume_breakpoint_at_caller (get_current_frame ());
+ /* We're doing a "next".
+
+ Normal (forward) execution: set a breakpoint at the
+ callee's return address (the address at which the caller
+ will resume).
+
+ Reverse (backward) execution. set the step-resume
+ breakpoint at the start of the function that we just
+ stepped into (backwards), and continue to there. When we
+ get there, we'll need to single-step back to the
+ caller. */
+
+ if (target_get_execution_direction () == EXEC_REVERSE)
+ {
+ /* FIXME: I'm not sure if we've handled the frame for
+ recursion. */
+
+ struct symtab_and_line sr_sal;
+ init_sal (&sr_sal);
+ sr_sal.pc = ecs->stop_func_start;
+ insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
+ }
+ else
+ insert_step_resume_breakpoint_at_caller (get_current_frame ());
+
keep_going (ecs);
return;
}
return;
}
- /* Set a breakpoint at callee's return address (the address at
- which the caller will resume). */
- insert_step_resume_breakpoint_at_caller (get_current_frame ());
+ if (target_get_execution_direction () == EXEC_REVERSE)
+ {
+ /* Set a breakpoint at callee's start address.
+ From there we can step once and be back in the caller. */
+ /* FIXME: I'm not sure we've handled the frame for recursion. */
+ struct symtab_and_line sr_sal;
+ init_sal (&sr_sal);
+ sr_sal.pc = ecs->stop_func_start;
+ insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
+ }
+ else
+ {
+ /* Set a breakpoint at callee's return address (the address
+ at which the caller will resume). */
+ insert_step_resume_breakpoint_at_caller (get_current_frame ());
+ }
keep_going (ecs);
return;
}
ecs->stop_func_start = gdbarch_skip_prologue
(current_gdbarch, ecs->stop_func_start);
+ if (target_get_execution_direction () == EXEC_REVERSE)
+ {
+ ecs->sal = find_pc_line (stop_pc, 0);
+
+ /* OK, we're just gonna keep stepping here. */
+ if (ecs->sal.pc == stop_pc)
+ {
+ /* We're there already. Just stop stepping now. */
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+ /* Else just reset the step range and keep going.
+ No step-resume breakpoint, they don't work for
+ epilogues, which can have multiple entry paths. */
+ step_range_start = ecs->sal.pc;
+ step_range_end = ecs->sal.end;
+ keep_going (ecs);
+ return;
+ }
+ /* else... */
ecs->sal = find_pc_line (ecs->stop_func_start, 0);
/* Use the step_resume_break to step until the end of the prologue,
even if that involves jumps (as it seems to on the vax under
annotate_signal_string_end ();
ui_out_text (uiout, ".\n");
break;
+ case NO_HISTORY:
+ /* Reverse execution: target ran out of history info. */
+ ui_out_text (uiout, "\nNo more reverse-execution history.\n");
+ break;
default:
internal_error (__FILE__, __LINE__,
_("print_stop_reason: unrecognized enum value"));
set_thread (pid, 0); /* Run this thread. */
buf = rs->buf;
- if (siggnal != TARGET_SIGNAL_0)
+ if (target_get_execution_direction () == EXEC_REVERSE)
+ {
+ /* We don't pass signals to the target in reverse exec mode. */
+ if (info_verbose && siggnal != TARGET_SIGNAL_0)
+ warning (" - Can't pass signal %d to target in reverse: ignored.\n",
+ siggnal);
+ strcpy (buf, step ? "bs" : "bc");
+ }
+ else if (siggnal != TARGET_SIGNAL_0)
{
buf[0] = step ? 'S' : 'C';
buf[1] = tohex (((int) siggnal >> 4) & 0xf);
/* We're out of sync with the target now. Did it continue or not?
Not is more likely, so report a stop. */
warning (_("Remote failure reply: %s"), buf);
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = TARGET_SIGNAL_0;
+ if (buf[1] == '0' && buf[2] == '6')
+ {
+ status->kind = TARGET_WAITKIND_NO_HISTORY;
+ }
+ else
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_0;
+ }
goto got_status;
case 'F': /* File-I/O request. */
remote_fileio_request (buf);
help_list (remote_cmdlist, "remote ", -1, gdb_stdout);
}
+/* Reverse execution.
+ FIXME: set up as a capability. */
+static enum exec_direction_kind remote_execdir = EXEC_FORWARD;
+
+static enum exec_direction_kind remote_get_execdir (void)
+{
+ if (remote_debug && info_verbose)
+ printf_filtered ("remote execdir is %s\n",
+ remote_execdir == EXEC_FORWARD ? "forward" :
+ remote_execdir == EXEC_REVERSE ? "reverse" :
+ "unknown");
+ return remote_execdir;
+}
+
+static int remote_set_execdir (enum exec_direction_kind dir)
+{
+ if (remote_debug && info_verbose)
+ printf_filtered ("Set remote execdir: %s\n",
+ dir == EXEC_FORWARD ? "forward" :
+ dir == EXEC_REVERSE ? "reverse" :
+ "bad direction");
+
+ /* FIXME: check target for capability. */
+ if (dir == EXEC_FORWARD || dir == EXEC_REVERSE)
+ return (remote_execdir = dir);
+ else
+ return EXEC_ERROR;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_has_registers = 1;
remote_ops.to_has_execution = 1;
remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
+ remote_ops.to_get_execdir = remote_get_execdir;
+ remote_ops.to_set_execdir = remote_set_execdir;
remote_ops.to_magic = OPS_MAGIC;
remote_ops.to_memory_map = remote_memory_map;
remote_ops.to_flash_erase = remote_flash_erase;
--- /dev/null
+/* 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."));
+}
INHERIT (to_find_memory_regions, t);
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_thread_local_address, t);
+ INHERIT (to_get_execdir, t);
+ INHERIT (to_set_execdir, t);
/* Do not inherit to_read_description. */
/* Do not inherit to_search_memory. */
INHERIT (to_magic, t);
inferior, rather than being stuck in the remote_async_wait()
function. This way the event loop is responsive to other events,
like for instance the user typing. */
- TARGET_WAITKIND_IGNORE
+ TARGET_WAITKIND_IGNORE,
+
+ /* The target has run out of history information,
+ and cannot run backward any further. */
+ TARGET_WAITKIND_NO_HISTORY
};
struct target_waitstatus
value;
};
+/* Reverse execution. */
+enum exec_direction_kind
+ {
+ EXEC_FORWARD,
+ EXEC_REVERSE,
+ EXEC_ERROR
+ };
+
/* Possible types of events that the inferior handler will have to
deal with. */
enum inferior_event_type
const gdb_byte *pattern, ULONGEST pattern_len,
CORE_ADDR *found_addrp);
+ /* Set execution direction (forward/reverse). */
+ int (*to_set_execdir) (enum exec_direction_kind);
+ /* Get execution direction (forward/reverse). */
+ enum exec_direction_kind (*to_get_execdir) (void);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
#define target_watchpoint_addr_within_range(target, addr, start, length) \
(*target.to_watchpoint_addr_within_range) (target, addr, start, length)
+/* Forward/reverse execution direction.
+ These will only be implemented by a target that supports reverse execution.
+*/
+#define target_get_execution_direction() \
+ (current_target.to_get_execdir ? \
+ (*current_target.to_get_execdir) () : EXEC_ERROR)
+
+#define target_set_execution_direction(DIR) \
+ (current_target.to_set_execdir ? \
+ (*current_target.to_set_execdir) (DIR) : EXEC_ERROR)
+
+
extern const struct target_desc *target_read_description (struct target_ops *);
/* Utility implementation of searching memory. */