xref: /dflybsd-src/contrib/gdb-7/gdb/reverse.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Reverse execution and reverse debugging.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2006-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "gdb_string.h"
225796c8dcSSimon Schubert #include "target.h"
235796c8dcSSimon Schubert #include "top.h"
245796c8dcSSimon Schubert #include "cli/cli-cmds.h"
255796c8dcSSimon Schubert #include "cli/cli-decode.h"
26c50c785cSJohn Marino #include "cli/cli-utils.h"
275796c8dcSSimon Schubert #include "inferior.h"
28cf7f2e2dSJohn Marino #include "regcache.h"
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert /* User interface:
315796c8dcSSimon Schubert    reverse-step, reverse-next etc.  */
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert static void
exec_direction_default(void * notused)345796c8dcSSimon Schubert exec_direction_default (void *notused)
355796c8dcSSimon Schubert {
365796c8dcSSimon Schubert   /* Return execution direction to default state.  */
375796c8dcSSimon Schubert   execution_direction = EXEC_FORWARD;
385796c8dcSSimon Schubert }
395796c8dcSSimon Schubert 
405796c8dcSSimon Schubert /* exec_reverse_once -- accepts an arbitrary gdb command (string),
415796c8dcSSimon Schubert    and executes it with exec-direction set to 'reverse'.
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert    Used to implement reverse-next etc. commands.  */
445796c8dcSSimon Schubert 
455796c8dcSSimon Schubert static void
exec_reverse_once(char * cmd,char * args,int from_tty)465796c8dcSSimon Schubert exec_reverse_once (char *cmd, char *args, int from_tty)
475796c8dcSSimon Schubert {
485796c8dcSSimon Schubert   char *reverse_command;
495796c8dcSSimon Schubert   enum exec_direction_kind dir = execution_direction;
505796c8dcSSimon Schubert   struct cleanup *old_chain;
515796c8dcSSimon Schubert 
525796c8dcSSimon Schubert   if (dir == EXEC_REVERSE)
535796c8dcSSimon Schubert     error (_("Already in reverse mode.  Use '%s' or 'set exec-dir forward'."),
545796c8dcSSimon Schubert 	   cmd);
555796c8dcSSimon Schubert 
565796c8dcSSimon Schubert   if (!target_can_execute_reverse)
575796c8dcSSimon Schubert     error (_("Target %s does not support this command."), target_shortname);
585796c8dcSSimon Schubert 
595796c8dcSSimon Schubert   reverse_command = xstrprintf ("%s %s", cmd, args ? args : "");
605796c8dcSSimon Schubert   old_chain = make_cleanup (exec_direction_default, NULL);
615796c8dcSSimon Schubert   make_cleanup (xfree, reverse_command);
625796c8dcSSimon Schubert   execution_direction = EXEC_REVERSE;
635796c8dcSSimon Schubert   execute_command (reverse_command, from_tty);
645796c8dcSSimon Schubert   do_cleanups (old_chain);
655796c8dcSSimon Schubert }
665796c8dcSSimon Schubert 
675796c8dcSSimon Schubert static void
reverse_step(char * args,int from_tty)685796c8dcSSimon Schubert reverse_step (char *args, int from_tty)
695796c8dcSSimon Schubert {
705796c8dcSSimon Schubert   exec_reverse_once ("step", args, from_tty);
715796c8dcSSimon Schubert }
725796c8dcSSimon Schubert 
735796c8dcSSimon Schubert static void
reverse_stepi(char * args,int from_tty)745796c8dcSSimon Schubert reverse_stepi (char *args, int from_tty)
755796c8dcSSimon Schubert {
765796c8dcSSimon Schubert   exec_reverse_once ("stepi", args, from_tty);
775796c8dcSSimon Schubert }
785796c8dcSSimon Schubert 
795796c8dcSSimon Schubert static void
reverse_next(char * args,int from_tty)805796c8dcSSimon Schubert reverse_next (char *args, int from_tty)
815796c8dcSSimon Schubert {
825796c8dcSSimon Schubert   exec_reverse_once ("next", args, from_tty);
835796c8dcSSimon Schubert }
845796c8dcSSimon Schubert 
855796c8dcSSimon Schubert static void
reverse_nexti(char * args,int from_tty)865796c8dcSSimon Schubert reverse_nexti (char *args, int from_tty)
875796c8dcSSimon Schubert {
885796c8dcSSimon Schubert   exec_reverse_once ("nexti", args, from_tty);
895796c8dcSSimon Schubert }
905796c8dcSSimon Schubert 
915796c8dcSSimon Schubert static void
reverse_continue(char * args,int from_tty)925796c8dcSSimon Schubert reverse_continue (char *args, int from_tty)
935796c8dcSSimon Schubert {
945796c8dcSSimon Schubert   exec_reverse_once ("continue", args, from_tty);
955796c8dcSSimon Schubert }
965796c8dcSSimon Schubert 
975796c8dcSSimon Schubert static void
reverse_finish(char * args,int from_tty)985796c8dcSSimon Schubert reverse_finish (char *args, int from_tty)
995796c8dcSSimon Schubert {
1005796c8dcSSimon Schubert   exec_reverse_once ("finish", args, from_tty);
1015796c8dcSSimon Schubert }
1025796c8dcSSimon Schubert 
103cf7f2e2dSJohn Marino /* Data structures for a bookmark list.  */
104cf7f2e2dSJohn Marino 
105cf7f2e2dSJohn Marino struct bookmark {
106cf7f2e2dSJohn Marino   struct bookmark *next;
107cf7f2e2dSJohn Marino   int number;
108cf7f2e2dSJohn Marino   CORE_ADDR pc;
109cf7f2e2dSJohn Marino   struct symtab_and_line sal;
110cf7f2e2dSJohn Marino   gdb_byte *opaque_data;
111cf7f2e2dSJohn Marino };
112cf7f2e2dSJohn Marino 
113cf7f2e2dSJohn Marino static struct bookmark *bookmark_chain;
114cf7f2e2dSJohn Marino static int bookmark_count;
115cf7f2e2dSJohn Marino 
116cf7f2e2dSJohn Marino #define ALL_BOOKMARKS(B) for ((B) = bookmark_chain; (B); (B) = (B)->next)
117cf7f2e2dSJohn Marino 
118cf7f2e2dSJohn Marino #define ALL_BOOKMARKS_SAFE(B,TMP)           \
119cf7f2e2dSJohn Marino      for ((B) = bookmark_chain;             \
120cf7f2e2dSJohn Marino           (B) ? ((TMP) = (B)->next, 1) : 0; \
121cf7f2e2dSJohn Marino           (B) = (TMP))
122cf7f2e2dSJohn Marino 
123cf7f2e2dSJohn Marino /* save_bookmark_command -- implement "bookmark" command.
124cf7f2e2dSJohn Marino    Call target method to get a bookmark identifier.
125cf7f2e2dSJohn Marino    Insert bookmark identifier into list.
126cf7f2e2dSJohn Marino 
127cf7f2e2dSJohn Marino    Identifier will be a malloc string (gdb_byte *).
128cf7f2e2dSJohn Marino    Up to us to free it as required.  */
129cf7f2e2dSJohn Marino 
130cf7f2e2dSJohn Marino static void
save_bookmark_command(char * args,int from_tty)131cf7f2e2dSJohn Marino save_bookmark_command (char *args, int from_tty)
132cf7f2e2dSJohn Marino {
133cf7f2e2dSJohn Marino   /* Get target's idea of a bookmark.  */
134cf7f2e2dSJohn Marino   gdb_byte *bookmark_id = target_get_bookmark (args, from_tty);
135cf7f2e2dSJohn Marino   struct bookmark *b, *b1;
136cf7f2e2dSJohn Marino   struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
137cf7f2e2dSJohn Marino 
138cf7f2e2dSJohn Marino   /* CR should not cause another identical bookmark.  */
139cf7f2e2dSJohn Marino   dont_repeat ();
140cf7f2e2dSJohn Marino 
141cf7f2e2dSJohn Marino   if (bookmark_id == NULL)
142cf7f2e2dSJohn Marino     error (_("target_get_bookmark failed."));
143cf7f2e2dSJohn Marino 
144cf7f2e2dSJohn Marino   /* Set up a bookmark struct.  */
145cf7f2e2dSJohn Marino   b = xcalloc (1, sizeof (struct bookmark));
146cf7f2e2dSJohn Marino   b->number = ++bookmark_count;
147cf7f2e2dSJohn Marino   init_sal (&b->sal);
148cf7f2e2dSJohn Marino   b->pc = regcache_read_pc (get_current_regcache ());
149cf7f2e2dSJohn Marino   b->sal = find_pc_line (b->pc, 0);
150cf7f2e2dSJohn Marino   b->sal.pspace = get_frame_program_space (get_current_frame ());
151cf7f2e2dSJohn Marino   b->opaque_data = bookmark_id;
152cf7f2e2dSJohn Marino   b->next = NULL;
153cf7f2e2dSJohn Marino 
154cf7f2e2dSJohn Marino   /* Add this bookmark to the end of the chain, so that a list
155cf7f2e2dSJohn Marino      of bookmarks will come out in order of increasing numbers.  */
156cf7f2e2dSJohn Marino 
157cf7f2e2dSJohn Marino   b1 = bookmark_chain;
158cf7f2e2dSJohn Marino   if (b1 == 0)
159cf7f2e2dSJohn Marino     bookmark_chain = b;
160cf7f2e2dSJohn Marino   else
161cf7f2e2dSJohn Marino     {
162cf7f2e2dSJohn Marino       while (b1->next)
163cf7f2e2dSJohn Marino 	b1 = b1->next;
164cf7f2e2dSJohn Marino       b1->next = b;
165cf7f2e2dSJohn Marino     }
166cf7f2e2dSJohn Marino   printf_filtered (_("Saved bookmark %d at %s\n"), b->number,
167cf7f2e2dSJohn Marino 		     paddress (gdbarch, b->sal.pc));
168cf7f2e2dSJohn Marino }
169cf7f2e2dSJohn Marino 
170cf7f2e2dSJohn Marino /* Implement "delete bookmark" command.  */
171cf7f2e2dSJohn Marino 
172cf7f2e2dSJohn Marino static int
delete_one_bookmark(int num)173c50c785cSJohn Marino delete_one_bookmark (int num)
174cf7f2e2dSJohn Marino {
175c50c785cSJohn Marino   struct bookmark *b1, *b;
176c50c785cSJohn Marino 
177c50c785cSJohn Marino   /* Find bookmark with corresponding number.  */
178c50c785cSJohn Marino   ALL_BOOKMARKS (b)
179c50c785cSJohn Marino     if (b->number == num)
180c50c785cSJohn Marino       break;
181cf7f2e2dSJohn Marino 
182cf7f2e2dSJohn Marino   /* Special case, first item in list.  */
183cf7f2e2dSJohn Marino   if (b == bookmark_chain)
184cf7f2e2dSJohn Marino     bookmark_chain = b->next;
185cf7f2e2dSJohn Marino 
186a45ae5f8SJohn Marino   /* Find bookmark preceding "marked" one, so we can unlink.  */
187cf7f2e2dSJohn Marino   if (b)
188cf7f2e2dSJohn Marino     {
189cf7f2e2dSJohn Marino       ALL_BOOKMARKS (b1)
190cf7f2e2dSJohn Marino 	if (b1->next == b)
191cf7f2e2dSJohn Marino 	  {
192cf7f2e2dSJohn Marino 	    /* Found designated bookmark.  Unlink and delete.  */
193cf7f2e2dSJohn Marino 	    b1->next = b->next;
194cf7f2e2dSJohn Marino 	    break;
195cf7f2e2dSJohn Marino 	  }
196cf7f2e2dSJohn Marino       xfree (b->opaque_data);
197cf7f2e2dSJohn Marino       xfree (b);
198cf7f2e2dSJohn Marino       return 1;		/* success */
199cf7f2e2dSJohn Marino     }
200cf7f2e2dSJohn Marino   return 0;		/* failure */
201cf7f2e2dSJohn Marino }
202cf7f2e2dSJohn Marino 
203cf7f2e2dSJohn Marino static void
delete_all_bookmarks(void)204cf7f2e2dSJohn Marino delete_all_bookmarks (void)
205cf7f2e2dSJohn Marino {
206cf7f2e2dSJohn Marino   struct bookmark *b, *b1;
207cf7f2e2dSJohn Marino 
208cf7f2e2dSJohn Marino   ALL_BOOKMARKS_SAFE (b, b1)
209cf7f2e2dSJohn Marino     {
210cf7f2e2dSJohn Marino       xfree (b->opaque_data);
211cf7f2e2dSJohn Marino       xfree (b);
212cf7f2e2dSJohn Marino     }
213cf7f2e2dSJohn Marino   bookmark_chain = NULL;
214cf7f2e2dSJohn Marino }
215cf7f2e2dSJohn Marino 
216cf7f2e2dSJohn Marino static void
delete_bookmark_command(char * args,int from_tty)217cf7f2e2dSJohn Marino delete_bookmark_command (char *args, int from_tty)
218cf7f2e2dSJohn Marino {
219c50c785cSJohn Marino   int num;
220c50c785cSJohn Marino   struct get_number_or_range_state state;
221cf7f2e2dSJohn Marino 
222cf7f2e2dSJohn Marino   if (bookmark_chain == NULL)
223cf7f2e2dSJohn Marino     {
224cf7f2e2dSJohn Marino       warning (_("No bookmarks."));
225cf7f2e2dSJohn Marino       return;
226cf7f2e2dSJohn Marino     }
227cf7f2e2dSJohn Marino 
228cf7f2e2dSJohn Marino   if (args == NULL || args[0] == '\0')
229cf7f2e2dSJohn Marino     {
230cf7f2e2dSJohn Marino       if (from_tty && !query (_("Delete all bookmarks? ")))
231cf7f2e2dSJohn Marino 	return;
232cf7f2e2dSJohn Marino       delete_all_bookmarks ();
233cf7f2e2dSJohn Marino       return;
234cf7f2e2dSJohn Marino     }
235cf7f2e2dSJohn Marino 
236c50c785cSJohn Marino   init_number_or_range (&state, args);
237c50c785cSJohn Marino   while (!state.finished)
238c50c785cSJohn Marino     {
239c50c785cSJohn Marino       num = get_number_or_range (&state);
240c50c785cSJohn Marino       if (!delete_one_bookmark (num))
241cf7f2e2dSJohn Marino 	/* Not found.  */
242c50c785cSJohn Marino 	warning (_("No bookmark #%d."), num);
243c50c785cSJohn Marino     }
244cf7f2e2dSJohn Marino }
245cf7f2e2dSJohn Marino 
246cf7f2e2dSJohn Marino /* Implement "goto-bookmark" command.  */
247cf7f2e2dSJohn Marino 
248cf7f2e2dSJohn Marino static void
goto_bookmark_command(char * args,int from_tty)249cf7f2e2dSJohn Marino goto_bookmark_command (char *args, int from_tty)
250cf7f2e2dSJohn Marino {
251cf7f2e2dSJohn Marino   struct bookmark *b;
252cf7f2e2dSJohn Marino   unsigned long num;
253cf7f2e2dSJohn Marino 
254cf7f2e2dSJohn Marino   if (args == NULL || args[0] == '\0')
255cf7f2e2dSJohn Marino     error (_("Command requires an argument."));
256cf7f2e2dSJohn Marino 
257cf7f2e2dSJohn Marino   if (strncmp (args, "start", strlen ("start")) == 0
258cf7f2e2dSJohn Marino       || strncmp (args, "begin", strlen ("begin")) == 0
259cf7f2e2dSJohn Marino       || strncmp (args, "end",   strlen ("end")) == 0)
260cf7f2e2dSJohn Marino     {
261cf7f2e2dSJohn Marino       /* Special case.  Give target opportunity to handle.  */
262cf7f2e2dSJohn Marino       target_goto_bookmark (args, from_tty);
263cf7f2e2dSJohn Marino       return;
264cf7f2e2dSJohn Marino     }
265cf7f2e2dSJohn Marino 
266cf7f2e2dSJohn Marino   if (args[0] == '\'' || args[0] == '\"')
267cf7f2e2dSJohn Marino     {
268cf7f2e2dSJohn Marino       /* Special case -- quoted string.  Pass on to target.  */
269cf7f2e2dSJohn Marino       if (args[strlen (args) - 1] != args[0])
270cf7f2e2dSJohn Marino 	error (_("Unbalanced quotes: %s"), args);
271cf7f2e2dSJohn Marino       target_goto_bookmark (args, from_tty);
272cf7f2e2dSJohn Marino       return;
273cf7f2e2dSJohn Marino     }
274cf7f2e2dSJohn Marino 
275cf7f2e2dSJohn Marino   /* General case.  Bookmark identified by bookmark number.  */
276c50c785cSJohn Marino   num = get_number (&args);
277cf7f2e2dSJohn Marino   ALL_BOOKMARKS (b)
278cf7f2e2dSJohn Marino     if (b->number == num)
279cf7f2e2dSJohn Marino       break;
280cf7f2e2dSJohn Marino 
281cf7f2e2dSJohn Marino   if (b)
282cf7f2e2dSJohn Marino     {
283cf7f2e2dSJohn Marino       /* Found.  Send to target method.  */
284cf7f2e2dSJohn Marino       target_goto_bookmark (b->opaque_data, from_tty);
285cf7f2e2dSJohn Marino       return;
286cf7f2e2dSJohn Marino     }
287cf7f2e2dSJohn Marino   /* Not found.  */
288cf7f2e2dSJohn Marino   error (_("goto-bookmark: no bookmark found for '%s'."), args);
289cf7f2e2dSJohn Marino }
290cf7f2e2dSJohn Marino 
291c50c785cSJohn Marino static int
bookmark_1(int bnum)292c50c785cSJohn Marino bookmark_1 (int bnum)
293c50c785cSJohn Marino {
294c50c785cSJohn Marino   struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
295c50c785cSJohn Marino   struct bookmark *b;
296c50c785cSJohn Marino   int matched = 0;
297c50c785cSJohn Marino 
298c50c785cSJohn Marino   ALL_BOOKMARKS (b)
299c50c785cSJohn Marino   {
300c50c785cSJohn Marino     if (bnum == -1 || bnum == b->number)
301c50c785cSJohn Marino       {
302c50c785cSJohn Marino 	printf_filtered ("   %d       %s    '%s'\n",
303c50c785cSJohn Marino 			 b->number,
304c50c785cSJohn Marino 			 paddress (gdbarch, b->pc),
305c50c785cSJohn Marino 			 b->opaque_data);
306c50c785cSJohn Marino 	matched++;
307c50c785cSJohn Marino       }
308c50c785cSJohn Marino   }
309c50c785cSJohn Marino 
310c50c785cSJohn Marino   if (bnum > 0 && matched == 0)
311c50c785cSJohn Marino     printf_filtered ("No bookmark #%d\n", bnum);
312c50c785cSJohn Marino 
313c50c785cSJohn Marino   return matched;
314c50c785cSJohn Marino }
315c50c785cSJohn Marino 
316cf7f2e2dSJohn Marino /* Implement "info bookmarks" command.  */
317cf7f2e2dSJohn Marino 
318cf7f2e2dSJohn Marino static void
bookmarks_info(char * args,int from_tty)319cf7f2e2dSJohn Marino bookmarks_info (char *args, int from_tty)
320cf7f2e2dSJohn Marino {
321cf7f2e2dSJohn Marino   int bnum = -1;
322cf7f2e2dSJohn Marino 
323cf7f2e2dSJohn Marino   if (!bookmark_chain)
324cf7f2e2dSJohn Marino     printf_filtered (_("No bookmarks.\n"));
325c50c785cSJohn Marino   else if (args == NULL || *args == '\0')
326c50c785cSJohn Marino     bookmark_1 (-1);
327c50c785cSJohn Marino   else
328c50c785cSJohn Marino     {
329c50c785cSJohn Marino       struct get_number_or_range_state state;
330c50c785cSJohn Marino 
331c50c785cSJohn Marino       init_number_or_range (&state, args);
332c50c785cSJohn Marino       while (!state.finished)
333c50c785cSJohn Marino 	{
334c50c785cSJohn Marino 	  bnum = get_number_or_range (&state);
335c50c785cSJohn Marino 	  bookmark_1 (bnum);
336cf7f2e2dSJohn Marino 	}
337c50c785cSJohn Marino     }
338cf7f2e2dSJohn Marino }
339cf7f2e2dSJohn Marino 
340cf7f2e2dSJohn Marino 
3415796c8dcSSimon Schubert /* Provide a prototype to silence -Wmissing-prototypes.  */
3425796c8dcSSimon Schubert extern initialize_file_ftype _initialize_reverse;
3435796c8dcSSimon Schubert 
3445796c8dcSSimon Schubert void
_initialize_reverse(void)3455796c8dcSSimon Schubert _initialize_reverse (void)
3465796c8dcSSimon Schubert {
3475796c8dcSSimon Schubert   add_com ("reverse-step", class_run, reverse_step, _("\
3485796c8dcSSimon Schubert Step program backward until it reaches the beginning of another source line.\n\
3495796c8dcSSimon Schubert Argument N means do this N times (or till program stops for another reason).")
3505796c8dcSSimon Schubert 	   );
3515796c8dcSSimon Schubert   add_com_alias ("rs", "reverse-step", class_alias, 1);
3525796c8dcSSimon Schubert 
3535796c8dcSSimon Schubert   add_com ("reverse-next", class_run, reverse_next, _("\
3545796c8dcSSimon Schubert Step program backward, proceeding through subroutine calls.\n\
3555796c8dcSSimon Schubert Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\
3565796c8dcSSimon Schubert when they do, the call is treated as one instruction.\n\
3575796c8dcSSimon Schubert Argument N means do this N times (or till program stops for another reason).")
3585796c8dcSSimon Schubert 	   );
3595796c8dcSSimon Schubert   add_com_alias ("rn", "reverse-next", class_alias, 1);
3605796c8dcSSimon Schubert 
3615796c8dcSSimon Schubert   add_com ("reverse-stepi", class_run, reverse_stepi, _("\
3625796c8dcSSimon Schubert Step backward exactly one instruction.\n\
3635796c8dcSSimon Schubert Argument N means do this N times (or till program stops for another reason).")
3645796c8dcSSimon Schubert 	   );
3655796c8dcSSimon Schubert   add_com_alias ("rsi", "reverse-stepi", class_alias, 0);
3665796c8dcSSimon Schubert 
3675796c8dcSSimon Schubert   add_com ("reverse-nexti", class_run, reverse_nexti, _("\
3685796c8dcSSimon Schubert Step backward one instruction, but proceed through called subroutines.\n\
3695796c8dcSSimon Schubert Argument N means do this N times (or till program stops for another reason).")
3705796c8dcSSimon Schubert 	   );
3715796c8dcSSimon Schubert   add_com_alias ("rni", "reverse-nexti", class_alias, 0);
3725796c8dcSSimon Schubert 
3735796c8dcSSimon Schubert   add_com ("reverse-continue", class_run, reverse_continue, _("\
3745796c8dcSSimon Schubert Continue program being debugged but run it in reverse.\n\
3755796c8dcSSimon Schubert If proceeding from breakpoint, a number N may be used as an argument,\n\
3765796c8dcSSimon Schubert which means to set the ignore count of that breakpoint to N - 1 (so that\n\
3775796c8dcSSimon Schubert the breakpoint won't break until the Nth time it is reached)."));
3785796c8dcSSimon Schubert   add_com_alias ("rc", "reverse-continue", class_alias, 0);
3795796c8dcSSimon Schubert 
3805796c8dcSSimon Schubert   add_com ("reverse-finish", class_run, reverse_finish, _("\
3815796c8dcSSimon Schubert Execute backward until just before selected stack frame is called."));
382cf7f2e2dSJohn Marino 
383cf7f2e2dSJohn Marino   add_com ("bookmark", class_bookmark, save_bookmark_command, _("\
384cf7f2e2dSJohn Marino Set a bookmark in the program's execution history.\n\
385cf7f2e2dSJohn Marino A bookmark represents a point in the execution history \n\
386cf7f2e2dSJohn Marino that can be returned to at a later point in the debug session."));
387cf7f2e2dSJohn Marino   add_info ("bookmarks", bookmarks_info, _("\
388cf7f2e2dSJohn Marino Status of user-settable bookmarks.\n\
389cf7f2e2dSJohn Marino Bookmarks are user-settable markers representing a point in the \n\
390cf7f2e2dSJohn Marino execution history that can be returned to later in the same debug \n\
391cf7f2e2dSJohn Marino session."));
392cf7f2e2dSJohn Marino   add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\
393cf7f2e2dSJohn Marino Delete a bookmark from the bookmark list.\n\
394c50c785cSJohn Marino Argument is a bookmark number or numbers,\n\
395c50c785cSJohn Marino  or no argument to delete all bookmarks.\n"),
396cf7f2e2dSJohn Marino 	   &deletelist);
397cf7f2e2dSJohn Marino   add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\
398cf7f2e2dSJohn Marino Go to an earlier-bookmarked point in the program's execution history.\n\
399cf7f2e2dSJohn Marino Argument is the bookmark number of a bookmark saved earlier by using \n\
400cf7f2e2dSJohn Marino the 'bookmark' command, or the special arguments:\n\
401cf7f2e2dSJohn Marino   start (beginning of recording)\n\
402cf7f2e2dSJohn Marino   end   (end of recording)\n"));
4035796c8dcSSimon Schubert }
404