+/* Handle the "D" packet. */
+
+static void
+handle_detach (char *own_buf)
+{
+ client_state &cs = get_client_state ();
+
+ process_info *process;
+
+ if (cs.multi_process)
+ {
+ /* skip 'D;' */
+ int pid = strtol (&own_buf[2], NULL, 16);
+
+ process = find_process_pid (pid);
+ }
+ else
+ {
+ process = (current_thread != nullptr
+ ? get_thread_process (current_thread)
+ : nullptr);
+ }
+
+ if (process == NULL)
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ if ((tracing && disconnected_tracing) || any_persistent_commands (process))
+ {
+ if (tracing && disconnected_tracing)
+ fprintf (stderr,
+ "Disconnected tracing in effect, "
+ "leaving gdbserver attached to the process\n");
+
+ if (any_persistent_commands (process))
+ fprintf (stderr,
+ "Persistent commands are present, "
+ "leaving gdbserver attached to the process\n");
+
+ /* Make sure we're in non-stop/async mode, so we we can both
+ wait for an async socket accept, and handle async target
+ events simultaneously. There's also no point either in
+ having the target stop all threads, when we're going to
+ pass signals down without informing GDB. */
+ if (!non_stop)
+ {
+ if (debug_threads)
+ debug_printf ("Forcing non-stop mode\n");
+
+ non_stop = 1;
+ start_non_stop (1);
+ }
+
+ process->gdb_detached = 1;
+
+ /* Detaching implicitly resumes all threads. */
+ target_continue_no_signal (minus_one_ptid);
+
+ write_ok (own_buf);
+ return;
+ }
+
+ fprintf (stderr, "Detaching from process %d\n", process->pid);
+ stop_tracing ();
+ if (detach_inferior (process) != 0)
+ write_enn (own_buf);
+ else
+ {
+ discard_queued_stop_replies (ptid_t (process->pid));
+ write_ok (own_buf);
+
+ if (extended_protocol || target_running ())
+ {
+ /* There is still at least one inferior remaining or
+ we are in extended mode, so don't terminate gdbserver,
+ and instead treat this like a normal program exit. */
+ cs.last_status.kind = TARGET_WAITKIND_EXITED;
+ cs.last_status.value.integer = 0;
+ cs.last_ptid = ptid_t (process->pid);
+
+ current_thread = NULL;
+ }
+ else
+ {
+ putpkt (own_buf);
+ remote_close ();
+
+ /* If we are attached, then we can exit. Otherwise, we
+ need to hang around doing nothing, until the child is
+ gone. */
+ join_inferior (process);
+ exit (0);
+ }