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