* linux-fork.c (linux_fork_detach): New.
authorPedro Alves <palves@redhat.com>
Sun, 28 Dec 2008 16:14:57 +0000 (16:14 +0000)
committerPedro Alves <palves@redhat.com>
Sun, 28 Dec 2008 16:14:57 +0000 (16:14 +0000)
* linux-fork.h (linux_fork_detach): Declare.
* linux-nat.c (linux_child_follow_fork): When following the fork
child, add the child inferior before possibly detaching from the
parent.  Don't reinstall ourselves.
(linux_nat_detach): Call linux_fork_detach if there are other
forks to debug.
* linux-thread-db.c (thread_db_detach): Don't call
target_mourn_inferior.  Instead inline the necessary bits.
* inf-ptrace.c (inf_ptrace_detach): Don't unpush the target if
there are other inferiors to debug.

gdb/ChangeLog
gdb/inf-ptrace.c
gdb/linux-fork.c
gdb/linux-fork.h
gdb/linux-nat.c
gdb/linux-thread-db.c

index c21bf2bd4d9ed28da40a5b2ecedc72edfbb1f651..aa64ed337fa516cf364cc88d622a27017a8079b8 100644 (file)
@@ -1,3 +1,17 @@
+2008-12-28  Pedro Alves  <pedro@codesourcery.com>
+
+       * linux-fork.c (linux_fork_detach): New.
+       * linux-fork.h (linux_fork_detach): Declare.
+       * linux-nat.c (linux_child_follow_fork): When following the fork
+       child, add the child inferior before possibly detaching from the
+       parent.  Don't reinstall ourselves.
+       (linux_nat_detach): Call linux_fork_detach if there are other
+       forks to debug.
+       * linux-thread-db.c (thread_db_detach): Don't call
+       target_mourn_inferior.  Instead inline the necessary bits.
+       * inf-ptrace.c (inf_ptrace_detach): Don't unpush the target if
+       there are other inferiors to debug.
+
 2008-12-28  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        Fix TYPE_HIGH_BOUND for TYPE_CODE_RANGE using arbitrary TYPE_NFIELDS in
index 8a34db71993d6cd34beac8592ce12bfe16e022b9..8ae1161a9d652984e218f5abd6e2d335c64dc2ac 100644 (file)
@@ -309,7 +309,9 @@ inf_ptrace_detach (struct target_ops *ops, char *args, int from_tty)
 
   inferior_ptid = null_ptid;
   detach_inferior (pid);
-  unpush_target (ops);
+
+  if (!have_inferiors ())
+    unpush_target (ops);
 }
 
 /* Kill the inferior.  */
index 3d6492284500484424e33fd428b5fdb7efd8e071..4450385983aa0507a0e1f63a11afd7772e8d339f 100644 (file)
@@ -387,6 +387,40 @@ linux_fork_mourn_inferior (void)
     delete_fork (inferior_ptid);
 }
 
+/* The current inferior_ptid is being detached, but there are other
+   viable forks to debug.  Detach and delete it and context-switch to
+   the first available.  */
+
+extern void
+linux_fork_detach (char *args, int from_tty)
+{
+  /* OK, inferior_ptid is the one we are detaching from.  We need to
+     delete it from the fork_list, and switch to the next available
+     fork.  */
+
+  if (ptrace (PTRACE_DETACH, PIDGET (inferior_ptid), 0, 0))
+    error (_("Unable to detach %s"), target_pid_to_str (inferior_ptid));
+
+  delete_fork (inferior_ptid);
+  /* Delete process from GDB's inferior list.  */
+  delete_inferior (ptid_get_pid (inferior_ptid));
+
+  /* There should still be a fork - if there's only one left,
+     delete_fork won't remove it, because we haven't updated
+     inferior_ptid yet.  */
+  gdb_assert (fork_list);
+
+  fork_load_infrun_state (fork_list);
+
+  if (from_tty)
+    printf_filtered (_("[Switching to %s]\n"),
+                    target_pid_to_str (inferior_ptid));
+
+  /* If there's only one fork, switch back to non-fork mode.  */
+  if (fork_list->next == NULL)
+    delete_fork (inferior_ptid);
+}
+
 /* Fork list <-> user interface.  */
 
 static void
index cea1fc9041f9a10e4d38788ec23b6707ed941fdf..54dc19e64679fa78e834614dde56348f60b8d88a 100644 (file)
@@ -23,6 +23,7 @@ extern struct fork_info *find_fork_pid (pid_t);
 extern void fork_save_infrun_state (struct fork_info *, int);
 extern void linux_fork_killall (void);
 extern void linux_fork_mourn_inferior (void);
+extern void linux_fork_detach (char *, int);
 extern int  forks_exist_p (void);
 
 struct fork_info *fork_list;
index d90fb07b8b2f924f75e4ece50807d1d85832f399..ac5a37545a08d2dd78da34438a2a4727864535a1 100644 (file)
@@ -826,6 +826,11 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
                            child_pid);
        }
 
+      /* Add the new inferior first, so that the target_detach below
+        doesn't unpush the target.  */
+
+      add_inferior (child_pid);
+
       /* If we're vforking, we may want to hold on to the parent until
         the child exits or execs.  At exec time we can remove the old
         breakpoints from the parent and detach it; at exit time we
@@ -868,12 +873,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
        target_detach (NULL, 0);
 
       inferior_ptid = ptid_build (child_pid, child_pid, 0);
-      add_inferior (child_pid);
-
-      /* Reinstall ourselves, since we might have been removed in
-        target_detach (which does other necessary cleanup).  */
 
-      push_target (ops);
       linux_nat_switch_fork (inferior_ptid);
       check_for_thread_db ();
 
@@ -1621,12 +1621,24 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
-  pid = GET_PID (inferior_ptid);
-  inferior_ptid = pid_to_ptid (pid);
-  linux_ops->to_detach (ops, args, from_tty);
+  pid = ptid_get_pid (inferior_ptid);
 
   if (target_can_async_p ())
     drain_queued_events (pid);
+
+  if (forks_exist_p ())
+    {
+      /* Multi-fork case.  The current inferior_ptid is being detached
+        from, but there are other viable forks to debug.  Detach from
+        the current fork, and context-switch to the first
+        available.  */
+      linux_fork_detach (args, from_tty);
+
+      if (non_stop && target_can_async_p ())
+       target_async (inferior_event_handler, 0);
+    }
+  else
+    linux_ops->to_detach (ops, args, from_tty);
 }
 
 /* Resume LP.  */
index cf0dd6a8ff5b5814e5a674ea253a51e6a064bde2..4bed21824f3e594a278b53b3d537ae4a33d3d2e2 100644 (file)
@@ -784,10 +784,15 @@ thread_db_detach (struct target_ops *ops, char *args, int from_tty)
 {
   disable_thread_event_reporting ();
 
-  target_beneath->to_detach (target_beneath, args, from_tty);
+  /* Forget about the child's process ID.  We shouldn't need it
+     anymore.  */
+  proc_handle.pid = 0;
 
-  /* Should this be done by detach_command?  */
-  target_mourn_inferior ();
+  /* Detach thread_db target ops.  */
+  unpush_target (&thread_db_ops);
+  using_thread_db = 0;
+
+  target_beneath->to_detach (target_beneath, args, from_tty);
 }
 
 /* Check if PID is currently stopped at the location of a thread event