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