]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/reverse.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / reverse.c
CommitLineData
b2175913
MS
1/* Reverse execution and reverse debugging.
2
213516ef 3 Copyright (C) 2006-2023 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
05374cfd 47 if (!target_can_execute_reverse ())
d777bf0d 48 error (_("Target %s does not support this command."), target_shortname ());
b2175913 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 {
243cf0f6
TT
95 int number = 0;
96 CORE_ADDR pc = 0;
6b04bdb7 97 struct symtab_and_line sal;
243cf0f6 98 gdb::unique_xmalloc_ptr<gdb_byte> opaque_data;
6b04bdb7
MS
99};
100
243cf0f6 101static std::vector<struct bookmark> all_bookmarks;
6b04bdb7
MS
102static int bookmark_count;
103
6b04bdb7
MS
104/* save_bookmark_command -- implement "bookmark" command.
105 Call target method to get a bookmark identifier.
106 Insert bookmark identifier into list.
107
108 Identifier will be a malloc string (gdb_byte *).
109 Up to us to free it as required. */
110
111static void
0b39b52e 112save_bookmark_command (const char *args, int from_tty)
6b04bdb7
MS
113{
114 /* Get target's idea of a bookmark. */
115 gdb_byte *bookmark_id = target_get_bookmark (args, from_tty);
ac7936df 116 struct gdbarch *gdbarch = get_current_regcache ()->arch ();
6b04bdb7
MS
117
118 /* CR should not cause another identical bookmark. */
119 dont_repeat ();
120
121 if (bookmark_id == NULL)
122 error (_("target_get_bookmark failed."));
123
124 /* Set up a bookmark struct. */
243cf0f6
TT
125 all_bookmarks.emplace_back ();
126 bookmark &b = all_bookmarks.back ();
127 b.number = ++bookmark_count;
128 b.pc = regcache_read_pc (get_current_regcache ());
129 b.sal = find_pc_line (b.pc, 0);
130 b.sal.pspace = get_frame_program_space (get_current_frame ());
131 b.opaque_data.reset (bookmark_id);
132
133 gdb_printf (_("Saved bookmark %d at %s\n"), b.number,
134 paddress (gdbarch, b.sal.pc));
6b04bdb7
MS
135}
136
137/* Implement "delete bookmark" command. */
138
243cf0f6 139static bool
7d357efd 140delete_one_bookmark (int num)
6b04bdb7 141{
7d357efd 142 /* Find bookmark with corresponding number. */
243cf0f6
TT
143 for (auto iter = all_bookmarks.begin ();
144 iter != all_bookmarks.end ();
145 ++iter)
6b04bdb7 146 {
243cf0f6
TT
147 if (iter->number == num)
148 {
149 all_bookmarks.erase (iter);
150 return true;
151 }
6b04bdb7 152 }
243cf0f6 153 return false;
6b04bdb7
MS
154}
155
156static void
243cf0f6 157delete_all_bookmarks ()
6b04bdb7 158{
243cf0f6 159 all_bookmarks.clear ();
6b04bdb7
MS
160}
161
162static void
8949cb87 163delete_bookmark_command (const char *args, int from_tty)
6b04bdb7 164{
243cf0f6 165 if (all_bookmarks.empty ())
6b04bdb7
MS
166 {
167 warning (_("No bookmarks."));
168 return;
169 }
170
171 if (args == NULL || args[0] == '\0')
172 {
173 if (from_tty && !query (_("Delete all bookmarks? ")))
174 return;
175 delete_all_bookmarks ();
176 return;
177 }
178
bfd28288
PA
179 number_or_range_parser parser (args);
180 while (!parser.finished ())
7d357efd 181 {
bfd28288 182 int num = parser.get_number ();
7d357efd
MS
183 if (!delete_one_bookmark (num))
184 /* Not found. */
185 warning (_("No bookmark #%d."), num);
186 }
6b04bdb7
MS
187}
188
189/* Implement "goto-bookmark" command. */
190
191static void
0b39b52e 192goto_bookmark_command (const char *args, int from_tty)
6b04bdb7 193{
6b04bdb7 194 unsigned long num;
0b39b52e 195 const char *p = args;
6b04bdb7
MS
196
197 if (args == NULL || args[0] == '\0')
198 error (_("Command requires an argument."));
199
61012eef
GB
200 if (startswith (args, "start")
201 || startswith (args, "begin")
202 || startswith (args, "end"))
6b04bdb7
MS
203 {
204 /* Special case. Give target opportunity to handle. */
0f928d68 205 target_goto_bookmark ((gdb_byte *) args, from_tty);
6b04bdb7
MS
206 return;
207 }
208
209 if (args[0] == '\'' || args[0] == '\"')
210 {
211 /* Special case -- quoted string. Pass on to target. */
212 if (args[strlen (args) - 1] != args[0])
213 error (_("Unbalanced quotes: %s"), args);
0f928d68 214 target_goto_bookmark ((gdb_byte *) args, from_tty);
6b04bdb7
MS
215 return;
216 }
217
218 /* General case. Bookmark identified by bookmark number. */
7d357efd 219 num = get_number (&args);
0c13193f
YQ
220
221 if (num == 0)
222 error (_("goto-bookmark: invalid bookmark number '%s'."), p);
223
243cf0f6 224 for (const bookmark &iter : all_bookmarks)
6b04bdb7 225 {
243cf0f6
TT
226 if (iter.number == num)
227 {
228 /* Found. Send to target method. */
229 target_goto_bookmark (iter.opaque_data.get (), from_tty);
230 return;
231 }
6b04bdb7
MS
232 }
233 /* Not found. */
0c13193f 234 error (_("goto-bookmark: no bookmark found for '%s'."), p);
6b04bdb7
MS
235}
236
7d357efd
MS
237static int
238bookmark_1 (int bnum)
239{
ac7936df 240 struct gdbarch *gdbarch = get_current_regcache ()->arch ();
7d357efd
MS
241 int matched = 0;
242
243cf0f6
TT
243 for (const bookmark &iter : all_bookmarks)
244 {
245 if (bnum == -1 || bnum == iter.number)
246 {
247 gdb_printf (" %d %s '%s'\n",
248 iter.number,
249 paddress (gdbarch, iter.pc),
250 iter.opaque_data.get ());
251 matched++;
252 }
253 }
7d357efd
MS
254
255 if (bnum > 0 && matched == 0)
6cb06a8c 256 gdb_printf ("No bookmark #%d\n", bnum);
7d357efd
MS
257
258 return matched;
259}
260
6b04bdb7
MS
261/* Implement "info bookmarks" command. */
262
263static void
1d12d88f 264info_bookmarks_command (const char *args, int from_tty)
6b04bdb7 265{
243cf0f6 266 if (all_bookmarks.empty ())
6cb06a8c 267 gdb_printf (_("No bookmarks.\n"));
7d357efd
MS
268 else if (args == NULL || *args == '\0')
269 bookmark_1 (-1);
270 else
197f0a60 271 {
bfd28288
PA
272 number_or_range_parser parser (args);
273 while (!parser.finished ())
197f0a60 274 {
bfd28288 275 int bnum = parser.get_number ();
197f0a60
TT
276 bookmark_1 (bnum);
277 }
278 }
6b04bdb7
MS
279}
280
6c265988 281void _initialize_reverse ();
b2175913 282void
6c265988 283_initialize_reverse ()
b2175913 284{
3947f654
SM
285 cmd_list_element *reverse_step_cmd
286 = add_com ("reverse-step", class_run, reverse_step, _("\
b2175913 287Step program backward until it reaches the beginning of another source line.\n\
3947f654
SM
288Argument N means do this N times (or till program stops for another reason)."));
289 add_com_alias ("rs", reverse_step_cmd, class_run, 1);
b2175913 290
3947f654
SM
291 cmd_list_element *reverse_next_cmd
292 = add_com ("reverse-next", class_run, reverse_next, _("\
b2175913
MS
293Step program backward, proceeding through subroutine calls.\n\
294Like the \"reverse-step\" command as long as subroutine calls do not happen;\n\
295when they do, the call is treated as one instruction.\n\
3947f654
SM
296Argument N means do this N times (or till program stops for another reason)."));
297 add_com_alias ("rn", reverse_next_cmd, class_run, 1);
b2175913 298
3947f654
SM
299 cmd_list_element *reverse_stepi_cmd
300 = add_com ("reverse-stepi", class_run, reverse_stepi, _("\
b2175913 301Step backward exactly one instruction.\n\
3947f654
SM
302Argument N means do this N times (or till program stops for another reason)."));
303 add_com_alias ("rsi", reverse_stepi_cmd, class_run, 0);
b2175913 304
3947f654
SM
305 cmd_list_element *reverse_nexti_cmd
306 = add_com ("reverse-nexti", class_run, reverse_nexti, _("\
b2175913 307Step backward one instruction, but proceed through called subroutines.\n\
3947f654
SM
308Argument N means do this N times (or till program stops for another reason)."));
309 add_com_alias ("rni", reverse_nexti_cmd, class_run, 0);
b2175913 310
3947f654
SM
311 cmd_list_element *reverse_continue_cmd
312 = add_com ("reverse-continue", class_run, reverse_continue, _("\
b2175913
MS
313Continue program being debugged but run it in reverse.\n\
314If proceeding from breakpoint, a number N may be used as an argument,\n\
315which means to set the ignore count of that breakpoint to N - 1 (so that\n\
316the breakpoint won't break until the Nth time it is reached)."));
3947f654 317 add_com_alias ("rc", reverse_continue_cmd, class_run, 0);
b2175913
MS
318
319 add_com ("reverse-finish", class_run, reverse_finish, _("\
320Execute backward until just before selected stack frame is called."));
6b04bdb7
MS
321
322 add_com ("bookmark", class_bookmark, save_bookmark_command, _("\
323Set a bookmark in the program's execution history.\n\
324A bookmark represents a point in the execution history \n\
325that can be returned to at a later point in the debug session."));
11db9430 326 add_info ("bookmarks", info_bookmarks_command, _("\
6b04bdb7
MS
327Status of user-settable bookmarks.\n\
328Bookmarks are user-settable markers representing a point in the \n\
329execution history that can be returned to later in the same debug \n\
330session."));
331 add_cmd ("bookmark", class_bookmark, delete_bookmark_command, _("\
332Delete a bookmark from the bookmark list.\n\
7d357efd 333Argument is a bookmark number or numbers,\n\
89549d7f 334 or no argument to delete all bookmarks."),
6b04bdb7
MS
335 &deletelist);
336 add_com ("goto-bookmark", class_bookmark, goto_bookmark_command, _("\
337Go to an earlier-bookmarked point in the program's execution history.\n\
338Argument is the bookmark number of a bookmark saved earlier by using \n\
339the 'bookmark' command, or the special arguments:\n\
340 start (beginning of recording)\n\
89549d7f 341 end (end of recording)"));
b2175913 342}