PR gdb/11321
authorPedro Alves <palves@redhat.com>
Wed, 24 Feb 2010 20:49:50 +0000 (20:49 +0000)
committerPedro Alves <palves@redhat.com>
Wed, 24 Feb 2010 20:49:50 +0000 (20:49 +0000)
* inferior.h (prepare_for_detach): Declare.
(struct inferior) <detaching>: New field.
* infrun.c (prepare_for_detach): New.
(handle_inferior_event) <random signal>: Don't stop if detaching.
* target.c (target_detach): Call prepare_for_detach.

gdb/ChangeLog
gdb/inferior.h
gdb/infrun.c
gdb/target.c

index 44c7653729ebca57518c51f054ecfa2bf38f33e4..962a3c954bff917586e619eb76b399b0aa8c5219 100644 (file)
@@ -1,3 +1,13 @@
+2010-02-24  Pedro Alves  <pedro@codesourcery.com>
+
+       PR gdb/11321
+
+       * inferior.h (prepare_for_detach): Declare.
+       (struct inferior) <detaching>: New field.
+       * infrun.c (prepare_for_detach): New.
+       (handle_inferior_event) <random signal>: Don't stop if detaching.
+       * target.c (target_detach): Call prepare_for_detach.
+
 2010-02-24  Pedro Alves  <pedro@codesourcery.com>
 
        Per-process displaced stepping queue.
index bd6f1c892d184d144640215da44ed05cf23a201d..dc87a9e1929b520bf60d0c9e4a8b7ee4642469cd 100644 (file)
@@ -185,6 +185,8 @@ extern void address_to_signed_pointer (struct gdbarch *gdbarch,
 
 extern void wait_for_inferior (int treat_exec_as_sigtrap);
 
+extern void prepare_for_detach (void);
+
 extern void fetch_inferior_event (void *);
 
 extern void init_wait_for_inferior (void);
@@ -478,6 +480,9 @@ struct inferior
      either by exiting or execing.  */
   int waiting_for_vfork_done;
 
+  /* True if we're in the process of detaching from this inferior.  */
+  int detaching;
+
   /* What is left to do for an execution command after any thread of
      this inferior stops.  For continuations associated with a
      specific thread, see `struct thread_info'.  */
index 7379107020a3f5e87ac8549a5d7832edbb123d4c..83cfe3c124be228d6df9f59858fa61ef469dbd43 100644 (file)
@@ -2331,6 +2331,84 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
   ui_file_delete (tmp_stream);
 }
 
+/* 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
+   pad.  */
+
+void
+prepare_for_detach (void)
+{
+  struct inferior *inf = current_inferior ();
+  ptid_t pid_ptid = pid_to_ptid (inf->pid);
+  struct cleanup *old_chain_1;
+  struct displaced_step_inferior_state *displaced;
+
+  displaced = get_displaced_stepping_state (inf->pid);
+
+  /* Is any thread of this process displaced stepping?  If not,
+     there's nothing else to do.  */
+  if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid))
+    return;
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+                       "displaced-stepping in-process while detaching");
+
+  old_chain_1 = make_cleanup_restore_integer (&inf->detaching);
+  inf->detaching = 1;
+
+  while (!ptid_equal (displaced->step_ptid, null_ptid))
+    {
+      struct cleanup *old_chain_2;
+      struct execution_control_state ecss;
+      struct execution_control_state *ecs;
+
+      ecs = &ecss;
+      memset (ecs, 0, sizeof (*ecs));
+
+      overlay_cache_invalid = 1;
+
+      /* We have to invalidate the registers BEFORE calling
+        target_wait because they can be loaded from the target while
+        in target_wait.  This makes remote debugging a bit more
+        efficient for those targets that provide critical registers
+        as part of their normal status mechanism. */
+
+      registers_changed ();
+
+      if (deprecated_target_wait_hook)
+       ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0);
+      else
+       ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0);
+
+      if (debug_infrun)
+       print_target_wait_results (pid_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
+        state.  */
+      old_chain_2 = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+
+      /* Now figure out what to do with the result of the result.  */
+      handle_inferior_event (ecs);
+
+      /* No error, don't finish the state yet.  */
+      discard_cleanups (old_chain_2);
+
+      /* 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)
+       {
+         discard_cleanups (old_chain_1);
+         error (_("Program exited while detaching"));
+       }
+    }
+
+  discard_cleanups (old_chain_1);
+}
+
 /* Wait for control to return from inferior to debugger.
 
    If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
@@ -3787,6 +3865,7 @@ process_event_stop_test:
     {
       /* Signal not for debugging purposes.  */
       int printed = 0;
+      struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
 
       if (debug_infrun)
         fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n",
@@ -3805,7 +3884,8 @@ process_event_stop_test:
         to remain stopped.  */
       if (stop_soon != NO_STOP_QUIETLY
          || ecs->event_thread->stop_requested
-         || signal_stop_state (ecs->event_thread->stop_signal))
+         || (!inf->detaching
+             && signal_stop_state (ecs->event_thread->stop_signal)))
        {
          stop_stepping (ecs);
          return;
index e6659c9aac460ca709e364cee82935d367f164f2..1f90171d57a87df404d369b562343fb49f7777b9 100644 (file)
@@ -2077,6 +2077,8 @@ target_detach (char *args, int from_tty)
        them before detaching.  */
     remove_breakpoints_pid (PIDGET (inferior_ptid));
 
+  prepare_for_detach ();
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_detach != NULL)