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