+static void
+attach_command_continuation (void *args)
+{
+ struct attach_command_continuation_args *a = args;
+ attach_command_post_wait (a->args, a->from_tty, a->async_exec);
+}
+
+static void
+attach_command_continuation_free_args (void *args)
+{
+ struct attach_command_continuation_args *a = args;
+ xfree (a->args);
+ xfree (a);
+}
+
+void
+attach_command (char *args, int from_tty)
+{
+ char *exec_file;
+ char *full_exec_path = NULL;
+ int async_exec = 0;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+ dont_repeat (); /* Not for the faint of heart */
+
+ if (target_supports_multi_process ())
+ /* Don't complain if we can be attached to multiple processes. */
+ ;
+ else if (target_has_execution)
+ {
+ if (query ("A program is being debugged already. Kill it? "))
+ target_kill ();
+ else
+ error (_("Not killed."));
+ }
+
+ /* Clean up any leftovers from other runs. Some other things from
+ this function should probably be moved into target_pre_inferior. */
+ target_pre_inferior (from_tty);
+
+ if (non_stop && !target_supports_non_stop ())
+ error (_("Cannot attach to this target in non-stop mode"));
+
+ if (args)
+ {
+ async_exec = strip_bg_char (&args);
+
+ /* If we get a request for running in the bg but the target
+ doesn't support it, error out. */
+ if (async_exec && !target_can_async_p ())
+ error (_("Asynchronous execution not supported on this target."));
+ }
+
+ /* If we don't get a request of running in the bg, then we need
+ to simulate synchronous (fg) execution. */
+ if (!async_exec && target_can_async_p ())
+ {
+ /* Simulate synchronous execution */
+ async_disable_stdin ();
+ make_cleanup ((make_cleanup_ftype *)async_enable_stdin, NULL);
+ }
+
+ target_attach (args, from_tty);
+
+ /* Set up the "saved terminal modes" of the inferior
+ based on what modes we are starting it with. */
+ target_terminal_init ();
+
+ /* Set up execution context to know that we should return from
+ wait_for_inferior as soon as the target reports a stop. */
+ init_wait_for_inferior ();
+ clear_proceed_status ();
+
+ if (non_stop)
+ {
+ /* If we find that the current thread isn't stopped, explicitly
+ do so now, because we're going to install breakpoints and
+ poke at memory. */
+
+ if (async_exec)
+ /* The user requested an `attach&'; stop just one thread. */
+ target_stop (inferior_ptid);
+ else
+ /* The user requested an `attach', so stop all threads of this
+ inferior. */
+ target_stop (pid_to_ptid (ptid_get_pid (inferior_ptid)));
+ }
+
+ /* Some system don't generate traps when attaching to inferior.
+ E.g. Mach 3 or GNU hurd. */
+ if (!target_attach_no_wait)
+ {
+ struct inferior *inferior = current_inferior ();
+
+ /* Careful here. See comments in inferior.h. Basically some
+ OSes don't ignore SIGSTOPs on continue requests anymore. We
+ need a way for handle_inferior_event to reset the stop_signal
+ variable after an attach, and this is what
+ STOP_QUIETLY_NO_SIGSTOP is for. */
+ inferior->stop_soon = STOP_QUIETLY_NO_SIGSTOP;
+
+ if (target_can_async_p ())
+ {
+ /* sync_execution mode. Wait for stop. */
+ struct attach_command_continuation_args *a;
+
+ a = xmalloc (sizeof (*a));
+ a->args = xstrdup (args);
+ a->from_tty = from_tty;
+ a->async_exec = async_exec;
+ add_inferior_continuation (attach_command_continuation, a,
+ attach_command_continuation_free_args);
+ discard_cleanups (back_to);
+ return;
+ }
+
+ wait_for_inferior (0);
+ }
+
+ attach_command_post_wait (args, from_tty, async_exec);
+ discard_cleanups (back_to);