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