X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Frecord.c;h=548acfe36411d56a47dae2fdb8b61f48b2f2aaae;hb=4e9668d0d1ddad73af7c20a92a00704fbea2a8d9;hp=2736a1eb17b7c1608a95275ea54b924c7aba601e;hpb=0ccfeeae972c51bf2c8c3bc5a66d72d62f75398d;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/record.c b/gdb/record.c index 2736a1eb17..548acfe364 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-2013 Free Software Foundation, Inc. + Copyright (C) 2008-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -21,7 +21,7 @@ #include "gdbcmd.h" #include "completer.h" #include "record.h" -#include "observer.h" +#include "observable.h" #include "inferior.h" #include "common/common-utils.h" #include "cli/cli-utils.h" @@ -48,6 +48,7 @@ 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; struct cmd_list_element *set_record_cmdlist = NULL; struct cmd_list_element *show_record_cmdlist = NULL; struct cmd_list_element *info_record_cmdlist = NULL; @@ -56,18 +57,12 @@ struct cmd_list_element *info_record_cmdlist = NULL; if (record_debug) \ fprintf_unfiltered (gdb_stdlog, "record: " msg "\n", ##args) -/* Find the record target in the target stack. */ +/* See record.h. */ -static struct target_ops * +struct target_ops * find_record_target (void) { - struct target_ops *t; - - for (t = current_target.beneath; t != NULL; t = t->beneath) - if (t->to_stratum == record_stratum) - return t; - - return NULL; + return find_target_at (record_stratum); } /* Check that recording is active. Throw an error, if it isn't. */ @@ -87,6 +82,59 @@ require_record_target (void) /* See record.h. */ +void +record_preopen (void) +{ + /* Check if a record target is already running. */ + if (find_record_target () != NULL) + error (_("The process is already being recorded. Use \"record stop\" to " + "stop recording first.")); +} + +/* 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); + else + error (_("Invalid format.")); + } + else if (strcmp (method, "full") == 0) + { + if (format == NULL) + execute_command_to_string ("record full", from_tty); + else + error (_("Invalid format.")); + } + else if (strcmp (method, "btrace") == 0) + { + if (format == NULL) + execute_command_to_string ("record btrace", from_tty); + else if (strcmp (format, "bts") == 0) + execute_command_to_string ("record btrace bts", from_tty); + else if (strcmp (format, "pt") == 0) + execute_command_to_string ("record btrace pt", from_tty); + 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); +} + +/* See record.h. */ + int record_read_memory (struct gdbarch *gdbarch, CORE_ADDR memaddr, gdb_byte *myaddr, @@ -106,10 +154,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 ()); - if (t->to_stop_recording != NULL) - t->to_stop_recording (); + t->stop_recording (); } /* Unpush the record target. */ @@ -117,7 +164,7 @@ 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); } @@ -125,11 +172,11 @@ record_unpush (struct target_ops *t) /* See record.h. */ void -record_disconnect (struct target_ops *t, char *args, int from_tty) +record_disconnect (struct target_ops *t, const char *args, int from_tty) { gdb_assert (t->to_stratum == record_stratum); - DEBUG ("disconnect %s", t->to_shortname); + DEBUG ("disconnect %s", t->shortname ()); record_stop (t); record_unpush (t); @@ -140,16 +187,16 @@ record_disconnect (struct target_ops *t, char *args, int from_tty) /* See record.h. */ void -record_detach (struct target_ops *t, char *args, int from_tty) +record_detach (struct target_ops *t, inferior *inf, int from_tty) { gdb_assert (t->to_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. */ @@ -159,13 +206,13 @@ record_mourn_inferior (struct target_ops *t) { gdb_assert (t->to_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. */ @@ -175,7 +222,7 @@ record_kill (struct target_ops *t) { gdb_assert (t->to_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. */ @@ -184,6 +231,26 @@ record_kill (struct target_ops *t) target_kill (); } +/* See record.h. */ + +int +record_check_stopped_by_breakpoint (const address_space *aspace, + CORE_ADDR pc, + enum target_stop_reason *reason) +{ + if (breakpoint_inserted_here_p (aspace, pc)) + { + if (hardware_breakpoint_inserted_here_p (aspace, pc)) + *reason = TARGET_STOPPED_BY_HW_BREAKPOINT; + else + *reason = TARGET_STOPPED_BY_SW_BREAKPOINT; + return 1; + } + + *reason = TARGET_STOPPED_BY_NO_REASON; + return 0; +} + /* Implement "show record debug" command. */ static void @@ -197,7 +264,7 @@ show_record_debug (struct ui_file *file, int from_tty, /* Alias for "target record". */ static void -cmd_record_start (char *args, int from_tty) +cmd_record_start (const char *args, int from_tty) { execute_command ("target record-full", from_tty); } @@ -206,11 +273,11 @@ 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 ()) + if (!target_record_is_replaying (inferior_ptid)) { printf_unfiltered (_("Already at end of record list.\n")); return; @@ -232,7 +299,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; @@ -244,23 +311,23 @@ cmd_record_stop (char *args, int from_tty) printf_unfiltered (_("Process record is stopped and all execution " "logs are deleted.\n")); - observer_notify_record_changed (current_inferior (), 0); + gdb::observers::record_changed.notify (current_inferior (), 0, NULL, NULL); } /* The "set record" command. */ static void -set_record_command (char *args, int from_tty) +set_record_command (const char *args, int from_tty) { printf_unfiltered (_("\"set record\" must be followed " - "by an apporpriate subcommand.\n")); + "by an appropriate 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) +show_record_command (const char *args, int from_tty) { cmd_show_list (show_record_cmdlist, from_tty, ""); } @@ -268,7 +335,7 @@ show_record_command (char *args, int 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; @@ -279,17 +346,17 @@ info_record_command (char *args, int from_tty) return; } - printf_filtered (_("Active record target: %s\n"), t->to_shortname); - if (t->to_info_record != NULL) - t->to_info_record (); + printf_filtered (_("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 (); @@ -299,50 +366,74 @@ cmd_record_save (char *args, int from_tty) { /* Default recfile name is "gdb_record.PID". */ xsnprintf (recfilename_buffer, sizeof (recfilename_buffer), - "gdb_record.%d", PIDGET (inferior_ptid)); + "gdb_record.%d", ptid_get_pid (inferior_ptid)); recfilename = recfilename_buffer; } target_save_record (recfilename); } +/* See record.h. */ + +void +record_goto (const char *arg) +{ + ULONGEST insn; + + if (arg == NULL || *arg == '\0') + error (_("Command requires an argument (insn number to go to).")); + + insn = parse_and_eval_long (arg); + + require_record_target (); + target_goto_record (insn); +} + /* "record goto" command. Argument is an instruction number, as given by "info record". Rewinds the recording (forward or backward) to the given instruction. */ -void -cmd_record_goto (char *arg, int from_tty) +static void +cmd_record_goto (const char *arg, int from_tty) +{ + record_goto (arg); +} + +/* The "record goto begin" command. */ + +static void +cmd_record_goto_begin (const char *arg, int from_tty) { + if (arg != NULL && *arg != '\0') + error (_("Junk after argument: %s."), arg); + require_record_target (); + target_goto_record_begin (); +} - if (arg == NULL || *arg == '\0') - error (_("Command requires an argument (insn number to go to).")); +/* The "record goto end" command. */ - if (strncmp (arg, "start", strlen ("start")) == 0 - || strncmp (arg, "begin", strlen ("begin")) == 0) - target_goto_record_begin (); - else if (strncmp (arg, "end", strlen ("end")) == 0) - target_goto_record_end (); - else - { - ULONGEST insn; +static void +cmd_record_goto_end (const char *arg, int from_tty) +{ + if (arg != NULL && *arg != '\0') + error (_("Junk after argument: %s."), arg); - insn = parse_and_eval_long (arg); - target_goto_record (insn); - } + require_record_target (); + target_goto_record_end (); } /* 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); @@ -357,23 +448,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); @@ -381,11 +474,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; @@ -411,6 +504,7 @@ get_insn_history_modifiers (char **arg) switch (*args) { case 'm': + case 's': modifiers |= DISASSEMBLY_SOURCE; modifiers |= DISASSEMBLY_FILENAME; break; @@ -459,15 +553,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); @@ -523,14 +615,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; @@ -553,10 +642,13 @@ get_call_history_modifiers (char **arg) switch (*args) { case 'l': - modifiers |= record_print_src_line; + modifiers |= RECORD_PRINT_SRC_LINE; break; case 'i': - modifiers |= record_print_insn_range; + modifiers |= RECORD_PRINT_INSN_RANGE; + break; + case 'c': + modifiers |= RECORD_PRINT_INDENT_CALLS; break; default: error (_("Invalid modifier: %c."), *args); @@ -575,15 +667,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); @@ -643,7 +733,7 @@ cmd_record_call_history (char *arg, int from_tty) is the real setting the command allows changing. */ static void -validate_history_size (unsigned int *command_var, int *setting) +validate_history_size (unsigned int *command_var, unsigned int *setting) { if (*command_var != UINT_MAX && *command_var > INT_MAX) { @@ -663,7 +753,7 @@ validate_history_size (unsigned int *command_var, 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, @@ -675,16 +765,13 @@ 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) { @@ -701,16 +788,16 @@ _initialize_record (void) add_setshow_uinteger_cmd ("instruction-history-size", no_class, &record_insn_history_size_setshow_var, _("\ Set number of instructions to print in \"record instruction-history\"."), _("\ -Show number of instructions to print in \"record instruction-history\"."), - NULL, +Show number of instructions to print in \"record instruction-history\"."), _("\ +A size of \"unlimited\" means unlimited instructions. The default is 10."), set_record_insn_history_size, NULL, &set_record_cmdlist, &show_record_cmdlist); add_setshow_uinteger_cmd ("function-call-history-size", no_class, &record_call_history_size_setshow_var, _("\ Set number of function to print in \"record function-call-history\"."), _("\ -Show number of functions to print in \"record function-call-history\"."), - NULL, +Show number of functions to print in \"record function-call-history\"."), _("\ +A size of \"unlimited\" means unlimited lines. The default is 10."), set_record_call_history_size, NULL, &set_record_cmdlist, &show_record_cmdlist); @@ -751,14 +838,23 @@ Default filename is 'gdb_record.'."), &record_cmdlist); add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); - add_cmd ("goto", class_obscure, cmd_record_goto, _("\ + 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_cmdlist); + &record_goto_cmdlist, "record goto ", 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); + + add_cmd ("end", class_obscure, cmd_record_goto_end, + _("Go to the end of the execution log."), + &record_goto_cmdlist); add_cmd ("instruction-history", class_obscure, cmd_record_insn_history, _("\ Print disassembled instructions stored in the execution log.\n\ -With a /m modifier, source lines are included (if available).\n\ +With a /m or /s modifier, source lines are included (if available).\n\ With a /r modifier, raw instructions in hex are included.\n\ With a /f modifier, function names are omitted.\n\ With a /p modifier, current position markers are omitted.\n\ @@ -783,6 +879,7 @@ function.\n\ Without modifiers, it prints the function name.\n\ With a /l modifier, the source file and line number range is included.\n\ With a /i modifier, the instruction number range is included.\n\ +With a /c modifier, the output is indented based on the call stack depth.\n\ With no argument, prints ten more lines after the previous ten-line print.\n\ \"record function-call-history -\" prints ten lines before a previous ten-line \ print.\n\