/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2021 Free Software Foundation, Inc.
+ Copyright (C) 1986-2022 Free Software Foundation, Inc.
This file is part of GDB.
#include "scoped-mock-context.h"
#include "test-target.h"
#include "gdbsupport/common-debug.h"
+#include "gdbsupport/buildargv.h"
/* Prototypes for local functions */
static void wait_for_inferior (inferior *inf);
+static void restart_threads (struct thread_info *event_thread,
+ inferior *inf = nullptr);
+
+static bool start_step_over (void);
+
+static bool step_over_info_valid_p (void);
+
/* Asynchronous signal handler registered as event loop source for
when we have pending events ready to be passed to the core. */
static struct async_event_handler *infrun_async_inferior_event_token;
show_step_stop_if_no_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Mode of the step operation is %s.\n"), value);
+ gdb_printf (file, _("Mode of the step operation is %s.\n"), value);
}
/* proceed and normal_stop use this to notify the user when the
show_debug_infrun (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Inferior debugging is %s.\n"), value);
+ gdb_printf (file, _("Inferior debugging is %s.\n"), value);
}
/* Support for disabling address space randomization. */
struct cmd_list_element *c, const char *value)
{
if (target_supports_disable_randomization ())
- fprintf_filtered (file,
- _("Disabling randomization of debuggee's "
- "virtual address space is %s.\n"),
- value);
+ gdb_printf (file,
+ _("Disabling randomization of debuggee's "
+ "virtual address space is %s.\n"),
+ value);
else
- fputs_filtered (_("Disabling randomization of debuggee's "
- "virtual address space is unsupported on\n"
- "this platform.\n"), file);
+ gdb_puts (_("Disabling randomization of debuggee's "
+ "virtual address space is unsupported on\n"
+ "this platform.\n"), file);
}
static void
show_non_stop (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file,
- _("Controlling the inferior in non-stop mode is %s.\n"),
- value);
+ gdb_printf (file,
+ _("Controlling the inferior in non-stop mode is %s.\n"),
+ value);
}
/* "Observer mode" is somewhat like a more extreme version of
}
if (from_tty)
- printf_filtered (_("Observer mode is now %s.\n"),
- (observer_mode ? "on" : "off"));
+ gdb_printf (_("Observer mode is now %s.\n"),
+ (observer_mode ? "on" : "off"));
}
static void
show_observer_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Observer mode is %s.\n"), value);
+ gdb_printf (file, _("Observer mode is %s.\n"), value);
}
/* This updates the value of observer mode based on changes in
/* Let the user know if things change. */
if (newval != observer_mode)
- printf_filtered (_("Observer mode is now %s.\n"),
- (newval ? "on" : "off"));
+ gdb_printf (_("Observer mode is now %s.\n"),
+ (newval ? "on" : "off"));
observer_mode = observer_mode_1 = newval;
}
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Stopping for shared library events is %s.\n"),
- value);
+ gdb_printf (file, _("Stopping for shared library events is %s.\n"),
+ value);
}
/* True after stop if current stack frame should be printed. */
static bool stop_print_frame;
/* This is a cached copy of the target/ptid/waitstatus of the last
- event returned by target_wait()/deprecated_target_wait_hook().
+ event returned by target_wait().
This information is returned by get_last_target_status(). */
static process_stratum_target *target_last_proc_target;
static ptid_t target_last_wait_ptid;
show_follow_fork_mode_string (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file,
- _("Debugger response to a program "
- "call of fork or vfork is \"%s\".\n"),
- value);
+ gdb_printf (file,
+ _("Debugger response to a program "
+ "call of fork or vfork is \"%s\".\n"),
+ value);
}
\f
static bool
follow_fork_inferior (bool follow_child, bool detach_fork)
{
- target_waitkind fork_kind = inferior_thread ()->pending_follow.kind;
+ target_waitkind fork_kind = inferior_thread ()->pending_follow.kind ();
gdb_assert (fork_kind == TARGET_WAITKIND_FORKED
|| fork_kind == TARGET_WAITKIND_VFORKED);
bool has_vforked = fork_kind == TARGET_WAITKIND_VFORKED;
ptid_t parent_ptid = inferior_ptid;
- ptid_t child_ptid = inferior_thread ()->pending_follow.value.related_pid;
+ ptid_t child_ptid = inferior_thread ()->pending_follow.child_ptid ();
if (has_vforked
&& !non_stop /* Non-stop always resumes both branches. */
the parent stays blocked. If we're telling the parent to run
in the foreground, the user will not be able to ctrl-c to get
back the terminal, effectively hanging the debug session. */
- fprintf_filtered (gdb_stderr, _("\
+ gdb_printf (gdb_stderr, _("\
Can not resume the parent process over vfork in the foreground while\n\
holding the child stopped. Try \"set detach-on-fork\" or \
\"set schedule-multiple\".\n"));
inferior *parent_inf = current_inferior ();
inferior *child_inf = nullptr;
+ gdb_assert (parent_inf->thread_waiting_for_vfork_done == nullptr);
+
if (!follow_child)
{
/* Detach new forked process? */
ptid_t process_ptid = ptid_t (child_ptid.pid ());
target_terminal::ours_for_output ();
- fprintf_filtered (gdb_stdlog,
- _("[Detaching after %s from child %s]\n"),
- has_vforked ? "vfork" : "fork",
- target_pid_to_str (process_ptid).c_str ());
+ gdb_printf (_("[Detaching after %s from child %s]\n"),
+ has_vforked ? "vfork" : "fork",
+ target_pid_to_str (process_ptid).c_str ());
}
}
else
}
else
{
- child_inf->aspace = new_address_space ();
+ child_inf->aspace = new address_space ();
child_inf->pspace = new program_space (child_inf->aspace);
child_inf->removable = 1;
clone_program_space (child_inf->pspace, parent_inf->pspace);
insert breakpoints, so that we can debug it. A
subsequent child exec or exit is enough to know when does
the child stops using the parent's address space. */
- parent_inf->waiting_for_vfork_done = detach_fork;
+ parent_inf->thread_waiting_for_vfork_done
+ = detach_fork ? inferior_thread () : nullptr;
parent_inf->pspace->breakpoints_not_allowed = detach_fork;
}
}
std::string child_pid = target_pid_to_str (child_ptid);
target_terminal::ours_for_output ();
- fprintf_filtered (gdb_stdlog,
- _("[Attaching after %s %s to child %s]\n"),
- parent_pid.c_str (),
- has_vforked ? "vfork" : "fork",
- child_pid.c_str ());
+ gdb_printf (_("[Attaching after %s %s to child %s]\n"),
+ parent_pid.c_str (),
+ has_vforked ? "vfork" : "fork",
+ child_pid.c_str ());
}
/* Add the new inferior first, so that the target_detach below
child_inf->gdbarch = parent_inf->gdbarch;
copy_inferior_target_desc_info (child_inf, parent_inf);
- program_space *parent_pspace = parent_inf->pspace;
-
- /* If this is a vfork child, then the address-space is shared
- with the parent. If we detached from the parent, then we can
- reuse the parent's program/address spaces. */
- if (has_vforked || detach_fork)
+ if (has_vforked)
{
- child_inf->pspace = parent_pspace;
- child_inf->aspace = child_inf->pspace->aspace;
+ /* If this is a vfork child, then the address-space is shared
+ with the parent. */
+ child_inf->aspace = parent_inf->aspace;
+ child_inf->pspace = parent_inf->pspace;
exec_on_vfork (child_inf);
}
+ else if (detach_fork)
+ {
+ /* We follow the child and detach from the parent: move the parent's
+ program space to the child. This simplifies some things, like
+ doing "next" over fork() and landing on the expected line in the
+ child (note, that is broken with "set detach-on-fork off").
+
+ Before assigning brand new spaces for the parent, remove
+ breakpoints from it: because the new pspace won't match
+ currently inserted locations, the normal detach procedure
+ wouldn't remove them, and we would leave them inserted when
+ detaching. */
+ remove_breakpoints_inf (parent_inf);
+
+ child_inf->aspace = parent_inf->aspace;
+ child_inf->pspace = parent_inf->pspace;
+ parent_inf->aspace = new address_space ();
+ parent_inf->pspace = new program_space (parent_inf->aspace);
+ clone_program_space (parent_inf->pspace, child_inf->pspace);
+
+ /* The parent inferior is still the current one, so keep things
+ in sync. */
+ set_current_program_space (parent_inf->pspace);
+ }
else
{
- child_inf->aspace = new_address_space ();
+ child_inf->aspace = new address_space ();
child_inf->pspace = new program_space (child_inf->aspace);
child_inf->removable = 1;
child_inf->symfile_flags = SYMFILE_NO_READ;
- clone_program_space (child_inf->pspace, parent_pspace);
+ clone_program_space (child_inf->pspace, parent_inf->pspace);
}
}
if (child_inf != nullptr)
gdb_assert (!child_inf->thread_list.empty ());
+ /* Clear the parent thread's pending follow field. Do this before calling
+ target_detach, so that the target can differentiate the two following
+ cases:
+
+ - We continue past a fork with "follow-fork-mode == child" &&
+ "detach-on-fork on", and therefore detach the parent. In that
+ case the target should not detach the fork child.
+ - We run to a fork catchpoint and the user types "detach". In that
+ case, the target should detach the fork child in addition to the
+ parent.
+
+ The former case will have pending_follow cleared, the later will have
+ pending_follow set. */
+ thread_info *parent_thread = find_thread_ptid (parent_inf, parent_ptid);
+ gdb_assert (parent_thread != nullptr);
+ parent_thread->pending_follow.set_spurious ();
+
/* Detach the parent if needed. */
if (follow_child)
{
child_inf->pending_detach = 0;
parent_inf->vfork_child = child_inf;
parent_inf->pending_detach = detach_fork;
- parent_inf->waiting_for_vfork_done = 0;
}
else if (detach_fork)
{
ptid_t process_ptid = ptid_t (parent_ptid.pid ());
target_terminal::ours_for_output ();
- fprintf_filtered (gdb_stdlog,
- _("[Detaching after fork from "
- "parent %s]\n"),
- target_pid_to_str (process_ptid).c_str ());
+ gdb_printf (_("[Detaching after fork from "
+ "parent %s]\n"),
+ target_pid_to_str (process_ptid).c_str ());
}
target_detach (parent_inf, 0);
{
bool follow_child = (follow_fork_mode_string == follow_fork_mode_child);
bool should_resume = true;
- struct thread_info *tp;
/* Copy user stepping state to the new inferior thread. FIXME: the
followed fork child thread should have a copy of most of the
int current_line = 0;
symtab *current_symtab = NULL;
struct frame_id step_frame_id = { 0 };
- struct thread_fsm *thread_fsm = NULL;
if (!non_stop)
{
/* If not stopped at a fork event, then there's nothing else to
do. */
- if (wait_status.kind != TARGET_WAITKIND_FORKED
- && wait_status.kind != TARGET_WAITKIND_VFORKED)
+ if (wait_status.kind () != TARGET_WAITKIND_FORKED
+ && wait_status.kind () != TARGET_WAITKIND_VFORKED)
return 1;
/* Check if we switched over from WAIT_PTID, since the event was
}
}
- tp = inferior_thread ();
+ thread_info *tp = inferior_thread ();
/* If there were any forks/vforks that were caught and are now to be
followed, then do so now. */
- switch (tp->pending_follow.kind)
+ switch (tp->pending_follow.kind ())
{
case TARGET_WAITKIND_FORKED:
case TARGET_WAITKIND_VFORKED:
{
ptid_t parent, child;
+ std::unique_ptr<struct thread_fsm> thread_fsm;
/* If the user did a next/step, etc, over a fork call,
preserve the stepping state in the fork child. */
step_frame_id = tp->control.step_frame_id;
exception_resume_breakpoint
= clone_momentary_breakpoint (tp->control.exception_resume_breakpoint);
- thread_fsm = tp->thread_fsm;
+ thread_fsm = tp->release_thread_fsm ();
/* For now, delete the parent's sr breakpoint, otherwise,
parent/child sr breakpoints are considered duplicates,
tp->control.step_range_end = 0;
tp->control.step_frame_id = null_frame_id;
delete_exception_resume_breakpoint (tp);
- tp->thread_fsm = NULL;
}
parent = inferior_ptid;
- child = tp->pending_follow.value.related_pid;
+ child = tp->pending_follow.child_ptid ();
+
+ /* If handling a vfork, stop all the inferior's threads, they will be
+ restarted when the vfork shared region is complete. */
+ if (tp->pending_follow.kind () == TARGET_WAITKIND_VFORKED
+ && target_is_non_stop_p ())
+ stop_all_threads ("handling vfork", tp->inf);
process_stratum_target *parent_targ = tp->inf->process_target ();
/* Set up inferior(s) as specified by the caller, and tell the
}
else
{
- /* This pending follow fork event is now handled, one way
- or another. The previous selected thread may be gone
- from the lists by now, but if it is still around, need
- to clear the pending follow request. */
- tp = find_thread_ptid (parent_targ, parent);
- if (tp)
- tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
-
/* This makes sure we don't try to apply the "Switched
over from WAIT_PID" logic above. */
nullify_last_target_wait_ptid ();
tp->control.step_frame_id = step_frame_id;
tp->control.exception_resume_breakpoint
= exception_resume_breakpoint;
- tp->thread_fsm = thread_fsm;
+ tp->set_thread_fsm (std::move (thread_fsm));
}
else
{
default:
internal_error (__FILE__, __LINE__,
"Unexpected pending_follow.kind %d\n",
- tp->pending_follow.kind);
+ tp->pending_follow.kind ());
break;
}
insert_breakpoints ();
}
-/* The child has exited or execed: resume threads of the parent the
- user wanted to be executing. */
+/* The child has exited or execed: resume THREAD, a thread of the parent,
+ if it was meant to be executing. */
-static int
-proceed_after_vfork_done (struct thread_info *thread,
- void *arg)
+static void
+proceed_after_vfork_done (thread_info *thread)
{
- int pid = * (int *) arg;
-
- if (thread->ptid.pid () == pid
- && thread->state == THREAD_RUNNING
- && !thread->executing
+ if (thread->state == THREAD_RUNNING
+ && !thread->executing ()
&& !thread->stop_requested
&& thread->stop_signal () == GDB_SIGNAL_0)
{
infrun_debug_printf ("resuming vfork parent thread %s",
- target_pid_to_str (thread->ptid).c_str ());
+ thread->ptid.to_string ().c_str ());
switch_to_thread (thread);
clear_proceed_status (0);
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
-
- return 0;
}
/* Called whenever we notice an exec or exit event, to handle
if (inf->vfork_parent)
{
- int resume_parent = -1;
+ inferior *resume_parent = nullptr;
/* This exec or exit marks the end of the shared memory region
between the parent and the child. Break the bonds. */
if (exec)
{
- fprintf_filtered (gdb_stdlog,
- _("[Detaching vfork parent %s "
- "after child exec]\n"), pidstr.c_str ());
+ gdb_printf (_("[Detaching vfork parent %s "
+ "after child exec]\n"), pidstr.c_str ());
}
else
{
- fprintf_filtered (gdb_stdlog,
- _("[Detaching vfork parent %s "
- "after child exit]\n"), pidstr.c_str ());
+ gdb_printf (_("[Detaching vfork parent %s "
+ "after child exit]\n"), pidstr.c_str ());
}
}
inf->removable = 1;
set_current_program_space (inf->pspace);
- resume_parent = vfork_parent->pid;
+ resume_parent = vfork_parent;
}
else
{
inf->symfile_flags = SYMFILE_NO_READ;
clone_program_space (inf->pspace, vfork_parent->pspace);
- resume_parent = vfork_parent->pid;
+ resume_parent = vfork_parent;
}
gdb_assert (current_program_space == inf->pspace);
- if (non_stop && resume_parent != -1)
+ if (non_stop && resume_parent != nullptr)
{
/* If the user wanted the parent to be running, let it go
free now. */
scoped_restore_current_thread restore_thread;
infrun_debug_printf ("resuming vfork parent process %d",
- resume_parent);
+ resume_parent->pid);
- iterate_over_threads (proceed_after_vfork_done, &resume_parent);
+ for (thread_info *thread : resume_parent->threads ())
+ proceed_after_vfork_done (thread);
}
}
}
+/* Handle TARGET_WAITKIND_VFORK_DONE. */
+
+static void
+handle_vfork_done (thread_info *event_thread)
+{
+ /* We only care about this event if inferior::thread_waiting_for_vfork_done is
+ set, that is if we are waiting for a vfork child not under our control
+ (because we detached it) to exec or exit.
+
+ If an inferior has vforked and we are debugging the child, we don't use
+ the vfork-done event to get notified about the end of the shared address
+ space window. We rely instead on the child's exec or exit event, and the
+ inferior::vfork_{parent,child} fields are used instead. See
+ handle_vfork_child_exec_or_exit for that. */
+ if (event_thread->inf->thread_waiting_for_vfork_done == nullptr)
+ {
+ infrun_debug_printf ("not waiting for a vfork-done event");
+ return;
+ }
+
+ INFRUN_SCOPED_DEBUG_ENTER_EXIT;
+
+ /* We stopped all threads (other than the vforking thread) of the inferior in
+ follow_fork and kept them stopped until now. It should therefore not be
+ possible for another thread to have reported a vfork during that window.
+ If THREAD_WAITING_FOR_VFORK_DONE is set, it has to be the same thread whose
+ vfork-done we are handling right now. */
+ gdb_assert (event_thread->inf->thread_waiting_for_vfork_done == event_thread);
+
+ event_thread->inf->thread_waiting_for_vfork_done = nullptr;
+ event_thread->inf->pspace->breakpoints_not_allowed = 0;
+
+ /* On non-stop targets, we stopped all the inferior's threads in follow_fork,
+ resume them now. On all-stop targets, everything that needs to be resumed
+ will be when we resume the event thread. */
+ if (target_is_non_stop_p ())
+ {
+ /* restart_threads and start_step_over may change the current thread, make
+ sure we leave the event thread as the current thread. */
+ scoped_restore_current_thread restore_thread;
+
+ insert_breakpoints ();
+ start_step_over ();
+
+ if (!step_over_info_valid_p ())
+ restart_threads (event_thread, event_thread->inf);
+ }
+}
+
/* Enum strings for "set|show follow-exec-mode". */
static const char follow_exec_mode_new[] = "new";
show_follow_exec_mode_string (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
+ gdb_printf (file, _("Follow exec mode is \"%s\".\n"), value);
}
/* EXEC_FILE_TARGET is assumed to be non-NULL. */
/* What is this a.out's name? */
process_ptid = ptid_t (pid);
- printf_unfiltered (_("%s is executing new program: %s\n"),
- target_pid_to_str (process_ptid).c_str (),
- exec_file_target);
+ gdb_printf (_("%s is executing new program: %s\n"),
+ target_pid_to_str (process_ptid).c_str (),
+ exec_file_target);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
infrun_inferior_exit (struct inferior *inf)
{
inf->displaced_step_state.reset ();
+ inf->thread_waiting_for_vfork_done = nullptr;
}
static void
one in progress at the time of the exec, it must have been the exec'ing
thread. */
clear_step_over_info ();
+
+ inf->thread_waiting_for_vfork_done = nullptr;
}
/* If ON, and the architecture supports it, GDB will use displaced
const char *value)
{
if (can_use_displaced_stepping == AUTO_BOOLEAN_AUTO)
- fprintf_filtered (file,
- _("Debugger's willingness to use displaced stepping "
- "to step over breakpoints is %s (currently %s).\n"),
- value, target_is_non_stop_p () ? "on" : "off");
+ gdb_printf (file,
+ _("Debugger's willingness to use displaced stepping "
+ "to step over breakpoints is %s (currently %s).\n"),
+ value, target_is_non_stop_p () ? "on" : "off");
else
- fprintf_filtered (file,
- _("Debugger's willingness to use displaced stepping "
- "to step over breakpoints is %s.\n"), value);
+ gdb_printf (file,
+ _("Debugger's willingness to use displaced stepping "
+ "to step over breakpoints is %s.\n"), value);
}
/* Return true if the gdbarch implements the required methods to use
it is likely that it will return unavailable, so don't bother asking. */
displaced_debug_printf ("deferring step of %s",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
global_thread_step_over_chain_enqueue (tp);
return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
}
displaced_debug_printf ("displaced-stepping %s now",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
scoped_restore_current_thread restore_thread;
if (status == DISPLACED_STEP_PREPARE_STATUS_CANT)
{
displaced_debug_printf ("failed to prepare (%s)",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
return DISPLACED_STEP_PREPARE_STATUS_CANT;
}
displaced_debug_printf ("not enough resources available, "
"deferring step of %s",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
global_thread_step_over_chain_enqueue (tp);
displaced_debug_printf ("prepared successfully thread=%s, "
"original_pc=%s, displaced_pc=%s",
- target_pid_to_str (tp->ptid).c_str (),
+ tp->ptid.to_string ().c_str (),
paddress (gdbarch, original_pc),
paddress (gdbarch, displaced_pc));
discarded between events. */
struct execution_control_state
{
+ execution_control_state ()
+ {
+ this->reset ();
+ }
+
+ void reset ()
+ {
+ this->target = nullptr;
+ this->ptid = null_ptid;
+ this->event_thread = nullptr;
+ ws = target_waitstatus ();
+ stop_func_filled_in = 0;
+ stop_func_start = 0;
+ stop_func_end = 0;
+ stop_func_name = nullptr;
+ wait_some_more = 0;
+ hit_singlestep_breakpoint = 0;
+ }
+
process_stratum_target *target;
ptid_t ptid;
/* The thread that got the event, if this was a thread event; NULL
static void
reset_ecs (struct execution_control_state *ecs, struct thread_info *tp)
{
- memset (ecs, 0, sizeof (*ecs));
+ ecs->reset ();
ecs->event_thread = tp;
ecs->ptid = tp->ptid;
}
continue;
}
+ if (tp->inf->thread_waiting_for_vfork_done != nullptr)
+ {
+ /* When we stop all threads, handling a vfork, any thread in the step
+ over chain remains there. A user could also try to continue a
+ thread stopped at a breakpoint while another thread is waiting for
+ a vfork-done event. In any case, we don't want to start a step
+ over right now. */
+ continue;
+ }
+
/* Remove thread from the THREADS_TO_STEP chain. If anything goes wrong
while we try to prepare the displaced step, we don't add it back to
the global step over chain. This is to avoid a thread staying in the
if (tp->control.trap_expected
|| tp->resumed ()
- || tp->executing)
+ || tp->executing ())
{
internal_error (__FILE__, __LINE__,
"[%s] has inconsistent state: "
"trap_expected=%d, resumed=%d, executing=%d\n",
- target_pid_to_str (tp->ptid).c_str (),
+ tp->ptid.to_string ().c_str (),
tp->control.trap_expected,
tp->resumed (),
- tp->executing);
+ tp->executing ());
}
infrun_debug_printf ("resuming [%s] for step-over",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
/* keep_going_pass_signal skips the step-over if the breakpoint
is no longer inserted. In all-stop, we want to keep looking
if (tp->resumed ())
{
infrun_debug_printf ("[%s] was resumed.",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
gdb_assert (!thread_is_in_step_over_chain (tp));
}
else
{
infrun_debug_printf ("[%s] was NOT resumed.",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
gdb_assert (thread_is_in_step_over_chain (tp));
}
show_scheduler_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file,
- _("Mode for locking scheduler "
- "during execution is \"%s\".\n"),
- value);
+ gdb_printf (file,
+ _("Mode for locking scheduler "
+ "during execution is \"%s\".\n"),
+ value);
}
static void
return a wildcard ptid. */
if (target_is_non_stop_p ())
return inferior_ptid;
- else
- return user_visible_resume_ptid (user_step);
+
+ /* The rest of the function assumes non-stop==off and
+ target-non-stop==off.
+
+ If a thread is waiting for a vfork-done event, it means breakpoints are out
+ for this inferior (well, program space in fact). We don't want to resume
+ any thread other than the one waiting for vfork done, otherwise these other
+ threads could miss breakpoints. So if a thread in the resumption set is
+ waiting for a vfork-done event, resume only that thread.
+
+ The resumption set width depends on whether schedule-multiple is on or off.
+
+ Note that if the target_resume interface was more flexible, we could be
+ smarter here when schedule-multiple is on. For example, imagine 3
+ inferiors with 2 threads each (1.1, 1.2, 2.1, 2.2, 3.1 and 3.2). Threads
+ 2.1 and 3.2 are both waiting for a vfork-done event. Then we could ask the
+ target(s) to resume:
+
+ - All threads of inferior 1
+ - Thread 2.1
+ - Thread 3.2
+
+ Since we don't have that flexibility (we can only pass one ptid), just
+ resume the first thread waiting for a vfork-done event we find (e.g. thread
+ 2.1). */
+ if (sched_multi)
+ {
+ for (inferior *inf : all_non_exited_inferiors ())
+ if (inf->thread_waiting_for_vfork_done != nullptr)
+ return inf->thread_waiting_for_vfork_done->ptid;
+ }
+ else if (current_inferior ()->thread_waiting_for_vfork_done != nullptr)
+ return current_inferior ()->thread_waiting_for_vfork_done->ptid;
+
+ return user_visible_resume_ptid (user_step);
}
/* Wrapper for target_resume, that handles infrun-specific
else
target_pass_signals (signal_pass);
- target_resume (resume_ptid, step, sig);
+ infrun_debug_printf ("resume_ptid=%s, step=%d, sig=%s",
+ resume_ptid.to_string ().c_str (),
+ step, gdb_signal_to_symbol_string (sig));
- if (target_can_async_p ())
- target_async (1);
+ target_resume (resume_ptid, step, sig);
}
/* Resume the inferior. SIG is the signal to give the inferior
infrun_debug_printf
("thread %s has pending wait "
"status %s (currently_stepping=%d).",
- target_pid_to_str (tp->ptid).c_str (),
- target_waitstatus_to_string (&tp->pending_waitstatus ()).c_str (),
+ tp->ptid.to_string ().c_str (),
+ tp->pending_waitstatus ().to_string ().c_str (),
currently_stepping (tp));
tp->inf->process_target ()->threads_executing = true;
{
warning (_("Couldn't deliver signal %s to %s."),
gdb_signal_to_name (sig),
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
}
tp->set_stop_signal (GDB_SIGNAL_0);
if (target_can_async_p ())
{
- target_async (1);
+ target_async (true);
/* Tell the event loop we have an event to process. */
mark_async_event_handler (infrun_async_inferior_event_token);
}
/* Depends on stepped_breakpoint. */
step = currently_stepping (tp);
- if (current_inferior ()->waiting_for_vfork_done)
+ if (current_inferior ()->thread_waiting_for_vfork_done != nullptr)
{
/* Don't try to single-step a vfork parent that is waiting for
the child to get out of the shared memory region (by exec'ing
"current thread [%s] at %s",
step, gdb_signal_to_symbol_string (sig),
tp->control.trap_expected,
- target_pid_to_str (inferior_ptid).c_str (),
+ inferior_ptid.to_string ().c_str (),
paddress (gdbarch, pc));
/* Normally, by the time we reach `resume', the breakpoints are either
&& use_displaced_stepping (tp)
&& !step_over_info_valid_p ()
&& sig == GDB_SIGNAL_0
- && !current_inferior ()->waiting_for_vfork_done)
+ && current_inferior ()->thread_waiting_for_vfork_done == nullptr)
{
displaced_step_prepare_status prepare_status
= displaced_step_prepare (tp);
/* Fallback to stepping over the breakpoint in-line. */
if (target_is_non_stop_p ())
- stop_all_threads ();
+ stop_all_threads ("displaced stepping falling back on inline stepping");
set_step_over_info (regcache->aspace (),
regcache_read_pc (regcache), 0, tp->global_num);
step = gdbarch_displaced_step_hw_singlestep (gdbarch);
}
else
- gdb_assert_not_reached (_("Invalid displaced_step_prepare_status "
- "value."));
+ gdb_assert_not_reached ("Invalid displaced_step_prepare_status "
+ "value.");
}
/* Do we need to do it the hard way, w/temp breakpoints? */
do displaced stepping. */
infrun_debug_printf ("resume: [%s] stepped breakpoint",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
tp->stepped_breakpoint = 1;
static void
clear_proceed_status_thread (struct thread_info *tp)
{
- infrun_debug_printf ("%s", target_pid_to_str (tp->ptid).c_str ());
+ infrun_debug_printf ("%s", tp->ptid.to_string ().c_str ());
/* If we're starting a new sequence, then the previous finished
single-step is no longer relevant. */
{
infrun_debug_printf ("pending event of %s was a finished step. "
"Discarding.",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
tp->clear_pending_waitstatus ();
tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
{
infrun_debug_printf
("thread %s has pending wait status %s (currently_stepping=%d).",
- target_pid_to_str (tp->ptid).c_str (),
- target_waitstatus_to_string (&tp->pending_waitstatus ()).c_str (),
+ tp->ptid.to_string ().c_str (),
+ tp->pending_waitstatus ().to_string ().c_str (),
currently_stepping (tp));
}
}
if (!signal_pass_state (tp->stop_signal ()))
tp->set_stop_signal (GDB_SIGNAL_0);
- delete tp->thread_fsm;
- tp->thread_fsm = NULL;
+ tp->release_thread_fsm ();
tp->control.trap_expected = 0;
tp->control.step_range_start = 0;
CORE_ADDR pc;
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- bool started;
/* If we're stopped at a fork/vfork, follow the branch set by the
"set follow-fork-mode" command; otherwise, we'll just proceed
if (addr == (CORE_ADDR) -1)
{
- if (pc == cur_thr->stop_pc ()
+ if (cur_thr->stop_pc_p ()
+ && pc == cur_thr->stop_pc ()
&& breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
gdb_assert (!thread_is_in_step_over_chain (tp));
infrun_debug_printf ("need to step-over [%s] first",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
global_thread_step_over_chain_enqueue (tp);
}
{
scoped_disable_commit_resumed disable_commit_resumed ("proceeding");
-
- started = start_step_over ();
+ bool step_over_started = start_step_over ();
if (step_over_info_valid_p ())
{
other thread was already doing one. In either case, don't
resume anything else until the step-over is finished. */
}
- else if (started && !target_is_non_stop_p ())
+ else if (step_over_started && !target_is_non_stop_p ())
{
/* A new displaced stepping sequence was started. In all-stop,
we can't talk to the target anymore until it next stops. */
if (!tp->inf->has_execution ())
{
infrun_debug_printf ("[%s] target has no execution",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
continue;
}
if (tp->resumed ())
{
infrun_debug_printf ("[%s] resumed",
- target_pid_to_str (tp->ptid).c_str ());
- gdb_assert (tp->executing || tp->has_pending_waitstatus ());
+ tp->ptid.to_string ().c_str ());
+ gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
continue;
}
if (thread_is_in_step_over_chain (tp))
{
infrun_debug_printf ("[%s] needs step-over",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
+ continue;
+ }
+
+ /* If a thread of that inferior is waiting for a vfork-done
+ (for a detached vfork child to exec or exit), breakpoints are
+ removed. We must not resume any thread of that inferior, other
+ than the one waiting for the vfork-done. */
+ if (tp->inf->thread_waiting_for_vfork_done != nullptr
+ && tp != tp->inf->thread_waiting_for_vfork_done)
+ {
+ infrun_debug_printf ("[%s] another thread of this inferior is "
+ "waiting for vfork-done",
+ tp->ptid.to_string ().c_str ());
continue;
}
infrun_debug_printf ("resuming %s",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
reset_ecs (ecs, tp);
switch_to_thread (tp);
error (_("Command aborted."));
}
}
- else if (!cur_thr->resumed () && !thread_is_in_step_over_chain (cur_thr))
+ else if (!cur_thr->resumed ()
+ && !thread_is_in_step_over_chain (cur_thr)
+ /* In non-stop, forbid resuming a thread if some other thread of
+ that inferior is waiting for a vfork-done event (this means
+ breakpoints are out for this inferior). */
+ && !(non_stop
+ && cur_thr->inf->thread_waiting_for_vfork_done != nullptr))
{
/* The thread wasn't started, and isn't queued, run it now. */
reset_ecs (ecs, cur_thr);
{
if (tp->state != THREAD_RUNNING)
continue;
- if (tp->executing)
+ if (tp->executing ())
continue;
/* Remove matching threads from the step-over queue, so
if (!tp->has_pending_waitstatus ())
{
target_waitstatus ws;
- ws.kind = TARGET_WAITKIND_STOPPED;
- ws.value.sig = GDB_SIGNAL_0;
+ ws.set_stopped (GDB_SIGNAL_0);
tp->set_pending_waitstatus (ws);
}
void
print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
- const struct target_waitstatus *ws)
+ const struct target_waitstatus &ws)
{
infrun_debug_printf ("target_wait (%s [%s], status) =",
waiton_ptid.to_string ().c_str (),
infrun_debug_printf (" %s [%s],",
result_ptid.to_string ().c_str (),
target_pid_to_str (result_ptid).c_str ());
- infrun_debug_printf (" %s", target_waitstatus_to_string (ws).c_str ());
+ infrun_debug_printf (" %s", ws.to_string ().c_str ());
}
/* Select a thread at random, out of those which are resumed and have
return nullptr;
}
- infrun_debug_printf ("Found %s.", target_pid_to_str (thread->ptid).c_str ());
+ infrun_debug_printf ("Found %s.", thread->ptid.to_string ().c_str ());
gdb_assert (thread->resumed ());
gdb_assert (thread->has_pending_waitstatus ());
do_target_wait_1 (inferior *inf, ptid_t ptid,
target_waitstatus *status, target_wait_flags options)
{
- ptid_t event_ptid;
struct thread_info *tp;
/* We know that we are looking for an event in the target of inferior
else
{
infrun_debug_printf ("Waiting for specific thread %s.",
- target_pid_to_str (ptid).c_str ());
+ ptid.to_string ().c_str ());
/* We have a specific thread to check. */
tp = find_thread_ptid (inf, ptid);
if (pc != tp->stop_pc ())
{
infrun_debug_printf ("PC of %s changed. was=%s, now=%s",
- target_pid_to_str (tp->ptid).c_str (),
+ tp->ptid.to_string ().c_str (),
paddress (gdbarch, tp->stop_pc ()),
paddress (gdbarch, pc));
discard = 1;
else if (!breakpoint_inserted_here_p (regcache->aspace (), pc))
{
infrun_debug_printf ("previous breakpoint of %s, at %s gone",
- target_pid_to_str (tp->ptid).c_str (),
+ tp->ptid.to_string ().c_str (),
paddress (gdbarch, pc));
discard = 1;
if (discard)
{
infrun_debug_printf ("pending event of %s cancelled.",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
tp->clear_pending_waitstatus ();
target_waitstatus ws;
- ws.kind = TARGET_WAITKIND_SPURIOUS;
+ ws.set_spurious ();
tp->set_pending_waitstatus (ws);
tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
}
if (tp != NULL)
{
infrun_debug_printf ("Using pending wait status %s for %s.",
- target_waitstatus_to_string
- (&tp->pending_waitstatus ()).c_str (),
- target_pid_to_str (tp->ptid).c_str ());
+ tp->pending_waitstatus ().to_string ().c_str (),
+ tp->ptid.to_string ().c_str ());
/* Now that we've selected our final event LWP, un-adjust its PC
if it was a software breakpoint (and the target doesn't
if (!target_can_async_p ())
options &= ~TARGET_WNOHANG;
- if (deprecated_target_wait_hook)
- event_ptid = deprecated_target_wait_hook (ptid, status, options);
- else
- event_ptid = target_wait (ptid, status, options);
-
- return event_ptid;
+ return target_wait (ptid, status, options);
}
/* Wrapper for target_wait that first checks whether threads have
if (num_inferiors == 0)
{
- ecs->ws.kind = TARGET_WAITKIND_IGNORE;
+ ecs->ws.set_ignore ();
return false;
}
{
ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, options);
ecs->target = inf->process_target ();
- return (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
+ return (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
};
/* Needed in 'all-stop + target-non-stop' mode, because we end up
return true;
}
- ecs->ws.kind = TARGET_WAITKIND_IGNORE;
+ ecs->ws.set_ignore ();
return false;
}
};
static bool handle_one (const wait_one_event &event);
-static void restart_threads (struct thread_info *event_thread);
/* Prepare and stabilize the inferior for detaching it. E.g.,
detaching while a thread is displaced stepping is a recipe for
if (tp->inf == inf)
{
infrun_debug_printf ("removing thread %s from global step over chain",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
global_thread_step_over_chain_remove (tp);
}
{
if (thr->displaced_step_state.in_progress ())
{
- if (thr->executing)
+ if (thr->executing ())
{
if (!thr->stop_requested)
{
event.ptid = do_target_wait_1 (inf, pid_ptid, &event.ws, 0);
if (debug_infrun)
- print_target_wait_results (pid_ptid, event.ptid, &event.ws);
+ print_target_wait_results (pid_ptid, event.ptid, event.ws);
handle_one (event);
}
}
}
+/* If all-stop, but there exists a non-stop target, stop all threads
+ now that we're presenting the stop to the user. */
+
+static void
+stop_all_threads_if_all_stop_mode ()
+{
+ if (!non_stop && exists_non_stop_target ())
+ stop_all_threads ("presenting stop to user in all-stop");
+}
+
/* Wait for control to return from inferior to debugger.
If inferior gets a signal, we may decide to start it up again
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- memset (ecs, 0, sizeof (*ecs));
-
overlay_cache_invalid = 1;
/* Flush target cache before starting to handle each event.
ecs->target = inf->process_target ();
if (debug_infrun)
- print_target_wait_results (minus_one_ptid, ecs->ptid, &ecs->ws);
+ print_target_wait_results (minus_one_ptid, ecs->ptid, ecs->ws);
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
break;
}
+ stop_all_threads_if_all_stop_mode ();
+
/* No error, don't finish the state yet. */
finish_state.release ();
}
static void
clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
{
- if (ecs->event_thread != NULL
- && ecs->event_thread->thread_fsm != NULL)
- ecs->event_thread->thread_fsm->clean_up (ecs->event_thread);
+ /* The first clean_up call below assumes the event thread is the current
+ one. */
+ if (ecs->event_thread != nullptr)
+ gdb_assert (ecs->event_thread == inferior_thread ());
+
+ if (ecs->event_thread != nullptr
+ && ecs->event_thread->thread_fsm () != nullptr)
+ ecs->event_thread->thread_fsm ()->clean_up (ecs->event_thread);
if (!non_stop)
{
+ scoped_restore_current_thread restore_thread;
+
for (thread_info *thr : all_non_exited_threads ())
{
- if (thr->thread_fsm == NULL)
+ if (thr->thread_fsm () == nullptr)
continue;
if (thr == ecs->event_thread)
continue;
switch_to_thread (thr);
- thr->thread_fsm->clean_up (thr);
+ thr->thread_fsm ()->clean_up (thr);
}
-
- if (ecs->event_thread != NULL)
- switch_to_thread (ecs->event_thread);
}
}
{
target_terminal::ours ();
gdb::observers::sync_execution_done.notify ();
- ui_register_input_event_handler (ui);
+ ui->register_file_handler ();
}
}
struct execution_control_state *ecs = &ecss;
int cmd_done = 0;
- memset (ecs, 0, sizeof (*ecs));
-
/* Events are always processed with the main UI as current UI. This
way, warnings, debug output, etc. are always consistently sent to
the main console. */
return;
}
- gdb_assert (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
+ gdb_assert (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
/* Switch to the target that generated the event, so we can do
target calls. */
switch_to_target_no_thread (ecs->target);
if (debug_infrun)
- print_target_wait_results (minus_one_ptid, ecs->ptid, &ecs->ws);
+ print_target_wait_results (minus_one_ptid, ecs->ptid, ecs->ws);
/* If an error happens while handling the event, propagate GDB's
knowledge of the executing state to the frontend/user running
delete_just_stopped_threads_infrun_breakpoints ();
- if (thr != NULL)
- {
- struct thread_fsm *thread_fsm = thr->thread_fsm;
-
- if (thread_fsm != NULL)
- should_stop = thread_fsm->should_stop (thr);
- }
+ if (thr != nullptr && thr->thread_fsm () != nullptr)
+ should_stop = thr->thread_fsm ()->should_stop (thr);
if (!should_stop)
{
bool should_notify_stop = true;
int proceeded = 0;
+ stop_all_threads_if_all_stop_mode ();
+
clean_up_just_stopped_threads_fsms (ecs);
- if (thr != NULL && thr->thread_fsm != NULL)
- should_notify_stop = thr->thread_fsm->should_notify_stop ();
+ if (thr != nullptr && thr->thread_fsm () != nullptr)
+ should_notify_stop
+ = thr->thread_fsm ()->should_notify_stop ();
if (should_notify_stop)
{
selected.". */
if (!non_stop
&& cmd_done
- && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
+ && ecs->ws.kind () != TARGET_WAITKIND_NO_RESUMED)
restore_thread.dont_restore ();
}
}
reinstalled here. */
}
+ /* Handling this event might have caused some inferiors to become prunable.
+ For example, the exit of an inferior that was automatically added. Try
+ to get rid of them. Keeping those around slows down things linearly.
+
+ Note that this never removes the current inferior. Therefore, call this
+ after RESTORE_THREAD went out of scope, in case the event inferior (which was
+ temporarily made the current inferior) is meant to be deleted.
+
+ Call this before all_uis_check_sync_execution_done, so that notifications about
+ removed inferiors appear before the prompt. */
+ prune_inferiors ();
+
/* If a UI was in sync execution mode, and now isn't, restore its
prompt (a synchronous execution command has finished, and we're
ready for input). */
&& exec_done_display_p
&& (inferior_ptid == null_ptid
|| inferior_thread ()->state != THREAD_RUNNING))
- printf_unfiltered (_("completed.\n"));
+ gdb_printf (_("completed.\n"));
}
/* See infrun.h. */
tp->current_symtab = sal.symtab;
tp->current_line = sal.line;
+
+ infrun_debug_printf
+ ("symtab = %s, line = %d, step_frame_id = %s, step_stack_frame_id = %s",
+ tp->current_symtab != nullptr ? tp->current_symtab->filename : "<null>",
+ tp->current_line,
+ tp->control.step_frame_id.to_string ().c_str (),
+ tp->control.step_stack_frame_id.to_string ().c_str ());
}
/* Clear context switchable stepping state. */
void
set_last_target_status (process_stratum_target *target, ptid_t ptid,
- target_waitstatus status)
+ const target_waitstatus &status)
{
target_last_proc_target = target;
target_last_wait_ptid = ptid;
|| ecs->event_thread != inferior_thread ()))
{
infrun_debug_printf ("Switching context from %s to %s",
- target_pid_to_str (inferior_ptid).c_str (),
- target_pid_to_str (ecs->ptid).c_str ());
+ inferior_ptid.to_string ().c_str (),
+ ecs->ptid.to_string ().c_str ());
}
switch_to_thread (ecs->event_thread);
static void
adjust_pc_after_break (struct thread_info *thread,
- const target_waitstatus *ws)
+ const target_waitstatus &ws)
{
struct regcache *regcache;
struct gdbarch *gdbarch;
target with both of these set in GDB history, and it seems unlikely to be
correct, so gdbarch_have_nonsteppable_watchpoint is not checked here. */
- if (ws->kind != TARGET_WAITKIND_STOPPED)
+ if (ws.kind () != TARGET_WAITKIND_STOPPED)
return;
- if (ws->value.sig != GDB_SIGNAL_TRAP)
+ if (ws.sig () != GDB_SIGNAL_TRAP)
return;
/* In reverse execution, when a breakpoint is hit, the instruction
{
if (ecs->event_thread->stop_requested)
{
- ecs->ws.kind = TARGET_WAITKIND_STOPPED;
- ecs->ws.value.sig = GDB_SIGNAL_0;
+ ecs->ws.set_stopped (GDB_SIGNAL_0);
handle_signal_stop (ecs);
return true;
}
context_switch (ecs);
regcache = get_thread_regcache (ecs->event_thread);
- syscall_number = ecs->ws.value.syscall_number;
+ syscall_number = ecs->ws.syscall_number ();
ecs->event_thread->set_stop_pc (regcache_read_pc (regcache));
if (catch_syscall_enabled () > 0
- && catching_syscall_number (syscall_number) > 0)
+ && catching_syscall_number (syscall_number))
{
infrun_debug_printf ("syscall number=%d", syscall_number);
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (regcache->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, &ecs->ws);
+ = bpstat_stop_status_nowatch (regcache->aspace (),
+ ecs->event_thread->stop_pc (),
+ ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return false;
stop_func_start is NOT advanced when in a range of a
non-contiguous block that does not contain the entry pc. */
if (block != nullptr
- && ecs->stop_func_start <= BLOCK_ENTRY_PC (block)
- && BLOCK_ENTRY_PC (block) < ecs->stop_func_end)
+ && ecs->stop_func_start <= block->entry_pc ()
+ && block->entry_pc () < ecs->stop_func_end)
{
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (gdbarch);
don't get any event. */
target_dcache_invalidate ();
- if (deprecated_target_wait_hook)
- event_ptid = deprecated_target_wait_hook (minus_one_ptid, ws, TARGET_WNOHANG);
- else
- event_ptid = target_wait (minus_one_ptid, ws, TARGET_WNOHANG);
+ event_ptid = target_wait (minus_one_ptid, ws, TARGET_WNOHANG);
if (debug_infrun)
- print_target_wait_results (minus_one_ptid, event_ptid, ws);
+ print_target_wait_results (minus_one_ptid, event_ptid, *ws);
return event_ptid;
}
event.target = target;
event.ptid = poll_one_curr_target (&event.ws);
- if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED)
+ if (event.ws.kind () == TARGET_WAITKIND_NO_RESUMED)
{
/* If nothing is resumed, remove the target from the
event loop. */
- target_async (0);
+ target_async (false);
}
- else if (event.ws.kind != TARGET_WAITKIND_IGNORE)
+ else if (event.ws.kind () != TARGET_WAITKIND_IGNORE)
return event;
}
if (nfds == 0)
{
/* No waitable targets left. All must be stopped. */
- return {NULL, minus_one_ptid, {TARGET_WAITKIND_NO_RESUMED}};
+ target_waitstatus ws;
+ ws.set_no_resumed ();
+ return {NULL, minus_one_ptid, std::move (ws)};
}
QUIT;
/* Save the thread's event and stop reason to process it later. */
static void
-save_waitstatus (struct thread_info *tp, const target_waitstatus *ws)
+save_waitstatus (struct thread_info *tp, const target_waitstatus &ws)
{
- infrun_debug_printf ("saving status %s for %d.%ld.%ld",
- target_waitstatus_to_string (ws).c_str (),
- tp->ptid.pid (),
- tp->ptid.lwp (),
- tp->ptid.tid ());
+ infrun_debug_printf ("saving status %s for %s",
+ ws.to_string ().c_str (),
+ tp->ptid.to_string ().c_str ());
/* Record for later. */
- tp->set_pending_waitstatus (*ws);
+ tp->set_pending_waitstatus (ws);
- if (ws->kind == TARGET_WAITKIND_STOPPED
- && ws->value.sig == GDB_SIGNAL_TRAP)
+ if (ws.kind () == TARGET_WAITKIND_STOPPED
+ && ws.sig () == GDB_SIGNAL_TRAP)
{
struct regcache *regcache = get_thread_regcache (tp);
const address_space *aspace = regcache->aspace ();
CORE_ADDR pc = regcache_read_pc (regcache);
- adjust_pc_after_break (tp, &tp->pending_waitstatus ());
+ adjust_pc_after_break (tp, tp->pending_waitstatus ());
scoped_restore_current_thread restore_thread;
switch_to_thread (tp);
static void
mark_non_executing_threads (process_stratum_target *target,
ptid_t event_ptid,
- struct target_waitstatus ws)
+ const target_waitstatus &ws)
{
ptid_t mark_ptid;
if (!target_is_non_stop_p ())
mark_ptid = minus_one_ptid;
- else if (ws.kind == TARGET_WAITKIND_SIGNALLED
- || ws.kind == TARGET_WAITKIND_EXITED)
+ else if (ws.kind () == TARGET_WAITKIND_SIGNALLED
+ || ws.kind () == TARGET_WAITKIND_EXITED)
{
/* If we're handling a process exit in non-stop mode, even
though threads haven't been deleted yet, one would think
handle_one (const wait_one_event &event)
{
infrun_debug_printf
- ("%s %s", target_waitstatus_to_string (&event.ws).c_str (),
- target_pid_to_str (event.ptid).c_str ());
+ ("%s %s", event.ws.to_string ().c_str (),
+ event.ptid.to_string ().c_str ());
- if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED)
+ if (event.ws.kind () == TARGET_WAITKIND_NO_RESUMED)
{
/* All resumed threads exited. */
return true;
}
- else if (event.ws.kind == TARGET_WAITKIND_THREAD_EXITED
- || event.ws.kind == TARGET_WAITKIND_EXITED
- || event.ws.kind == TARGET_WAITKIND_SIGNALLED)
+ else if (event.ws.kind () == TARGET_WAITKIND_THREAD_EXITED
+ || event.ws.kind () == TARGET_WAITKIND_EXITED
+ || event.ws.kind () == TARGET_WAITKIND_SIGNALLED)
{
/* One thread/process exited/signalled. */
gdb_assert (t != nullptr);
infrun_debug_printf
- ("using %s", target_pid_to_str (t->ptid).c_str ());
+ ("using %s", t->ptid.to_string ().c_str ());
}
else
{
/* Check if this is the first time we see this thread.
Don't bother adding if it individually exited. */
if (t == nullptr
- && event.ws.kind != TARGET_WAITKIND_THREAD_EXITED)
+ && event.ws.kind () != TARGET_WAITKIND_THREAD_EXITED)
t = add_thread (event.target, event.ptid);
}
switch_to_thread_no_regs (t);
mark_non_executing_threads (event.target, event.ptid,
event.ws);
- save_waitstatus (t, &event.ws);
+ save_waitstatus (t, event.ws);
t->stop_requested = false;
}
}
t = add_thread (event.target, event.ptid);
t->stop_requested = 0;
- t->executing = 0;
+ t->set_executing (false);
t->set_resumed (false);
t->control.may_range_step = 0;
/* This may be the first time we see the inferior report
a stop. */
- inferior *inf = find_inferior_ptid (event.target, event.ptid);
- if (inf->needs_setup)
+ if (t->inf->needs_setup)
{
switch_to_thread_no_regs (t);
setup_inferior (0);
}
- if (event.ws.kind == TARGET_WAITKIND_STOPPED
- && event.ws.value.sig == GDB_SIGNAL_0)
+ if (event.ws.kind () == TARGET_WAITKIND_STOPPED
+ && event.ws.sig () == GDB_SIGNAL_0)
{
/* We caught the event that we intended to catch, so
there's no event to save as pending. */
/* Add it back to the step-over queue. */
infrun_debug_printf
("displaced-step of %s canceled",
- target_pid_to_str (t->ptid).c_str ());
+ t->ptid.to_string ().c_str ());
t->control.trap_expected = 0;
if (!t->inf->detaching)
struct regcache *regcache;
infrun_debug_printf
- ("target_wait %s, saving status for %d.%ld.%ld",
- target_waitstatus_to_string (&event.ws).c_str (),
- t->ptid.pid (), t->ptid.lwp (), t->ptid.tid ());
+ ("target_wait %s, saving status for %s",
+ event.ws.to_string ().c_str (),
+ t->ptid.to_string ().c_str ());
/* Record for later. */
- save_waitstatus (t, &event.ws);
+ save_waitstatus (t, event.ws);
- sig = (event.ws.kind == TARGET_WAITKIND_STOPPED
- ? event.ws.value.sig : GDB_SIGNAL_0);
+ sig = (event.ws.kind () == TARGET_WAITKIND_STOPPED
+ ? event.ws.sig () : GDB_SIGNAL_0);
if (displaced_step_finish (t, sig)
== DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
infrun_debug_printf ("saved stop_pc=%s for %s "
"(currently_stepping=%d)",
paddress (target_gdbarch (), t->stop_pc ()),
- target_pid_to_str (t->ptid).c_str (),
+ t->ptid.to_string ().c_str (),
currently_stepping (t));
}
}
/* See infrun.h. */
void
-stop_all_threads (void)
+stop_all_threads (const char *reason, inferior *inf)
{
/* We may need multiple passes to discover all threads. */
int pass;
gdb_assert (exists_non_stop_target ());
- infrun_debug_printf ("starting");
+ INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason,
+ inf != nullptr ? inf->num : -1);
+
+ infrun_debug_show_threads ("non-exited threads",
+ all_non_exited_threads ());
scoped_restore_current_thread restore_thread;
- /* Enable thread events of all targets. */
+ /* Enable thread events on relevant targets. */
for (auto *target : all_non_exited_process_targets ())
{
+ if (inf != nullptr && inf->process_target () != target)
+ continue;
+
switch_to_target_no_thread (target);
target_thread_events (true);
}
SCOPE_EXIT
{
- /* Disable thread events of all targets. */
+ /* Disable thread events on relevant targets. */
for (auto *target : all_non_exited_process_targets ())
{
+ if (inf != nullptr && inf->process_target () != target)
+ continue;
+
switch_to_target_no_thread (target);
target_thread_events (false);
}
for (auto *target : all_non_exited_process_targets ())
{
+ if (inf != nullptr && inf->process_target () != target)
+ continue;
+
switch_to_target_no_thread (target);
update_thread_list ();
}
to tell the target to stop. */
for (thread_info *t : all_non_exited_threads ())
{
+ if (inf != nullptr && t->inf != inf)
+ continue;
+
/* For a single-target setting with an all-stop target,
we would not even arrive here. For a multi-target
setting, until GDB is able to handle a mixture of
if (!target_is_non_stop_p ())
continue;
- if (t->executing)
+ if (t->executing ())
{
/* If already stopping, don't request a stop again.
We just haven't seen the notification yet. */
if (!t->stop_requested)
{
infrun_debug_printf (" %s executing, need stop",
- target_pid_to_str (t->ptid).c_str ());
+ t->ptid.to_string ().c_str ());
target_stop (t->ptid);
t->stop_requested = 1;
}
else
{
infrun_debug_printf (" %s executing, already stopping",
- target_pid_to_str (t->ptid).c_str ());
+ t->ptid.to_string ().c_str ());
}
if (t->stop_requested)
else
{
infrun_debug_printf (" %s not executing",
- target_pid_to_str (t->ptid).c_str ());
+ t->ptid.to_string ().c_str ());
/* The thread may be not executing, but still be
resumed with a pending status to process. */
inferior *curr_inf = current_inferior ();
scoped_restore_current_thread restore_thread;
-
- for (auto *target : all_non_exited_process_targets ())
- {
- switch_to_target_no_thread (target);
- update_thread_list ();
- }
+ update_thread_list ();
/* If:
for (thread_info *thread : all_non_exited_threads ())
{
- if (swap_terminal && thread->executing)
+ if (swap_terminal && thread->executing ())
{
if (thread->inf != curr_inf)
{
swap_terminal = false;
}
- if (!ignore_event
- && (thread->executing || thread->has_pending_waitstatus ()))
+ if (!ignore_event && thread->resumed ())
{
/* Either there were no unwaited-for children left in the
target at some point, but there are now, or some target
end. */
scoped_value_mark free_values;
- infrun_debug_printf ("%s", target_waitstatus_to_string (&ecs->ws).c_str ());
+ infrun_debug_printf ("%s", ecs->ws.to_string ().c_str ());
- if (ecs->ws.kind == TARGET_WAITKIND_IGNORE)
+ if (ecs->ws.kind () == TARGET_WAITKIND_IGNORE)
{
/* We had an event in the inferior, but we are not interested in
handling it at this level. The lower layers have already
return;
}
- if (ecs->ws.kind == TARGET_WAITKIND_THREAD_EXITED)
+ if (ecs->ws.kind () == TARGET_WAITKIND_THREAD_EXITED)
{
prepare_to_wait (ecs);
return;
}
- if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED
+ if (ecs->ws.kind () == TARGET_WAITKIND_NO_RESUMED
&& handle_no_resumed (ecs))
return;
/* Always clear state belonging to the previous time we stopped. */
stop_stack_dummy = STOP_NONE;
- if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED)
+ if (ecs->ws.kind () == TARGET_WAITKIND_NO_RESUMED)
{
/* No unwaited-for children left. IOW, all resumed children
have exited. */
return;
}
- if (ecs->ws.kind != TARGET_WAITKIND_EXITED
- && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+ if (ecs->ws.kind () != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind () != TARGET_WAITKIND_SIGNALLED)
{
ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
/* If it's a new thread, add it to the thread database. */
}
/* Dependent on valid ECS->EVENT_THREAD. */
- adjust_pc_after_break (ecs->event_thread, &ecs->ws);
+ adjust_pc_after_break (ecs->event_thread, ecs->ws);
/* Dependent on the current PC value modified by adjust_pc_after_break. */
reinit_frame_cache ();
non-executable stack. This happens for call dummy breakpoints
for architectures like SPARC that place call dummies on the
stack. */
- if (ecs->ws.kind == TARGET_WAITKIND_STOPPED
- && (ecs->ws.value.sig == GDB_SIGNAL_ILL
- || ecs->ws.value.sig == GDB_SIGNAL_SEGV
- || ecs->ws.value.sig == GDB_SIGNAL_EMT))
+ if (ecs->ws.kind () == TARGET_WAITKIND_STOPPED
+ && (ecs->ws.sig () == GDB_SIGNAL_ILL
+ || ecs->ws.sig () == GDB_SIGNAL_SEGV
+ || ecs->ws.sig () == GDB_SIGNAL_EMT))
{
struct regcache *regcache = get_thread_regcache (ecs->event_thread);
regcache_read_pc (regcache)))
{
infrun_debug_printf ("Treating signal as SIGTRAP");
- ecs->ws.value.sig = GDB_SIGNAL_TRAP;
+ ecs->ws.set_stopped (GDB_SIGNAL_TRAP);
}
}
mark_non_executing_threads (ecs->target, ecs->ptid, ecs->ws);
- switch (ecs->ws.kind)
+ switch (ecs->ws.kind ())
{
case TARGET_WAITKIND_LOADED:
{
handle_solib_event ();
+ ecs->event_thread->set_stop_pc (regcache_read_pc (regcache));
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (regcache->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, &ecs->ws);
+ = bpstat_stop_status_nowatch (regcache->aspace (),
+ ecs->event_thread->stop_pc (),
+ ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return;
/* Clearing any previous state of convenience variables. */
clear_exit_convenience_vars ();
- if (ecs->ws.kind == TARGET_WAITKIND_EXITED)
+ if (ecs->ws.kind () == TARGET_WAITKIND_EXITED)
{
/* Record the exit code in the convenience variable $_exitcode, so
that the user can inspect this again later. */
set_internalvar_integer (lookup_internalvar ("_exitcode"),
- (LONGEST) ecs->ws.value.integer);
+ (LONGEST) ecs->ws.exit_status ());
/* Also record this in the inferior itself. */
current_inferior ()->has_exit_code = 1;
- current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
+ current_inferior ()->exit_code = (LONGEST) ecs->ws.exit_status ();
/* Support the --return-child-result option. */
- return_child_result_value = ecs->ws.value.integer;
+ return_child_result_value = ecs->ws.exit_status ();
- gdb::observers::exited.notify (ecs->ws.value.integer);
+ gdb::observers::exited.notify (ecs->ws.exit_status ());
}
else
{
which holds the signal uncaught by the inferior. */
set_internalvar_integer (lookup_internalvar ("_exitsignal"),
gdbarch_gdb_signal_to_target (gdbarch,
- ecs->ws.value.sig));
+ ecs->ws.sig ()));
}
else
{
"signal number.");
}
- gdb::observers::signal_exited.notify (ecs->ws.value.sig);
+ gdb::observers::signal_exited.notify (ecs->ws.sig ());
}
gdb_flush (gdb_stdout);
gdbarch_displaced_step_restore_all_in_ptid. This is not
enforced during gdbarch validation to support architectures
which support displaced stepping but not forks. */
- if (ecs->ws.kind == TARGET_WAITKIND_FORKED
+ if (ecs->ws.kind () == TARGET_WAITKIND_FORKED
&& gdbarch_supports_displaced_stepping (gdbarch))
gdbarch_displaced_step_restore_all_in_ptid
- (gdbarch, parent_inf, ecs->ws.value.related_pid);
+ (gdbarch, parent_inf, ecs->ws.child_ptid ());
/* If displaced stepping is supported, and thread ecs->ptid is
displaced stepping. */
child_regcache
= get_thread_arch_aspace_regcache (parent_inf->process_target (),
- ecs->ws.value.related_pid,
+ ecs->ws.child_ptid (),
gdbarch,
parent_inf->aspace);
/* Read PC value of parent process. */
need to unpatch at follow/detach time instead to be certain
that new breakpoints added between catchpoint hit time and
vfork follow are detached. */
- if (ecs->ws.kind != TARGET_WAITKIND_VFORKED)
+ if (ecs->ws.kind () != TARGET_WAITKIND_VFORKED)
{
/* This won't actually modify the breakpoint list, but will
physically remove the breakpoints from the child. */
- detach_breakpoints (ecs->ws.value.related_pid);
+ detach_breakpoints (ecs->ws.child_ptid ());
}
delete_just_stopped_threads_single_step_breakpoints ();
(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_current_regcache ()->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, &ecs->ws);
+ = bpstat_stop_status_nowatch (get_current_regcache ()->aspace (),
+ ecs->event_thread->stop_pc (),
+ ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return;
/* Note that one of these may be an invalid pointer,
depending on detach_fork. */
thread_info *parent = ecs->event_thread;
- thread_info *child
- = find_thread_ptid (targ, ecs->ws.value.related_pid);
+ thread_info *child = find_thread_ptid (targ, ecs->ws.child_ptid ());
/* At this point, the parent is marked running, and the
child is marked stopped. */
ecs->ptid = inferior_ptid;
if (should_resume)
- keep_going (ecs);
+ {
+ /* Never call switch_back_to_stepped_thread if we are waiting for
+ vfork-done (waiting for an external vfork child to exec or
+ exit). We will resume only the vforking thread for the purpose
+ of collecting the vfork-done event, and we will restart any
+ step once the critical shared address space window is done. */
+ if ((!follow_child
+ && detach_fork
+ && parent->inf->thread_waiting_for_vfork_done != nullptr)
+ || !switch_back_to_stepped_thread (ecs))
+ keep_going (ecs);
+ }
else
stop_waiting (ecs);
return;
context_switch (ecs);
- current_inferior ()->waiting_for_vfork_done = 0;
- current_inferior ()->pspace->breakpoints_not_allowed = 0;
+ handle_vfork_done (ecs->event_thread);
+ gdb_assert (inferior_thread () == ecs->event_thread);
if (handle_stop_requested (ecs))
return;
- /* This also takes care of reinserting breakpoints in the
- previously locked inferior. */
- keep_going (ecs);
+ if (!switch_back_to_stepped_thread (ecs))
+ {
+ gdb_assert (inferior_thread () == ecs->event_thread);
+ /* This also takes care of reinserting breakpoints in the
+ previously locked inferior. */
+ keep_going (ecs);
+ }
return;
case TARGET_WAITKIND_EXECD:
/* This causes the eventpoints and symbol table to be reset.
Must do this now, before trying to determine whether to
stop. */
- follow_exec (inferior_ptid, ecs->ws.value.execd_pathname);
+ follow_exec (inferior_ptid, ecs->ws.execd_pathname ());
/* In follow_exec we may have deleted the original thread and
created a new one. Make sure that the event thread is the
(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_current_regcache ()->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, &ecs->ws);
-
- /* Note that this may be referenced from inside
- bpstat_stop_status above, through inferior_has_execd. */
- xfree (ecs->ws.value.execd_pathname);
- ecs->ws.value.execd_pathname = NULL;
+ = bpstat_stop_status_nowatch (get_current_regcache ()->aspace (),
+ ecs->event_thread->stop_pc (),
+ ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return;
}
/* Restart threads back to what they were trying to do back when we
- paused them for an in-line step-over. The EVENT_THREAD thread is
- ignored. */
+ paused them (because of an in-line step-over or vfork, for example).
+ The EVENT_THREAD thread is ignored (not restarted).
+
+ If INF is non-nullptr, only resume threads from INF. */
static void
-restart_threads (struct thread_info *event_thread)
+restart_threads (struct thread_info *event_thread, inferior *inf)
{
+ INFRUN_SCOPED_DEBUG_START_END ("event_thread=%s, inf=%d",
+ event_thread->ptid.to_string ().c_str (),
+ inf != nullptr ? inf->num : -1);
+
+ gdb_assert (!step_over_info_valid_p ());
+
/* In case the instruction just stepped spawned a new thread. */
update_thread_list ();
for (thread_info *tp : all_non_exited_threads ())
{
+ if (inf != nullptr && tp->inf != inf)
+ continue;
+
if (tp->inf->detaching)
{
infrun_debug_printf ("restart threads: [%s] inferior detaching",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
continue;
}
if (tp == event_thread)
{
infrun_debug_printf ("restart threads: [%s] is event thread",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
continue;
}
if (!(tp->state == THREAD_RUNNING || tp->control.in_infcall))
{
infrun_debug_printf ("restart threads: [%s] not meant to be running",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
continue;
}
if (tp->resumed ())
{
infrun_debug_printf ("restart threads: [%s] resumed",
- target_pid_to_str (tp->ptid).c_str ());
- gdb_assert (tp->executing || tp->has_pending_waitstatus ());
+ tp->ptid.to_string ().c_str ());
+ gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
continue;
}
if (thread_is_in_step_over_chain (tp))
{
infrun_debug_printf ("restart threads: [%s] needs step-over",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
gdb_assert (!tp->resumed ());
continue;
}
if (tp->has_pending_waitstatus ())
{
infrun_debug_printf ("restart threads: [%s] has pending status",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
tp->set_resumed (true);
continue;
}
internal_error (__FILE__, __LINE__,
"thread [%s] needs a step-over, but not in "
"step-over queue\n",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
}
if (currently_stepping (tp))
{
infrun_debug_printf ("restart threads: [%s] was stepping",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
keep_going_stepped_thread (tp);
}
else
struct execution_control_state *ecs = &ecss;
infrun_debug_printf ("restart threads: [%s] continuing",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
reset_ecs (ecs, tp);
switch_to_thread (tp);
keep_going_pass_signal (ecs);
gdb_assert (pending != tp);
/* Record the event thread's event for later. */
- save_waitstatus (tp, &ecs->ws);
+ save_waitstatus (tp, ecs->ws);
/* This was cleared early, by handle_inferior_event. Set it
so this pending event is considered by
do_target_wait. */
tp->set_resumed (true);
- gdb_assert (!tp->executing);
+ gdb_assert (!tp->executing ());
regcache = get_thread_regcache (tp);
tp->set_stop_pc (regcache_read_pc (regcache));
infrun_debug_printf ("saved stop_pc=%s for %s "
"(currently_stepping=%d)",
paddress (target_gdbarch (), tp->stop_pc ()),
- target_pid_to_str (tp->ptid).c_str (),
+ tp->ptid.to_string ().c_str (),
currently_stepping (tp));
/* This in-line step-over finished; clear this so we won't
enum stop_kind stop_soon;
int random_signal;
- gdb_assert (ecs->ws.kind == TARGET_WAITKIND_STOPPED);
+ gdb_assert (ecs->ws.kind () == TARGET_WAITKIND_STOPPED);
- ecs->event_thread->set_stop_signal (ecs->ws.value.sig);
+ ecs->event_thread->set_stop_signal (ecs->ws.sig ());
/* Do we need to clean up the state of a thread that has
completed a displaced single-step? (Doing so usually affects
{
infrun_debug_printf ("[%s] hit another thread's single-step "
"breakpoint",
- target_pid_to_str (ecs->ptid).c_str ());
+ ecs->ptid.to_string ().c_str ());
ecs->hit_singlestep_breakpoint = 1;
}
}
else
{
infrun_debug_printf ("[%s] hit its single-step breakpoint",
- target_pid_to_str (ecs->ptid).c_str ());
+ ecs->ptid.to_string ().c_str ());
}
}
delete_just_stopped_threads_single_step_breakpoints ();
&& ecs->event_thread->stepping_over_watchpoint)
stopped_by_watchpoint = 0;
else
- stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
+ stopped_by_watchpoint = watchpoints_triggered (ecs->ws);
/* If necessary, step over this watchpoint. We'll be back to display
it in a moment. */
ecs->event_thread->control.stop_step = 0;
stop_print_frame = true;
stopped_by_random_signal = 0;
- bpstat stop_chain = NULL;
+ bpstat *stop_chain = nullptr;
/* Hide inlined functions starting here, unless we just performed stepi or
nexti. After stepi and nexti, always show the innermost frame (not any
that's an extremely unlikely scenario. */
if (!pc_at_non_inline_function (aspace,
ecs->event_thread->stop_pc (),
- &ecs->ws)
+ ecs->ws)
&& !(ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
&& ecs->event_thread->control.trap_expected
&& pc_at_non_inline_function (aspace,
ecs->event_thread->prev_pc,
- &ecs->ws)))
+ ecs->ws)))
{
stop_chain = build_bpstat_chain (aspace,
ecs->event_thread->stop_pc (),
- &ecs->ws);
+ ecs->ws);
skip_inline_frames (ecs->event_thread, stop_chain);
/* Re-fetch current thread's frame in case that invalidated
ecs->event_thread->control.stop_bpstat
= bpstat_stop_status (get_current_regcache ()->aspace (),
ecs->event_thread->stop_pc (),
- ecs->event_thread, &ecs->ws, stop_chain);
+ ecs->event_thread, ecs->ws, stop_chain);
/* Following in case break condition called a
function. */
ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
ecs->event_thread->control.step_range_end = stop_pc_sal.end;
ecs->event_thread->control.may_range_step = 1;
+ infrun_debug_printf
+ ("updated step range, start = %s, end = %s, may_range_step = %d",
+ paddress (gdbarch, ecs->event_thread->control.step_range_start),
+ paddress (gdbarch, ecs->event_thread->control.step_range_end),
+ ecs->event_thread->control.may_range_step);
if (refresh_step_info)
set_step_info (ecs->event_thread, frame, stop_pc_sal);
{
infrun_debug_printf
("need to finish step-over of [%s]",
- target_pid_to_str (ecs->event_thread->ptid).c_str ());
+ ecs->event_thread->ptid.to_string ().c_str ());
keep_going (ecs);
return true;
}
if (ecs->hit_singlestep_breakpoint)
{
infrun_debug_printf ("need to step [%s] over single-step breakpoint",
- target_pid_to_str (ecs->ptid).c_str ());
+ ecs->ptid.to_string ().c_str ());
keep_going (ecs);
return true;
}
{
infrun_debug_printf
("thread [%s] still needs step-over",
- target_pid_to_str (ecs->event_thread->ptid).c_str ());
+ ecs->event_thread->ptid.to_string ().c_str ());
keep_going (ecs);
return true;
}
/* If we have any thread that is already executing, then we
don't need to resume the target -- it is already been
resumed. */
- if (thr->executing)
+ if (thr->executing ())
return;
/* If we have a pending event to process, skip resuming the
cases such as throwing an exception from inside a signal
handler. */
- b = SYMBOL_BLOCK_VALUE (func);
+ b = func->value_block ();
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- if (!SYMBOL_IS_ARGUMENT (sym))
+ if (!sym->is_argument ())
continue;
if (argno == 0)
/* Let callers know we don't want to wait for the inferior anymore. */
ecs->wait_some_more = 0;
-
- /* If all-stop, but there exists a non-stop target, stop all
- threads now that we're presenting the stop to the user. */
- if (!non_stop && exists_non_stop_target ())
- stop_all_threads ();
}
/* Like keep_going, but passes the signal to the inferior, even if the
infrun_debug_printf ("%s has trap_expected set, "
"resuming to collect trap",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
/* We haven't yet gotten our trap, and either: intercepted a
non-signal event (e.g., a fork); or took a signal which we
{
infrun_debug_printf ("step-over already in progress: "
"step-over for %s deferred",
- target_pid_to_str (tp->ptid).c_str ());
+ tp->ptid.to_string ().c_str ());
global_thread_step_over_chain_enqueue (tp);
}
else
- {
- infrun_debug_printf ("step-over in progress: resume of %s deferred",
- target_pid_to_str (tp->ptid).c_str ());
- }
+ infrun_debug_printf ("step-over in progress: resume of %s deferred",
+ tp->ptid.to_string ().c_str ());
}
else
{
we're about to step over, otherwise other threads could miss
it. */
if (step_over_info_valid_p () && target_is_non_stop_p ())
- stop_all_threads ();
+ stop_all_threads ("starting in-line step-over");
/* Stop stepping if inserting breakpoints fails. */
try
;
else if (show_thread_that_caused_stop ())
{
- const char *name;
-
uiout->text ("\nThread ");
uiout->field_string ("thread-id", print_thread_id (thr));
- name = thr->name != NULL ? thr->name : target_thread_name (thr);
+ const char *name = thread_name (thr);
if (name != NULL)
{
uiout->text (" \"");
based on the event(s) that just occurred. */
static void
-print_stop_location (struct target_waitstatus *ws)
+print_stop_location (const target_waitstatus &ws)
{
int bpstat_ret;
enum print_what source_flag;
int do_frame_printing = 1;
struct thread_info *tp = inferior_thread ();
- bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws->kind);
+ bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws.kind ());
switch (bpstat_ret)
{
case PRINT_UNKNOWN:
{
scoped_restore save_uiout = make_scoped_restore (¤t_uiout, uiout);
- print_stop_location (&last);
+ print_stop_location (last);
/* Display the auto-display expressions. */
if (displays)
}
tp = inferior_thread ();
- if (tp->thread_fsm != NULL
- && tp->thread_fsm->finished_p ())
+ if (tp->thread_fsm () != nullptr
+ && tp->thread_fsm ()->finished_p ())
{
struct return_value_info *rv;
- rv = tp->thread_fsm->return_value ();
- if (rv != NULL)
+ rv = tp->thread_fsm ()->return_value ();
+ if (rv != nullptr)
print_return_value (uiout, rv);
}
}
if (remove_breakpoints ())
{
target_terminal::ours_for_output ();
- printf_filtered (_("Cannot remove breakpoints because "
- "program is no longer writable.\nFurther "
- "execution is probably impossible.\n"));
+ gdb_printf (_("Cannot remove breakpoints because "
+ "program is no longer writable.\nFurther "
+ "execution is probably impossible.\n"));
}
}
}
if (!non_stop)
finish_ptid = minus_one_ptid;
- else if (last.kind == TARGET_WAITKIND_SIGNALLED
- || last.kind == TARGET_WAITKIND_EXITED)
+ else if (last.kind () == TARGET_WAITKIND_SIGNALLED
+ || last.kind () == TARGET_WAITKIND_EXITED)
{
/* On some targets, we may still have live threads in the
inferior when we get a process exit event. E.g., for
if (inferior_ptid != null_ptid)
finish_ptid = ptid_t (inferior_ptid.pid ());
}
- else if (last.kind != TARGET_WAITKIND_NO_RESUMED)
+ else if (last.kind () != TARGET_WAITKIND_NO_RESUMED)
finish_ptid = inferior_ptid;
gdb::optional<scoped_finish_thread_state> maybe_finish_thread_state;
instead of after. */
update_thread_list ();
- if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+ if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
gdb::observers::signal_received.notify (inferior_thread ()->stop_signal ());
/* As with the notification of thread events, we want to delay
if (!non_stop
&& previous_inferior_ptid != inferior_ptid
&& target_has_execution ()
- && last.kind != TARGET_WAITKIND_SIGNALLED
- && last.kind != TARGET_WAITKIND_EXITED
- && last.kind != TARGET_WAITKIND_NO_RESUMED)
+ && last.kind () != TARGET_WAITKIND_SIGNALLED
+ && last.kind () != TARGET_WAITKIND_EXITED
+ && last.kind () != TARGET_WAITKIND_NO_RESUMED)
{
SWITCH_THRU_ALL_UIS ()
{
target_terminal::ours_for_output ();
- printf_filtered (_("[Switching to %s]\n"),
- target_pid_to_str (inferior_ptid).c_str ());
+ gdb_printf (_("[Switching to %s]\n"),
+ target_pid_to_str (inferior_ptid).c_str ());
annotate_thread_changed ();
}
previous_inferior_ptid = inferior_ptid;
}
- if (last.kind == TARGET_WAITKIND_NO_RESUMED)
+ if (last.kind () == TARGET_WAITKIND_NO_RESUMED)
{
SWITCH_THRU_ALL_UIS ()
if (current_ui->prompt_state == PROMPT_BLOCKED)
{
target_terminal::ours_for_output ();
- printf_filtered (_("No unwaited-for children left.\n"));
+ gdb_printf (_("No unwaited-for children left.\n"));
}
}
/* Look up the hook_stop and run it (CLI internally handles problem
of stop_command's pre-hook not existing). */
- if (stop_command != NULL)
- {
- stop_context saved_context;
-
- try
- {
- execute_cmd_pre_hook (stop_command);
- }
- catch (const gdb_exception &ex)
- {
- exception_fprintf (gdb_stderr, ex,
- "Error while running hook_stop:\n");
- }
+ stop_context saved_context;
- /* If the stop hook resumes the target, then there's no point in
- trying to notify about the previous stop; its context is
- gone. Likewise if the command switches thread or inferior --
- the observers would print a stop for the wrong
- thread/inferior. */
- if (saved_context.changed ())
- return 1;
+ try
+ {
+ execute_cmd_pre_hook (stop_command);
+ }
+ catch (const gdb_exception &ex)
+ {
+ exception_fprintf (gdb_stderr, ex,
+ "Error while running hook_stop:\n");
}
+ /* If the stop hook resumes the target, then there's no point in
+ trying to notify about the previous stop; its context is
+ gone. Likewise if the command switches thread or inferior --
+ the observers would print a stop for the wrong
+ thread/inferior. */
+ if (saved_context.changed ())
+ return 1;
+
/* Notify observers about the stop. This is where the interpreters
print the stop event. */
if (inferior_ptid != null_ptid)
if (target_has_execution ())
{
- if (last.kind != TARGET_WAITKIND_SIGNALLED
- && last.kind != TARGET_WAITKIND_EXITED
- && last.kind != TARGET_WAITKIND_NO_RESUMED)
+ if (last.kind () != TARGET_WAITKIND_SIGNALLED
+ && last.kind () != TARGET_WAITKIND_EXITED
+ && last.kind () != TARGET_WAITKIND_NO_RESUMED)
/* Delete the breakpoint we stopped at, if it wants to be deleted.
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (inferior_thread ()->control.stop_bpstat);
}
- /* Try to get rid of automatically added inferiors that are no
- longer needed. Keeping those around slows down things linearly.
- Note that this never removes the current inferior. */
- prune_inferiors ();
-
return 0;
}
\f
static void
sig_print_header (void)
{
- printf_filtered (_("Signal Stop\tPrint\tPass "
- "to program\tDescription\n"));
+ gdb_printf (_("Signal Stop\tPrint\tPass "
+ "to program\tDescription\n"));
}
static void
if (name_padding <= 0)
name_padding = 0;
- printf_filtered ("%s", name);
- printf_filtered ("%*.*s ", name_padding, name_padding, " ");
- printf_filtered ("%s\t", signal_stop[oursig] ? "Yes" : "No");
- printf_filtered ("%s\t", signal_print[oursig] ? "Yes" : "No");
- printf_filtered ("%s\t\t", signal_program[oursig] ? "Yes" : "No");
- printf_filtered ("%s\n", gdb_signal_to_string (oursig));
+ gdb_printf ("%s", name);
+ gdb_printf ("%*.*s ", name_padding, name_padding, " ");
+ gdb_printf ("%s\t", signal_stop[oursig] ? "Yes" : "No");
+ gdb_printf ("%s\t", signal_print[oursig] ? "Yes" : "No");
+ gdb_printf ("%s\t\t", signal_program[oursig] ? "Yes" : "No");
+ gdb_printf ("%s\n", gdb_signal_to_string (oursig));
}
/* Specify how various signals in the inferior should be handled. */
sigs[signum] = 1;
}
else
- printf_unfiltered (_("Not confirmed, unchanged.\n"));
+ gdb_printf (_("Not confirmed, unchanged.\n"));
}
break;
case GDB_SIGNAL_0:
return;
}
- printf_filtered ("\n");
+ gdb_printf ("\n");
/* These ugly casts brought to you by the native VAX compiler. */
for (oursig = GDB_SIGNAL_FIRST;
(int) oursig < (int) GDB_SIGNAL_LAST;
sig_print_info (oursig);
}
- printf_filtered (_("\nUse the \"handle\" command "
- "to change these tables.\n"));
+ gdb_printf (_("\nUse the \"handle\" command "
+ "to change these tables.\n"));
}
/* The $_siginfo convenience variable is a bit special. We don't know
target_read (current_inferior ()->top_target (),
TARGET_OBJECT_SIGNAL_INFO,
NULL,
- value_contents_all_raw (v),
+ value_contents_all_raw (v).data (),
value_offset (v),
TYPE_LENGTH (value_type (v)));
transferred = target_write (current_inferior ()->top_target (),
TARGET_OBJECT_SIGNAL_INFO,
NULL,
- value_contents_all_raw (fromval),
+ value_contents_all_raw (fromval).data (),
value_offset (v),
TYPE_LENGTH (value_type (fromval)));
{
switch (execution_direction) {
case EXEC_FORWARD:
- fprintf_filtered (out, _("Forward.\n"));
+ gdb_printf (out, _("Forward.\n"));
break;
case EXEC_REVERSE:
- fprintf_filtered (out, _("Reverse.\n"));
+ gdb_printf (out, _("Reverse.\n"));
break;
default:
internal_error (__FILE__, __LINE__,
show_schedule_multiple (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Resuming the execution of threads "
- "of all processes is %s.\n"), value);
+ gdb_printf (file, _("Resuming the execution of threads "
+ "of all processes is %s.\n"), value);
}
/* Implementation of `siginfo' variable. */
{
siginfo_make_value,
NULL,
- NULL
};
/* Callback for infrun's target events source. This is marked when a
all signals cumulatively specified."));
set_cmd_completer (c, handle_completer);
- if (!dbx_commands)
- stop_command = add_cmd ("stop", class_obscure,
- not_just_help_class_command, _("\
+ stop_command = add_cmd ("stop", class_obscure,
+ not_just_help_class_command, _("\
There is no `stop' command, but you can set a hook on `stop'.\n\
This allows you to set a list of commands to be run each time execution\n\
of the program stops."), &cmdlist);