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.
This commit is contained in:
Mark Kettenis
2001-10-14 11:30:37 +00:00
parent 9fa87a061b
commit cacab7c477
3 changed files with 132 additions and 19 deletions

View File

@ -1,3 +1,27 @@
2001-10-14 Mark Kettenis <kettenis@gnu.org>
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.
2001-10-13 Andrew Cagney <ac131313@redhat.com> 2001-10-13 Andrew Cagney <ac131313@redhat.com>
S/390 31 & 64 bit target and GNU/Linux native support. S/390 31 & 64 bit target and GNU/Linux native support.

View File

@ -87,6 +87,11 @@ extern int cannot_store_register (int regno);
/* Override child_resume in `infptrace.c'. */ /* Override child_resume in `infptrace.c'. */
#define CHILD_RESUME #define CHILD_RESUME
/* Override child_wait in `inftarg.c'. */
struct target_waitstatus;
extern ptid_t child_wait (ptid_t ptid, struct target_waitstatus *ourstatus);
#define CHILD_WAIT
/* FIXME: kettenis/2000-09-03: This should be moved to ../nm-linux.h /* FIXME: kettenis/2000-09-03: This should be moved to ../nm-linux.h
once we have converted all Linux targets to use the new threads once we have converted all Linux targets to use the new threads
stuff (without the #undef of course). */ stuff (without the #undef of course). */

View File

@ -75,6 +75,11 @@ struct lwp_info
and overall process id. */ and overall process id. */
ptid_t ptid; 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 /* Non-zero if we sent this LWP a SIGSTOP (but the LWP didn't report
it back yet). */ it back yet). */
int signalled; int signalled;
@ -115,8 +120,6 @@ static int threaded;
#define is_lwp(ptid) (GET_LWP (ptid) != 0) #define is_lwp(ptid) (GET_LWP (ptid) != 0)
#define BUILD_LWP(lwp, pid) ptid_build (pid, lwp, 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 /* If the last reported event was a SIGTRAP, this variable is set to
the process id of the LWP/thread that got it. */ the process id of the LWP/thread that got it. */
ptid_t trap_ptid; ptid_t trap_ptid;
@ -352,18 +355,33 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
if (verbose) if (verbose)
printf_filtered ("[New %s]\n", target_pid_to_str (ptid)); 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); lp = find_lwp_pid (ptid);
if (lp == NULL) if (lp == NULL)
lp = add_lwp (ptid); 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; pid_t pid;
stop_wait_callback (lp, NULL); 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) lin_lwp_attach (char *args, int from_tty)
{ {
struct lwp_info *lp; struct lwp_info *lp;
pid_t pid;
int status;
/* FIXME: We should probably accept a list of process id's, and /* FIXME: We should probably accept a list of process id's, and
attach all of them. */ attach all of them. */
child_ops.to_attach (args, from_tty); child_ops.to_attach (args, from_tty);
/* Add the initial process as the first LWP to the list. */ /* 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 /* Make sure the initial process is stopped. The user-level threads
layer might want to poke around in the inferior, and that won't layer might want to poke around in the inferior, and that won't
work if things haven't stabilized yet. */ work if things haven't stabilized yet. */
lp->signalled = 1; pid = waitpid (GET_PID (inferior_ptid), &status, 0);
stop_wait_callback (lp, NULL); if (pid == -1 && errno == ECHILD)
gdb_assert (lp->status == 0); {
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. */ /* Fake the SIGSTOP that core GDB expects. */
lp->status = W_STOPCODE (SIGSTOP); 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)); 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, if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
WSTOPSIG (lp->status)) < 0) WSTOPSIG (lp->status)) < 0)
@ -433,7 +466,7 @@ lin_lwp_detach (char *args, int from_tty)
{ {
iterate_over_lwps (detach_callback, NULL); 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); gdb_assert (num_lwps == 1);
trap_ptid = null_ptid; trap_ptid = null_ptid;
@ -610,8 +643,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
gdb_assert (lp->status == 0); gdb_assert (lp->status == 0);
pid = waitpid (GET_LWP (lp->ptid), &status, pid = waitpid (GET_LWP (lp->ptid), &status, lp->cloned ? __WCLONE : 0);
is_cloned (lp->ptid) ? __WCLONE : 0);
if (pid == -1 && errno == ECHILD) if (pid == -1 && errno == ECHILD)
/* OK, the proccess has disappeared. We'll catch the actual /* OK, the proccess has disappeared. We'll catch the actual
exit event in lin_lwp_wait. */ exit event in lin_lwp_wait. */
@ -888,6 +920,55 @@ resumed_callback (struct lwp_info *lp, void *data)
return lp->resumed; 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 static ptid_t
lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus) 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 /* 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 process or not. And we have to convert it to something that
the layer beneath us can understand. */ the layer beneath us can understand. */
options = is_cloned (lp->ptid) ? __WCLONE : 0; options = lp->cloned ? __WCLONE : 0;
pid = GET_LWP (ptid); pid = GET_LWP (ptid);
} }
@ -997,6 +1078,9 @@ lin_lwp_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
if (! lp) if (! lp)
{ {
lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid))); lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid)));
if (options & __WCLONE)
lp->cloned = 1;
if (threaded) if (threaded)
{ {
gdb_assert (WIFSTOPPED (status) 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 /* For cloned processes we must check both with __WCLONE and
without, since the exit status of a cloned process isn't reported without, since the exit status of a cloned process isn't reported
with __WCLONE. */ with __WCLONE. */
if (is_cloned (lp->ptid)) if (lp->cloned)
{ {
do do
{ {