/* Memory-access and commands for "inferior" process, for GDB.
- Copyright (C) 1986-2015 Free Software Foundation, Inc.
+ Copyright (C) 1986-2016 Free Software Foundation, Inc.
This file is part of GDB.
#include "cli/cli-utils.h"
#include "infcall.h"
#include "thread-fsm.h"
+#include "top.h"
+#include "interps.h"
/* Local functions: */
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 *
{
/* 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,
simulate synchronous (fg) execution. Note no cleanup is
necessary for this. stdin is re-enabled whenever an error
reaches the top level. */
- async_disable_stdin ();
+ all_uis_on_sync_execution_starting ();
}
}
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,
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"));
/* If true, this is a stepi/nexti, otherwise a step/step. */
int single_inst;
-
- /* The thread that the command was run on. */
- int thread;
};
-static void step_command_fsm_clean_up (struct thread_fsm *self);
-static int step_command_fsm_should_stop (struct thread_fsm *self);
+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);
/* Allocate a new step_command_fsm. */
static struct step_command_fsm *
-new_step_command_fsm (void)
+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);
+ thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops, cmd_interp);
return sm;
}
sm->skip_subroutines = skip_subroutines;
sm->single_inst = single_inst;
sm->count = count;
- sm->thread = thread->num;
/* Leave the si command alone. */
if (!sm->single_inst || sm->skip_subroutines)
/* Setup the execution command state machine to handle all the COUNT
steps. */
thr = inferior_thread ();
- step_sm = new_step_command_fsm ();
+ step_sm = new_step_command_fsm (command_interp ());
thr->thread_fsm = &step_sm->thread_fsm;
step_command_fsm_prepare (step_sm, skip_subroutines,
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
else
{
+ int proceeded;
+
/* Stepped into an inline frame. Pretend that we've
stopped. */
- thread_fsm_clean_up (thr->thread_fsm);
- normal_stop ();
- inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ 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 ();
}
}
will need to keep going. */
static int
-step_command_fsm_should_stop (struct thread_fsm *self)
+step_command_fsm_should_stop (struct thread_fsm *self, struct thread_info *tp)
{
struct step_command_fsm *sm = (struct step_command_fsm *) self;
- struct thread_info *tp = find_thread_id (sm->thread);
if (tp->control.stop_step)
{
/* Implementation of the 'clean_up' FSM method for stepping commands. */
static void
-step_command_fsm_clean_up (struct thread_fsm *self)
+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 (sm->thread);
+ delete_longjmp_breakpoint (thread->global_num);
}
/* Implementation of the 'async_reply_reason' FSM method for stepping
&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);
{
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."));
}
int thread;
};
-static int until_next_fsm_should_stop (struct thread_fsm *self);
-static void until_next_fsm_clean_up (struct thread_fsm *self);
+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);
/* Allocate a new until_next_fsm. */
static struct until_next_fsm *
-new_until_next_fsm (int thread)
+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);
+ thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops, cmd_interp);
sm->thread = thread;
no arg) command. */
static int
-until_next_fsm_should_stop (struct thread_fsm *self)
+until_next_fsm_should_stop (struct thread_fsm *self,
+ struct thread_info *tp)
{
- struct thread_info *tp = inferior_thread ();
-
if (tp->control.stop_step)
thread_fsm_set_finished (self);
arg) command. */
static void
-until_next_fsm_clean_up (struct thread_fsm *self)
+until_next_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
{
struct until_next_fsm *sm = (struct until_next_fsm *) self;
- delete_longjmp_breakpoint (sm->thread);
+ delete_longjmp_breakpoint (thread->global_num);
}
/* Implementation of the 'async_reply_reason' FSM method for the until
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;
set_longjmp_breakpoint (tp, get_frame_id (frame));
old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
- sm = new_until_next_fsm (tp->num);
+ sm = new_until_next_fsm (command_interp (), tp->global_num);
tp->thread_fsm = &sm->thread_fsm;
discard_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 regcache *stop_regs;
struct gdbarch *gdbarch;
struct value *value;
- struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ struct cleanup *cleanup;
- /* 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);
- }
+ stop_regs = regcache_dup (get_current_regcache ());
+ cleanup = make_cleanup_regcache_xfree (stop_regs);
gdbarch = get_regcache_arch (stop_regs);
/* The base class. */
struct thread_fsm thread_fsm;
- /* The thread that was current when the command was executed. */
- int thread;
-
/* The momentary breakpoint set at the function's return address in
the caller. */
struct breakpoint *breakpoint;
struct return_value_info return_value;
};
-static int finish_command_fsm_should_stop (struct thread_fsm *self);
-static void finish_command_fsm_clean_up (struct thread_fsm *self);
+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_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 (int thread)
+new_finish_command_fsm (struct interp *cmd_interp)
{
struct finish_command_fsm *sm;
sm = XCNEW (struct finish_command_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops);
-
- sm->thread = thread;
+ thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops, cmd_interp);
return sm;
}
marks the FSM finished. */
static int
-finish_command_fsm_should_stop (struct thread_fsm *self)
+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;
- struct thread_info *tp = find_thread_id (f->thread);
if (f->function != NULL
&& bpstat_find_breakpoint (tp->control.stop_bpstat,
struct value *func;
func = read_var_value (f->function, NULL, get_current_frame ());
- rv->value = get_return_value (func, rv->type, NULL);
- rv->value_history_index = record_latest_value (rv->value);
+ 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)
commands. */
static void
-finish_command_fsm_clean_up (struct thread_fsm *self)
+finish_command_fsm_clean_up (struct thread_fsm *self,
+ struct thread_info *thread)
{
struct finish_command_fsm *f = (struct finish_command_fsm *) self;
delete_breakpoint (f->breakpoint);
f->breakpoint = NULL;
}
- delete_longjmp_breakpoint (f->thread);
+ delete_longjmp_breakpoint (thread->global_num);
}
/* Implementation of the 'return_value' FSM method for the finish
static enum async_reply_reason
finish_command_fsm_async_reply_reason (struct thread_fsm *self)
{
- struct finish_command_fsm *f = (struct finish_command_fsm *) self;
-
if (execution_direction == EXEC_REVERSE)
return EXEC_ASYNC_END_STEPPING_RANGE;
else
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);
+
+ return frame;
+}
+
/* "finish": Set a temporary breakpoint at the place the selected
frame will return to, then continue. */
tp = inferior_thread ();
- sm = new_finish_command_fsm (tp->num);
+ sm = new_finish_command_fsm (command_interp ());
tp->thread_fsm = &sm->thread_fsm;
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. */
sm->function = find_pc_function (get_frame_pc (get_selected_frame (NULL)));
if (execution_direction == EXEC_REVERSE)
finish_backward (sm);
else
- finish_forward (sm, frame);
+ {
+ frame = skip_finish_frames (frame);
+
+ if (frame == NULL)
+ error (_("Cannot find the caller frame."));
+
+ finish_forward (sm, frame);
+ }
}
\f
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));
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 (char *args, int from_tty, enum attach_post_wait_mode mode)
+{
+ struct inferior *inferior;
- if (async_exec)
+ inferior = current_inferior ();
+ inferior->control.stop_soon = NO_STOP_QUIETLY;
+
+ if (inferior->needs_setup)
+ setup_inferior (from_tty);
+
+ 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. */
- async_enable_stdin ();
-
/* At least the current thread is already stopped. */
/* In all-stop, by definition, all threads have to be already
selected thread is stopped, others may still be executing.
Be sure to explicitly stop all threads of the process. This
should have no effect on already stopped threads. */
- if (target_is_non_stop_p ())
+ 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);
+ inferior->needs_setup = 1;
+
if (target_is_non_stop_p ())
{
/* If we find that the current thread isn't stopped, explicitly
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 attach_command_continuation_args *a;
- struct inferior *inferior = current_inferior ();
/* 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;
- /* sync_execution mode. Wait for stop. */
+ /* Wait for stop. */
a = XNEW (struct attach_command_continuation_args);
a->args = xstrdup (args);
a->from_tty = from_tty;
- a->async_exec = async_exec;
+ a->mode = mode;
add_inferior_continuation (attach_command_continuation, a,
attach_command_continuation_free_args);
/* Done with ARGS. */
/* 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
notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
{
struct cleanup* old_chain;
- int async_exec;
+ enum attach_post_wait_mode mode;
old_chain = make_cleanup (null_cleanup, NULL);
- /* 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;
+ mode = leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING;
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 (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. */
a = XNEW (struct attach_command_continuation_args);
a->args = xstrdup ("");
a->from_tty = from_tty;
- a->async_exec = async_exec;
+ a->mode = mode;
add_inferior_continuation (attach_command_continuation, a,
attach_command_continuation_free_args);
return;
}
- async_exec = leave_running;
- attach_command_post_wait ("" /* args */, from_tty, async_exec);
+ attach_post_wait ("" /* args */, from_tty, mode);
do_cleanups (old_chain);
}
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_interrupt (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,
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);
+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);
add_com_alias ("tty", "set inferior-tty", class_alias, 0);
cmd_name = "args";