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