/* Memory-access and commands for "inferior" process, for GDB.
- Copyright (C) 1986-2015 Free Software Foundation, Inc.
+ Copyright (C) 1986-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "linespec.h"
#include "cli/cli-utils.h"
#include "infcall.h"
+#include "thread-fsm.h"
+#include "top.h"
+#include "interps.h"
+#include "common/gdb_optional.h"
/* Local functions: */
-static void nofp_registers_info (char *, int);
+static void info_registers_command (char *, int);
static void until_next_command (int);
static void unset_command (char *, int);
-static void float_info (char *, int);
+static void info_float_command (char *, int);
static void disconnect_command (char *, int);
static void environment_info (char *, int);
-static void program_info (char *, int);
+static void info_program_command (char *, int);
static void finish_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);
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 *
#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;
{
/* 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,
/* 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);
}
}
if (background && !target->to_can_async_p (target))
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 ();
}
}
static void
run_command_1 (char *args, int from_tty, int tbreak_at_main)
{
- char *exec_file;
+ const char *exec_file;
struct cleanup *old_chain;
ptid_t ptid;
struct ui_out *uiout = current_uiout;
if (tbreak_at_main)
tbreak_command (main_name (), 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
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 ();
}
/* Done with ARGS. */
/* 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),
+ run_target->to_create_inferior (run_target, 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. */
{
/* 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);
- if (sync_execution)
+ if (current_ui->prompt_state == PROMPT_BLOCKED)
{
/* If all threads in the target were already running,
proceed_thread_callback ends up never calling proceed,
*/
target_terminal_inferior ();
}
-
- /* Restore selected ptid. */
- do_cleanups (old_chain);
}
else
{
args = strip_bg_char (args, &async_exec);
args_chain = make_cleanup (xfree, args);
- prepare_execution_command (¤t_target, async_exec);
-
if (args != NULL)
{
if (startswith (args, "-a"))
/* Done with ARGS. */
do_cleanups (args_chain);
+ ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
+
+ if (!non_stop || !all_threads)
+ {
+ ensure_valid_thread ();
+ ensure_not_running ();
+ }
+
+ prepare_execution_command (¤t_target, async_exec);
+
if (from_tty)
printf_filtered (_("Continuing.\n"));
static void
set_step_frame (void)
{
- struct symtab_and_line sal;
- CORE_ADDR pc;
- struct frame_info *frame = get_current_frame ();
- struct thread_info *tp = inferior_thread ();
+ frame_info *frame = get_current_frame ();
- find_frame_sal (frame, &sal);
+ symtab_and_line sal = find_frame_sal (frame);
set_step_info (frame, sal);
- pc = get_frame_pc (frame);
+
+ CORE_ADDR pc = get_frame_pc (frame);
+ thread_info *tp = inferior_thread ();
tp->control.step_start_function = find_pc_function (pc);
}
delete_longjmp_breakpoint (thread);
}
+/* Data for the FSM that manages the step/next/stepi/nexti
+ commands. */
+
+struct step_command_fsm
+{
+ /* The base class. */
+ struct thread_fsm thread_fsm;
+
+ /* 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;
+};
+
+static void step_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
+static int step_command_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
+static enum async_reply_reason
+ step_command_fsm_async_reply_reason (struct thread_fsm *self);
+
+/* step_command_fsm's vtable. */
+
+static struct thread_fsm_ops step_command_fsm_ops =
+{
+ NULL,
+ step_command_fsm_clean_up,
+ step_command_fsm_should_stop,
+ NULL, /* return_value */
+ step_command_fsm_async_reply_reason,
+};
+
+/* Allocate a new step_command_fsm. */
+
+static struct step_command_fsm *
+new_step_command_fsm (struct interp *cmd_interp)
+{
+ struct step_command_fsm *sm;
+
+ sm = XCNEW (struct step_command_fsm);
+ thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops, cmd_interp);
+
+ return sm;
+}
+
+/* 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)
{
- int count = 1;
- struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ int count;
int async_exec;
- int thread = -1;
struct cleanup *args_chain;
+ struct thread_info *thr;
+ struct step_command_fsm *step_sm;
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
/* Done with ARGS. */
do_cleanups (args_chain);
- 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);
- }
-
- /* 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);
+ clear_proceed_status (1);
- if (!target_has_execution)
- break;
- else
- {
- struct thread_info *tp = inferior_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->thread_fsm;
- 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. */
+ thread_fsm_clean_up (thr->thread_fsm, 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;
-};
-
-/* 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. */
+/* 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. */
-static void
-step_1_continuation (void *args, int err)
+static int
+step_command_fsm_should_stop (struct thread_fsm *self, struct thread_info *tp)
{
- struct step_1_continuation_args *a = args;
+ struct step_command_fsm *sm = (struct step_command_fsm *) self;
- 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 (--sm->count > 0)
+ return prepare_one_step (sm);
- 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;
+ thread_fsm_set_finished (self);
}
- /* 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 1;
}
-/* 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)
+step_command_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
+{
+ struct step_command_fsm *sm = (struct step_command_fsm *) self;
+
+ if (!sm->single_inst || sm->skip_subroutines)
+ delete_longjmp_breakpoint (thread->global_num);
+}
+
+/* Implementation of the 'async_reply_reason' FSM method for stepping
+ commands. */
+
+static enum async_reply_reason
+step_command_fsm_async_reply_reason (struct thread_fsm *self)
{
- struct frame_info *frame = get_current_frame ();
+ return EXEC_ASYNC_END_STEPPING_RANGE;
+}
- if (count > 0)
+/* 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 (1);
set_step_frame ();
- if (!single_inst)
+ if (!sm->single_inst)
{
CORE_ADDR pc;
/* Step at an inlined function behaves like "down". */
- if (!skip_subroutines
+ if (!sm->skip_subroutines
&& inline_skipped_frames (inferior_ptid))
{
ptid_t resume_ptid;
set_running (resume_ptid, 1);
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 ();
-
- if (target_can_async_p ())
- inferior_event_handler (INF_EXEC_COMPLETE, NULL);
- }
- return;
+ sm->count--;
+ return prepare_one_step (sm);
}
pc = get_frame_pc (frame);
&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);
{
/* 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);
- tp->control.stepping_command = 1;
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
-
- /* 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. */
+ thread_fsm_set_finished (&sm->thread_fsm);
+ return 1;
}
\f
{
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;
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"));
- }
-
- sal = sals.sals[0];
- xfree (sals.sals);
+ std::vector<symtab_and_line> sals
+ = decode_line_with_last_displayed (arg, DECODE_LINE_FUNFIRSTLINE);
+ if (sals.size () != 1)
+ error (_("Unreasonable jump request"));
/* Done with ARGS. */
do_cleanups (args_chain);
+ symtab_and_line &sal = sals[0];
+
if (sal.symtab == 0 && sal.pc == 0)
error (_("No source file has been specified."));
oursig = gdb_signal_from_command (num);
}
+ do_cleanups (args_chain);
+
/* 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
{
if (!must_confirm)
printf_unfiltered (_("Note:\n"));
- printf_unfiltered (_(" Thread %d previously stopped with signal %s, %s.\n"),
- tp->num,
+ 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 %d (the current thread) with specified signal will\n"
+ && !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? "),
- inferior_thread ()->num))
+ print_thread_id (inferior_thread ())))
error (_("Not confirmed."));
}
tp->suspend.stop_signal = oursig;
}
-/* Continuation args to be passed to the "until" command
- continuation. */
-struct until_next_continuation_args
+/* Data for the FSM that manages the until (with no argument)
+ command. */
+
+struct until_next_fsm
{
- /* The thread that was current when the command was executed. */
+ /* The base class. */
+ struct thread_fsm thread_fsm;
+
+ /* The thread that as current when the command was executed. */
int thread;
};
-/* A continuation callback for until_next_command. */
+static int until_next_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
+static void until_next_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
+static enum async_reply_reason
+ until_next_fsm_async_reply_reason (struct thread_fsm *self);
+
+/* until_next_fsm's vtable. */
+
+static struct thread_fsm_ops until_next_fsm_ops =
+{
+ NULL, /* dtor */
+ until_next_fsm_clean_up,
+ until_next_fsm_should_stop,
+ NULL, /* return_value */
+ until_next_fsm_async_reply_reason,
+};
+
+/* Allocate a new until_next_fsm. */
+
+static struct until_next_fsm *
+new_until_next_fsm (struct interp *cmd_interp, int thread)
+{
+ struct until_next_fsm *sm;
+
+ sm = XCNEW (struct until_next_fsm);
+ thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops, cmd_interp);
+
+ sm->thread = thread;
+
+ return sm;
+}
+
+/* Implementation of the 'should_stop' FSM method for the until (with
+ no arg) command. */
+
+static int
+until_next_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *tp)
+{
+ if (tp->control.stop_step)
+ thread_fsm_set_finished (self);
+
+ return 1;
+}
+
+/* Implementation of the 'clean_up' FSM method for the until (with no
+ arg) command. */
static void
-until_next_continuation (void *arg, int err)
+until_next_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
{
- struct until_next_continuation_args *a = arg;
+ struct until_next_fsm *sm = (struct until_next_fsm *) self;
- delete_longjmp_breakpoint (a->thread);
+ delete_longjmp_breakpoint (thread->global_num);
+}
+
+/* Implementation of the 'async_reply_reason' FSM method for the until
+ (with no arg) command. */
+
+static enum async_reply_reason
+until_next_fsm_async_reply_reason (struct thread_fsm *self)
+{
+ return EXEC_ASYNC_END_STEPPING_RANGE;
}
/* Proceed until we reach a different source line with pc greater than
struct symbol *func;
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
- int thread = tp->num;
+ int thread = tp->global_num;
struct cleanup *old_chain;
+ struct until_next_fsm *sm;
clear_proceed_status (0);
set_step_frame ();
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);
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
-
- 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;
+ sm = new_until_next_fsm (command_interp (), tp->global_num);
+ tp->thread_fsm = &sm->thread_fsm;
+ discard_cleanups (old_chain);
- add_continuation (tp, until_next_continuation, cont_args, xfree);
- }
- else
- do_cleanups (old_chain);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
static void
right after an inferior call has finished. */
struct value *
-get_return_value (struct value *function, struct type *value_type,
- struct dummy_frame_context_saver *ctx_saver)
+get_return_value (struct value *function, struct type *value_type)
{
- struct regcache *stop_regs = NULL;
- struct gdbarch *gdbarch;
+ regcache stop_regs (regcache::readonly, *get_current_regcache ());
+ struct gdbarch *gdbarch = stop_regs.arch ();
struct value *value;
- struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
-
- /* If registers were not saved, use the current registers. */
- if (ctx_saver != NULL)
- stop_regs = dummy_frame_context_saver_get_regs (ctx_saver);
- else
- {
- stop_regs = regcache_dup (get_current_regcache ());
- make_cleanup_regcache_xfree (stop_regs);
- }
-
- gdbarch = get_regcache_arch (stop_regs);
value_type = check_typedef (value_type);
gdb_assert (TYPE_CODE (value_type) != TYPE_CODE_VOID);
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
value = allocate_value (value_type);
- gdbarch_return_value (gdbarch, function, value_type, stop_regs,
+ gdbarch_return_value (gdbarch, function, value_type, &stop_regs,
value_contents_raw (value), NULL);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
- do_cleanups (cleanup);
-
return value;
}
-/* Print the result of a function at the end of a 'finish' command.
- DTOR_DATA (if not NULL) can represent inferior registers right after
- an inferior call has finished. */
+/* 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 dummy_frame_context_saver *ctx_saver)
+struct return_value_info
{
- struct value *value = get_return_value (function, value_type, ctx_saver);
- 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 (value)
+ /* If we captured a value, this is the value history index. */
+ int value_history_index;
+};
+
+/* 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, " = ");
+ uiout->text ("Value returned is ");
+ uiout->field_fmt ("gdb-result-var", "$%d",
+ rv->value_history_index);
+ uiout->text (" = ");
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);
+
+ string_file stb;
+
+ value_print (rv->value, &stb, &opts);
+ uiout->field_stream ("return-value", stb);
+ uiout->text ("\n");
}
else
{
- struct cleanup *oldchain;
- char *type_name;
+ 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");
+ }
+}
+
+/* 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. */
+
+void
+print_return_value (struct ui_out *uiout, struct return_value_info *rv)
+{
+ if (rv->type == NULL || TYPE_CODE (rv->type) == TYPE_CODE_VOID)
+ return;
- type_name = type_to_string (value_type);
- oldchain = make_cleanup (xfree, type_name);
- ui_out_text (uiout, "Value returned has type: ");
- ui_out_field_string (uiout, "return-type", type_name);
- ui_out_text (uiout, ".");
- ui_out_text (uiout, " Cannot determine contents\n");
- do_cleanups (oldchain);
+ 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 (ex, RETURN_MASK_ALL)
+ {
+ exception_print (gdb_stdout, ex);
+ }
+ END_CATCH
}
-/* 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. */
+/* Data for the FSM that manages the finish command. */
-struct finish_command_continuation_args
+struct finish_command_fsm
{
- /* The thread that as current when the command was executed. */
- int thread;
+ /* The base class. */
+ struct thread_fsm thread_fsm;
+
+ /* The momentary breakpoint set at the function's return address in
+ the caller. */
struct breakpoint *breakpoint;
+
+ /* The function that we're stepping out of. */
struct symbol *function;
- /* Inferior registers stored right before dummy_frame has been freed
- after an inferior call. It can be NULL if no inferior call was
- involved, GDB will then use current inferior registers. */
- struct dummy_frame_context_saver *ctx_saver;
+ /* If the FSM finishes successfully, this stores the function's
+ return value. */
+ struct return_value_info return_value;
};
-static void
-finish_command_continuation (void *arg, int err)
+static int finish_command_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *thread);
+static void finish_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread);
+static struct return_value_info *
+ finish_command_fsm_return_value (struct thread_fsm *self);
+static enum async_reply_reason
+ finish_command_fsm_async_reply_reason (struct thread_fsm *self);
+
+/* finish_command_fsm's vtable. */
+
+static struct thread_fsm_ops finish_command_fsm_ops =
+{
+ NULL, /* dtor */
+ finish_command_fsm_clean_up,
+ finish_command_fsm_should_stop,
+ finish_command_fsm_return_value,
+ finish_command_fsm_async_reply_reason,
+ NULL, /* should_notify_stop */
+};
+
+/* Allocate a new finish_command_fsm. */
+
+static struct finish_command_fsm *
+new_finish_command_fsm (struct interp *cmd_interp)
{
- struct finish_command_continuation_args *a = arg;
+ struct finish_command_fsm *sm;
- if (!err)
- {
- struct thread_info *tp = NULL;
- bpstat bs = NULL;
+ sm = XCNEW (struct finish_command_fsm);
+ thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops, cmd_interp);
- if (!ptid_equal (inferior_ptid, null_ptid)
- && target_has_execution
- && is_stopped (inferior_ptid))
- {
- tp = inferior_thread ();
- bs = tp->control.stop_bpstat;
- }
+ return sm;
+}
- if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
- && a->function != NULL)
- {
- struct type *value_type;
+/* 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. */
- value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function));
- if (!value_type)
- internal_error (__FILE__, __LINE__,
- _("finish_command: function has no target type"));
+static int
+finish_command_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *tp)
+{
+ struct finish_command_fsm *f = (struct finish_command_fsm *) self;
+ struct return_value_info *rv = &f->return_value;
- if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
- {
- struct value *func;
+ if (f->function != NULL
+ && bpstat_find_breakpoint (tp->control.stop_bpstat,
+ f->breakpoint) != NULL)
+ {
+ /* We're done. */
+ thread_fsm_set_finished (self);
- func = read_var_value (a->function, get_current_frame ());
- TRY
- {
- /* 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, a->ctx_saver);
- }
- CATCH (ex, RETURN_MASK_ALL)
- {
- exception_print (gdb_stdout, ex);
- }
- END_CATCH
- }
- }
+ rv->type = TYPE_TARGET_TYPE (SYMBOL_TYPE (f->function));
+ if (rv->type == NULL)
+ internal_error (__FILE__, __LINE__,
+ _("finish_command: function has no target type"));
- /* 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 */);
+ if (TYPE_CODE (rv->type) != TYPE_CODE_VOID)
+ {
+ struct value *func;
+
+ func = read_var_value (f->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. */
+ thread_fsm_set_finished (self);
}
- delete_breakpoint (a->breakpoint);
- delete_longjmp_breakpoint (a->thread);
+ return 1;
}
+/* Implementation of the 'clean_up' FSM method for the finish
+ commands. */
+
static void
-finish_command_continuation_free_arg (void *arg)
+finish_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread)
{
- struct finish_command_continuation_args *cargs = arg;
+ struct finish_command_fsm *f = (struct finish_command_fsm *) self;
+
+ if (f->breakpoint != NULL)
+ {
+ delete_breakpoint (f->breakpoint);
+ f->breakpoint = NULL;
+ }
+ delete_longjmp_breakpoint (thread->global_num);
+}
+
+/* Implementation of the 'return_value' FSM method for the finish
+ commands. */
+
+static struct return_value_info *
+finish_command_fsm_return_value (struct thread_fsm *self)
+{
+ struct finish_command_fsm *f = (struct finish_command_fsm *) self;
+
+ return &f->return_value;
+}
+
+/* Implementation of the 'async_reply_reason' FSM method for the
+ finish commands. */
- if (cargs->ctx_saver != NULL)
- dummy_frame_context_saver_drop (cargs->ctx_saver);
- xfree (cargs);
+static enum async_reply_reason
+finish_command_fsm_async_reply_reason (struct thread_fsm *self)
+{
+ 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 ();
{
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,
}
}
-/* 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 = make_cleanup (null_cleanup, NULL);
- struct finish_command_continuation_args *cargs;
- int thread = tp->num;
- struct dummy_frame_context_saver *saver = NULL;
sal = find_pc_line (get_frame_pc (frame), 0);
sal.pc = get_frame_pc (frame);
- if (get_frame_type (frame) == DUMMY_FRAME)
- {
- saver = dummy_frame_context_saver_setup (get_stack_frame_id (frame),
- inferior_ptid);
- make_cleanup (dummy_frame_context_saver_cleanup, saver);
- }
-
- 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;
- make_cleanup_delete_breakpoint (breakpoint);
-
set_longjmp_breakpoint (tp, frame_id);
- make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
/* 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;
- cargs->ctx_saver = saver;
- add_continuation (tp, finish_command_continuation, cargs,
- finish_command_continuation_free_arg);
+
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
+}
- discard_cleanups (old_chain);
- if (!target_can_async_p ())
- do_all_continuations (0);
+/* 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);
+
+ return frame;
}
/* "finish": Set a temporary breakpoint at the place the selected
finish_command (char *arg, int from_tty)
{
struct frame_info *frame;
- struct symbol *function;
int async_exec;
struct cleanup *args_chain;
+ struct finish_command_fsm *sm;
+ struct thread_info *tp;
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
clear_proceed_status (0);
+ tp = inferior_thread ();
+
+ sm = new_finish_command_fsm (command_interp ());
+
+ tp->thread_fsm = &sm->thread_fsm;
+
/* 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)
{
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;
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. */
printf_filtered (_("Run back to call of "));
else
{
- if (function != NULL && TYPE_NO_RETURN (function->type)
+ if (sm->function != NULL && TYPE_NO_RETURN (sm->function->type)
&& !query (_("warning: Function %s does not return normally.\n"
"Try to finish anyway? "),
- SYMBOL_PRINT_NAME (function)))
+ SYMBOL_PRINT_NAME (sm->function)))
error (_("Not confirmed."));
printf_filtered (_("Run till exit from "));
}
}
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);
+ }
}
\f
static void
-program_info (char *args, int from_tty)
+info_program_command (char *args, int from_tty)
{
bpstat bs;
int num, stat;
{
if (var)
{
- char *val = get_in_environ (current_inferior ()->environment, var);
+ const char *val = current_inferior ()->environment.get (var);
if (val)
{
}
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");
}
}
printf_filtered (_("Setting environment variable "
"\"%s\" to null value.\n"),
var);
- set_in_environ (current_inferior ()->environment, var, "");
+ current_inferior ()->environment.set (var, "");
}
else
- set_in_environ (current_inferior ()->environment, var, val);
+ current_inferior ()->environment.set (var, val);
xfree (var);
}
/* 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). */
path_info (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");
}
path_command (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);
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));
opts.deref_ref = 1;
val_print (regtype,
- value_contents_for_printing (val),
value_embedded_offset (val), 0,
file, 0, val, &opts, current_language);
if (print_raw_format)
{
fprintf_filtered (file, "\t(raw ");
- print_hex_chars (file, valaddr, TYPE_LENGTH (regtype), byte_order);
+ print_hex_chars (file, valaddr, TYPE_LENGTH (regtype), byte_order,
+ true);
fprintf_filtered (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);
/* If not a vector register, print it also according to its
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);
}
}
static void
-all_registers_info (char *addr_exp, int from_tty)
+info_all_registers_command (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 (char *addr_exp, int from_tty)
{
registers_info (addr_exp, 0);
}
}
static void
-vector_info (char *args, int from_tty)
+info_vector_command (char *args, int from_tty)
{
if (!target_has_registers)
error (_("The program has no registers now."));
{
/* 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 ();
+ scoped_restore_current_thread restore_thread;
iterate_over_threads (proceed_after_attach_callback, &pid);
-
- /* Restore selected ptid. */
- do_cleanups (old_chain);
}
-/* 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)
{
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. */
if (get_exec_file (0) == NULL)
- exec_file_locate_attach (ptid_get_pid (inferior_ptid), from_tty);
+ exec_file_locate_attach (ptid_get_pid (inferior_ptid), 1, from_tty);
else
{
reopen_exec_file ();
target_post_attach (ptid_get_pid (inferior_ptid));
post_create_inferior (¤t_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,
+
+ /* 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;
+
+ 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. */
}
}
}
- 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
should have no effect on already stopped threads. */
if (non_stop)
target_stop (pid_to_ptid (inferior->pid));
+ else if (target_is_non_stop_p ())
+ {
+ struct thread_info *thread;
+ struct thread_info *lowest = inferior_thread ();
+ int pid = current_inferior ()->pid;
+
+ 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. */
+ ALL_NON_EXITED_THREADS (thread)
+ {
+ if (ptid_get_pid (thread->ptid) == pid)
+ {
+ if (thread->inf->num < lowest->inf->num
+ || thread->per_inf_num < lowest->per_inf_num)
+ lowest = thread;
+ }
+ }
+
+ switch_to_thread (lowest->ptid);
+ }
/* Tell the user/frontend where we're stopped. */
normal_stop ();
{
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)
{
int async_exec;
struct cleanup *args_chain;
struct target_ops *attach_target;
+ struct inferior *inferior = current_inferior ();
+ enum attach_post_wait_mode mode;
dont_repeat (); /* Not for the faint of heart */
init_wait_for_inferior ();
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
target_stop (pid_to_ptid (ptid_get_pid (inferior_ptid)));
}
+ 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)
{
- 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
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);
-
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
- return;
- }
-
- wait_for_inferior ();
+ /* 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);
+ /* Done with ARGS. */
+ do_cleanups (args_chain);
+
+ if (!target_is_async_p ())
+ mark_infrun_async_event_handler ();
+ return;
}
/* Done with ARGS. */
do_cleanups (args_chain);
- attach_command_post_wait (args, from_tty, async_exec);
+ attach_post_wait (args, from_tty, mode);
}
/* We had just found out that the target was already attached to an
void
notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
{
- struct cleanup* old_chain;
- int async_exec;
-
- old_chain = make_cleanup (null_cleanup, NULL);
+ enum attach_post_wait_mode mode
+ = leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING;
- /* 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;
+ gdb::optional<scoped_restore_current_thread> restore_thread;
- if (!ptid_equal (inferior_ptid, null_ptid))
- make_cleanup_restore_current_thread ();
+ if (inferior_ptid != null_ptid)
+ restore_thread.emplace ();
- switch_to_thread (ptid);
+ /* Avoid reading registers -- we haven't fetched the target
+ description yet. */
+ switch_to_thread_no_regs (find_thread_ptid (ptid));
/* 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))
{
+ struct attach_command_continuation_args *a;
struct inferior *inferior = current_inferior ();
/* We're going to install breakpoints, and poke at memory,
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);
}
/*
target_detach (args, 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 ()))
ptid = minus_one_ptid;
else
ptid = inferior_ptid;
- target_stop (ptid);
+
+ if (non_stop)
+ target_stop (ptid);
+ else
+ target_interrupt (ptid);
/* Tag the thread as having been explicitly requested to stop, so
other parts of gdb know not to resume this thread automatically,
/* interrupt [-a]
Stop the execution of the target while running in async mode, in
- the backgound. In all-stop, stop the whole process. In non-stop
+ 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. */
}
static void
-float_info (char *args, int from_tty)
+info_float_command (char *args, int from_tty)
{
struct frame_info *frame;
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,
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\
+Args may include \"*\", or \"[...]\"; they are expanded using the\n\
+shell that will start the program (specified by the \"$SHELL\"\
+environment\nvariable). Input and output redirection with \">\",\
+\"<\", or \">>\"\nare 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."));
+use \"set args\" without arguments.\n\
+To start the inferior without using a shell, use \"set \
+startup-with-shell off\"."));
set_cmd_completer (c, filename_completer);
add_com_alias ("r", "run", class_run, 1);
otherwise all the threads in the program are stopped. To \n\
interrupt all running threads in non-stop mode, use the -a option."));
- c = 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."));
add_info_alias ("r", "registers", 1);
set_cmd_completer (c, reg_or_group_completer);
- c = 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."));
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,
+ add_info ("float", info_float_command,
_("Print the status of the floating point unit\n"));
- add_info ("vector", vector_info,
+ add_info ("vector", info_vector_command,
_("Print the status of the vector unit\n"));
add_prefix_cmd ("proc", class_info, info_proc_cmd,