X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Frecord.c;h=828c19968a3d9fb92f04fff12d66bec1abc164b2;hb=HEAD;hp=1af134f68fe870f06086f260ffcc1b519a995b9d;hpb=38b022b4452f996fb5a8598f80d850b594621bcf;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdb/record.c b/gdb/record.c index 1af134f68fe..b25445713fd 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -1,6 +1,6 @@ /* Process record and replay target for GDB, the GNU debugger. - Copyright (C) 2008-2016 Free Software Foundation, Inc. + Copyright (C) 2008-2024 Free Software Foundation, Inc. This file is part of GDB. @@ -17,15 +17,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "defs.h" -#include "gdbcmd.h" +#include "cli/cli-cmds.h" #include "completer.h" #include "record.h" -#include "observer.h" +#include "observable.h" #include "inferior.h" -#include "common/common-utils.h" +#include "gdbsupport/common-utils.h" #include "cli/cli-utils.h" #include "disasm.h" +#include "interps.h" +#include "top.h" #include @@ -48,14 +49,14 @@ static unsigned int record_call_history_size = 10; static unsigned int record_call_history_size_setshow_var; struct cmd_list_element *record_cmdlist = NULL; -struct cmd_list_element *record_goto_cmdlist = NULL; +static struct cmd_list_element *record_goto_cmdlist = NULL; struct cmd_list_element *set_record_cmdlist = NULL; struct cmd_list_element *show_record_cmdlist = NULL; struct cmd_list_element *info_record_cmdlist = NULL; #define DEBUG(msg, args...) \ if (record_debug) \ - fprintf_unfiltered (gdb_stdlog, "record: " msg "\n", ##args) + gdb_printf (gdb_stdlog, "record: " msg "\n", ##args) /* See record.h. */ @@ -74,8 +75,8 @@ require_record_target (void) t = find_record_target (); if (t == NULL) - error (_("No record target is currently active.\n" - "Use one of the \"target record-\" commands first.")); + error (_("No recording is currently active.\n" + "Use the \"record full\" or \"record btrace\" command first.")); return t; } @@ -93,6 +94,48 @@ record_preopen (void) /* See record.h. */ +void +record_start (const char *method, const char *format, int from_tty) +{ + if (method == NULL) + { + if (format == NULL) + execute_command_to_string ("record", from_tty, false); + else + error (_("Invalid format.")); + } + else if (strcmp (method, "full") == 0) + { + if (format == NULL) + execute_command_to_string ("record full", from_tty, false); + else + error (_("Invalid format.")); + } + else if (strcmp (method, "btrace") == 0) + { + if (format == NULL) + execute_command_to_string ("record btrace", from_tty, false); + else if (strcmp (format, "bts") == 0) + execute_command_to_string ("record btrace bts", from_tty, false); + else if (strcmp (format, "pt") == 0) + execute_command_to_string ("record btrace pt", from_tty, false); + else + error (_("Invalid format.")); + } + else + error (_("Invalid method.")); +} + +/* See record.h. */ + +void +record_stop (int from_tty) +{ + execute_command_to_string ("record stop", from_tty, false); +} + +/* See record.h. */ + int record_read_memory (struct gdbarch *gdbarch, CORE_ADDR memaddr, gdb_byte *myaddr, @@ -112,9 +155,9 @@ record_read_memory (struct gdbarch *gdbarch, static void record_stop (struct target_ops *t) { - DEBUG ("stop %s", t->to_shortname); + DEBUG ("stop %s", t->shortname ()); - t->to_stop_recording (t); + t->stop_recording (); } /* Unpush the record target. */ @@ -122,9 +165,9 @@ record_stop (struct target_ops *t) static void record_unpush (struct target_ops *t) { - DEBUG ("unpush %s", t->to_shortname); + DEBUG ("unpush %s", t->shortname ()); - unpush_target (t); + current_inferior ()->unpush_target (t); } /* See record.h. */ @@ -132,9 +175,9 @@ record_unpush (struct target_ops *t) void record_disconnect (struct target_ops *t, const char *args, int from_tty) { - gdb_assert (t->to_stratum == record_stratum); + gdb_assert (t->stratum () == record_stratum); - DEBUG ("disconnect %s", t->to_shortname); + DEBUG ("disconnect %s", t->shortname ()); record_stop (t); record_unpush (t); @@ -145,16 +188,16 @@ record_disconnect (struct target_ops *t, const char *args, int from_tty) /* See record.h. */ void -record_detach (struct target_ops *t, const char *args, int from_tty) +record_detach (struct target_ops *t, inferior *inf, int from_tty) { - gdb_assert (t->to_stratum == record_stratum); + gdb_assert (t->stratum () == record_stratum); - DEBUG ("detach %s", t->to_shortname); + DEBUG ("detach %s", t->shortname ()); record_stop (t); record_unpush (t); - target_detach (args, from_tty); + target_detach (inf, from_tty); } /* See record.h. */ @@ -162,15 +205,15 @@ record_detach (struct target_ops *t, const char *args, int from_tty) void record_mourn_inferior (struct target_ops *t) { - gdb_assert (t->to_stratum == record_stratum); + gdb_assert (t->stratum () == record_stratum); - DEBUG ("mourn inferior %s", t->to_shortname); + DEBUG ("mourn inferior %s", t->shortname ()); /* It is safer to not stop recording. Resources will be freed when threads are discarded. */ record_unpush (t); - target_mourn_inferior (); + target_mourn_inferior (inferior_ptid); } /* See record.h. */ @@ -178,9 +221,9 @@ record_mourn_inferior (struct target_ops *t) void record_kill (struct target_ops *t) { - gdb_assert (t->to_stratum == record_stratum); + gdb_assert (t->stratum () == record_stratum); - DEBUG ("kill %s", t->to_shortname); + DEBUG ("kill %s", t->shortname ()); /* It is safer to not stop recording. Resources will be freed when threads are discarded. */ @@ -192,7 +235,8 @@ record_kill (struct target_ops *t) /* See record.h. */ int -record_check_stopped_by_breakpoint (struct address_space *aspace, CORE_ADDR pc, +record_check_stopped_by_breakpoint (const address_space *aspace, + CORE_ADDR pc, enum target_stop_reason *reason) { if (breakpoint_inserted_here_p (aspace, pc)) @@ -204,7 +248,6 @@ record_check_stopped_by_breakpoint (struct address_space *aspace, CORE_ADDR pc, return 1; } - *reason = TARGET_STOPPED_BY_NO_REASON; return 0; } @@ -214,15 +257,20 @@ static void show_record_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Debugging of process record target is %s.\n"), - value); + gdb_printf (file, _("Debugging of process record target is %s.\n"), + value); } -/* Alias for "target record". */ +/* Alias for "target record-full". */ static void -cmd_record_start (char *args, int from_tty) +cmd_record_start (const char *args, int from_tty) { + /* As 'record' is a prefix command then if the user types 'record blah' + GDB will search for the 'blah' sub-command and either run that instead + of calling this function, or throw an error if 'blah' doesn't exist. + As a result, we only get here if no args are given. */ + gdb_assert (args == nullptr); execute_command ("target record-full", from_tty); } @@ -230,20 +278,20 @@ cmd_record_start (char *args, int from_tty) of replay until the end. */ static void -cmd_record_delete (char *args, int from_tty) +cmd_record_delete (const char *args, int from_tty) { require_record_target (); if (!target_record_is_replaying (inferior_ptid)) { - printf_unfiltered (_("Already at end of record list.\n")); + gdb_printf (_("Already at end of record list.\n")); return; } if (!target_supports_delete_record ()) { - printf_unfiltered (_("The current record target does not support " - "this operation.\n")); + gdb_printf (_("The current record target does not support " + "this operation.\n")); return; } @@ -256,7 +304,7 @@ cmd_record_delete (char *args, int from_tty) /* Implement the "stoprecord" or "record stop" command. */ static void -cmd_record_stop (char *args, int from_tty) +cmd_record_stop (const char *args, int from_tty) { struct target_ops *t; @@ -265,54 +313,38 @@ cmd_record_stop (char *args, int from_tty) record_stop (t); record_unpush (t); - printf_unfiltered (_("Process record is stopped and all execution " - "logs are deleted.\n")); + gdb_printf (_("Process record is stopped and all execution " + "logs are deleted.\n")); - observer_notify_record_changed (current_inferior (), 0, NULL, NULL); + interps_notify_record_changed (current_inferior (), 0, NULL, NULL); } -/* The "set record" command. */ - -static void -set_record_command (char *args, int from_tty) -{ - printf_unfiltered (_("\"set record\" must be followed " - "by an apporpriate subcommand.\n")); - help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout); -} - -/* The "show record" command. */ - -static void -show_record_command (char *args, int from_tty) -{ - cmd_show_list (show_record_cmdlist, from_tty, ""); -} /* The "info record" command. */ static void -info_record_command (char *args, int from_tty) +info_record_command (const char *args, int from_tty) { struct target_ops *t; t = find_record_target (); if (t == NULL) { - printf_filtered (_("No record target is currently active.\n")); + gdb_printf (_("No recording is currently active.\n")); return; } - printf_filtered (_("Active record target: %s\n"), t->to_shortname); - t->to_info_record (t); + gdb_printf (_("Active record target: %s\n"), t->shortname ()); + t->info_record (); } /* The "record save" command. */ static void -cmd_record_save (char *args, int from_tty) +cmd_record_save (const char *args, int from_tty) { - char *recfilename, recfilename_buffer[40]; + const char *recfilename; + char recfilename_buffer[40]; require_record_target (); @@ -322,7 +354,7 @@ cmd_record_save (char *args, int from_tty) { /* Default recfile name is "gdb_record.PID". */ xsnprintf (recfilename_buffer, sizeof (recfilename_buffer), - "gdb_record.%d", ptid_get_pid (inferior_ptid)); + "gdb_record.%d", inferior_ptid.pid ()); recfilename = recfilename_buffer; } @@ -351,7 +383,7 @@ record_goto (const char *arg) Rewinds the recording (forward or backward) to the given instruction. */ static void -cmd_record_goto (char *arg, int from_tty) +cmd_record_goto (const char *arg, int from_tty) { record_goto (arg); } @@ -359,7 +391,7 @@ cmd_record_goto (char *arg, int from_tty) /* The "record goto begin" command. */ static void -cmd_record_goto_begin (char *arg, int from_tty) +cmd_record_goto_begin (const char *arg, int from_tty) { if (arg != NULL && *arg != '\0') error (_("Junk after argument: %s."), arg); @@ -371,7 +403,7 @@ cmd_record_goto_begin (char *arg, int from_tty) /* The "record goto end" command. */ static void -cmd_record_goto_end (char *arg, int from_tty) +cmd_record_goto_end (const char *arg, int from_tty) { if (arg != NULL && *arg != '\0') error (_("Junk after argument: %s."), arg); @@ -383,13 +415,13 @@ cmd_record_goto_end (char *arg, int from_tty) /* Read an instruction number from an argument string. */ static ULONGEST -get_insn_number (char **arg) +get_insn_number (const char **arg) { ULONGEST number; const char *begin, *end, *pos; begin = *arg; - pos = skip_spaces_const (begin); + pos = skip_spaces (begin); if (!isdigit (*pos)) error (_("Expected positive number, got: %s."), pos); @@ -404,23 +436,25 @@ get_insn_number (char **arg) /* Read a context size from an argument string. */ static int -get_context_size (char **arg) +get_context_size (const char **arg) { - char *pos; - int number; + const char *pos; + char *end; pos = skip_spaces (*arg); if (!isdigit (*pos)) error (_("Expected positive number, got: %s."), pos); - return strtol (pos, arg, 10); + long result = strtol (pos, &end, 10); + *arg = end; + return result; } /* Complain about junk at the end of an argument string. */ static void -no_chunk (char *arg) +no_chunk (const char *arg) { if (*arg != 0) error (_("Junk after argument: %s."), arg); @@ -428,11 +462,11 @@ no_chunk (char *arg) /* Read instruction-history modifiers from an argument string. */ -static int -get_insn_history_modifiers (char **arg) +static gdb_disassembly_flags +get_insn_history_modifiers (const char **arg) { - int modifiers; - char *args; + gdb_disassembly_flags modifiers; + const char *args; modifiers = 0; args = *arg; @@ -465,6 +499,9 @@ get_insn_history_modifiers (char **arg) case 'r': modifiers |= DISASSEMBLY_RAW_INSN; break; + case 'b': + modifiers |= DISASSEMBLY_RAW_BYTES; + break; case 'f': modifiers |= DISASSEMBLY_OMIT_FNAME; break; @@ -507,15 +544,13 @@ command_size_to_target_size (unsigned int size) /* The "record instruction-history" command. */ static void -cmd_record_insn_history (char *arg, int from_tty) +cmd_record_insn_history (const char *arg, int from_tty) { - int flags, size; - require_record_target (); - flags = get_insn_history_modifiers (&arg); + gdb_disassembly_flags flags = get_insn_history_modifiers (&arg); - size = command_size_to_target_size (record_insn_history_size); + int size = command_size_to_target_size (record_insn_history_size); if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) target_insn_history (size, flags); @@ -571,14 +606,11 @@ cmd_record_insn_history (char *arg, int from_tty) /* Read function-call-history modifiers from an argument string. */ -static int -get_call_history_modifiers (char **arg) +static record_print_flags +get_call_history_modifiers (const char **arg) { - int modifiers; - char *args; - - modifiers = 0; - args = *arg; + record_print_flags modifiers = 0; + const char *args = *arg; if (args == NULL) return modifiers; @@ -626,15 +658,13 @@ get_call_history_modifiers (char **arg) /* The "record function-call-history" command. */ static void -cmd_record_call_history (char *arg, int from_tty) +cmd_record_call_history (const char *arg, int from_tty) { - int flags, size; - require_record_target (); - flags = get_call_history_modifiers (&arg); + record_print_flags flags = get_call_history_modifiers (&arg); - size = command_size_to_target_size (record_call_history_size); + int size = command_size_to_target_size (record_call_history_size); if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0) target_call_history (size, flags); @@ -714,7 +744,7 @@ validate_history_size (unsigned int *command_var, unsigned int *setting) [0..UINT_MAX]. See command_size_to_target_size. */ static void -set_record_insn_history_size (char *args, int from_tty, +set_record_insn_history_size (const char *args, int from_tty, struct cmd_list_element *c) { validate_history_size (&record_insn_history_size_setshow_var, @@ -726,18 +756,16 @@ set_record_insn_history_size (char *args, int from_tty, [0..UINT_MAX]. See command_size_to_target_size. */ static void -set_record_call_history_size (char *args, int from_tty, +set_record_call_history_size (const char *args, int from_tty, struct cmd_list_element *c) { validate_history_size (&record_call_history_size_setshow_var, &record_call_history_size); } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_record; - +void _initialize_record (); void -_initialize_record (void) +_initialize_record () { struct cmd_list_element *c; @@ -765,52 +793,61 @@ A size of \"unlimited\" means unlimited lines. The default is 10."), set_record_call_history_size, NULL, &set_record_cmdlist, &show_record_cmdlist); - c = add_prefix_cmd ("record", class_obscure, cmd_record_start, + cmd_list_element *record_cmd + = add_prefix_cmd ("record", class_obscure, cmd_record_start, _("Start recording."), - &record_cmdlist, "record ", 0, &cmdlist); - set_cmd_completer (c, filename_completer); + &record_cmdlist, 0, &cmdlist); + add_com_alias ("rec", record_cmd, class_obscure, 1); + + set_show_commands setshow_record_cmds + = add_setshow_prefix_cmd ("record", class_support, + _("Set record options."), + _("Show record options."), + &set_record_cmdlist, &show_record_cmdlist, + &setlist, &showlist); - add_com_alias ("rec", "record", class_obscure, 1); - add_prefix_cmd ("record", class_support, set_record_command, - _("Set record options"), &set_record_cmdlist, - "set record ", 0, &setlist); - add_alias_cmd ("rec", "record", class_obscure, 1, &setlist); - add_prefix_cmd ("record", class_support, show_record_command, - _("Show record options"), &show_record_cmdlist, - "show record ", 0, &showlist); - add_alias_cmd ("rec", "record", class_obscure, 1, &showlist); - add_prefix_cmd ("record", class_support, info_record_command, - _("Info record options"), &info_record_cmdlist, - "info record ", 0, &infolist); - add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); + + add_alias_cmd ("rec", setshow_record_cmds.set, class_obscure, 1, &setlist); + add_alias_cmd ("rec", setshow_record_cmds.show, class_obscure, 1, &showlist); + + cmd_list_element *info_record_cmd + = add_prefix_cmd ("record", class_support, info_record_command, + _("Info record options."), &info_record_cmdlist, + 0, &infolist); + add_alias_cmd ("rec", info_record_cmd, class_obscure, 1, &infolist); c = add_cmd ("save", class_obscure, cmd_record_save, _("Save the execution log to a file.\n\ -Argument is optional filename.\n\ -Default filename is 'gdb_record.'."), +Usage: record save [FILENAME]\n\ +Default filename is 'gdb_record.PROCESS_ID'."), &record_cmdlist); set_cmd_completer (c, filename_completer); - add_cmd ("delete", class_obscure, cmd_record_delete, - _("Delete the rest of execution log and start recording it anew."), - &record_cmdlist); - add_alias_cmd ("d", "delete", class_obscure, 1, &record_cmdlist); - add_alias_cmd ("del", "delete", class_obscure, 1, &record_cmdlist); - - add_cmd ("stop", class_obscure, cmd_record_stop, - _("Stop the record/replay target."), - &record_cmdlist); - add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); + cmd_list_element *record_delete_cmd + = add_cmd ("delete", class_obscure, cmd_record_delete, + _("Delete the rest of execution log and start recording it \ +anew."), + &record_cmdlist); + add_alias_cmd ("d", record_delete_cmd, class_obscure, 1, &record_cmdlist); + add_alias_cmd ("del", record_delete_cmd, class_obscure, 1, &record_cmdlist); + + cmd_list_element *record_stop_cmd + = add_cmd ("stop", class_obscure, cmd_record_stop, + _("Stop the record/replay target."), + &record_cmdlist); + add_alias_cmd ("s", record_stop_cmd, class_obscure, 1, &record_cmdlist); add_prefix_cmd ("goto", class_obscure, cmd_record_goto, _("\ Restore the program to its state at instruction number N.\n\ Argument is instruction number, as shown by 'info record'."), - &record_goto_cmdlist, "record goto ", 1, &record_cmdlist); + &record_goto_cmdlist, 1, &record_cmdlist); - add_cmd ("begin", class_obscure, cmd_record_goto_begin, - _("Go to the beginning of the execution log."), - &record_goto_cmdlist); - add_alias_cmd ("start", "begin", class_obscure, 1, &record_goto_cmdlist); + cmd_list_element *record_goto_begin_cmd + = add_cmd ("begin", class_obscure, cmd_record_goto_begin, + _("Go to the beginning of the execution log."), + &record_goto_cmdlist); + add_alias_cmd ("start", record_goto_begin_cmd, class_obscure, 1, + &record_goto_cmdlist); add_cmd ("end", class_obscure, cmd_record_goto_end, _("Go to the end of the execution log."), @@ -834,7 +871,7 @@ If the second argument is preceded by '+' or '-', it specifies the distance \ from the first argument.\n\ The number of instructions to disassemble can be defined with \"set record \ instruction-history-size\"."), - &record_cmdlist); + &record_cmdlist); add_cmd ("function-call-history", class_obscure, cmd_record_call_history, _("\ Prints the execution history at function granularity.\n\ @@ -854,7 +891,7 @@ If the second argument is preceded by '+' or '-', it specifies the distance \ from the first argument.\n\ The number of functions to print can be defined with \"set record \ function-call-history-size\"."), - &record_cmdlist); + &record_cmdlist); /* Sync command control variables. */ record_insn_history_size_setshow_var = record_insn_history_size;