From 7a7d33537f13d7556f60efb202b0895712e8ad7d Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Sun, 28 Dec 2008 16:14:57 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 14 ++++++++++++++ gdb/inf-ptrace.c | 4 +++- gdb/linux-fork.c | 34 ++++++++++++++++++++++++++++++++++ gdb/linux-fork.h | 1 + gdb/linux-nat.c | 28 ++++++++++++++++++++-------- gdb/linux-thread-db.c | 11 ++++++++--- 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 + + * 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 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 -- 2.30.2