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