return false;
}
+/* An event reported by wait_one. */
+
+struct wait_one_event
+{
+ /* The target the event came out of. */
+ process_stratum_target *target;
+
+ /* The PTID the event was for. */
+ ptid_t ptid;
+
+ /* The waitstatus. */
+ target_waitstatus ws;
+};
+
+static bool handle_one (const wait_one_event &event);
+
/* Prepare and stabilize the inferior for detaching it. E.g.,
detaching while a thread is displaced stepping is a recipe for
crashing it, as nothing would readjust the PC out of the scratch
{
struct inferior *inf = current_inferior ();
ptid_t pid_ptid = ptid_t (inf->pid);
-
- /* Is any thread of this process displaced stepping? If not,
- there's nothing else to do. */
- if (displaced_step_in_progress (inf))
- return;
-
- infrun_debug_printf ("displaced-stepping in-process while detaching");
+ scoped_restore_current_thread restore_thread;
scoped_restore restore_detaching = make_scoped_restore (&inf->detaching, true);
- while (displaced_step_in_progress (inf))
+ /* Remove all threads of INF from the global step-over chain. We
+ want to stop any ongoing step-over, not start any new one. */
+ thread_info *next;
+ for (thread_info *tp = global_thread_step_over_chain_head;
+ tp != nullptr;
+ tp = next)
{
- struct execution_control_state ecss;
- struct execution_control_state *ecs;
+ next = global_thread_step_over_chain_next (tp);
+ if (tp->inf == inf)
+ global_thread_step_over_chain_remove (tp);
+ }
- ecs = &ecss;
- memset (ecs, 0, sizeof (*ecs));
+ if (displaced_step_in_progress (inf))
+ {
+ infrun_debug_printf ("displaced-stepping in-process while detaching");
- overlay_cache_invalid = 1;
- /* Flush target cache before starting to handle each event.
- Target was running and cache could be stale. This is just a
- heuristic. Running threads may modify target memory, but we
- don't get any event. */
- target_dcache_invalidate ();
+ /* Stop threads currently displaced stepping, aborting it. */
- do_target_wait (pid_ptid, ecs, 0);
+ for (thread_info *thr : inf->non_exited_threads ())
+ {
+ if (thr->displaced_step_state.in_progress ())
+ {
+ if (thr->executing)
+ {
+ if (!thr->stop_requested)
+ {
+ target_stop (thr->ptid);
+ thr->stop_requested = true;
+ }
+ }
+ else
+ thr->resumed = false;
+ }
+ }
- if (debug_infrun)
- print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws);
+ while (displaced_step_in_progress (inf))
+ {
+ wait_one_event event;
- /* If an error happens while handling the event, propagate GDB's
- knowledge of the executing state to the frontend/user running
- state. */
- scoped_finish_thread_state finish_state (inf->process_target (),
- minus_one_ptid);
+ event.target = inf->process_target ();
+ event.ptid = do_target_wait_1 (inf, pid_ptid, &event.ws, 0);
- /* Now figure out what to do with the result of the result. */
- handle_inferior_event (ecs);
+ if (debug_infrun)
+ print_target_wait_results (pid_ptid, event.ptid, &event.ws);
- /* No error, don't finish the state yet. */
- finish_state.release ();
+ handle_one (event);
+ }
- /* Breakpoints and watchpoints are not installed on the target
- at this point, and signals are passed directly to the
- inferior, so this must mean the process is gone. */
- if (!ecs->wait_some_more)
- error (_("Program exited while detaching"));
+ /* It's OK to leave some of the threads of INF stopped, since
+ they'll be detached shortly. */
}
}
return event_ptid;
}
-/* An event reported by wait_one. */
-
-struct wait_one_event
-{
- /* The target the event came out of. */
- process_stratum_target *target;
-
- /* The PTID the event was for. */
- ptid_t ptid;
-
- /* The waitstatus. */
- target_waitstatus ws;
-};
-
/* Wait for one event out of any target. */
static wait_one_event
/* Handle one event after stopping threads. If the eventing thread
reports back any interesting event, we leave it pending. If the
eventing thread was in the middle of a displaced step, we
- cancel/finish it. Returns true if there are no resumed threads
- left in the target (thus there's no point in waiting further),
- false otherwise. */
+ cancel/finish it, and unless the thread's inferior is being
+ detached, put the thread back in the step-over chain. Returns true
+ if there are no resumed threads left in the target (thus there's no
+ point in waiting further), false otherwise. */
static bool
handle_one (const wait_one_event &event)
target_pid_to_str (t->ptid).c_str ());
t->control.trap_expected = 0;
- global_thread_step_over_chain_enqueue (t);
+ if (!t->inf->detaching)
+ global_thread_step_over_chain_enqueue (t);
}
}
else
{
/* Add it back to the step-over queue. */
t->control.trap_expected = 0;
- global_thread_step_over_chain_enqueue (t);
+ if (!t->inf->detaching)
+ global_thread_step_over_chain_enqueue (t);
}
regcache = get_thread_regcache (t);
if (random_signal)
{
/* Signal not for debugging purposes. */
- struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal;
infrun_debug_printf ("random signal (%s)",
to remain stopped. */
if (stop_soon != NO_STOP_QUIETLY
|| ecs->event_thread->stop_requested
- || (!inf->detaching
- && signal_stop_state (ecs->event_thread->suspend.stop_signal)))
+ || signal_stop_state (ecs->event_thread->suspend.stop_signal))
{
stop_waiting (ecs);
return;