*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / reverse.c
CommitLineData
b2175913
MS
1/* Reverse execution and reverse debugging.
2
4c38e0a4 3 Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
b2175913
MS
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
5b1ba0e5 9 the Free Software Foundation; either version 3 of the License, or
b2175913
MS
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
5b1ba0e5 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
b2175913
MS
19
20#include "defs.h"
21#include "gdb_string.h"
22#include "target.h"
23#include "top.h"
24#include "cli/cli-cmds.h"
25#include "cli/cli-decode.h"
26#include "inferior.h"
6b04bdb7 27#include "regcache.h"
b2175913
MS
28
29/* User interface:
30 reverse-step, reverse-next etc. */
31
b4f899bb
MS
32static void
33exec_direction_default (void *notused)
b2175913
MS
34{
35 /* Return execution direction to default state. */
36 execution_direction = EXEC_FORWARD;
37}
38
39/* exec_reverse_once -- accepts an arbitrary gdb command (string),
40 and executes it with exec-direction set to 'reverse'.
41
42 Used to implement reverse-next etc. commands. */
43
44static void
45exec_reverse_once (char *cmd, char *args, int from_tty)
46{
47 char *reverse_command;
48 enum exec_direction_kind dir = execution_direction;
49 struct cleanup *old_chain;
50
51 if (dir == EXEC_ERROR)
52 error (_("Target %s does not support this command."), target_shortname);
53
54 if (dir == EXEC_REVERSE)
55 error (_("Already in reverse mode. Use '%s' or 'set exec-dir forward'."),
56 cmd);
57
58 if (!target_can_execute_reverse)
59 error (_("Target %s does not support this command."), target_shortname);
60
61 reverse_command = xstrprintf ("%s %s", cmd, args ? args : "");
62 old_chain = make_cleanup (exec_direction_default, NULL);
63 make_cleanup (xfree, reverse_command);
64 execution_direction = EXEC_REVERSE;
65 execute_command (reverse_command, from_tty);
66 do_cleanups (old_chain);
67}
68
69static void
70reverse_step (char *args, int from_tty)
71{
72 exec_reverse_once ("step", args, from_tty);
73}
74
75static void
76reverse_stepi (char *args, int from_tty)
77{
78 exec_reverse_once ("stepi", args, from_tty);
79}
80
81static void
82reverse_next (char *args, int from_tty)
83{
84 exec_reverse_once ("next", args, from_tty);
85}
86
87static void
88reverse_nexti (char *args, int from_tty)
89{
90 exec_reverse_once ("nexti", args, from_tty);
91}
92
93static void
94reverse_continue (char *args, int from_tty)
95{
96 exec_reverse_once ("continue", args, from_tty);
97}
98
99static void
100reverse_finish (char *args, int from_tty)
101{
102 exec_reverse_once ("finish", args, from_tty);
103}
104
6b04bdb7
MS
105/* Data structures for a bookmark list. */
106
107struct bookmark {
108 struct bookmark *next;
109 int number;
110 CORE_ADDR pc;
111 struct symtab_and_line sal;
112 gdb_byte *opaque_data;
113};
114
115static struct bookmark *bookmark_chain;
116static int bookmark_count;
117
118#define ALL_BOOKMARKS(B) for ((B) = bookmark_chain; (B); (B) = (B)->next)
119
120#define ALL_BOOKMARKS_SAFE(B,TMP) \
121 for ((B) = bookmark_chain; \
122 (B) ? ((TMP) = (B)->next, 1) : 0; \
123 (B) = (TMP))
124
125/* save_bookmark_command -- implement "bookmark" command.
126 Call target method to get a bookmark identifier.
127 Insert bookmark identifier into list.
128
129 Identifier will be a malloc string (gdb_byte *).
130 Up to us to free it as required. */
131
132static void
133save_bookmark_command (char *args, int from_tty)
134{
135 /* Get target's idea of a bookmark. */
136 gdb_byte *bookmark_id = target_get_bookmark (args, from_tty);
137 struct bookmark *b, *b1;
138 struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
139
140 /* CR should not cause another identical bookmark. */
141 dont_repeat ();
142
143 if (bookmark_id == NULL)
144 error (_("target_get_bookmark failed."));
145
146 /* Set up a bookmark struct. */
147 b = xcalloc (1, sizeof (struct bookmark));
148 b->number = ++bookmark_count;
149 init_sal (&b->sal);
150 b->pc = regcache_read_pc (get_current_regcache ());
151 b->sal = find_pc_line (b->pc, 0);
152 b->sal.pspace = get_frame_program_space (get_current_frame ());
153 b->opaque_data = bookmark_id;
154 b->next = NULL;
155
156 /* Add this bookmark to the end of the chain, so that a list
157 of bookmarks will come out in order of increasing numbers. */
158
159 b1 = bookmark_chain;
160 if (b1 == 0)
161 bookmark_chain = b;
162 else
163 {
164 while (b1->next)
165 b1 = b1->next;
166 b1->next = b;
167 }
168 printf_filtered (_("Saved bookmark %d at %s\n"), b->number,
169 paddress (gdbarch, b->sal.pc));
170}
171
172/* Implement "delete bookmark" command. */
173
174static int
175delete_one_bookmark (struct bookmark *b)
176{
177 struct bookmark *b1;
178
179 /* Special case, first item in list. */
180 if (b == bookmark_chain)
181 bookmark_chain = b->next;
182
183 /* Find bookmark preceeding "marked" one, so we can unlink. */
184 if (b)
185 {
186 ALL_BOOKMARKS (b1)
187 if (b1->next == b)
188 {
189 /* Found designated bookmark. Unlink and delete. */
190 b1->next = b->next;
191 break;
192 }
193 xfree (b->opaque_data);
194 xfree (b);
195 return 1; /* success */
196 }
197 return 0; /* failure */
198}
199
200static void
201delete_all_bookmarks (void)
202{
203 struct bookmark *b, *b1;
204
205 ALL_BOOKMARKS_SAFE (b, b1)
206 {
207 xfree (b->opaque_data);
208 xfree (b);
209 }
210 bookmark_chain = NULL;
211}
212
213static void
214delete_bookmark_command (char *args, int from_tty)
215{
6b4398f7 216 struct bookmark *b;
6b04bdb7
MS
217 unsigned long num;
218
219 if (bookmark_chain == NULL)
220 {
221 warning (_("No bookmarks."));
222 return;
223 }
224
225 if (args == NULL || args[0] == '\0')
226 {
227 if (from_tty && !query (_("Delete all bookmarks? ")))
228 return;
229 delete_all_bookmarks ();
230 return;
231 }
232
233 num = strtoul (args, NULL, 0);
234 /* Find bookmark with corresponding number. */
235 ALL_BOOKMARKS (b)
236 if (b->number == num)
237 break;
238
239 if (!delete_one_bookmark (b))
240 /* Not found. */
241 error (_("delete bookmark: no bookmark found for '%s'."), args);
242}
243
244/* Implement "goto-bookmark" command. */
245
246static void
247goto_bookmark_command (char *args, int from_tty)
248{
249 struct bookmark *b;
250 unsigned long num;
251
252 if (args == NULL || args[0] == '\0')
253 error (_("Command requires an argument."));
254
255 if (strncmp (args, "start", strlen ("start")) == 0
256 || strncmp (args, "begin", strlen ("begin")) == 0
257 || strncmp (args, "end", strlen ("end")) == 0)
258 {
259 /* Special case. Give target opportunity to handle. */
260 target_goto_bookmark (args, from_tty);
261 return;
262 }
263
264 if (args[0] == '\'' || args[0] == '\"')
265 {
266 /* Special case -- quoted string. Pass on to target. */
267 if (args[strlen (args) - 1] != args[0])
268 error (_("Unbalanced quotes: %s"), args);
269 target_goto_bookmark (args, from_tty);
270 return;
271 }
272
273 /* General case. Bookmark identified by bookmark number. */
274 num = strtoul (args, NULL, 0);
275 ALL_BOOKMARKS (b)
276 if (b->number == num)
277 break;
278
279 if (b)
280 {
281 /* Found. Send to target method. */
282 target_goto_bookmark (b->opaque_data, from_tty);
283 return;
284 }
285 /* Not found. */
286 error (_("goto-bookmark: no bookmark found for '%s'."), args);
287}
288
289/* Implement "info bookmarks" command. */
290
291static void
292bookmarks_info (char *args, int from_tty)
293{
294 struct bookmark *b;
295 int bnum = -1;
296 struct gdbarch *gdbarch;
297
298 if (args)
299 bnum = parse_and_eval_long (args);
300
301 if (!bookmark_chain)
302 {
303 printf_filtered (_("No bookmarks.\n"));
304 return;
305 }
306
307 gdbarch = get_regcache_arch (get_current_regcache ());
308 printf_filtered (_("Bookmark Address Opaque\n"));
309 printf_filtered (_(" ID Data \n"));
310
311 ALL_BOOKMARKS (b)
312 printf_filtered (" %d %s '%s'\n",
313 b->number,
314 paddress (gdbarch, b->pc),
315 b->opaque_data);
316}
317
318
2c0b251b
PA
319/* Provide a prototype to silence -Wmissing-prototypes. */
320extern initialize_file_ftype _initialize_reverse;
321
b2175913
MS
322void
323_initialize_reverse (void)
324{
325 add_com ("reverse-step", class_run, reverse_step, _("\
326Step program backward until it reaches the beginning of another source line.\n\
327Argument N means do this N times (or till program stops for another reason).")
328 );
329 add_com_alias ("rs", "reverse-step", class_alias, 1);
330
331 add_com ("reverse-next", class_run, reverse_next, _("\
332Step program backward, proceeding through subroutine calls.\n\
333Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\
334when they do, the call is treated as one instruction.\n\
335Argument N means do this N times (or till program stops for another reason).")
336 );
337 add_com_alias ("rn", "reverse-next", class_alias, 1);
338
339 add_com ("reverse-stepi", class_run, reverse_stepi, _("\
340Step backward exactly one instruction.\n\
341Argument N means do this N times (or till program stops for another reason).")
342 );
343 add_com_alias ("rsi", "reverse-stepi", class_alias, 0);
344
345 add_com ("reverse-nexti", class_run, reverse_nexti, _("\
346Step backward one instruction, but proceed through called subroutines.\n\
347Argument N means do this N times (or till program stops for another reason).")
348 );
349 add_com_alias ("rni", "reverse-nexti", class_alias, 0);
350
351 add_com ("reverse-continue", class_run, reverse_continue, _("\
352Continue program being debugged but run it in reverse.\n\
353If proceeding from breakpoint, a number N may be used as an argument,\n\
354which means to set the ignore count of that breakpoint to N - 1 (so that\n\
355the breakpoint won't break until the Nth time it is reached)."));
356 add_com_alias ("rc", "reverse-continue", class_alias, 0);
357
358 add_com ("reverse-finish", class_run, reverse_finish, _("\
359Execute backward until just before selected stack frame is called."));
6b04bdb7
MS
360
361 add_com ("bookmark", class_bookmark, save_bookmark_command, _("\
362Set a bookmark in the program's execution history.\n\
363A bookmark represents a point in the execution history \n\
364that can be returned to at a later point in the debug session."));
365 add_info ("bookmarks", bookmarks_info, _("\
366Status of user-settable bookmarks.\n\
367Bookmarks are user-settable markers representing a point in the \n\
368execution history that can be returned to later in the same debug \n\
369session."));
370 add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\
371Delete a bookmark from the bookmark list.\n\
372Argument is a bookmark number, or no argument to delete all bookmarks.\n"),
373 &deletelist);
374 add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\
375Go to an earlier-bookmarked point in the program's execution history.\n\
376Argument is the bookmark number of a bookmark saved earlier by using \n\
377the 'bookmark' command, or the special arguments:\n\
378 start (beginning of recording)\n\
379 end (end of recording)\n"));
b2175913 380}
This page took 0.20783 seconds and 4 git commands to generate.