diff options
author | Mark Kettenis <kettenis@gnu.org> | 2001-10-14 11:30:37 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@gnu.org> | 2001-10-14 11:30:37 +0000 |
commit | cacab7c47722fd1c63c95d4c4a5b761ba6823632 (patch) | |
tree | 1db8ef95227453d7235bfb4398a40632ece33a9d /gdb/lin-lwp.c | |
parent | 9fa87a061b790901650cffd1bb6ae59fb531a9d4 (diff) | |
download | gdb-cacab7c47722fd1c63c95d4c4a5b761ba6823632.zip gdb-cacab7c47722fd1c63c95d4c4a5b761ba6823632.tar.gz gdb-cacab7c47722fd1c63c95d4c4a5b761ba6823632.tar.bz2 |
Fix attaching to cloned processes. This fixes PR gdb/61.
* lin-lwp.c (struct lwp_info): Add new member `cloned'.
(is_cloned) Removed.
(lin_lwp_attach_lwp): Don't call stop_wait_callback. Instead call
waitpid explicitly. Mark the LWP as cloned if waitpid fails and
retry with __WCLONE flag.
(lin_lwp_attach): Likewise. Warn if attaching to a cloned process.
(detach_callback): Replace use of is_cloned with explicit check on
LWP id and process id.
(stop_wait_callback): Replace use of is_cloned with check if LWP
is marked as cloned.
[CHILD_WAIT] (child_wait): New function.
(lin_lwp_wait): Replace use of is_cloned with check if LWP is
marked as cloned. Mark newly detected LWPs as cloned if detected
by waitpid with __WCLONE flag.
(kill_wait_callback): Replace use of is_cloned with check if LWP
is marked as cloned.
* config/i386/nm-linux.h (struct target_waitstatus): Add forward
declaration.
(child_wait): Add prototype.
(CHILD_WAIT): Define.
Diffstat (limited to 'gdb/lin-lwp.c')
-rw-r--r-- | gdb/lin-lwp.c | 122 |
1 files changed, 103 insertions, 19 deletions
diff --git a/gdb/lin-lwp.c b/gdb/lin-lwp.c index 385b235..22d9d74 100644 --- a/gdb/lin-lwp.c +++ b/gdb/lin-lwp.c @@ -75,6 +75,11 @@ struct lwp_info and overall process id. */ ptid_t ptid; + /* Non-zero if this LWP is cloned. In this context "cloned" means + that the LWP is reporting to its parent using a signal other than + SIGCHLD. */ + int cloned; + /* Non-zero if we sent this LWP a SIGSTOP (but the LWP didn't report it back yet). */ int signalled; @@ -115,8 +120,6 @@ static int threaded; #define is_lwp(ptid) (GET_LWP (ptid) != 0) #define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 0) -#define is_cloned(pid) (GET_LWP (pid) != GET_PID (pid)) - /* If the last reported event was a SIGTRAP, this variable is set to the process id of the LWP/thread that got it. */ ptid_t trap_ptid; @@ -352,18 +355,33 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose) if (verbose) printf_filtered ("[New %s]\n", target_pid_to_str (ptid)); - /* We assume that we're already tracing the initial process. */ - if (is_cloned (ptid) && ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) - error ("Can't attach %s: %s", target_pid_to_str (ptid), strerror (errno)); - lp = find_lwp_pid (ptid); if (lp == NULL) lp = add_lwp (ptid); - if (is_cloned (ptid)) + /* We assume that we're already attached to any LWP that has an + id equal to the overall process id. */ + if (GET_LWP (ptid) != GET_PID (ptid)) { - lp->signalled = 1; - stop_wait_callback (lp, NULL); + pid_t pid; + int status; + + if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) + error ("Can't attach %s: %s", target_pid_to_str (ptid), + strerror (errno)); + + pid = waitpid (GET_LWP (ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + { + /* Try again with __WCLONE to check cloned processes. */ + pid = waitpid (GET_LWP (ptid), &status, __WCLONE); + lp->cloned = 1; + } + + gdb_assert (pid == GET_LWP (ptid) + && WIFSTOPPED (status) && WSTOPSIG (status)); + + lp->stopped = 1; } } @@ -371,20 +389,33 @@ static void lin_lwp_attach (char *args, int from_tty) { struct lwp_info *lp; + pid_t pid; + int status; /* FIXME: We should probably accept a list of process id's, and attach all of them. */ child_ops.to_attach (args, from_tty); /* Add the initial process as the first LWP to the list. */ - lp = add_lwp (BUILD_LWP (PIDGET (inferior_ptid), PIDGET (inferior_ptid))); + lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid))); /* Make sure the initial process is stopped. The user-level threads layer might want to poke around in the inferior, and that won't work if things haven't stabilized yet. */ - lp->signalled = 1; - stop_wait_callback (lp, NULL); - gdb_assert (lp->status == 0); + pid = waitpid (GET_PID (inferior_ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + { + warning ("%s is a cloned process", target_pid_to_str (inferior_ptid)); + + /* Try again with __WCLONE to check cloned processes. */ + pid = waitpid (GET_PID (inferior_ptid), &status, __WCLONE); + lp->cloned = 1; + } + + gdb_assert (pid == GET_PID (inferior_ptid) + && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP); + + lp->stopped = 1; /* Fake the SIGSTOP that core GDB expects. */ lp->status = W_STOPCODE (SIGSTOP); @@ -415,7 +446,9 @@ detach_callback (struct lwp_info *lp, void *data) gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status)); } - if (is_cloned (lp->ptid)) + /* We don't actually detach from the LWP that has an id equal to the + overall process id just yet. */ + if (GET_LWP (lp->ptid) != GET_PID (lp->ptid)) { if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0, WSTOPSIG (lp->status)) < 0) @@ -433,7 +466,7 @@ lin_lwp_detach (char *args, int from_tty) { iterate_over_lwps (detach_callback, NULL); - /* Only the initial (uncloned) process should be left right now. */ + /* Only the initial process should be left right now. */ gdb_assert (num_lwps == 1); trap_ptid = null_ptid; @@ -610,8 +643,7 @@ stop_wait_callback (struct lwp_info *lp, void *data) gdb_assert (lp->status == 0); - pid = waitpid (GET_LWP (lp->ptid), &status, - is_cloned (lp->ptid) ? __WCLONE : 0); + pid = waitpid (GET_LWP (lp->ptid), &status, lp->cloned ? __WCLONE : 0); if (pid == -1 && errno == ECHILD) /* OK, the proccess has disappeared. We'll catch the actual exit event in lin_lwp_wait. */ @@ -888,6 +920,55 @@ resumed_callback (struct lwp_info *lp, void *data) return lp->resumed; } +#ifdef CHILD_WAIT + +/* We need to override child_wait to support attaching to cloned + processes, since a normal wait (as done by the default version) + ignores those processes. */ + +/* Wait for child PTID to do something. Return id of the child, + minus_one_ptid in case of error; store status into *OURSTATUS. */ + +ptid_t +child_wait (ptid_t ptid, struct target_waitstatus *ourstatus) +{ + int save_errno; + int status; + pid_t pid; + + do + { + set_sigint_trap (); /* Causes SIGINT to be passed on to the + attached process. */ + set_sigio_trap (); + + pid = waitpid (GET_PID (ptid), &status, 0); + if (pid == -1 && errno == ECHILD) + /* Try again with __WCLONE to check cloned processes. */ + pid = waitpid (GET_PID (ptid), &status, __WCLONE); + save_errno = errno; + + clear_sigio_trap (); + clear_sigint_trap (); + } + while (pid == -1 && errno == EINTR); + + if (pid == -1) + { + warning ("Child process unexpectedly missing: %s", strerror (errno)); + + /* Claim it exited with unknown signal. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + return minus_one_ptid; + } + + store_waitstatus (ourstatus, status); + return pid_to_ptid (pid); +} + +#endif + static ptid_t lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) { @@ -954,7 +1035,7 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) /* If we have to wait, take into account whether PID is a cloned process or not. And we have to convert it to something that the layer beneath us can understand. */ - options = is_cloned (lp->ptid) ? __WCLONE : 0; + options = lp->cloned ? __WCLONE : 0; pid = GET_LWP (ptid); } @@ -997,6 +1078,9 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) if (! lp) { lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid))); + if (options & __WCLONE) + lp->cloned = 1; + if (threaded) { gdb_assert (WIFSTOPPED (status) @@ -1189,7 +1273,7 @@ kill_wait_callback (struct lwp_info *lp, void *data) /* For cloned processes we must check both with __WCLONE and without, since the exit status of a cloned process isn't reported with __WCLONE. */ - if (is_cloned (lp->ptid)) + if (lp->cloned) { do { |