summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorPedro Alves <pedro@codesourcery.com>2008-12-28 16:14:56 +0000
committerPedro Alves <pedro@codesourcery.com>2008-12-28 16:14:56 +0000
commit027a0a007cabf6cb23b35c53f5cbc172904d84ba (patch)
tree35afe6599889252fd31d1c81b85944539e873abe /gdb
parent43f17405181c357d49d5193f0d16665964e6e5b0 (diff)
downloadgdb-027a0a007cabf6cb23b35c53f5cbc172904d84ba.tar.gz
* 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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog14
-rw-r--r--gdb/inf-ptrace.c4
-rw-r--r--gdb/linux-fork.c34
-rw-r--r--gdb/linux-fork.h1
-rw-r--r--gdb/linux-nat.c28
-rw-r--r--gdb/linux-thread-db.c11
6 files changed, 80 insertions, 12 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c21bf2bd4d9..aa64ed337fa 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 8a34db71993..8ae1161a9d6 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -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. */
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 3d649228450..4450385983a 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -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
diff --git a/gdb/linux-fork.h b/gdb/linux-fork.h
index cea1fc9041f..54dc19e6467 100644
--- a/gdb/linux-fork.h
+++ b/gdb/linux-fork.h
@@ -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;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index d90fb07b8b2..ac5a37545a0 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -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. */
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index cf0dd6a8ff5..4bed21824f3 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -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