X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfcmd.c;h=2bf21e26f1924e0af1b3c94ff88e677a3be80909;hb=f4ec508eaed65ad7555858498c1cbbf420bce90a;hp=2e70b474d63a3fabc1932d204593cf2356af3ade;hpb=8bc2fe488957946d2cdccda3ce8d4f39e4003ea0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 2e70b474d6..2bf21e26f1 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1,6 +1,6 @@ /* Memory-access and commands for "inferior" process, for GDB. - Copyright (C) 1986-2014 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -19,13 +19,12 @@ #include "defs.h" #include "arch-utils.h" -#include -#include #include "symtab.h" #include "gdbtypes.h" #include "frame.h" #include "inferior.h" -#include "environ.h" +#include "infrun.h" +#include "gdbsupport/environ.h" #include "value.h" #include "gdbcmd.h" #include "symfile.h" @@ -35,19 +34,14 @@ #include "objfiles.h" #include "completer.h" #include "ui-out.h" -#include "event-top.h" -#include "parser-defs.h" #include "regcache.h" #include "reggroups.h" #include "block.h" #include "solib.h" #include -#include "gdb_assert.h" -#include "observer.h" +#include "observable.h" #include "target-descriptions.h" #include "user-regs.h" -#include "exceptions.h" -#include "cli/cli-decode.h" #include "gdbthread.h" #include "valprint.h" #include "inline-frame.h" @@ -55,60 +49,19 @@ #include "inf-loop.h" #include "continuations.h" #include "linespec.h" -#include "cli/cli-utils.h" +#include "thread-fsm.h" +#include "top.h" +#include "interps.h" +#include "skip.h" +#include "gdbsupport/gdb_optional.h" +#include "source.h" +#include "cli/cli-style.h" /* Local functions: */ -static void nofp_registers_info (char *, int); - -static void print_return_value (struct value *function, - struct type *value_type); - static void until_next_command (int); -static void until_command (char *, int); - -static void path_info (char *, int); - -static void path_command (char *, int); - -static void unset_command (char *, int); - -static void float_info (char *, int); - -static void disconnect_command (char *, int); - -static void unset_environment_command (char *, int); - -static void set_environment_command (char *, int); - -static void environment_info (char *, int); - -static void program_info (char *, int); - -static void finish_command (char *, int); - -static void signal_command (char *, int); - -static void jump_command (char *, int); - -static void step_1 (int, int, char *); -static void step_once (int skip_subroutines, int single_inst, - int count, int thread); - -static void next_command (char *, int); - -static void step_command (char *, int); - -static void run_command (char *, int); - -static void run_no_args_command (char *args, int from_tty); - -static void go_command (char *line_no, int from_tty); - -static int strip_bg_char (char **); - -void _initialize_infcmd (void); +static void step_1 (int, int, const char *); #define ERROR_NO_INFERIOR \ if (!target_has_execution) error (_("The program is not being run.")); @@ -121,6 +74,10 @@ void _initialize_infcmd (void); static char *inferior_args_scratch; +/* Scratch area where the new cwd will be stored by 'set cwd'. */ + +static char *inferior_cwd_scratch; + /* Scratch area where 'set inferior-tty' will store user-provided value. We'll immediate copy it into per-inferior storage. */ @@ -133,10 +90,6 @@ static char *inferior_io_terminal_scratch; ptid_t inferior_ptid; -/* Address at which inferior stopped. */ - -CORE_ADDR stop_pc; - /* Nonzero if stopped due to completion of a stack dummy routine. */ enum stop_stack_kind stop_stack_dummy; @@ -146,10 +99,6 @@ enum stop_stack_kind stop_stack_dummy; int stopped_by_random_signal; -/* See inferior.h. */ - -int startup_with_shell = 1; - /* Accessor routines. */ @@ -160,7 +109,11 @@ void set_inferior_io_terminal (const char *terminal_name) { xfree (current_inferior ()->terminal); - current_inferior ()->terminal = terminal_name ? xstrdup (terminal_name) : 0; + + if (terminal_name != NULL && *terminal_name != '\0') + current_inferior ()->terminal = xstrdup (terminal_name); + else + current_inferior ()->terminal = NULL; } const char * @@ -170,7 +123,7 @@ get_inferior_io_terminal (void) } static void -set_inferior_tty_command (char *args, int from_tty, +set_inferior_tty_command (const char *args, int from_tty, struct cmd_list_element *c) { /* CLI has assigned the user-provided value to inferior_io_terminal_scratch. @@ -193,7 +146,7 @@ show_inferior_tty_command (struct ui_file *file, int from_tty, "is \"%s\".\n"), inferior_io_terminal); } -char * +const char * get_inferior_args (void) { if (current_inferior ()->argc != 0) @@ -216,7 +169,7 @@ get_inferior_args (void) NEWARGS is not transferred. */ void -set_inferior_args (char *newargs) +set_inferior_args (const char *newargs) { xfree (current_inferior ()->args); current_inferior ()->args = newargs ? xstrdup (newargs) : NULL; @@ -232,8 +185,9 @@ set_inferior_args_vector (int argc, char **argv) } /* Notice when `set args' is run. */ + static void -set_args_command (char *args, int from_tty, struct cmd_list_element *c) +set_args_command (const char *args, int from_tty, struct cmd_list_element *c) { /* CLI has assigned the user-provided value to inferior_args_scratch. Now route it to current inferior. */ @@ -241,6 +195,7 @@ set_args_command (char *args, int from_tty, struct cmd_list_element *c) } /* Notice when `show args' is run. */ + static void show_args_command (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -250,9 +205,64 @@ show_args_command (struct ui_file *file, int from_tty, deprecated_show_value_hack (file, from_tty, c, get_inferior_args ()); } +/* See gdbsupport/common-inferior.h. */ + +void +set_inferior_cwd (const char *cwd) +{ + struct inferior *inf = current_inferior (); + + gdb_assert (inf != NULL); + + if (cwd == NULL) + inf->cwd.reset (); + else + inf->cwd.reset (xstrdup (cwd)); +} + +/* See gdbsupport/common-inferior.h. */ + +const char * +get_inferior_cwd () +{ + return current_inferior ()->cwd.get (); +} + +/* Handle the 'set cwd' command. */ + +static void +set_cwd_command (const char *args, int from_tty, struct cmd_list_element *c) +{ + if (*inferior_cwd_scratch == '\0') + set_inferior_cwd (NULL); + else + set_inferior_cwd (inferior_cwd_scratch); +} + +/* Handle the 'show cwd' command. */ + +static void +show_cwd_command (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + const char *cwd = get_inferior_cwd (); + + if (cwd == NULL) + fprintf_filtered (gdb_stdout, + _("\ +You have not set the inferior's current working directory.\n\ +The inferior will inherit GDB's cwd if native debugging, or the remote\n\ +server's cwd if remote debugging.\n")); + else + fprintf_filtered (gdb_stdout, + _("Current working directory that will be used " + "when starting the inferior is \"%s\".\n"), cwd); +} + /* Compute command-line string given argument vector. This does the same shell processing as fork_inferior. */ + char * construct_inferior_arguments (int argc, char **argv) { @@ -263,14 +273,14 @@ construct_inferior_arguments (int argc, char **argv) #ifdef __MINGW32__ /* This holds all the characters considered special to the Windows shells. */ - char *special = "\"!&*|[]{}<>?`~^=;, \t\n"; - const char quote = '"'; + static const char special[] = "\"!&*|[]{}<>?`~^=;, \t\n"; + static const char quote = '"'; #else /* This holds all the characters considered special to the typical Unix shells. We include `^' because the SunOS /bin/sh treats it as a synonym for `|'. */ - char *special = "\"!#$&*()\\|[]{}<>?'`~^; \t\n"; - const char quote = '\''; + static const char special[] = "\"!#$&*()\\|[]{}<>?'`~^; \t\n"; + static const char quote = '\''; #endif int i; int length = 0; @@ -369,34 +379,41 @@ construct_inferior_arguments (int argc, char **argv) } -/* This function detects whether or not a '&' character (indicating - background execution) has been added as *the last* of the arguments ARGS - of a command. If it has, it removes it and returns 1. Otherwise it - does nothing and returns 0. */ -static int -strip_bg_char (char **args) +/* This function strips the '&' character (indicating background + execution) that is added as *the last* of the arguments ARGS of a + command. A copy of the incoming ARGS without the '&' is returned, + unless the resulting string after stripping is empty, in which case + NULL is returned. *BG_CHAR_P is an output boolean that indicates + whether the '&' character was found. */ + +static gdb::unique_xmalloc_ptr +strip_bg_char (const char *args, int *bg_char_p) { - char *p = NULL; + const char *p; - p = strchr (*args, '&'); + if (args == NULL || *args == '\0') + { + *bg_char_p = 0; + return NULL; + } - if (p) + p = args + strlen (args); + if (p[-1] == '&') { - if (p == (*args + strlen (*args) - 1)) - { - if (strlen (*args) > 1) - { - do - p--; - while (*p == ' ' || *p == '\t'); - *(p + 1) = '\0'; - } - else - *args = 0; - return 1; - } + p--; + while (p > args && isspace (p[-1])) + p--; + + *bg_char_p = 1; + if (p != args) + return gdb::unique_xmalloc_ptr + (savestring (args, p - args)); + else + return gdb::unique_xmalloc_ptr (nullptr); } - return 0; + + *bg_char_p = 0; + return make_unique_xstrdup (args); } /* Common actions to take after creating any sort of inferior, by any @@ -406,10 +423,9 @@ strip_bg_char (char **args) void post_create_inferior (struct target_ops *target, int from_tty) { - volatile struct gdb_exception ex; /* Be sure we own the terminal in case write operations are performed. */ - target_terminal_ours (); + target_terminal::ours_for_output (); /* If the target hasn't taken care of this already, do it now. Targets which need to access registers during to_open, @@ -420,13 +436,18 @@ post_create_inferior (struct target_ops *target, int from_tty) /* Now that we know the register layout, retrieve current PC. But if the PC is unavailable (e.g., we're opening a core file with missing registers info), ignore it. */ - stop_pc = 0; - TRY_CATCH (ex, RETURN_MASK_ERROR) + thread_info *thr = inferior_thread (); + + thr->suspend.stop_pc = 0; + try { - stop_pc = regcache_read_pc (get_current_regcache ()); + thr->suspend.stop_pc = regcache_read_pc (get_current_regcache ()); + } + catch (const gdb_exception_error &ex) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw; } - if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR) - throw_exception (ex); if (exec_bfd) { @@ -451,7 +472,7 @@ post_create_inferior (struct target_ops *target, int from_tty) /* If the solist is global across processes, there's no need to refetch it here. */ if (!gdbarch_has_global_solist (target_gdbarch ())) - solib_add (NULL, 0, target, auto_solib_add); + solib_add (NULL, 0, auto_solib_add); } } @@ -467,7 +488,7 @@ post_create_inferior (struct target_ops *target, int from_tty) if the now pushed target supports hardware watchpoints. */ breakpoint_re_set (); - observer_notify_inferior_created (target, from_tty); + gdb::observers::inferior_created.notify (target, from_tty); } /* Kill the inferior if already running. This function is designed @@ -478,7 +499,7 @@ post_create_inferior (struct target_ops *target, int from_tty) static void kill_if_already_running (int from_tty) { - if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution) + if (inferior_ptid != null_ptid && target_has_execution) { /* Bail out before killing the program if we will not be able to restart it. */ @@ -492,42 +513,50 @@ Start it from the beginning? "))) } } -/* Prepare for execution command. TARGET is the target that will run - the command. BACKGROUND determines whether this is a foreground - (synchronous) or background (asynchronous) command. */ +/* See inferior.h. */ -static void +void prepare_execution_command (struct target_ops *target, int background) { /* If we get a request for running in the bg but the target doesn't support it, error out. */ - if (background && !target->to_can_async_p (target)) + if (background && !target->can_async_p ()) error (_("Asynchronous execution not supported on this target.")); - /* If we don't get a request of running in the bg, then we need - to simulate synchronous (fg) execution. */ - if (!background && target->to_can_async_p (target)) + if (!background) { - /* Simulate synchronous execution. Note no cleanup is necessary - for this. stdin is re-enabled whenever an error reaches the - top level. */ - async_disable_stdin (); + /* If we get a request for running in the fg, then we need to + simulate synchronous (fg) execution. Note no cleanup is + necessary for this. stdin is re-enabled whenever an error + reaches the top level. */ + all_uis_on_sync_execution_starting (); } } -/* Implement the "run" command. If TBREAK_AT_MAIN is set, then insert - a temporary breakpoint at the begining of the main program before - running the program. */ +/* Determine how the new inferior will behave. */ + +enum run_how + { + /* Run program without any explicit stop during startup. */ + RUN_NORMAL, + + /* Stop at the beginning of the program's main function. */ + RUN_STOP_AT_MAIN, + + /* Stop at the first instruction of the program. */ + RUN_STOP_AT_FIRST_INSN + }; + +/* Implement the "run" command. Force a stop during program start if + requested by RUN_HOW. */ static void -run_command_1 (char *args, int from_tty, int tbreak_at_main) +run_command_1 (const char *args, int from_tty, enum run_how run_how) { - char *exec_file; - struct cleanup *old_chain; - ptid_t ptid; + const char *exec_file; struct ui_out *uiout = current_uiout; struct target_ops *run_target; - int async_exec = 0; + int async_exec; dont_repeat (); @@ -550,8 +579,8 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main) reopen_exec_file (); reread_symbols (); - if (args != NULL) - async_exec = strip_bg_char (&args); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (args, &async_exec); + args = stripped.get (); /* Do validation and preparation before possibly changing anything in the inferior. */ @@ -560,16 +589,19 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main) prepare_execution_command (run_target, async_exec); - if (non_stop && !run_target->to_supports_non_stop (run_target)) + if (non_stop && !run_target->supports_non_stop ()) error (_("The target does not support running in non-stop mode.")); /* Done. Can now set breakpoints, change inferior args, etc. */ - /* Insert the temporary breakpoint if a location was specified. */ - if (tbreak_at_main) - tbreak_command (main_name (), 0); + /* Insert temporary breakpoint in main function if requested. */ + if (run_how == RUN_STOP_AT_MAIN) + { + std::string arg = string_printf ("-qualified %s", main_name ()); + tbreak_command (arg.c_str (), 0); + } - exec_file = (char *) get_exec_file (0); + exec_file = get_exec_file (0); /* We keep symbols from add-symbol-file, on the grounds that the user might want to add some symbols before running the program @@ -585,23 +617,24 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main) if (from_tty) { - ui_out_field_string (uiout, NULL, "Starting program"); - ui_out_text (uiout, ": "); + uiout->field_string (NULL, "Starting program"); + uiout->text (": "); if (exec_file) - ui_out_field_string (uiout, "execfile", exec_file); - ui_out_spaces (uiout, 1); + uiout->field_string ("execfile", exec_file); + uiout->spaces (1); /* We call get_inferior_args() because we might need to compute the value now. */ - ui_out_field_string (uiout, "infargs", get_inferior_args ()); - ui_out_text (uiout, "\n"); - ui_out_flush (uiout); + uiout->field_string ("infargs", get_inferior_args ()); + uiout->text ("\n"); + uiout->flush (); } /* We call get_inferior_args() because we might need to compute the value now. */ - run_target->to_create_inferior (run_target, exec_file, get_inferior_args (), - environ_vector (current_inferior ()->environment), - from_tty); + run_target->create_inferior (exec_file, + std::string (get_inferior_args ()), + current_inferior ()->environment.envp (), + from_tty); /* to_create_inferior should push the target, so after this point we shouldn't refer to run_target again. */ run_target = NULL; @@ -612,43 +645,53 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main) events --- the frontend shouldn't see them as stopped. In all-stop, always finish the state of all threads, as we may be resuming more than just the new process. */ + process_stratum_target *finish_target; + ptid_t finish_ptid; if (non_stop) - ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + { + finish_target = current_inferior ()->process_target (); + finish_ptid = ptid_t (current_inferior ()->pid); + } else - ptid = minus_one_ptid; - old_chain = make_cleanup (finish_thread_state_cleanup, &ptid); + { + finish_target = nullptr; + finish_ptid = minus_one_ptid; + } + scoped_finish_thread_state finish_state (finish_target, finish_ptid); /* Pass zero for FROM_TTY, because at this point the "run" command has done its thing; now we are setting up the running program. */ - post_create_inferior (¤t_target, 0); + post_create_inferior (current_top_target (), 0); + + /* Queue a pending event so that the program stops immediately. */ + if (run_how == RUN_STOP_AT_FIRST_INSN) + { + thread_info *thr = inferior_thread (); + thr->suspend.waitstatus_pending_p = 1; + thr->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED; + thr->suspend.waitstatus.value.sig = GDB_SIGNAL_0; + } /* Start the target running. Do not use -1 continuation as it would skip breakpoint right at the entry point. */ - proceed (regcache_read_pc (get_current_regcache ()), GDB_SIGNAL_0, 0); + proceed (regcache_read_pc (get_current_regcache ()), GDB_SIGNAL_0); /* Since there was no error, there's no need to finish the thread states here. */ - discard_cleanups (old_chain); -} - -static void -run_command (char *args, int from_tty) -{ - run_command_1 (args, from_tty, 0); + finish_state.release (); } static void -run_no_args_command (char *args, int from_tty) +run_command (const char *args, int from_tty) { - set_inferior_args (""); + run_command_1 (args, from_tty, RUN_NORMAL); } - /* Start the execution of the program up until the beginning of the main program. */ static void -start_command (char *args, int from_tty) +start_command (const char *args, int from_tty) { /* Some languages such as Ada need to search inside the program minimal symbols for the location where to put the temporary @@ -657,7 +700,16 @@ start_command (char *args, int from_tty) error (_("No symbol table loaded. Use the \"file\" command.")); /* Run the program until reaching the main procedure... */ - run_command_1 (args, from_tty, 1); + run_command_1 (args, from_tty, RUN_STOP_AT_MAIN); +} + +/* Start the execution of the program stopping at the first + instruction. */ + +static void +starti_command (const char *args, int from_tty) +{ + run_command_1 (args, from_tty, RUN_STOP_AT_FIRST_INSN); } static int @@ -672,20 +724,23 @@ proceed_thread_callback (struct thread_info *thread, void *arg) much. If/when GDB gains a way to tell the target `hold this thread stopped until I say otherwise', then we can optimize this. */ - if (!is_stopped (thread->ptid)) + if (thread->state != THREAD_STOPPED) return 0; - switch_to_thread (thread->ptid); - clear_proceed_status (); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); + if (!thread->inf->has_execution ()) + return 0; + + switch_to_thread (thread); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); return 0; } static void ensure_valid_thread (void) { - if (ptid_equal (inferior_ptid, null_ptid) - || is_exited (inferior_ptid)) + if (inferior_ptid == null_ptid + || inferior_thread ()->state == THREAD_EXITED) error (_("Cannot execute this command without a live selected thread.")); } @@ -714,7 +769,7 @@ error_is_running (void) static void ensure_not_running (void) { - if (is_running (inferior_ptid)) + if (inferior_thread ()->state == THREAD_RUNNING) error_is_running (); } @@ -728,54 +783,69 @@ continue_1 (int all_threads) { /* Don't error out if the current thread is running, because there may be other stopped threads. */ - struct cleanup *old_chain; - /* Backup current thread and selected frame. */ - old_chain = make_cleanup_restore_current_thread (); + /* Backup current thread and selected frame and restore on scope + exit. */ + scoped_restore_current_thread restore_thread; iterate_over_threads (proceed_thread_callback, NULL); - /* Restore selected ptid. */ - do_cleanups (old_chain); + if (current_ui->prompt_state == PROMPT_BLOCKED) + { + /* If all threads in the target were already running, + proceed_thread_callback ends up never calling proceed, + and so nothing calls this to put the inferior's terminal + settings in effect and remove stdin from the event loop, + which we must when running a foreground command. E.g.: + + (gdb) c -a& + Continuing. + + (gdb) c -a + Continuing. + + */ + target_terminal::inferior (); + } } else { ensure_valid_thread (); ensure_not_running (); - clear_proceed_status (); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); } } /* continue [-a] [proceed-count] [&] */ + static void -continue_command (char *args, int from_tty) +continue_command (const char *args, int from_tty) { - int async_exec = 0; - int all_threads = 0; + int async_exec; + bool all_threads_p = false; + ERROR_NO_INFERIOR; /* Find out whether we must run in the background. */ - if (args != NULL) - async_exec = strip_bg_char (&args); - - prepare_execution_command (¤t_target, async_exec); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (args, &async_exec); + args = stripped.get (); if (args != NULL) { - if (strncmp (args, "-a", sizeof ("-a") - 1) == 0) + if (startswith (args, "-a")) { - all_threads = 1; + all_threads_p = true; args += sizeof ("-a") - 1; if (*args == '\0') args = NULL; } } - if (!non_stop && all_threads) + if (!non_stop && all_threads_p) error (_("`-a' is meaningless in all-stop mode.")); - if (args != NULL && all_threads) + if (args != NULL && all_threads_p) error (_("Can't resume all threads and specify " "proceed count simultaneously.")); @@ -789,14 +859,14 @@ continue_command (char *args, int from_tty) struct thread_info *tp; if (non_stop) - tp = find_thread_ptid (inferior_ptid); + tp = inferior_thread (); else { + process_stratum_target *last_target; ptid_t last_ptid; - struct target_waitstatus ws; - get_last_target_status (&last_ptid, &ws); - tp = find_thread_ptid (last_ptid); + get_last_target_status (&last_target, &last_ptid, nullptr); + tp = find_thread_ptid (last_target, last_ptid); } if (tp != NULL) bs = tp->control.stop_bpstat; @@ -821,10 +891,21 @@ continue_command (char *args, int from_tty) } } + ERROR_NO_INFERIOR; + ensure_not_tfind_mode (); + + if (!non_stop || !all_threads_p) + { + ensure_valid_thread (); + ensure_not_running (); + } + + prepare_execution_command (current_top_target (), async_exec); + if (from_tty) printf_filtered (_("Continuing.\n")); - continue_1 (all_threads); + continue_1 (all_threads_p); } /* Record the starting point of a "step" or "next" command. */ @@ -832,16 +913,20 @@ continue_command (char *args, int from_tty) static void set_step_frame (void) { - struct symtab_and_line sal; + frame_info *frame = get_current_frame (); + + symtab_and_line sal = find_frame_sal (frame); + set_step_info (frame, sal); - find_frame_sal (get_current_frame (), &sal); - set_step_info (get_current_frame (), sal); + CORE_ADDR pc = get_frame_pc (frame); + thread_info *tp = inferior_thread (); + tp->control.step_start_function = find_pc_function (pc); } /* Step until outside of current statement. */ static void -step_command (char *count_string, int from_tty) +step_command (const char *count_string, int from_tty) { step_1 (0, 0, count_string); } @@ -849,7 +934,7 @@ step_command (char *count_string, int from_tty) /* Likewise, but skip over subroutine calls as if single instructions. */ static void -next_command (char *count_string, int from_tty) +next_command (const char *count_string, int from_tty) { step_1 (1, 0, count_string); } @@ -857,186 +942,206 @@ next_command (char *count_string, int from_tty) /* Likewise, but step only one instruction. */ static void -stepi_command (char *count_string, int from_tty) +stepi_command (const char *count_string, int from_tty) { step_1 (0, 1, count_string); } static void -nexti_command (char *count_string, int from_tty) +nexti_command (const char *count_string, int from_tty) { step_1 (1, 1, count_string); } -void -delete_longjmp_breakpoint_cleanup (void *arg) +/* Data for the FSM that manages the step/next/stepi/nexti + commands. */ + +struct step_command_fsm : public thread_fsm { - int thread = * (int *) arg; - delete_longjmp_breakpoint (thread); + /* How many steps left in a "step N"-like command. */ + int count; + + /* If true, this is a next/nexti, otherwise a step/stepi. */ + int skip_subroutines; + + /* If true, this is a stepi/nexti, otherwise a step/step. */ + int single_inst; + + explicit step_command_fsm (struct interp *cmd_interp) + : thread_fsm (cmd_interp) + { + } + + void clean_up (struct thread_info *thread) override; + bool should_stop (struct thread_info *thread) override; + enum async_reply_reason do_async_reply_reason () override; +}; + +/* Prepare for a step/next/etc. command. Any target resource + allocated here is undone in the FSM's clean_up method. */ + +static void +step_command_fsm_prepare (struct step_command_fsm *sm, + int skip_subroutines, int single_inst, + int count, struct thread_info *thread) +{ + sm->skip_subroutines = skip_subroutines; + sm->single_inst = single_inst; + sm->count = count; + + /* Leave the si command alone. */ + if (!sm->single_inst || sm->skip_subroutines) + set_longjmp_breakpoint (thread, get_frame_id (get_current_frame ())); + + thread->control.stepping_command = 1; } +static int prepare_one_step (struct step_command_fsm *sm); + static void -step_1 (int skip_subroutines, int single_inst, char *count_string) +step_1 (int skip_subroutines, int single_inst, const char *count_string) { - int count = 1; - struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); - int async_exec = 0; - int thread = -1; + int count; + int async_exec; + struct thread_info *thr; + struct step_command_fsm *step_sm; ERROR_NO_INFERIOR; ensure_not_tfind_mode (); ensure_valid_thread (); ensure_not_running (); - if (count_string) - async_exec = strip_bg_char (&count_string); + gdb::unique_xmalloc_ptr stripped + = strip_bg_char (count_string, &async_exec); + count_string = stripped.get (); - prepare_execution_command (¤t_target, async_exec); + prepare_execution_command (current_top_target (), async_exec); count = count_string ? parse_and_eval_long (count_string) : 1; - if (!single_inst || skip_subroutines) /* Leave si command alone. */ - { - struct thread_info *tp = inferior_thread (); - - if (in_thread_list (inferior_ptid)) - thread = pid_to_thread_id (inferior_ptid); - - set_longjmp_breakpoint (tp, get_frame_id (get_current_frame ())); - - make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); - } + clear_proceed_status (1); - /* In synchronous case, all is well; each step_once call will step once. */ - if (!target_can_async_p ()) - { - for (; count > 0; count--) - { - step_once (skip_subroutines, single_inst, count, thread); + /* Setup the execution command state machine to handle all the COUNT + steps. */ + thr = inferior_thread (); + step_sm = new step_command_fsm (command_interp ()); + thr->thread_fsm = step_sm; - if (!target_has_execution) - break; - else - { - struct thread_info *tp = inferior_thread (); - - if (!tp->control.stop_step || !tp->step_multi) - { - /* If we stopped for some reason that is not stepping - there are no further steps to make. */ - tp->step_multi = 0; - break; - } - } - } + step_command_fsm_prepare (step_sm, skip_subroutines, + single_inst, count, thr); - do_cleanups (cleanups); - } + /* Do only one step for now, before returning control to the event + loop. Let the continuation figure out how many other steps we + need to do, and handle them one at the time, through + step_once. */ + if (!prepare_one_step (step_sm)) + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); else { - /* In the case of an asynchronous target things get complicated; - do only one step for now, before returning control to the - event loop. Let the continuation figure out how many other - steps we need to do, and handle them one at the time, through - step_once. */ - step_once (skip_subroutines, single_inst, count, thread); + int proceeded; - /* We are running, and the continuation is installed. It will - disable the longjmp breakpoint as appropriate. */ - discard_cleanups (cleanups); + /* Stepped into an inline frame. Pretend that we've + stopped. */ + thr->thread_fsm->clean_up (thr); + proceeded = normal_stop (); + if (!proceeded) + inferior_event_handler (INF_EXEC_COMPLETE, NULL); + all_uis_check_sync_execution_done (); } } -struct step_1_continuation_args -{ - int count; - int skip_subroutines; - int single_inst; - int thread; -}; +/* Implementation of the 'should_stop' FSM method for stepping + commands. Called after we are done with one step operation, to + check whether we need to step again, before we print the prompt and + return control to the user. If count is > 1, returns false, as we + will need to keep going. */ -/* Called after we are done with one step operation, to check whether - we need to step again, before we print the prompt and return control - to the user. If count is > 1, we will need to do one more call to - proceed(), via step_once(). Basically it is like step_once and - step_1_continuation are co-recursive. */ -static void -step_1_continuation (void *args, int err) +bool +step_command_fsm::should_stop (struct thread_info *tp) { - struct step_1_continuation_args *a = args; - - if (target_has_execution) + if (tp->control.stop_step) { - struct thread_info *tp; + /* There are more steps to make, and we did stop due to + ending a stepping range. Do another step. */ + if (--count > 0) + return prepare_one_step (this); - tp = inferior_thread (); - if (!err - && tp->step_multi && tp->control.stop_step) - { - /* There are more steps to make, and we did stop due to - ending a stepping range. Do another step. */ - step_once (a->skip_subroutines, a->single_inst, - a->count - 1, a->thread); - return; - } - tp->step_multi = 0; + set_finished (); } - /* We either hit an error, or stopped for some reason that is - not stepping, or there are no further steps to make. - Cleanup. */ - if (!a->single_inst || a->skip_subroutines) - delete_longjmp_breakpoint (a->thread); + return true; } -/* Do just one step operation. This is useful to implement the 'step - n' kind of commands. In case of asynchronous targets, we will have - to set up a continuation to be done after the target stops (after - this one step). For synch targets, the caller handles further - stepping. */ +/* Implementation of the 'clean_up' FSM method for stepping commands. */ -static void -step_once (int skip_subroutines, int single_inst, int count, int thread) +void +step_command_fsm::clean_up (struct thread_info *thread) { - struct frame_info *frame = get_current_frame (); + if (!single_inst || skip_subroutines) + delete_longjmp_breakpoint (thread->global_num); +} + +/* Implementation of the 'async_reply_reason' FSM method for stepping + commands. */ - if (count > 0) +enum async_reply_reason +step_command_fsm::do_async_reply_reason () +{ + return EXEC_ASYNC_END_STEPPING_RANGE; +} + +/* Prepare for one step in "step N". The actual target resumption is + done by the caller. Return true if we're done and should thus + report a stop to the user. Returns false if the target needs to be + resumed. */ + +static int +prepare_one_step (struct step_command_fsm *sm) +{ + if (sm->count > 0) { + struct frame_info *frame = get_current_frame (); + /* Don't assume THREAD is a valid thread id. It is set to -1 if the longjmp breakpoint was not required. Use the INFERIOR_PTID thread instead, which is the same thread when THREAD is set. */ struct thread_info *tp = inferior_thread (); - clear_proceed_status (); set_step_frame (); - if (!single_inst) + if (!sm->single_inst) { CORE_ADDR pc; /* Step at an inlined function behaves like "down". */ - if (!skip_subroutines - && inline_skipped_frames (inferior_ptid)) + if (!sm->skip_subroutines + && inline_skipped_frames (tp)) { ptid_t resume_ptid; + const char *fn = NULL; + symtab_and_line sal; + struct symbol *sym; /* Pretend that we've ran. */ resume_ptid = user_visible_resume_ptid (1); - set_running (resume_ptid, 1); + set_running (tp->inf->process_target (), resume_ptid, true); - step_into_inline_frame (inferior_ptid); - if (count > 1) - step_once (skip_subroutines, single_inst, count - 1, thread); - else - { - /* Pretend that we've stopped. */ - normal_stop (); + step_into_inline_frame (tp); + + frame = get_current_frame (); + sal = find_frame_sal (frame); + sym = get_frame_function (frame); - if (target_can_async_p ()) - inferior_event_handler (INF_EXEC_COMPLETE, NULL); + if (sym != NULL) + fn = sym->print_name (); + + if (sal.line == 0 + || !function_name_is_marked_for_skip (fn, sal)) + { + sm->count--; + return prepare_one_step (sm); } - return; } pc = get_frame_pc (frame); @@ -1061,7 +1166,7 @@ step_once (int skip_subroutines, int single_inst, int count, int thread) &tp->control.step_range_end) == 0) error (_("Cannot find bounds of current function")); - target_terminal_ours (); + target_terminal::ours_for_output (); printf_filtered (_("Single stepping until exit from function %s," "\nwhich has no line number information.\n"), name); @@ -1071,50 +1176,35 @@ step_once (int skip_subroutines, int single_inst, int count, int thread) { /* Say we are stepping, but stop after one insn whatever it does. */ tp->control.step_range_start = tp->control.step_range_end = 1; - if (!skip_subroutines) + if (!sm->skip_subroutines) /* It is stepi. Don't step over function calls, not even to functions lacking line numbers. */ tp->control.step_over_calls = STEP_OVER_NONE; } - if (skip_subroutines) + if (sm->skip_subroutines) tp->control.step_over_calls = STEP_OVER_ALL; - tp->step_multi = (count > 1); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1); - - /* For async targets, register a continuation to do any - additional steps. For sync targets, the caller will handle - further stepping. */ - if (target_can_async_p ()) - { - struct step_1_continuation_args *args; - - args = xmalloc (sizeof (*args)); - args->skip_subroutines = skip_subroutines; - args->single_inst = single_inst; - args->count = count; - args->thread = thread; - - add_intermediate_continuation (tp, step_1_continuation, args, xfree); - } + return 0; } + + /* Done. */ + sm->set_finished (); + return 1; } /* Continue program at specified address. */ static void -jump_command (char *arg, int from_tty) +jump_command (const char *arg, int from_tty) { struct gdbarch *gdbarch = get_current_arch (); CORE_ADDR addr; - struct symtabs_and_lines sals; - struct symtab_and_line sal; struct symbol *fn; struct symbol *sfn; - int async_exec = 0; + int async_exec; ERROR_NO_INFERIOR; ensure_not_tfind_mode (); @@ -1122,22 +1212,20 @@ jump_command (char *arg, int from_tty) ensure_not_running (); /* Find out whether we must run in the background. */ - if (arg != NULL) - async_exec = strip_bg_char (&arg); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (arg, &async_exec); + arg = stripped.get (); - prepare_execution_command (¤t_target, async_exec); + prepare_execution_command (current_top_target (), async_exec); if (!arg) error_no_arg (_("starting address")); - sals = decode_line_with_last_displayed (arg, DECODE_LINE_FUNFIRSTLINE); - if (sals.nelts != 1) - { - error (_("Unreasonable jump request")); - } + std::vector sals + = decode_line_with_last_displayed (arg, DECODE_LINE_FUNFIRSTLINE); + if (sals.size () != 1) + error (_("Unreasonable jump request")); - sal = sals.sals[0]; - xfree (sals.sals); + symtab_and_line &sal = sals[0]; if (sal.symtab == 0 && sal.pc == 0) error (_("No source file has been specified.")); @@ -1150,7 +1238,7 @@ jump_command (char *arg, int from_tty) if (fn != NULL && sfn != fn) { if (!query (_("Line %d is not in `%s'. Jump anyway? "), sal.line, - SYMBOL_PRINT_NAME (fn))) + fn->print_name ())) { error (_("Not confirmed.")); /* NOTREACHED */ @@ -1159,9 +1247,12 @@ jump_command (char *arg, int from_tty) if (sfn != NULL) { + struct obj_section *section; + fixup_symbol_section (sfn, 0); - if (section_is_overlay (SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sfn), sfn)) && - !section_is_mapped (SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sfn), sfn))) + section = SYMBOL_OBJ_SECTION (symbol_objfile (sfn), sfn); + if (section_is_overlay (section) + && !section_is_mapped (section)) { if (!query (_("WARNING!!! Destination is in " "unmapped overlay! Jump anyway? "))) @@ -1181,32 +1272,17 @@ jump_command (char *arg, int from_tty) printf_filtered (".\n"); } - clear_proceed_status (); - proceed (addr, GDB_SIGNAL_0, 0); + clear_proceed_status (0); + proceed (addr, GDB_SIGNAL_0); } - -/* Go to line or address in current procedure. */ -static void -go_command (char *line_no, int from_tty) -{ - if (line_no == (char *) NULL || !*line_no) - printf_filtered (_("Usage: go \n")); - else - { - tbreak_command (line_no, from_tty); - jump_command (line_no, from_tty); - } -} - - /* Continue program giving it specified signal. */ static void -signal_command (char *signum_exp, int from_tty) +signal_command (const char *signum_exp, int from_tty) { enum gdb_signal oursig; - int async_exec = 0; + int async_exec; dont_repeat (); /* Too dangerous. */ ERROR_NO_INFERIOR; @@ -1215,10 +1291,11 @@ signal_command (char *signum_exp, int from_tty) ensure_not_running (); /* Find out whether we must run in the background. */ - if (signum_exp != NULL) - async_exec = strip_bg_char (&signum_exp); + gdb::unique_xmalloc_ptr stripped + = strip_bg_char (signum_exp, &async_exec); + signum_exp = stripped.get (); - prepare_execution_command (¤t_target, async_exec); + prepare_execution_command (current_top_target (), async_exec); if (!signum_exp) error_no_arg (_("signal number")); @@ -1239,6 +1316,50 @@ signal_command (char *signum_exp, int from_tty) oursig = gdb_signal_from_command (num); } + /* Look for threads other than the current that this command ends up + resuming too (due to schedlock off), and warn if they'll get a + signal delivered. "signal 0" is used to suppress a previous + signal, but if the current thread is no longer the one that got + the signal, then the user is potentially suppressing the signal + of the wrong thread. */ + if (!non_stop) + { + int must_confirm = 0; + + /* This indicates what will be resumed. Either a single thread, + a whole process, or all threads of all processes. */ + ptid_t resume_ptid = user_visible_resume_ptid (0); + process_stratum_target *resume_target + = user_visible_resume_target (resume_ptid); + + thread_info *current = inferior_thread (); + + for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid)) + { + if (tp == current) + continue; + + if (tp->suspend.stop_signal != GDB_SIGNAL_0 + && signal_pass_state (tp->suspend.stop_signal)) + { + if (!must_confirm) + printf_unfiltered (_("Note:\n")); + printf_unfiltered (_(" Thread %s previously stopped with signal %s, %s.\n"), + print_thread_id (tp), + gdb_signal_to_name (tp->suspend.stop_signal), + gdb_signal_to_string (tp->suspend.stop_signal)); + must_confirm = 1; + } + } + + if (must_confirm + && !query (_("Continuing thread %s (the current thread) with specified signal will\n" + "still deliver the signals noted above to their respective threads.\n" + "Continue anyway? "), + print_thread_id (inferior_thread ()))) + error (_("Not confirmed.")); + } + if (from_tty) { if (oursig == GDB_SIGNAL_0) @@ -1248,26 +1369,97 @@ signal_command (char *signum_exp, int from_tty) gdb_signal_to_name (oursig)); } - clear_proceed_status (); - proceed ((CORE_ADDR) -1, oursig, 0); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, oursig); } -/* Continuation args to be passed to the "until" command - continuation. */ -struct until_next_continuation_args +/* Queue a signal to be delivered to the current thread. */ + +static void +queue_signal_command (const char *signum_exp, int from_tty) { - /* The thread that was current when the command was executed. */ + enum gdb_signal oursig; + struct thread_info *tp; + + ERROR_NO_INFERIOR; + ensure_not_tfind_mode (); + ensure_valid_thread (); + ensure_not_running (); + + if (signum_exp == NULL) + error_no_arg (_("signal number")); + + /* It would be even slicker to make signal names be valid expressions, + (the type could be "enum $signal" or some such), then the user could + assign them to convenience variables. */ + oursig = gdb_signal_from_name (signum_exp); + + if (oursig == GDB_SIGNAL_UNKNOWN) + { + /* No, try numeric. */ + int num = parse_and_eval_long (signum_exp); + + if (num == 0) + oursig = GDB_SIGNAL_0; + else + oursig = gdb_signal_from_command (num); + } + + if (oursig != GDB_SIGNAL_0 + && !signal_pass_state (oursig)) + error (_("Signal handling set to not pass this signal to the program.")); + + tp = inferior_thread (); + tp->suspend.stop_signal = oursig; +} + +/* Data for the FSM that manages the until (with no argument) + command. */ + +struct until_next_fsm : public thread_fsm +{ + /* The thread that as current when the command was executed. */ int thread; + + until_next_fsm (struct interp *cmd_interp, int thread) + : thread_fsm (cmd_interp), + thread (thread) + { + } + + bool should_stop (struct thread_info *thread) override; + void clean_up (struct thread_info *thread) override; + enum async_reply_reason do_async_reply_reason () override; }; -/* A continuation callback for until_next_command. */ +/* Implementation of the 'should_stop' FSM method for the until (with + no arg) command. */ -static void -until_next_continuation (void *arg, int err) +bool +until_next_fsm::should_stop (struct thread_info *tp) { - struct until_next_continuation_args *a = arg; + if (tp->control.stop_step) + set_finished (); - delete_longjmp_breakpoint (a->thread); + return true; +} + +/* Implementation of the 'clean_up' FSM method for the until (with no + arg) command. */ + +void +until_next_fsm::clean_up (struct thread_info *thread) +{ + delete_longjmp_breakpoint (thread->global_num); +} + +/* Implementation of the 'async_reply_reason' FSM method for the until + (with no arg) command. */ + +enum async_reply_reason +until_next_fsm::do_async_reply_reason () +{ + return EXEC_ASYNC_END_STEPPING_RANGE; } /* Proceed until we reach a different source line with pc greater than @@ -1286,10 +1478,10 @@ until_next_command (int from_tty) struct symbol *func; struct symtab_and_line sal; struct thread_info *tp = inferior_thread (); - int thread = tp->num; - struct cleanup *old_chain; + int thread = tp->global_num; + struct until_next_fsm *sm; - clear_proceed_status (); + clear_proceed_status (0); set_step_frame (); frame = get_current_frame (); @@ -1309,44 +1501,35 @@ until_next_command (int from_tty) error (_("Execution is not within a known function.")); tp->control.step_range_start = BMSYMBOL_VALUE_ADDRESS (msymbol); - tp->control.step_range_end = pc; + /* The upper-bound of step_range is exclusive. In order to make PC + within the range, set the step_range_end with PC + 1. */ + tp->control.step_range_end = pc + 1; } else { sal = find_pc_line (pc, 0); - tp->control.step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func)); + tp->control.step_range_start = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (func)); tp->control.step_range_end = sal.end; } tp->control.may_range_step = 1; tp->control.step_over_calls = STEP_OVER_ALL; - tp->step_multi = 0; /* Only one call to proceed */ - set_longjmp_breakpoint (tp, get_frame_id (frame)); - old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); + delete_longjmp_breakpoint_cleanup lj_deleter (thread); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1); + sm = new until_next_fsm (command_interp (), tp->global_num); + tp->thread_fsm = sm; + lj_deleter.release (); - if (target_can_async_p () && is_running (inferior_ptid)) - { - struct until_next_continuation_args *cont_args; - - discard_cleanups (old_chain); - cont_args = XNEW (struct until_next_continuation_args); - cont_args->thread = inferior_thread ()->num; - - add_continuation (tp, until_next_continuation, cont_args, xfree); - } - else - do_cleanups (old_chain); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); } static void -until_command (char *arg, int from_tty) +until_command (const char *arg, int from_tty) { - int async_exec = 0; + int async_exec; ERROR_NO_INFERIOR; ensure_not_tfind_mode (); @@ -1354,10 +1537,10 @@ until_command (char *arg, int from_tty) ensure_not_running (); /* Find out whether we must run in the background. */ - if (arg != NULL) - async_exec = strip_bg_char (&arg); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (arg, &async_exec); + arg = stripped.get (); - prepare_execution_command (¤t_target, async_exec); + prepare_execution_command (current_top_target (), async_exec); if (arg) until_break_command (arg, from_tty, 0); @@ -1366,9 +1549,9 @@ until_command (char *arg, int from_tty) } static void -advance_command (char *arg, int from_tty) +advance_command (const char *arg, int from_tty) { - int async_exec = 0; + int async_exec; ERROR_NO_INFERIOR; ensure_not_tfind_mode (); @@ -1379,35 +1562,26 @@ advance_command (char *arg, int from_tty) error_no_arg (_("a location")); /* Find out whether we must run in the background. */ - if (arg != NULL) - async_exec = strip_bg_char (&arg); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (arg, &async_exec); + arg = stripped.get (); - prepare_execution_command (¤t_target, async_exec); + prepare_execution_command (current_top_target (), async_exec); until_break_command (arg, from_tty, 1); } /* Return the value of the result of a function at the end of a 'finish' - command/BP. */ + command/BP. DTOR_DATA (if not NULL) can represent inferior registers + right after an inferior call has finished. */ struct value * get_return_value (struct value *function, struct type *value_type) { - struct regcache *stop_regs = stop_registers; - struct gdbarch *gdbarch; - struct value *value; - struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); - - /* If stop_registers were not saved, use the current registers. */ - if (!stop_regs) - { - stop_regs = regcache_dup (get_current_regcache ()); - make_cleanup_regcache_xfree (stop_regs); - } - - gdbarch = get_regcache_arch (stop_regs); + regcache *stop_regs = get_current_regcache (); + struct gdbarch *gdbarch = stop_regs->arch (); + struct value *value; - CHECK_TYPEDEF (value_type); + value_type = check_typedef (value_type); gdb_assert (TYPE_CODE (value_type) != TYPE_CODE_VOID); /* FIXME: 2003-09-27: When returning from a nested inferior function @@ -1434,130 +1608,190 @@ get_return_value (struct value *function, struct type *value_type) internal_error (__FILE__, __LINE__, _("bad switch")); } - do_cleanups (cleanup); - return value; } -/* Print the result of a function at the end of a 'finish' command. */ +/* The captured function return value/type and its position in the + value history. */ -static void -print_return_value (struct value *function, struct type *value_type) +struct return_value_info { - struct value *value = get_return_value (function, value_type); - struct ui_out *uiout = current_uiout; + /* The captured return value. May be NULL if we weren't able to + retrieve it. See get_return_value. */ + struct value *value; + + /* The return type. In some cases, we'll not be able extract the + return value, but we always know the type. */ + struct type *type; + + /* If we captured a value, this is the value history index. */ + int value_history_index; +}; - if (value) +/* Helper for print_return_value. */ + +static void +print_return_value_1 (struct ui_out *uiout, struct return_value_info *rv) +{ + if (rv->value != NULL) { struct value_print_options opts; - struct ui_file *stb; - struct cleanup *old_chain; /* Print it. */ - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); - ui_out_text (uiout, "Value returned is "); - ui_out_field_fmt (uiout, "gdb-result-var", "$%d", - record_latest_value (value)); - ui_out_text (uiout, " = "); - get_no_prettyformat_print_options (&opts); - value_print (value, stb, &opts); - ui_out_field_stream (uiout, "return-value", stb); - ui_out_text (uiout, "\n"); - do_cleanups (old_chain); + uiout->text ("Value returned is "); + uiout->field_fmt ("gdb-result-var", "$%d", + rv->value_history_index); + uiout->text (" = "); + get_user_print_options (&opts); + + if (opts.finish_print) + { + string_file stb; + value_print (rv->value, &stb, &opts); + uiout->field_stream ("return-value", stb); + } + else + uiout->field_string ("return-value", _(""), + metadata_style.style ()); + uiout->text ("\n"); } else { - ui_out_text (uiout, "Value returned has type: "); - ui_out_field_string (uiout, "return-type", TYPE_NAME (value_type)); - ui_out_text (uiout, "."); - ui_out_text (uiout, " Cannot determine contents\n"); + std::string type_name = type_to_string (rv->type); + uiout->text ("Value returned has type: "); + uiout->field_string ("return-type", type_name.c_str ()); + uiout->text ("."); + uiout->text (" Cannot determine contents\n"); } } -/* Stuff that needs to be done by the finish command after the target - has stopped. In asynchronous mode, we wait for the target to stop - in the call to poll or select in the event loop, so it is - impossible to do all the stuff as part of the finish_command - function itself. The only chance we have to complete this command - is in fetch_inferior_event, which is called by the event loop as - soon as it detects that the target has stopped. */ +/* Print the result of a function at the end of a 'finish' command. + RV points at an object representing the captured return value/type + and its position in the value history. */ -struct finish_command_continuation_args +void +print_return_value (struct ui_out *uiout, struct return_value_info *rv) { - /* The thread that as current when the command was executed. */ - int thread; - struct breakpoint *breakpoint; - struct symbol *function; + if (rv->type == NULL + || TYPE_CODE (check_typedef (rv->type)) == TYPE_CODE_VOID) + return; + + try + { + /* print_return_value_1 can throw an exception in some + circumstances. We need to catch this so that we still + delete the breakpoint. */ + print_return_value_1 (uiout, rv); + } + catch (const gdb_exception &ex) + { + exception_print (gdb_stdout, ex); + } +} + +/* Data for the FSM that manages the finish command. */ + +struct finish_command_fsm : public thread_fsm +{ + /* The momentary breakpoint set at the function's return address in + the caller. */ + breakpoint_up breakpoint; + + /* The function that we're stepping out of. */ + struct symbol *function = nullptr; + + /* If the FSM finishes successfully, this stores the function's + return value. */ + struct return_value_info return_value_info {}; + + explicit finish_command_fsm (struct interp *cmd_interp) + : thread_fsm (cmd_interp) + { + } + + bool should_stop (struct thread_info *thread) override; + void clean_up (struct thread_info *thread) override; + struct return_value_info *return_value () override; + enum async_reply_reason do_async_reply_reason () override; }; -static void -finish_command_continuation (void *arg, int err) +/* Implementation of the 'should_stop' FSM method for the finish + commands. Detects whether the thread stepped out of the function + successfully, and if so, captures the function's return value and + marks the FSM finished. */ + +bool +finish_command_fsm::should_stop (struct thread_info *tp) { - struct finish_command_continuation_args *a = arg; + struct return_value_info *rv = &return_value_info; - if (!err) + if (function != NULL + && bpstat_find_breakpoint (tp->control.stop_bpstat, + breakpoint.get ()) != NULL) { - struct thread_info *tp = NULL; - bpstat bs = NULL; + /* We're done. */ + set_finished (); - if (!ptid_equal (inferior_ptid, null_ptid) - && target_has_execution - && is_stopped (inferior_ptid)) - { - tp = inferior_thread (); - bs = tp->control.stop_bpstat; - } + rv->type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (rv->type == NULL) + internal_error (__FILE__, __LINE__, + _("finish_command: function has no target type")); - if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL - && a->function != NULL) + if (TYPE_CODE (check_typedef (rv->type)) != TYPE_CODE_VOID) { - struct type *value_type; + struct value *func; - value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function)); - if (!value_type) - internal_error (__FILE__, __LINE__, - _("finish_command: function has no target type")); + func = read_var_value (function, NULL, get_current_frame ()); + rv->value = get_return_value (func, rv->type); + if (rv->value != NULL) + rv->value_history_index = record_latest_value (rv->value); + } + } + else if (tp->control.stop_step) + { + /* Finishing from an inline frame, or reverse finishing. In + either case, there's no way to retrieve the return value. */ + set_finished (); + } - if (TYPE_CODE (value_type) != TYPE_CODE_VOID) - { - volatile struct gdb_exception ex; - struct value *func; + return true; +} - func = read_var_value (a->function, get_current_frame ()); - TRY_CATCH (ex, RETURN_MASK_ALL) - { - /* print_return_value can throw an exception in some - circumstances. We need to catch this so that we still - delete the breakpoint. */ - print_return_value (func, value_type); - } - if (ex.reason < 0) - exception_print (gdb_stdout, ex); - } - } +/* Implementation of the 'clean_up' FSM method for the finish + commands. */ - /* We suppress normal call of normal_stop observer and do it - here so that the *stopped notification includes the return - value. */ - if (bs != NULL && tp->control.proceed_to_finish) - observer_notify_normal_stop (bs, 1 /* print frame */); - } +void +finish_command_fsm::clean_up (struct thread_info *thread) +{ + breakpoint.reset (); + delete_longjmp_breakpoint (thread->global_num); +} - delete_breakpoint (a->breakpoint); - delete_longjmp_breakpoint (a->thread); +/* Implementation of the 'return_value' FSM method for the finish + commands. */ + +struct return_value_info * +finish_command_fsm::return_value () +{ + return &return_value_info; } -static void -finish_command_continuation_free_arg (void *arg) +/* Implementation of the 'async_reply_reason' FSM method for the + finish commands. */ + +enum async_reply_reason +finish_command_fsm::do_async_reply_reason () { - xfree (arg); + if (execution_direction == EXEC_REVERSE) + return EXEC_ASYNC_END_STEPPING_RANGE; + else + return EXEC_ASYNC_FUNCTION_FINISHED; } /* finish_backward -- helper function for finish_command. */ static void -finish_backward (struct symbol *function) +finish_backward (struct finish_command_fsm *sm) { struct symtab_and_line sal; struct thread_info *tp = inferior_thread (); @@ -1567,8 +1801,7 @@ finish_backward (struct symbol *function) pc = get_frame_pc (get_current_frame ()); if (find_pc_partial_function (pc, NULL, &func_addr, NULL) == 0) - internal_error (__FILE__, __LINE__, - _("Finish: couldn't find function.")); + error (_("Cannot find bounds of current function")); sal = find_pc_line (func_addr, 0); @@ -1586,82 +1819,89 @@ finish_backward (struct symbol *function) { struct frame_info *frame = get_selected_frame (NULL); struct gdbarch *gdbarch = get_frame_arch (frame); - struct symtab_and_line sr_sal; /* Set a step-resume at the function's entry point. Once that's hit, we'll do one more step backwards. */ - init_sal (&sr_sal); + symtab_and_line sr_sal; sr_sal.pc = sal.pc; sr_sal.pspace = get_frame_program_space (frame); insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, null_frame_id); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); } else { /* We're almost there -- we just need to back up by one more single-step. */ tp->control.step_range_start = tp->control.step_range_end = 1; - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); } } -/* finish_forward -- helper function for finish_command. */ +/* finish_forward -- helper function for finish_command. FRAME is the + frame that called the function we're about to step out of. */ static void -finish_forward (struct symbol *function, struct frame_info *frame) +finish_forward (struct finish_command_fsm *sm, struct frame_info *frame) { struct frame_id frame_id = get_frame_id (frame); struct gdbarch *gdbarch = get_frame_arch (frame); struct symtab_and_line sal; struct thread_info *tp = inferior_thread (); - struct breakpoint *breakpoint; - struct cleanup *old_chain; - struct finish_command_continuation_args *cargs; - int thread = tp->num; sal = find_pc_line (get_frame_pc (frame), 0); sal.pc = get_frame_pc (frame); - breakpoint = set_momentary_breakpoint (gdbarch, sal, - get_stack_frame_id (frame), - bp_finish); + sm->breakpoint = set_momentary_breakpoint (gdbarch, sal, + get_stack_frame_id (frame), + bp_finish); /* set_momentary_breakpoint invalidates FRAME. */ frame = NULL; - old_chain = make_cleanup_delete_breakpoint (breakpoint); - set_longjmp_breakpoint (tp, frame_id); - make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); - /* We want stop_registers, please... */ + /* We want to print return value, please... */ tp->control.proceed_to_finish = 1; - cargs = xmalloc (sizeof (*cargs)); - cargs->thread = thread; - cargs->breakpoint = breakpoint; - cargs->function = function; - add_continuation (tp, finish_command_continuation, cargs, - finish_command_continuation_free_arg); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); +} + +/* Skip frames for "finish". */ + +static struct frame_info * +skip_finish_frames (struct frame_info *frame) +{ + struct frame_info *start; + + do + { + start = frame; + + frame = skip_tailcall_frames (frame); + if (frame == NULL) + break; + + frame = skip_unwritable_frames (frame); + if (frame == NULL) + break; + } + while (start != frame); - discard_cleanups (old_chain); - if (!target_can_async_p ()) - do_all_continuations (0); + return frame; } /* "finish": Set a temporary breakpoint at the place the selected frame will return to, then continue. */ static void -finish_command (char *arg, int from_tty) +finish_command (const char *arg, int from_tty) { struct frame_info *frame; - struct symbol *function; - - int async_exec = 0; + int async_exec; + struct finish_command_fsm *sm; + struct thread_info *tp; ERROR_NO_INFERIOR; ensure_not_tfind_mode (); @@ -1669,10 +1909,10 @@ finish_command (char *arg, int from_tty) ensure_not_running (); /* Find out whether we must run in the background. */ - if (arg != NULL) - async_exec = strip_bg_char (&arg); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (arg, &async_exec); + arg = stripped.get (); - prepare_execution_command (¤t_target, async_exec); + prepare_execution_command (current_top_target (), async_exec); if (arg) error (_("The \"finish\" command does not take any arguments.")); @@ -1681,11 +1921,16 @@ finish_command (char *arg, int from_tty) if (frame == 0) error (_("\"finish\" not meaningful in the outermost frame.")); - clear_proceed_status (); + clear_proceed_status (0); + + tp = inferior_thread (); + + sm = new finish_command_fsm (command_interp ()); + + tp->thread_fsm = sm; /* Finishing from an inline frame is completely different. We don't - try to show the "return value" - no way to locate it. So we do - not need a completion. */ + try to show the "return value" - no way to locate it. */ if (get_frame_type (get_selected_frame (_("No selected frame."))) == INLINE_FRAME) { @@ -1694,11 +1939,7 @@ finish_command (char *arg, int from_tty) called by that frame. We don't use the magic "1" value for step_range_end, because then infrun will think this is nexti, and not step over the rest of this inlined function call. */ - struct thread_info *tp = inferior_thread (); - struct symtab_and_line empty_sal; - - init_sal (&empty_sal); - set_step_info (frame, empty_sal); + set_step_info (frame, {}); tp->control.step_range_start = get_frame_pc (frame); tp->control.step_range_end = tp->control.step_range_start; tp->control.step_over_calls = STEP_OVER_ALL; @@ -1711,18 +1952,13 @@ finish_command (char *arg, int from_tty) print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0); } - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); return; } - /* Ignore TAILCALL_FRAME type frames, they were executed already before - entering THISFRAME. */ - while (get_frame_type (frame) == TAILCALL_FRAME) - frame = get_prev_frame (frame); - /* Find the function we will return from. */ - function = find_pc_function (get_frame_pc (get_selected_frame (NULL))); + sm->function = find_pc_function (get_frame_pc (get_selected_frame (NULL))); /* Print info on the selected frame, including level number but not source. */ @@ -1731,25 +1967,39 @@ finish_command (char *arg, int from_tty) if (execution_direction == EXEC_REVERSE) printf_filtered (_("Run back to call of ")); else - printf_filtered (_("Run till exit from ")); + { + if (sm->function != NULL && TYPE_NO_RETURN (sm->function->type) + && !query (_("warning: Function %s does not return normally.\n" + "Try to finish anyway? "), + sm->function->print_name ())) + error (_("Not confirmed.")); + printf_filtered (_("Run till exit from ")); + } print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0); } if (execution_direction == EXEC_REVERSE) - finish_backward (function); + finish_backward (sm); else - finish_forward (function, frame); + { + frame = skip_finish_frames (frame); + + if (frame == NULL) + error (_("Cannot find the caller frame.")); + + finish_forward (sm, frame); + } } static void -program_info (char *args, int from_tty) +info_program_command (const char *args, int from_tty) { bpstat bs; int num, stat; - struct thread_info *tp; ptid_t ptid; + process_stratum_target *proc_target; if (!target_has_execution) { @@ -1758,26 +2008,29 @@ program_info (char *args, int from_tty) } if (non_stop) - ptid = inferior_ptid; - else { - struct target_waitstatus ws; - - get_last_target_status (&ptid, &ws); + ptid = inferior_ptid; + proc_target = current_inferior ()->process_target (); } + else + get_last_target_status (&proc_target, &ptid, nullptr); - if (ptid_equal (ptid, null_ptid) || is_exited (ptid)) + if (ptid == null_ptid || ptid == minus_one_ptid) + error (_("No selected thread.")); + + thread_info *tp = find_thread_ptid (proc_target, ptid); + + if (tp->state == THREAD_EXITED) error (_("Invalid selected thread.")); - else if (is_running (ptid)) + else if (tp->state == THREAD_RUNNING) error (_("Selected thread is running.")); - tp = find_thread_ptid (ptid); bs = tp->control.stop_bpstat; stat = bpstat_num (&bs, &num); target_files_info (); printf_filtered (_("Program stopped at %s.\n"), - paddress (target_gdbarch (), stop_pc)); + paddress (target_gdbarch (), tp->suspend.stop_pc)); if (tp->control.stop_step) printf_filtered (_("It stopped after being stepped.\n")); else if (stat != 0) @@ -1803,7 +2056,7 @@ program_info (char *args, int from_tty) gdb_signal_to_string (tp->suspend.stop_signal)); } - if (!from_tty) + if (from_tty) { printf_filtered (_("Type \"info stack\" or \"info " "registers\" for more information.\n")); @@ -1811,11 +2064,11 @@ program_info (char *args, int from_tty) } static void -environment_info (char *var, int from_tty) +environment_info (const char *var, int from_tty) { if (var) { - char *val = get_in_environ (current_inferior ()->environment, var); + const char *val = current_inferior ()->environment.get (var); if (val) { @@ -1833,26 +2086,26 @@ environment_info (char *var, int from_tty) } else { - char **vector = environ_vector (current_inferior ()->environment); + char **envp = current_inferior ()->environment.envp (); - while (*vector) + for (int idx = 0; envp[idx] != NULL; ++idx) { - puts_filtered (*vector++); + puts_filtered (envp[idx]); puts_filtered ("\n"); } } } static void -set_environment_command (char *arg, int from_tty) +set_environment_command (const char *arg, int from_tty) { - char *p, *val, *var; + const char *p, *val; int nullset = 0; if (arg == 0) error_no_arg (_("environment variable and value")); - /* Find seperation between variable name and value. */ + /* Find separation between variable name and value. */ p = (char *) strchr (arg, '='); val = (char *) strchr (arg, ' '); @@ -1893,34 +2146,30 @@ set_environment_command (char *arg, int from_tty) while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--; - var = savestring (arg, p - arg); + std::string var (arg, p - arg); if (nullset) { printf_filtered (_("Setting environment variable " "\"%s\" to null value.\n"), - var); - set_in_environ (current_inferior ()->environment, var, ""); + var.c_str ()); + current_inferior ()->environment.set (var.c_str (), ""); } else - set_in_environ (current_inferior ()->environment, var, val); - xfree (var); + current_inferior ()->environment.set (var.c_str (), val); } static void -unset_environment_command (char *var, int from_tty) +unset_environment_command (const char *var, int from_tty) { if (var == 0) { /* If there is no argument, delete all environment variables. Ask for confirmation if reading from the terminal. */ if (!from_tty || query (_("Delete all environment variables? "))) - { - free_environ (current_inferior ()->environment); - current_inferior ()->environment = make_environ (); - } + current_inferior ()->environment.clear (); } else - unset_in_environ (current_inferior ()->environment, var); + current_inferior ()->environment.unset (var); } /* Handle the execution path (PATH variable). */ @@ -1928,36 +2177,45 @@ unset_environment_command (char *var, int from_tty) static const char path_var_name[] = "PATH"; static void -path_info (char *args, int from_tty) +path_info (const char *args, int from_tty) { puts_filtered ("Executable and object file path: "); - puts_filtered (get_in_environ (current_inferior ()->environment, - path_var_name)); + puts_filtered (current_inferior ()->environment.get (path_var_name)); puts_filtered ("\n"); } /* Add zero or more directories to the front of the execution path. */ static void -path_command (char *dirname, int from_tty) +path_command (const char *dirname, int from_tty) { char *exec_path; - char *env; + const char *env; dont_repeat (); - env = get_in_environ (current_inferior ()->environment, path_var_name); + env = current_inferior ()->environment.get (path_var_name); /* Can be null if path is not set. */ if (!env) env = ""; exec_path = xstrdup (env); mod_path (dirname, &exec_path); - set_in_environ (current_inferior ()->environment, path_var_name, exec_path); + current_inferior ()->environment.set (path_var_name, exec_path); xfree (exec_path); if (from_tty) - path_info ((char *) NULL, from_tty); + path_info (NULL, from_tty); } +static void +pad_to_column (string_file &stream, int col) +{ + /* At least one space must be printed to separate columns. */ + stream.putc (' '); + const int size = stream.size (); + if (size < col) + stream.puts (n_spaces (col - size)); +} + /* Print out the register NAME with value VAL, to FILE, in the default fashion. */ @@ -1968,9 +2226,17 @@ default_print_one_register_info (struct ui_file *file, { struct type *regtype = value_type (val); int print_raw_format; + string_file format_stream; + enum tab_stops + { + value_column_1 = 15, + /* Give enough room for "0x", 16 hex digits and two spaces in + preceding column. */ + value_column_2 = value_column_1 + 2 + 16 + 2, + }; - fputs_filtered (name, file); - print_spaces_filtered (15 - strlen (name), file); + format_stream.puts (name); + pad_to_column (format_stream, value_column_1); print_raw_format = (value_entirely_available (val) && !value_optimized_out (val)); @@ -1980,24 +2246,24 @@ default_print_one_register_info (struct ui_file *file, if (TYPE_CODE (regtype) == TYPE_CODE_FLT || TYPE_CODE (regtype) == TYPE_CODE_DECFLOAT) { - int j; struct value_print_options opts; const gdb_byte *valaddr = value_contents_for_printing (val); - enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (regtype)); + enum bfd_endian byte_order = type_byte_order (regtype); get_user_print_options (&opts); opts.deref_ref = 1; val_print (regtype, - value_contents_for_printing (val), value_embedded_offset (val), 0, - file, 0, val, &opts, current_language); + &format_stream, 0, val, &opts, current_language); if (print_raw_format) { - fprintf_filtered (file, "\t(raw "); - print_hex_chars (file, valaddr, TYPE_LENGTH (regtype), byte_order); - fprintf_filtered (file, ")"); + pad_to_column (format_stream, value_column_2); + format_stream.puts ("(raw "); + print_hex_chars (&format_stream, valaddr, TYPE_LENGTH (regtype), + byte_order, true); + format_stream.putc (')'); } } else @@ -2008,23 +2274,22 @@ default_print_one_register_info (struct ui_file *file, get_formatted_print_options (&opts, 'x'); opts.deref_ref = 1; val_print (regtype, - value_contents_for_printing (val), value_embedded_offset (val), 0, - file, 0, val, &opts, current_language); + &format_stream, 0, val, &opts, current_language); /* If not a vector register, print it also according to its natural format. */ if (print_raw_format && TYPE_VECTOR (regtype) == 0) { + pad_to_column (format_stream, value_column_2); get_user_print_options (&opts); opts.deref_ref = 1; - fprintf_filtered (file, "\t"); val_print (regtype, - value_contents_for_printing (val), value_embedded_offset (val), 0, - file, 0, val, &opts, current_language); + &format_stream, 0, val, &opts, current_language); } } + fputs_filtered (format_stream.c_str (), file); fprintf_filtered (file, "\n"); } @@ -2046,8 +2311,7 @@ default_print_registers_info (struct gdbarch *gdbarch, int regnum, int print_all) { int i; - const int numregs = gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch); + const int numregs = gdbarch_num_cooked_regs (gdbarch); for (i = 0; i < numregs; i++) { @@ -2085,7 +2349,7 @@ default_print_registers_info (struct gdbarch *gdbarch, } void -registers_info (char *addr_exp, int fpregs) +registers_info (const char *addr_exp, int fpregs) { struct frame_info *frame; struct gdbarch *gdbarch; @@ -2104,7 +2368,7 @@ registers_info (char *addr_exp, int fpregs) while (*addr_exp != '\0') { - char *start; + const char *start; const char *end; /* Skip leading white space. */ @@ -2134,8 +2398,7 @@ registers_info (char *addr_exp, int fpregs) /* User registers lie completely outside of the range of normal registers. Catch them early so that the target never sees them. */ - if (regnum >= gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch)) + if (regnum >= gdbarch_num_cooked_regs (gdbarch)) { struct value *regval = value_of_user_reg (regnum, frame); const char *regname = user_reg_map_regnum_to_name (gdbarch, @@ -2174,8 +2437,7 @@ registers_info (char *addr_exp, int fpregs) int regnum; for (regnum = 0; - regnum < gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch); + regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { if (gdbarch_register_reggroup_p (gdbarch, regnum, group)) @@ -2193,13 +2455,13 @@ registers_info (char *addr_exp, int fpregs) } static void -all_registers_info (char *addr_exp, int from_tty) +info_all_registers_command (const char *addr_exp, int from_tty) { registers_info (addr_exp, 1); } static void -nofp_registers_info (char *addr_exp, int from_tty) +info_registers_command (const char *addr_exp, int from_tty) { registers_info (addr_exp, 0); } @@ -2217,10 +2479,7 @@ print_vector_info (struct ui_file *file, int regnum; int printed_something = 0; - for (regnum = 0; - regnum < gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch); - regnum++) + for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { if (gdbarch_register_reggroup_p (gdbarch, regnum, vector_reggroup)) { @@ -2234,7 +2493,7 @@ print_vector_info (struct ui_file *file, } static void -vector_info (char *args, int from_tty) +info_vector_command (const char *args, int from_tty) { if (!target_has_registers) error (_("The program has no registers now.")); @@ -2245,125 +2504,71 @@ vector_info (char *args, int from_tty) /* Kill the inferior process. Make us have no inferior. */ static void -kill_command (char *arg, int from_tty) +kill_command (const char *arg, int from_tty) { /* FIXME: This should not really be inferior_ptid (or target_has_execution). It should be a distinct flag that indicates that a target is active, cuz some targets don't have processes! */ - if (ptid_equal (inferior_ptid, null_ptid)) + if (inferior_ptid == null_ptid) error (_("The program is not being run.")); if (!query (_("Kill the program being debugged? "))) error (_("Not confirmed.")); + + int pid = current_inferior ()->pid; + /* Save the pid as a string before killing the inferior, since that + may unpush the current target, and we need the string after. */ + std::string pid_str = target_pid_to_str (ptid_t (pid)); + int infnum = current_inferior ()->num; + target_kill (); - /* If we still have other inferiors to debug, then don't mess with - with their threads. */ - if (!have_inferiors ()) - { - init_thread_list (); /* Destroy thread info. */ + if (print_inferior_events) + printf_unfiltered (_("[Inferior %d (%s) killed]\n"), + infnum, pid_str.c_str ()); - /* Killing off the inferior can leave us with a core file. If - so, print the state we are left in. */ - if (target_has_stack) - { - printf_filtered (_("In %s,\n"), target_longname); - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); - } - } bfd_cache_close_all (); } -/* Used in `attach&' command. ARG is a point to an integer - representing a process id. Proceed threads of this process iff +/* Used in `attach&' command. Proceed threads of inferior INF iff they stopped due to debugger request, and when they did, they - reported a clean stop (GDB_SIGNAL_0). Do not proceed threads - that have been explicitly been told to stop. */ - -static int -proceed_after_attach_callback (struct thread_info *thread, - void *arg) -{ - int pid = * (int *) arg; - - if (ptid_get_pid (thread->ptid) == pid - && !is_exited (thread->ptid) - && !is_executing (thread->ptid) - && !thread->stop_requested - && thread->suspend.stop_signal == GDB_SIGNAL_0) - { - switch_to_thread (thread->ptid); - clear_proceed_status (); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); - } - - return 0; -} + reported a clean stop (GDB_SIGNAL_0). Do not proceed threads that + have been explicitly been told to stop. */ static void -proceed_after_attach (int pid) +proceed_after_attach (inferior *inf) { /* Don't error out if the current thread is running, because there may be other stopped threads. */ - struct cleanup *old_chain; /* Backup current thread and selected frame. */ - old_chain = make_cleanup_restore_current_thread (); - - iterate_over_threads (proceed_after_attach_callback, &pid); + scoped_restore_current_thread restore_thread; - /* Restore selected ptid. */ - do_cleanups (old_chain); + for (thread_info *thread : inf->non_exited_threads ()) + if (!thread->executing + && !thread->stop_requested + && thread->suspend.stop_signal == GDB_SIGNAL_0) + { + switch_to_thread (thread); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); + } } -/* - * TODO: - * Should save/restore the tty state since it might be that the - * program to be debugged was started on this tty and it wants - * the tty in some state other than what we want. If it's running - * on another terminal or without a terminal, then saving and - * restoring the tty state is a harmless no-op. - * This only needs to be done if we are attaching to a process. - */ - -/* attach_command -- - takes a program started up outside of gdb and ``attaches'' to it. - This stops it cold in its tracks and allows us to start debugging it. - and wait for the trace-trap that results from attaching. */ +/* See inferior.h. */ -static void -attach_command_post_wait (char *args, int from_tty, int async_exec) +void +setup_inferior (int from_tty) { - char *exec_file; - char *full_exec_path = NULL; struct inferior *inferior; inferior = current_inferior (); - inferior->control.stop_soon = NO_STOP_QUIETLY; + inferior->needs_setup = 0; /* If no exec file is yet known, try to determine it from the process itself. */ - exec_file = (char *) get_exec_file (0); - if (!exec_file) - { - exec_file = target_pid_to_exec_file (ptid_get_pid (inferior_ptid)); - if (exec_file) - { - /* It's possible we don't have a full path, but rather just a - filename. Some targets, such as HP-UX, don't provide the - full path, sigh. - - Attempt to qualify the filename against the source path. - (If that fails, we'll just fall back on the original - filename. Not much more we can do...) */ - - if (!source_full_path_of (exec_file, &full_exec_path)) - full_exec_path = xstrdup (exec_file); - - exec_file_attach (full_exec_path, from_tty); - symbol_file_add_main (full_exec_path, from_tty); - } - } + if (get_exec_file (0) == NULL) + exec_file_locate_attach (inferior_ptid.pid (), 1, from_tty); else { reopen_exec_file (); @@ -2371,14 +2576,40 @@ attach_command_post_wait (char *args, int from_tty, int async_exec) } /* Take any necessary post-attaching actions for this platform. */ - target_post_attach (ptid_get_pid (inferior_ptid)); + target_post_attach (inferior_ptid.pid ()); + + post_create_inferior (current_top_target (), from_tty); +} + +/* What to do after the first program stops after attaching. */ +enum attach_post_wait_mode +{ + /* Do nothing. Leaves threads as they are. */ + ATTACH_POST_WAIT_NOTHING, + + /* Re-resume threads that are marked running. */ + ATTACH_POST_WAIT_RESUME, - post_create_inferior (¤t_target, from_tty); + /* Stop all threads. */ + ATTACH_POST_WAIT_STOP, +}; + +/* Called after we've attached to a process and we've seen it stop for + the first time. If ASYNC_EXEC is true, re-resume threads that + should be running. Else if ATTACH, */ + +static void +attach_post_wait (const char *args, int from_tty, enum attach_post_wait_mode mode) +{ + struct inferior *inferior; + + inferior = current_inferior (); + inferior->control.stop_soon = NO_STOP_QUIETLY; - /* Install inferior's terminal modes. */ - target_terminal_inferior (); + if (inferior->needs_setup) + setup_inferior (from_tty); - if (async_exec) + if (mode == ATTACH_POST_WAIT_RESUME) { /* The user requested an `attach&', so be sure to leave threads that didn't get a signal running. */ @@ -2388,24 +2619,21 @@ attach_command_post_wait (char *args, int from_tty, int async_exec) already running threads. If a thread has been stopped with a signal, leave it be. */ if (non_stop) - proceed_after_attach (inferior->pid); + proceed_after_attach (inferior); else { if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0) { - clear_proceed_status (); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); } } } - else + else if (mode == ATTACH_POST_WAIT_STOP) { /* The user requested a plain `attach', so be sure to leave the inferior stopped. */ - if (target_can_async_p ()) - async_enable_stdin (); - /* At least the current thread is already stopped. */ /* In all-stop, by definition, all threads have to be already @@ -2414,7 +2642,24 @@ attach_command_post_wait (char *args, int from_tty, int async_exec) Be sure to explicitly stop all threads of the process. This should have no effect on already stopped threads. */ if (non_stop) - target_stop (pid_to_ptid (inferior->pid)); + target_stop (ptid_t (inferior->pid)); + else if (target_is_non_stop_p ()) + { + struct thread_info *lowest = inferior_thread (); + + stop_all_threads (); + + /* It's not defined which thread will report the attach + stop. For consistency, always select the thread with + lowest GDB number, which should be the main thread, if it + still exists. */ + for (thread_info *thread : current_inferior ()->non_exited_threads ()) + if (thread->inf->num < lowest->inf->num + || thread->per_inf_num < lowest->per_inf_num) + lowest = thread; + + switch_to_thread (lowest); + } /* Tell the user/frontend where we're stopped. */ normal_stop (); @@ -2427,34 +2672,42 @@ struct attach_command_continuation_args { char *args; int from_tty; - int async_exec; + enum attach_post_wait_mode mode; }; static void attach_command_continuation (void *args, int err) { - struct attach_command_continuation_args *a = args; + struct attach_command_continuation_args *a + = (struct attach_command_continuation_args *) args; if (err) return; - attach_command_post_wait (a->args, a->from_tty, a->async_exec); + attach_post_wait (a->args, a->from_tty, a->mode); } static void attach_command_continuation_free_args (void *args) { - struct attach_command_continuation_args *a = args; + struct attach_command_continuation_args *a + = (struct attach_command_continuation_args *) args; xfree (a->args); xfree (a); } +/* "attach" command entry point. Takes a program started up outside + of gdb and ``attaches'' to it. This stops it cold in its tracks + and allows us to start debugging it. */ + void -attach_command (char *args, int from_tty) +attach_command (const char *args, int from_tty) { - int async_exec = 0; + int async_exec; struct target_ops *attach_target; + struct inferior *inferior = current_inferior (); + enum attach_post_wait_mode mode; dont_repeat (); /* Not for the faint of heart */ @@ -2474,31 +2727,49 @@ attach_command (char *args, int from_tty) this function should probably be moved into target_pre_inferior. */ target_pre_inferior (from_tty); - if (args != NULL) - async_exec = strip_bg_char (&args); + gdb::unique_xmalloc_ptr stripped = strip_bg_char (args, &async_exec); + args = stripped.get (); attach_target = find_attach_target (); prepare_execution_command (attach_target, async_exec); - if (non_stop && !attach_target->to_supports_non_stop (attach_target)) + if (non_stop && !attach_target->supports_non_stop ()) error (_("Cannot attach to this target in non-stop mode")); - attach_target->to_attach (attach_target, args, from_tty); + attach_target->attach (args, from_tty); /* to_attach should push the target, so after this point we shouldn't refer to attach_target again. */ attach_target = NULL; /* Set up the "saved terminal modes" of the inferior based on what modes we are starting it with. */ - target_terminal_init (); + target_terminal::init (); + + /* Install inferior's terminal modes. This may look like a no-op, + as we've just saved them above, however, this does more than + restore terminal settings: + + - installs a SIGINT handler that forwards SIGINT to the inferior. + Otherwise a Ctrl-C pressed just while waiting for the initial + stop would end up as a spurious Quit. + + - removes stdin from the event loop, which we need if attaching + in the foreground, otherwise on targets that report an initial + stop on attach (which are most) we'd process input/commands + while we're in the event loop waiting for that stop. That is, + before the attach continuation runs and the command is really + finished. */ + target_terminal::inferior (); /* Set up execution context to know that we should return from wait_for_inferior as soon as the target reports a stop. */ init_wait_for_inferior (); - clear_proceed_status (); + clear_proceed_status (0); - if (non_stop) + inferior->needs_setup = 1; + + if (target_is_non_stop_p ()) { /* If we find that the current thread isn't stopped, explicitly do so now, because we're going to install breakpoints and @@ -2510,14 +2781,16 @@ attach_command (char *args, int from_tty) else /* The user requested an `attach', so stop all threads of this inferior. */ - target_stop (pid_to_ptid (ptid_get_pid (inferior_ptid))); + target_stop (ptid_t (inferior_ptid.pid ())); } + mode = async_exec ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_STOP; + /* Some system don't generate traps when attaching to inferior. E.g. Mach 3 or GNU hurd. */ - if (!target_attach_no_wait) + if (!target_attach_no_wait ()) { - struct inferior *inferior = current_inferior (); + struct attach_command_continuation_args *a; /* Careful here. See comments in inferior.h. Basically some OSes don't ignore SIGSTOPs on continue requests anymore. We @@ -2526,24 +2799,24 @@ attach_command (char *args, int from_tty) STOP_QUIETLY_NO_SIGSTOP is for. */ inferior->control.stop_soon = STOP_QUIETLY_NO_SIGSTOP; - if (target_can_async_p ()) - { - /* sync_execution mode. Wait for stop. */ - struct attach_command_continuation_args *a; - - a = xmalloc (sizeof (*a)); - a->args = xstrdup (args); - a->from_tty = from_tty; - a->async_exec = async_exec; - add_inferior_continuation (attach_command_continuation, a, - attach_command_continuation_free_args); - return; - } + /* Wait for stop. */ + a = XNEW (struct attach_command_continuation_args); + a->args = xstrdup (args); + a->from_tty = from_tty; + a->mode = mode; + add_inferior_continuation (attach_command_continuation, a, + attach_command_continuation_free_args); - wait_for_inferior (); - } + /* Let infrun consider waiting for events out of this + target. */ + inferior->process_target ()->threads_executing = true; - attach_command_post_wait (args, from_tty, async_exec); + if (!target_is_async_p ()) + mark_infrun_async_event_handler (); + return; + } + else + attach_post_wait (args, from_tty, mode); } /* We had just found out that the target was already attached to an @@ -2555,29 +2828,26 @@ attach_command (char *args, int from_tty) as stopped. */ void -notice_new_inferior (ptid_t ptid, int leave_running, int from_tty) +notice_new_inferior (thread_info *thr, int leave_running, int from_tty) { - struct cleanup* old_chain; - int async_exec; + enum attach_post_wait_mode mode + = leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING; - old_chain = make_cleanup (null_cleanup, NULL); + gdb::optional restore_thread; - /* If in non-stop, leave threads as running as they were. If - they're stopped for some reason other than us telling it to, the - target reports a signal != GDB_SIGNAL_0. We don't try to - resume threads with such a stop signal. */ - async_exec = non_stop; + if (inferior_ptid != null_ptid) + restore_thread.emplace (); - if (!ptid_equal (inferior_ptid, null_ptid)) - make_cleanup_restore_current_thread (); - - switch_to_thread (ptid); + /* Avoid reading registers -- we haven't fetched the target + description yet. */ + switch_to_thread_no_regs (thr); /* When we "notice" a new inferior we need to do all the things we would normally do if we had just attached to it. */ - if (is_executing (inferior_ptid)) + if (thr->executing) { + struct attach_command_continuation_args *a; struct inferior *inferior = current_inferior (); /* We're going to install breakpoints, and poke at memory, @@ -2588,28 +2858,17 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty) inferior->control.stop_soon = STOP_QUIETLY_REMOTE; /* Wait for stop before proceeding. */ - if (target_can_async_p ()) - { - struct attach_command_continuation_args *a; + a = XNEW (struct attach_command_continuation_args); + a->args = xstrdup (""); + a->from_tty = from_tty; + a->mode = mode; + add_inferior_continuation (attach_command_continuation, a, + attach_command_continuation_free_args); - a = xmalloc (sizeof (*a)); - a->args = xstrdup (""); - a->from_tty = from_tty; - a->async_exec = async_exec; - add_inferior_continuation (attach_command_continuation, a, - attach_command_continuation_free_args); - - do_cleanups (old_chain); - return; - } - else - wait_for_inferior (); + return; } - async_exec = leave_running; - attach_command_post_wait ("" /* args */, from_tty, async_exec); - - do_cleanups (old_chain); + attach_post_wait ("" /* args */, from_tty, mode); } /* @@ -2624,29 +2883,31 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty) */ void -detach_command (char *args, int from_tty) +detach_command (const char *args, int from_tty) { dont_repeat (); /* Not for the faint of heart. */ - if (ptid_equal (inferior_ptid, null_ptid)) + if (inferior_ptid == null_ptid) error (_("The program is not being run.")); query_if_trace_running (from_tty); disconnect_tracing (); - target_detach (args, from_tty); + target_detach (current_inferior (), from_tty); + + /* The current inferior process was just detached successfully. Get + rid of breakpoints that no longer make sense. Note we don't do + this within target_detach because that is also used when + following child forks, and in that case we will want to transfer + breakpoints to the child, not delete them. */ + breakpoint_init_inferior (inf_exited); /* If the solist is global across inferiors, don't clear it when we detach from a single inferior. */ if (!gdbarch_has_global_solist (target_gdbarch ())) no_shared_libraries (NULL, from_tty); - /* If we still have inferiors to debug, then don't mess with their - threads. */ - if (!have_inferiors ()) - init_thread_list (); - if (deprecated_detach_hook) deprecated_detach_hook (); } @@ -2660,7 +2921,7 @@ detach_command (char *args, int from_tty) stopped processes on some native platforms (e.g. GNU/Linux). */ static void -disconnect_command (char *args, int from_tty) +disconnect_command (const char *args, int from_tty) { dont_repeat (); /* Not for the faint of heart. */ query_if_trace_running (from_tty); @@ -2672,15 +2933,14 @@ disconnect_command (char *args, int from_tty) deprecated_detach_hook (); } -void -interrupt_target_1 (int all_threads) -{ - ptid_t ptid; +/* Stop PTID in the current target, and tag the PTID threads as having + been explicitly requested to stop. PTID can be a thread, a + process, or minus_one_ptid, meaning all threads of all inferiors of + the current target. */ - if (all_threads) - ptid = minus_one_ptid; - else - ptid = inferior_ptid; +static void +stop_current_target_threads_ns (ptid_t ptid) +{ target_stop (ptid); /* Tag the thread as having been explicitly requested to stop, so @@ -2689,18 +2949,42 @@ interrupt_target_1 (int all_threads) non-stop mode, as when debugging a multi-threaded application in all-stop mode, we will only get one stop event --- it's undefined which thread will report the event. */ + set_stop_requested (current_inferior ()->process_target (), + ptid, 1); +} + +/* See inferior.h. */ + +void +interrupt_target_1 (bool all_threads) +{ if (non_stop) - set_stop_requested (ptid, 1); + { + if (all_threads) + { + scoped_restore_current_thread restore_thread; + + for (inferior *inf : all_inferiors ()) + { + switch_to_inferior_no_thread (inf); + stop_current_target_threads_ns (minus_one_ptid); + } + } + else + stop_current_target_threads_ns (inferior_ptid); + } + else + target_interrupt (); } -/* Stop the execution of the target while running in async mode, in - the backgound. In all-stop, stop the whole process. In non-stop +/* interrupt [-a] + Stop the execution of the target while running in async mode, in + the background. In all-stop, stop the whole process. In non-stop mode, stop the current thread only by default, or stop all threads if the `-a' switch is used. */ -/* interrupt [-a] */ static void -interrupt_target_command (char *args, int from_tty) +interrupt_command (const char *args, int from_tty) { if (target_can_async_p ()) { @@ -2709,7 +2993,7 @@ interrupt_target_command (char *args, int from_tty) dont_repeat (); /* Not for the faint of heart. */ if (args != NULL - && strncmp (args, "-a", sizeof ("-a") - 1) == 0) + && startswith (args, "-a")) all_threads = 1; if (!non_stop && all_threads) @@ -2719,57 +3003,52 @@ interrupt_target_command (char *args, int from_tty) } } -static void -print_float_info (struct ui_file *file, - struct frame_info *frame, const char *args) +/* See inferior.h. */ + +void +default_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, + struct frame_info *frame, const char *args) { - struct gdbarch *gdbarch = get_frame_arch (frame); + int regnum; + int printed_something = 0; - if (gdbarch_print_float_info_p (gdbarch)) - gdbarch_print_float_info (gdbarch, file, frame, args); - else + for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++) { - int regnum; - int printed_something = 0; - - for (regnum = 0; - regnum < gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch); - regnum++) + if (gdbarch_register_reggroup_p (gdbarch, regnum, float_reggroup)) { - if (gdbarch_register_reggroup_p (gdbarch, regnum, float_reggroup)) - { - printed_something = 1; - gdbarch_print_registers_info (gdbarch, file, frame, regnum, 1); - } + printed_something = 1; + gdbarch_print_registers_info (gdbarch, file, frame, regnum, 1); } - if (!printed_something) - fprintf_filtered (file, "No floating-point info " - "available for this processor.\n"); } + if (!printed_something) + fprintf_filtered (file, "No floating-point info " + "available for this processor.\n"); } static void -float_info (char *args, int from_tty) +info_float_command (const char *args, int from_tty) { + struct frame_info *frame; + if (!target_has_registers) error (_("The program has no registers now.")); - print_float_info (gdb_stdout, get_selected_frame (NULL), args); + frame = get_selected_frame (NULL); + gdbarch_print_float_info (get_frame_arch (frame), gdb_stdout, frame, args); } static void -unset_command (char *args, int from_tty) +unset_command (const char *args, int from_tty) { printf_filtered (_("\"unset\" must be followed by the " "name of an unset subcommand.\n")); - help_list (unsetlist, "unset ", -1, gdb_stdout); + help_list (unsetlist, "unset ", all_commands, gdb_stdout); } /* Implement `info proc' family of commands. */ static void -info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty) +info_proc_cmd_1 (const char *args, enum info_proc_what what, int from_tty) { struct gdbarch *gdbarch = get_current_arch (); @@ -2782,10 +3061,10 @@ info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty) } } -/* Implement `info proc' when given without any futher parameters. */ +/* Implement `info proc' when given without any further parameters. */ static void -info_proc_cmd (char *args, int from_tty) +info_proc_cmd (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_MINIMAL, from_tty); } @@ -2793,7 +3072,7 @@ info_proc_cmd (char *args, int from_tty) /* Implement `info proc mappings'. */ static void -info_proc_cmd_mappings (char *args, int from_tty) +info_proc_cmd_mappings (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_MAPPINGS, from_tty); } @@ -2801,7 +3080,7 @@ info_proc_cmd_mappings (char *args, int from_tty) /* Implement `info proc stat'. */ static void -info_proc_cmd_stat (char *args, int from_tty) +info_proc_cmd_stat (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_STAT, from_tty); } @@ -2809,7 +3088,7 @@ info_proc_cmd_stat (char *args, int from_tty) /* Implement `info proc status'. */ static void -info_proc_cmd_status (char *args, int from_tty) +info_proc_cmd_status (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_STATUS, from_tty); } @@ -2817,7 +3096,7 @@ info_proc_cmd_status (char *args, int from_tty) /* Implement `info proc cwd'. */ static void -info_proc_cmd_cwd (char *args, int from_tty) +info_proc_cmd_cwd (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_CWD, from_tty); } @@ -2825,7 +3104,7 @@ info_proc_cmd_cwd (char *args, int from_tty) /* Implement `info proc cmdline'. */ static void -info_proc_cmd_cmdline (char *args, int from_tty) +info_proc_cmd_cmdline (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_CMDLINE, from_tty); } @@ -2833,19 +3112,56 @@ info_proc_cmd_cmdline (char *args, int from_tty) /* Implement `info proc exe'. */ static void -info_proc_cmd_exe (char *args, int from_tty) +info_proc_cmd_exe (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_EXE, from_tty); } +/* Implement `info proc files'. */ + +static void +info_proc_cmd_files (const char *args, int from_tty) +{ + info_proc_cmd_1 (args, IP_FILES, from_tty); +} + /* Implement `info proc all'. */ static void -info_proc_cmd_all (char *args, int from_tty) +info_proc_cmd_all (const char *args, int from_tty) { info_proc_cmd_1 (args, IP_ALL, from_tty); } +/* Implement `show print finish'. */ + +static void +show_print_finish (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered (file, _("\ +Printing of return value after `finish' is %s.\n"), + value); +} + + +/* This help string is used for the run, start, and starti commands. + It is defined as a macro to prevent duplication. */ + +#define RUN_ARGS_HELP \ +"You may specify arguments to give it.\n\ +Args may include \"*\", or \"[...]\"; they are expanded using the\n\ +shell that will start the program (specified by the \"$SHELL\" environment\n\ +variable). Input and output redirection with \">\", \"<\", or \">>\"\n\ +are also allowed.\n\ +\n\ +With no arguments, uses arguments last specified (with \"run\" or \n\ +\"set args\"). To cancel previous arguments and run with no arguments,\n\ +use \"set args\" without arguments.\n\ +\n\ +To start the inferior without using a shell, use \"set startup-with-shell off\"." + void _initialize_infcmd (void) { @@ -2854,15 +3170,20 @@ _initialize_infcmd (void) const char *cmd_name; /* Add the filename of the terminal connected to inferior I/O. */ - add_setshow_filename_cmd ("inferior-tty", class_run, - &inferior_io_terminal_scratch, _("\ + add_setshow_optional_filename_cmd ("inferior-tty", class_run, + &inferior_io_terminal_scratch, _("\ Set terminal for future runs of program being debugged."), _("\ Show terminal for future runs of program being debugged."), _("\ -Usage: set inferior-tty /dev/pts/1"), - set_inferior_tty_command, - show_inferior_tty_command, - &setlist, &showlist); - add_com_alias ("tty", "set inferior-tty", class_alias, 0); +Usage: set inferior-tty [TTY]\n\n\ +If TTY is omitted, the default behavior of using the same terminal as GDB\n\ +is restored."), + set_inferior_tty_command, + show_inferior_tty_command, + &setlist, &showlist); + cmd_name = "inferior-tty"; + c = lookup_cmd (&cmd_name, setlist, "", -1, 1); + gdb_assert (c != NULL); + add_alias_cmd ("tty", c, class_alias, 0, &cmdlist); cmd_name = "args"; add_setshow_string_noescape_cmd (cmd_name, class_run, @@ -2877,6 +3198,25 @@ Follow this command with any number of args, to be passed to the program."), gdb_assert (c != NULL); set_cmd_completer (c, filename_completer); + cmd_name = "cwd"; + add_setshow_string_noescape_cmd (cmd_name, class_run, + &inferior_cwd_scratch, _("\ +Set the current working directory to be used when the inferior is started.\n\ +Changing this setting does not have any effect on inferiors that are\n\ +already running."), + _("\ +Show the current working directory that is used when the inferior is started."), + _("\ +Use this command to change the current working directory that will be used\n\ +when the inferior is started. This setting does not affect GDB's current\n\ +working directory."), + set_cwd_command, + show_cwd_command, + &setlist, &showlist); + c = lookup_cmd (&cmd_name, setlist, "", -1, 1); + gdb_assert (c != NULL); + set_cmd_completer (c, filename_completer); + c = add_cmd ("environment", no_class, environment_info, _("\ The environment to give the program, or one variable's value.\n\ With an argument VAR, prints the value of environment variable VAR to\n\ @@ -2956,7 +3296,24 @@ The SIGNAL argument is processed the same as the handle command.\n\ \n\ An argument of \"0\" means continue the program without sending it a signal.\n\ This is useful in cases where the program stopped because of a signal,\n\ -and you want to resume the program while discarding the signal.")); +and you want to resume the program while discarding the signal.\n\ +\n\ +In a multi-threaded program the signal is delivered to, or discarded from,\n\ +the current thread only.")); + set_cmd_completer (c, signal_completer); + + c = add_com ("queue-signal", class_run, queue_signal_command, _("\ +Queue a signal to be delivered to the current thread when it is resumed.\n\ +Usage: queue-signal SIGNAL\n\ +The SIGNAL argument is processed the same as the handle command.\n\ +It is an error if the handling state of SIGNAL is \"nopass\".\n\ +\n\ +An argument of \"0\" means remove any currently queued signal from\n\ +the current thread. This is useful in cases where the program stopped\n\ +because of a signal, and you want to resume it while discarding the signal.\n\ +\n\ +In a multi-threaded program the signal is queued with, or discarded from,\n\ +the current thread only.")); set_cmd_completer (c, signal_completer); add_com ("stepi", class_run, stepi_command, _("\ @@ -2986,8 +3343,6 @@ Unlike \"step\", if the current source line calls a subroutine,\n\ this command does not enter the subroutine, but instead steps over\n\ the call, in effect treating it as a single source line.")); add_com_alias ("n", "next", class_run, 1); - if (xdb_commands) - add_com_alias ("S", "next", class_run, 1); add_com ("step", class_run, step_command, _("\ Step program until it reaches a different source line.\n\ @@ -2997,6 +3352,7 @@ reason).")); add_com_alias ("s", "step", class_run, 1); c = add_com ("until", class_run, until_command, _("\ +Execute until past the current line or past a LOCATION.\n\ Execute until the program reaches a source line greater than the current\n\ or a specified location (same args as break command) within the current \ frame.")); @@ -3011,27 +3367,12 @@ Execution will also stop upon exit from the current stack frame.")); c = add_com ("jump", class_run, jump_command, _("\ Continue program being debugged at specified line or address.\n\ -Usage: jump \n\ +Usage: jump LOCATION\n\ Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ for an address to start at.")); set_cmd_completer (c, location_completer); add_com_alias ("j", "jump", class_run, 1); - if (xdb_commands) - { - c = add_com ("go", class_run, go_command, _("\ -Usage: go \n\ -Continue program being debugged, stopping at specified line or \n\ -address.\n\ -Give as argument either LINENUM or *ADDR, where ADDR is an \n\ -expression for an address to start at.\n\ -This command is a combination of tbreak and jump.")); - set_cmd_completer (c, location_completer); - } - - if (xdb_commands) - add_com_alias ("g", "go", class_run, 1); - add_com ("continue", class_run, continue_command, _("\ Continue program being debugged, after signal or breakpoint.\n\ Usage: continue [N]\n\ @@ -3047,63 +3388,60 @@ Specifying -a and an ignore count simultaneously is an error.")); add_com_alias ("fg", "cont", class_run, 1); c = add_com ("run", class_run, run_command, _("\ -Start debugged program. You may specify arguments to give it.\n\ -Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\ -Input and output redirection with \">\", \"<\", or \">>\" are also \ -allowed.\n\n\ -With no arguments, uses arguments last specified (with \"run\" \ -or \"set args\").\n\ -To cancel previous arguments and run with no arguments,\n\ -use \"set args\" without arguments.")); +Start debugged program.\n" +RUN_ARGS_HELP)); set_cmd_completer (c, filename_completer); add_com_alias ("r", "run", class_run, 1); - if (xdb_commands) - add_com ("R", class_run, run_no_args_command, - _("Start debugged program with no arguments.")); c = add_com ("start", class_run, start_command, _("\ -Run the debugged program until the beginning of the main procedure.\n\ -You may specify arguments to give to your program, just as with the\n\ -\"run\" command.")); +Start the debugged program stopping at the beginning of the main procedure.\n" +RUN_ARGS_HELP)); + set_cmd_completer (c, filename_completer); + + c = add_com ("starti", class_run, starti_command, _("\ +Start the debugged program stopping at the first instruction.\n" +RUN_ARGS_HELP)); set_cmd_completer (c, filename_completer); - add_com ("interrupt", class_run, interrupt_target_command, + add_com ("interrupt", class_run, interrupt_command, _("Interrupt the execution of the debugged program.\n\ If non-stop mode is enabled, interrupt only the current thread,\n\ otherwise all the threads in the program are stopped. To \n\ interrupt all running threads in non-stop mode, use the -a option.")); - add_info ("registers", nofp_registers_info, _("\ + c = add_info ("registers", info_registers_command, _("\ List of integer registers and their contents, for selected stack frame.\n\ -Register name as argument means describe only that register.")); +One or more register names as argument means describe the given registers.\n\ +One or more register group names as argument means describe the registers\n\ +in the named register groups.")); add_info_alias ("r", "registers", 1); + set_cmd_completer (c, reg_or_group_completer); - if (xdb_commands) - add_com ("lr", class_info, nofp_registers_info, _("\ -List of integer registers and their contents, for selected stack frame.\n\ -Register name as argument means describe only that register.")); - add_info ("all-registers", all_registers_info, _("\ + c = add_info ("all-registers", info_all_registers_command, _("\ List of all registers and their contents, for selected stack frame.\n\ -Register name as argument means describe only that register.")); +One or more register names as argument means describe the given registers.\n\ +One or more register group names as argument means describe the registers\n\ +in the named register groups.")); + set_cmd_completer (c, reg_or_group_completer); - add_info ("program", program_info, + add_info ("program", info_program_command, _("Execution status of the program.")); - add_info ("float", float_info, - _("Print the status of the floating point unit\n")); + add_info ("float", info_float_command, + _("Print the status of the floating point unit.")); - add_info ("vector", vector_info, - _("Print the status of the vector unit\n")); + add_info ("vector", info_vector_command, + _("Print the status of the vector unit.")); add_prefix_cmd ("proc", class_info, info_proc_cmd, _("\ -Show /proc process information about any running process.\n\ +Show additional information about a process.\n\ Specify any process id, or use the program being debugged by default."), &info_proc_cmdlist, "info proc ", 1/*allow-unknown*/, &infolist); add_cmd ("mappings", class_info, info_proc_cmd_mappings, _("\ -List of mapped memory regions."), +List memory regions mapped by the specified process."), &info_proc_cmdlist); add_cmd ("stat", class_info, info_proc_cmd_stat, _("\ @@ -3115,18 +3453,30 @@ List process info from /proc/PID/status."), &info_proc_cmdlist); add_cmd ("cwd", class_info, info_proc_cmd_cwd, _("\ -List current working directory of the process."), +List current working directory of the specified process."), &info_proc_cmdlist); add_cmd ("cmdline", class_info, info_proc_cmd_cmdline, _("\ -List command line arguments of the process."), +List command line arguments of the specified process."), &info_proc_cmdlist); add_cmd ("exe", class_info, info_proc_cmd_exe, _("\ -List absolute filename for executable of the process."), +List absolute filename for executable of the specified process."), + &info_proc_cmdlist); + + add_cmd ("files", class_info, info_proc_cmd_files, _("\ +List files opened by the specified process."), &info_proc_cmdlist); add_cmd ("all", class_info, info_proc_cmd_all, _("\ -List all available /proc info."), +List all available info about the specified process."), &info_proc_cmdlist); + + add_setshow_boolean_cmd ("finish", class_support, + &user_print_options.finish_print, _("\ +Set whether `finish' prints the return value."), _("\ +Show whether `finish' prints the return value."), NULL, + NULL, + show_print_finish, + &setprintlist, &showprintlist); }