Fix botched commit.

This commit is contained in:
Roland McGrath 2002-12-16 20:42:50 +00:00
parent 32be5979b4
commit 7bf10474b9

106
strace.c
View File

@ -1042,110 +1042,58 @@ int sig;
#ifdef LINUX
/*
* Linux wrongly insists the child be stopped
* before detaching. This creates numerous headaches
* as the process we are tracing may be running.
*
* First try to simply detach from the process; if it was
* already stopped, this will succeed and we're done.
*
* Otherwise stop the process by sending it a SIGSTOP
* signal.
*
* Once the process is stopped we have to make sure it
* received the SIGSTOP (it may have received a SIGTRAP or
* other signal). If it did not receive the SIGSTOP,
* restart the process and try again.
*
* Once stopped with a SIGSTOP, we can detach from the
* process via PTRACE_DETACH.
*
* before detaching. Arghh. We go through hoops
* to make a clean break of things.
*/
#if defined(SPARC)
#undef PTRACE_DETACH
#define PTRACE_DETACH PTRACE_SUNDETACH
#endif
if ((error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig)) == 0) {
/* On a clear day, you can see forever. */
} else {
}
else if (errno != ESRCH) {
/* Shouldn't happen. */
perror("detach: ptrace(PTRACE_DETACH, ...)");
}
else if (kill(tcp->pid, 0) < 0) {
if (errno != ESRCH)
perror("detach: checking sanity");
}
else if (kill(tcp->pid, SIGSTOP) < 0) {
if (errno != ESRCH)
perror("detach: stopping child");
}
else {
for (;;) {
if (kill(tcp->pid, 0) < 0) {
if (errno != ESRCH)
perror("detach: checking sanity");
}
else if (kill(tcp->pid, SIGSTOP) < 0) {
if (errno != ESRCH)
perror("detach: stopping child");
}
/*
* At this point the child should be stopped. Try to
* wait on it so we can get its stop status. Use WNOHANG
* to avoid this wait hanging.
*/
if (waitpid (tcp->pid, &status, (WUNTRACED | WNOHANG)) < 0) {
if (errno != ECHILD) {
if (waitpid(tcp->pid, &status, 0) < 0) {
if (errno != ECHILD)
perror("detach: waiting");
} else {
/*
* Try again, this time with the __WCLONE
* flag. Note we may get notifications
* for other processes/threads!
*/
errno = 0;
while (1) {
int x;
x = waitpid (-1, &status, __WCLONE);
if (x == tcp->pid || x < 0 || errno != 0)
break;
}
}
if (errno) {
perror ("Unable to wait on inferior");
return -1;
}
break;
}
/*
* At this point we have wait status for the
* inferior. If it did not stop, then all
* bets are off.
*/
if (!WIFSTOPPED(status)) {
/* Au revoir, mon ami. */
break;
}
/*
* If the process/thread has stopped with a
* SIGSTOP, then we can continue and detach
* with PTRACE_DETACH.
*/
if (WSTOPSIG(status) == SIGSTOP) {
if ((error = ptrace(PTRACE_DETACH,
tcp->pid, (char *) 1, sig)) < 0) {
tcp->pid, (char *) 1, sig)) < 0) {
if (errno != ESRCH)
perror("detach: ptrace(PTRACE_DETACH, ...)");
/* I died trying. */
}
break;
}
/*
* The process/thread did not stop with a SIGSTOP,
* so let it continue and try again to stop it with
* a SIGSTOP.
*/
if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
WSTOPSIG(status) == SIGTRAP ?
0 : WSTOPSIG(status))) < 0) {
WSTOPSIG(status) == SIGTRAP ?
0 : WSTOPSIG(status))) < 0) {
if (errno != ESRCH)
perror("detach: ptrace(PTRACE_CONT, ...)");
break;
}
}
}
#endif
#endif /* LINUX */
#if defined(SUNOS4)
/* PTRACE_DETACH won't respect `sig' argument, so we post it here. */