1 /* Process record and replay target for GDB, the GNU debugger.
3 Copyright (C) 2008-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "cli/cli-cmds.h"
21 #include "completer.h"
23 #include "observable.h"
25 #include "gdbsupport/common-utils.h"
26 #include "cli/cli-utils.h"
33 /* This is the debug switch for process record. */
34 unsigned int record_debug
= 0;
36 /* The number of instructions to print in "record instruction-history". */
37 static unsigned int record_insn_history_size
= 10;
39 /* The variable registered as control variable in the "record
40 instruction-history" command. Necessary for extra input
42 static unsigned int record_insn_history_size_setshow_var
;
44 /* The number of functions to print in "record function-call-history". */
45 static unsigned int record_call_history_size
= 10;
47 /* The variable registered as control variable in the "record
48 call-history" command. Necessary for extra input validation. */
49 static unsigned int record_call_history_size_setshow_var
;
51 struct cmd_list_element
*record_cmdlist
= NULL
;
52 static struct cmd_list_element
*record_goto_cmdlist
= NULL
;
53 struct cmd_list_element
*set_record_cmdlist
= NULL
;
54 struct cmd_list_element
*show_record_cmdlist
= NULL
;
55 struct cmd_list_element
*info_record_cmdlist
= NULL
;
57 #define DEBUG(msg, args...) \
59 gdb_printf (gdb_stdlog, "record: " msg "\n", ##args)
64 find_record_target (void)
66 return find_target_at (record_stratum
);
69 /* Check that recording is active. Throw an error, if it isn't. */
71 static struct target_ops
*
72 require_record_target (void)
76 t
= find_record_target ();
78 error (_("No recording is currently active.\n"
79 "Use the \"record full\" or \"record btrace\" command first."));
89 /* Check if a record target is already running. */
90 if (find_record_target () != NULL
)
91 error (_("The process is already being recorded. Use \"record stop\" to "
92 "stop recording first."));
98 record_start (const char *method
, const char *format
, int from_tty
)
103 execute_command_to_string ("record", from_tty
, false);
105 error (_("Invalid format."));
107 else if (strcmp (method
, "full") == 0)
110 execute_command_to_string ("record full", from_tty
, false);
112 error (_("Invalid format."));
114 else if (strcmp (method
, "btrace") == 0)
117 execute_command_to_string ("record btrace", from_tty
, false);
118 else if (strcmp (format
, "bts") == 0)
119 execute_command_to_string ("record btrace bts", from_tty
, false);
120 else if (strcmp (format
, "pt") == 0)
121 execute_command_to_string ("record btrace pt", from_tty
, false);
123 error (_("Invalid format."));
126 error (_("Invalid method."));
132 record_stop (int from_tty
)
134 execute_command_to_string ("record stop", from_tty
, false);
140 record_read_memory (struct gdbarch
*gdbarch
,
141 CORE_ADDR memaddr
, gdb_byte
*myaddr
,
144 int ret
= target_read_memory (memaddr
, myaddr
, len
);
147 DEBUG ("error reading memory at addr %s len = %ld.\n",
148 paddress (gdbarch
, memaddr
), (long) len
);
153 /* Stop recording. */
156 record_stop (struct target_ops
*t
)
158 DEBUG ("stop %s", t
->shortname ());
160 t
->stop_recording ();
163 /* Unpush the record target. */
166 record_unpush (struct target_ops
*t
)
168 DEBUG ("unpush %s", t
->shortname ());
170 current_inferior ()->unpush_target (t
);
176 record_disconnect (struct target_ops
*t
, const char *args
, int from_tty
)
178 gdb_assert (t
->stratum () == record_stratum
);
180 DEBUG ("disconnect %s", t
->shortname ());
185 target_disconnect (args
, from_tty
);
191 record_detach (struct target_ops
*t
, inferior
*inf
, int from_tty
)
193 gdb_assert (t
->stratum () == record_stratum
);
195 DEBUG ("detach %s", t
->shortname ());
200 target_detach (inf
, from_tty
);
206 record_mourn_inferior (struct target_ops
*t
)
208 gdb_assert (t
->stratum () == record_stratum
);
210 DEBUG ("mourn inferior %s", t
->shortname ());
212 /* It is safer to not stop recording. Resources will be freed when
213 threads are discarded. */
216 target_mourn_inferior (inferior_ptid
);
222 record_kill (struct target_ops
*t
)
224 gdb_assert (t
->stratum () == record_stratum
);
226 DEBUG ("kill %s", t
->shortname ());
228 /* It is safer to not stop recording. Resources will be freed when
229 threads are discarded. */
238 record_check_stopped_by_breakpoint (const address_space
*aspace
,
240 enum target_stop_reason
*reason
)
242 if (breakpoint_inserted_here_p (aspace
, pc
))
244 if (hardware_breakpoint_inserted_here_p (aspace
, pc
))
245 *reason
= TARGET_STOPPED_BY_HW_BREAKPOINT
;
247 *reason
= TARGET_STOPPED_BY_SW_BREAKPOINT
;
254 /* Implement "show record debug" command. */
257 show_record_debug (struct ui_file
*file
, int from_tty
,
258 struct cmd_list_element
*c
, const char *value
)
260 gdb_printf (file
, _("Debugging of process record target is %s.\n"),
264 /* Alias for "target record-full". */
267 cmd_record_start (const char *args
, int from_tty
)
269 /* As 'record' is a prefix command then if the user types 'record blah'
270 GDB will search for the 'blah' sub-command and either run that instead
271 of calling this function, or throw an error if 'blah' doesn't exist.
272 As a result, we only get here if no args are given. */
273 gdb_assert (args
== nullptr);
274 execute_command ("target record-full", from_tty
);
277 /* Truncate the record log from the present point
278 of replay until the end. */
281 cmd_record_delete (const char *args
, int from_tty
)
283 require_record_target ();
285 if (!target_record_is_replaying (inferior_ptid
))
287 gdb_printf (_("Already at end of record list.\n"));
291 if (!target_supports_delete_record ())
293 gdb_printf (_("The current record target does not support "
294 "this operation.\n"));
298 if (!from_tty
|| query (_("Delete the log from this point forward "
299 "and begin to record the running message "
301 target_delete_record ();
304 /* Implement the "stoprecord" or "record stop" command. */
307 cmd_record_stop (const char *args
, int from_tty
)
309 struct target_ops
*t
;
311 t
= require_record_target ();
316 gdb_printf (_("Process record is stopped and all execution "
317 "logs are deleted.\n"));
319 interps_notify_record_changed (current_inferior (), 0, NULL
, NULL
);
323 /* The "info record" command. */
326 info_record_command (const char *args
, int from_tty
)
328 struct target_ops
*t
;
330 t
= find_record_target ();
333 gdb_printf (_("No recording is currently active.\n"));
337 gdb_printf (_("Active record target: %s\n"), t
->shortname ());
341 /* The "record save" command. */
344 cmd_record_save (const char *args
, int from_tty
)
346 const char *recfilename
;
347 char recfilename_buffer
[40];
349 require_record_target ();
351 if (args
!= NULL
&& *args
!= 0)
355 /* Default recfile name is "gdb_record.PID". */
356 xsnprintf (recfilename_buffer
, sizeof (recfilename_buffer
),
357 "gdb_record.%d", inferior_ptid
.pid ());
358 recfilename
= recfilename_buffer
;
361 target_save_record (recfilename
);
367 record_goto (const char *arg
)
371 if (arg
== NULL
|| *arg
== '\0')
372 error (_("Command requires an argument (insn number to go to)."));
374 insn
= parse_and_eval_long (arg
);
376 require_record_target ();
377 target_goto_record (insn
);
380 /* "record goto" command. Argument is an instruction number,
381 as given by "info record".
383 Rewinds the recording (forward or backward) to the given instruction. */
386 cmd_record_goto (const char *arg
, int from_tty
)
391 /* The "record goto begin" command. */
394 cmd_record_goto_begin (const char *arg
, int from_tty
)
396 if (arg
!= NULL
&& *arg
!= '\0')
397 error (_("Junk after argument: %s."), arg
);
399 require_record_target ();
400 target_goto_record_begin ();
403 /* The "record goto end" command. */
406 cmd_record_goto_end (const char *arg
, int from_tty
)
408 if (arg
!= NULL
&& *arg
!= '\0')
409 error (_("Junk after argument: %s."), arg
);
411 require_record_target ();
412 target_goto_record_end ();
415 /* Read an instruction number from an argument string. */
418 get_insn_number (const char **arg
)
421 const char *begin
, *end
, *pos
;
424 pos
= skip_spaces (begin
);
427 error (_("Expected positive number, got: %s."), pos
);
429 number
= strtoulst (pos
, &end
, 10);
431 *arg
+= (end
- begin
);
436 /* Read a context size from an argument string. */
439 get_context_size (const char **arg
)
444 pos
= skip_spaces (*arg
);
447 error (_("Expected positive number, got: %s."), pos
);
449 long result
= strtol (pos
, &end
, 10);
454 /* Complain about junk at the end of an argument string. */
457 no_chunk (const char *arg
)
460 error (_("Junk after argument: %s."), arg
);
463 /* Read instruction-history modifiers from an argument string. */
465 static gdb_disassembly_flags
466 get_insn_history_modifiers (const char **arg
)
468 gdb_disassembly_flags modifiers
;
482 error (_("Missing modifier."));
484 for (; *args
; ++args
)
495 modifiers
|= DISASSEMBLY_OMIT_AUX_INSN
;
499 modifiers
|= DISASSEMBLY_SOURCE
;
500 modifiers
|= DISASSEMBLY_FILENAME
;
503 modifiers
|= DISASSEMBLY_RAW_INSN
;
506 modifiers
|= DISASSEMBLY_RAW_BYTES
;
509 modifiers
|= DISASSEMBLY_OMIT_FNAME
;
512 modifiers
|= DISASSEMBLY_OMIT_PC
;
515 error (_("Invalid modifier: %c."), *args
);
519 args
= skip_spaces (args
);
522 /* Update the argument string. */
528 /* The "set record instruction-history-size / set record
529 function-call-history-size" commands are unsigned, with UINT_MAX
530 meaning unlimited. The target interfaces works with signed int
531 though, to indicate direction, so map "unlimited" to INT_MAX, which
532 is about the same as unlimited in practice. If the user does have
533 a log that huge, she can fetch it in chunks across several requests,
534 but she'll likely have other problems first... */
537 command_size_to_target_size (unsigned int size
)
539 gdb_assert (size
<= INT_MAX
|| size
== UINT_MAX
);
541 if (size
== UINT_MAX
)
547 /* The "record instruction-history" command. */
550 cmd_record_insn_history (const char *arg
, int from_tty
)
552 require_record_target ();
554 gdb_disassembly_flags flags
= get_insn_history_modifiers (&arg
);
556 int size
= command_size_to_target_size (record_insn_history_size
);
558 if (arg
== NULL
|| *arg
== 0 || strcmp (arg
, "+") == 0)
559 target_insn_history (size
, flags
);
560 else if (strcmp (arg
, "-") == 0)
561 target_insn_history (-size
, flags
);
566 begin
= get_insn_number (&arg
);
570 arg
= skip_spaces (++arg
);
575 size
= get_context_size (&arg
);
579 target_insn_history_from (begin
, size
, flags
);
581 else if (*arg
== '-')
584 size
= get_context_size (&arg
);
588 target_insn_history_from (begin
, -size
, flags
);
592 end
= get_insn_number (&arg
);
596 target_insn_history_range (begin
, end
, flags
);
603 target_insn_history_from (begin
, size
, flags
);
610 /* Read function-call-history modifiers from an argument string. */
612 static record_print_flags
613 get_call_history_modifiers (const char **arg
)
615 record_print_flags modifiers
= 0;
616 const char *args
= *arg
;
626 error (_("Missing modifier."));
628 for (; *args
; ++args
)
639 modifiers
|= RECORD_PRINT_SRC_LINE
;
642 modifiers
|= RECORD_PRINT_INSN_RANGE
;
645 modifiers
|= RECORD_PRINT_INDENT_CALLS
;
648 modifiers
|= RECORD_DONT_PRINT_AUX
;
651 error (_("Invalid modifier: %c."), *args
);
655 args
= skip_spaces (args
);
658 /* Update the argument string. */
664 /* The "record function-call-history" command. */
667 cmd_record_call_history (const char *arg
, int from_tty
)
669 require_record_target ();
671 record_print_flags flags
= get_call_history_modifiers (&arg
);
673 int size
= command_size_to_target_size (record_call_history_size
);
675 if (arg
== NULL
|| *arg
== 0 || strcmp (arg
, "+") == 0)
676 target_call_history (size
, flags
);
677 else if (strcmp (arg
, "-") == 0)
678 target_call_history (-size
, flags
);
683 begin
= get_insn_number (&arg
);
687 arg
= skip_spaces (++arg
);
692 size
= get_context_size (&arg
);
696 target_call_history_from (begin
, size
, flags
);
698 else if (*arg
== '-')
701 size
= get_context_size (&arg
);
705 target_call_history_from (begin
, -size
, flags
);
709 end
= get_insn_number (&arg
);
713 target_call_history_range (begin
, end
, flags
);
720 target_call_history_from (begin
, size
, flags
);
727 /* Helper for "set record instruction-history-size" and "set record
728 function-call-history-size" input validation. COMMAND_VAR is the
729 variable registered in the command as control variable. *SETTING
730 is the real setting the command allows changing. */
733 validate_history_size (unsigned int *command_var
, unsigned int *setting
)
735 if (*command_var
!= UINT_MAX
&& *command_var
> INT_MAX
)
737 unsigned int new_value
= *command_var
;
739 /* Restore previous value. */
740 *command_var
= *setting
;
741 error (_("integer %u out of range"), new_value
);
744 /* Commit new value. */
745 *setting
= *command_var
;
748 /* Called by do_setshow_command. We only want values in the
749 [0..INT_MAX] range, while the command's machinery accepts
750 [0..UINT_MAX]. See command_size_to_target_size. */
753 set_record_insn_history_size (const char *args
, int from_tty
,
754 struct cmd_list_element
*c
)
756 validate_history_size (&record_insn_history_size_setshow_var
,
757 &record_insn_history_size
);
760 /* Called by do_setshow_command. We only want values in the
761 [0..INT_MAX] range, while the command's machinery accepts
762 [0..UINT_MAX]. See command_size_to_target_size. */
765 set_record_call_history_size (const char *args
, int from_tty
,
766 struct cmd_list_element
*c
)
768 validate_history_size (&record_call_history_size_setshow_var
,
769 &record_call_history_size
);
772 void _initialize_record ();
774 _initialize_record ()
776 struct cmd_list_element
*c
;
778 add_setshow_zuinteger_cmd ("record", no_class
, &record_debug
,
779 _("Set debugging of record/replay feature."),
780 _("Show debugging of record/replay feature."),
781 _("When enabled, debugging output for "
782 "record/replay feature is displayed."),
783 NULL
, show_record_debug
, &setdebuglist
,
786 add_setshow_uinteger_cmd ("instruction-history-size", no_class
,
787 &record_insn_history_size_setshow_var
, _("\
788 Set number of instructions to print in \"record instruction-history\"."), _("\
789 Show number of instructions to print in \"record instruction-history\"."), _("\
790 A size of \"unlimited\" means unlimited instructions. The default is 10."),
791 set_record_insn_history_size
, NULL
,
792 &set_record_cmdlist
, &show_record_cmdlist
);
794 add_setshow_uinteger_cmd ("function-call-history-size", no_class
,
795 &record_call_history_size_setshow_var
, _("\
796 Set number of function to print in \"record function-call-history\"."), _("\
797 Show number of functions to print in \"record function-call-history\"."), _("\
798 A size of \"unlimited\" means unlimited lines. The default is 10."),
799 set_record_call_history_size
, NULL
,
800 &set_record_cmdlist
, &show_record_cmdlist
);
802 cmd_list_element
*record_cmd
803 = add_prefix_cmd ("record", class_obscure
, cmd_record_start
,
804 _("Start recording."),
805 &record_cmdlist
, 0, &cmdlist
);
806 add_com_alias ("rec", record_cmd
, class_obscure
, 1);
808 set_show_commands setshow_record_cmds
809 = add_setshow_prefix_cmd ("record", class_support
,
810 _("Set record options."),
811 _("Show record options."),
812 &set_record_cmdlist
, &show_record_cmdlist
,
813 &setlist
, &showlist
);
816 add_alias_cmd ("rec", setshow_record_cmds
.set
, class_obscure
, 1, &setlist
);
817 add_alias_cmd ("rec", setshow_record_cmds
.show
, class_obscure
, 1, &showlist
);
819 cmd_list_element
*info_record_cmd
820 = add_prefix_cmd ("record", class_support
, info_record_command
,
821 _("Info record options."), &info_record_cmdlist
,
823 add_alias_cmd ("rec", info_record_cmd
, class_obscure
, 1, &infolist
);
825 c
= add_cmd ("save", class_obscure
, cmd_record_save
,
826 _("Save the execution log to a file.\n\
827 Usage: record save [FILENAME]\n\
828 Default filename is 'gdb_record.PROCESS_ID'."),
830 set_cmd_completer (c
, deprecated_filename_completer
);
832 cmd_list_element
*record_delete_cmd
833 = add_cmd ("delete", class_obscure
, cmd_record_delete
,
834 _("Delete the rest of execution log and start recording it \
837 add_alias_cmd ("d", record_delete_cmd
, class_obscure
, 1, &record_cmdlist
);
838 add_alias_cmd ("del", record_delete_cmd
, class_obscure
, 1, &record_cmdlist
);
840 cmd_list_element
*record_stop_cmd
841 = add_cmd ("stop", class_obscure
, cmd_record_stop
,
842 _("Stop the record/replay target."),
844 add_alias_cmd ("s", record_stop_cmd
, class_obscure
, 1, &record_cmdlist
);
846 add_prefix_cmd ("goto", class_obscure
, cmd_record_goto
, _("\
847 Restore the program to its state at instruction number N.\n\
848 Argument is instruction number, as shown by 'info record'."),
849 &record_goto_cmdlist
, 1, &record_cmdlist
);
851 cmd_list_element
*record_goto_begin_cmd
852 = add_cmd ("begin", class_obscure
, cmd_record_goto_begin
,
853 _("Go to the beginning of the execution log."),
854 &record_goto_cmdlist
);
855 add_alias_cmd ("start", record_goto_begin_cmd
, class_obscure
, 1,
856 &record_goto_cmdlist
);
858 add_cmd ("end", class_obscure
, cmd_record_goto_end
,
859 _("Go to the end of the execution log."),
860 &record_goto_cmdlist
);
862 add_cmd ("instruction-history", class_obscure
, cmd_record_insn_history
, _("\
863 Print disassembled instructions stored in the execution log.\n\
864 With a /m or /s modifier, source lines are included (if available).\n\
865 With a /r modifier, raw instructions in hex are included.\n\
866 With a /f modifier, function names are omitted.\n\
867 With a /p modifier, current position markers are omitted.\n\
868 With a /a modifier, omits output of auxiliary data, which is enabled\n\
870 With no argument, disassembles ten more instructions after the previous\n\
872 \"record instruction-history -\" disassembles ten instructions before a\n\
873 previous disassembly.\n\
874 One argument specifies an instruction number as shown by 'info record', and\n\
875 ten instructions are disassembled after that instruction.\n\
876 Two arguments with comma between them specify starting and ending instruction\n\
877 numbers to disassemble.\n\
878 If the second argument is preceded by '+' or '-', it specifies the distance\n\
879 from the first argument.\n\
880 The number of instructions to disassemble can be defined with\n\
881 \"set record instruction-history-size\"."),
884 add_cmd ("function-call-history", class_obscure
, cmd_record_call_history
, _("\
885 Prints the execution history at function granularity.\n\
886 It prints one line for each sequence of instructions that belong to the same\n\
888 Without modifiers, it prints the function name.\n\
889 With a /l modifier, the source file and line number range is included.\n\
890 With a /i modifier, the instruction number range is included.\n\
891 With a /c modifier, the output is indented based on the call stack depth.\n\
892 With a /a modifier, omits output of auxiliary data, which is enabled \
894 With no argument, prints ten more lines after the previous ten-line print.\n\
895 \"record function-call-history -\" prints ten lines before a previous ten-line\n\
897 One argument specifies a function number as shown by 'info record', and\n\
898 ten lines are printed after that function.\n\
899 Two arguments with comma between them specify a range of functions to print.\n\
900 If the second argument is preceded by '+' or '-', it specifies the distance\n\
901 from the first argument.\n\
902 The number of functions to print can be defined with\n\
903 \"set record function-call-history-size\"."),
906 /* Sync command control variables. */
907 record_insn_history_size_setshow_var
= record_insn_history_size
;
908 record_call_history_size_setshow_var
= record_call_history_size
;