mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-10-20 06:15:09 +08:00
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:
@ -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.
|
||||||
|
@ -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). */
|
||||||
|
122
gdb/lin-lwp.c
122
gdb/lin-lwp.c
@ -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
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user