constify some blockvector APIs
[deliverable/binutils-gdb.git] / gdb / reverse.c
CommitLineData
b2175913
MS
1/* Reverse execution and reverse debugging.
2
ecd75fc8 3 Copyright (C) 2006-2014 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"
0e9f083f 21#include <string.h>
b2175913
MS
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"
45741a9c 28#include "infrun.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
177b42fe 187 /* Find bookmark preceding "marked" one, so we can unlink. */
6b04bdb7
MS
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{
7d357efd 220 int num;
197f0a60 221 struct get_number_or_range_state state;
6b04bdb7
MS
222
223 if (bookmark_chain == NULL)
224 {
225 warning (_("No bookmarks."));
226 return;
227 }
228
229 if (args == NULL || args[0] == '\0')
230 {
231 if (from_tty && !query (_("Delete all bookmarks? ")))
232 return;
233 delete_all_bookmarks ();
234 return;
235 }
236
197f0a60
TT
237 init_number_or_range (&state, args);
238 while (!state.finished)
7d357efd 239 {
197f0a60 240 num = get_number_or_range (&state);
7d357efd
MS
241 if (!delete_one_bookmark (num))
242 /* Not found. */
243 warning (_("No bookmark #%d."), num);
244 }
6b04bdb7
MS
245}
246
247/* Implement "goto-bookmark" command. */
248
249static void
250goto_bookmark_command (char *args, int from_tty)
251{
252 struct bookmark *b;
253 unsigned long num;
0c13193f 254 char *p = args;
6b04bdb7
MS
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. */
0f928d68 264 target_goto_bookmark ((gdb_byte *) args, from_tty);
6b04bdb7
MS
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);
0f928d68 273 target_goto_bookmark ((gdb_byte *) args, from_tty);
6b04bdb7
MS
274 return;
275 }
276
277 /* General case. Bookmark identified by bookmark number. */
7d357efd 278 num = get_number (&args);
0c13193f
YQ
279
280 if (num == 0)
281 error (_("goto-bookmark: invalid bookmark number '%s'."), p);
282
6b04bdb7
MS
283 ALL_BOOKMARKS (b)
284 if (b->number == num)
285 break;
286
287 if (b)
288 {
289 /* Found. Send to target method. */
290 target_goto_bookmark (b->opaque_data, from_tty);
291 return;
292 }
293 /* Not found. */
0c13193f 294 error (_("goto-bookmark: no bookmark found for '%s'."), p);
6b04bdb7
MS
295}
296
7d357efd
MS
297static int
298bookmark_1 (int bnum)
299{
300 struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
301 struct bookmark *b;
302 int matched = 0;
303
304 ALL_BOOKMARKS (b)
305 {
306 if (bnum == -1 || bnum == b->number)
307 {
308 printf_filtered (" %d %s '%s'\n",
309 b->number,
310 paddress (gdbarch, b->pc),
311 b->opaque_data);
312 matched++;
313 }
314 }
315
316 if (bnum > 0 && matched == 0)
317 printf_filtered ("No bookmark #%d\n", bnum);
318
319 return matched;
320}
321
6b04bdb7
MS
322/* Implement "info bookmarks" command. */
323
324static void
325bookmarks_info (char *args, int from_tty)
326{
6b04bdb7 327 int bnum = -1;
6b04bdb7
MS
328
329 if (!bookmark_chain)
7d357efd
MS
330 printf_filtered (_("No bookmarks.\n"));
331 else if (args == NULL || *args == '\0')
332 bookmark_1 (-1);
333 else
197f0a60
TT
334 {
335 struct get_number_or_range_state state;
336
337 init_number_or_range (&state, args);
338 while (!state.finished)
339 {
340 bnum = get_number_or_range (&state);
341 bookmark_1 (bnum);
342 }
343 }
6b04bdb7
MS
344}
345
346
2c0b251b
PA
347/* Provide a prototype to silence -Wmissing-prototypes. */
348extern initialize_file_ftype _initialize_reverse;
349
b2175913
MS
350void
351_initialize_reverse (void)
352{
353 add_com ("reverse-step", class_run, reverse_step, _("\
354Step program backward until it reaches the beginning of another source line.\n\
355Argument N means do this N times (or till program stops for another reason).")
356 );
357 add_com_alias ("rs", "reverse-step", class_alias, 1);
358
359 add_com ("reverse-next", class_run, reverse_next, _("\
360Step program backward, proceeding through subroutine calls.\n\
361Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\
362when they do, the call is treated as one instruction.\n\
363Argument N means do this N times (or till program stops for another reason).")
364 );
365 add_com_alias ("rn", "reverse-next", class_alias, 1);
366
367 add_com ("reverse-stepi", class_run, reverse_stepi, _("\
368Step backward exactly one instruction.\n\
369Argument N means do this N times (or till program stops for another reason).")
370 );
371 add_com_alias ("rsi", "reverse-stepi", class_alias, 0);
372
373 add_com ("reverse-nexti", class_run, reverse_nexti, _("\
374Step backward one instruction, but proceed through called subroutines.\n\
375Argument N means do this N times (or till program stops for another reason).")
376 );
377 add_com_alias ("rni", "reverse-nexti", class_alias, 0);
378
379 add_com ("reverse-continue", class_run, reverse_continue, _("\
380Continue program being debugged but run it in reverse.\n\
381If proceeding from breakpoint, a number N may be used as an argument,\n\
382which means to set the ignore count of that breakpoint to N - 1 (so that\n\
383the breakpoint won't break until the Nth time it is reached)."));
384 add_com_alias ("rc", "reverse-continue", class_alias, 0);
385
386 add_com ("reverse-finish", class_run, reverse_finish, _("\
387Execute backward until just before selected stack frame is called."));
6b04bdb7
MS
388
389 add_com ("bookmark", class_bookmark, save_bookmark_command, _("\
390Set a bookmark in the program's execution history.\n\
391A bookmark represents a point in the execution history \n\
392that can be returned to at a later point in the debug session."));
393 add_info ("bookmarks", bookmarks_info, _("\
394Status of user-settable bookmarks.\n\
395Bookmarks are user-settable markers representing a point in the \n\
396execution history that can be returned to later in the same debug \n\
397session."));
398 add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\
399Delete a bookmark from the bookmark list.\n\
7d357efd
MS
400Argument is a bookmark number or numbers,\n\
401 or no argument to delete all bookmarks.\n"),
6b04bdb7
MS
402 &deletelist);
403 add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\
404Go to an earlier-bookmarked point in the program's execution history.\n\
405Argument is the bookmark number of a bookmark saved earlier by using \n\
406the 'bookmark' command, or the special arguments:\n\
407 start (beginning of recording)\n\
408 end (end of recording)\n"));
b2175913 409}
This page took 0.655567 seconds and 4 git commands to generate.