/* 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
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->aspace = parent_inf->aspace;
child_inf->pspace = parent_inf->pspace;
- parent_inf->aspace = new_address_space ();
+ parent_inf->aspace = new address_space ();
parent_inf->pspace = new program_space (parent_inf->aspace);
clone_program_space (parent_inf->pspace, child_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;
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)
{
}
}
- 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. */
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.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
target to do whatever is necessary to follow either parent
}
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.set_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
{
&& 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);
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 ());
}
}
}
}
+/* 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));
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
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 ());
}
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
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 ());
+ 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);
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;
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
};
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);
}
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
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 ();
}
}
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)
{
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. */
|| 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->sig () != GDB_SIGNAL_TRAP)
+ if (ws.sig () != GDB_SIGNAL_TRAP)
return;
/* In reverse execution, when a breakpoint is hit, the instruction
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;
}
{
/* 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)
return event;
/* 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 %s",
- target_waitstatus_to_string (ws).c_str (),
+ 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->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);
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)
{
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
{
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;
}
}
/* 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);
/* 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)
infrun_debug_printf
("target_wait %s, saving status for %s",
- target_waitstatus_to_string (&event.ws).c_str (),
+ 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.sig () : GDB_SIGNAL_0);
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 (!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:
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)
{
}
/* 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 ();
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;
(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;
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:
(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;
}
/* 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 ());
+ 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. */
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
{
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;
}
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
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"));
}
}
}
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 (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;
+ 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");
- }
-
- /* 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)
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);