diff -rc3p strace-4.4/strace.c /tmp/strace-4.4/strace.c *** strace-4.4/strace.c Fri Aug 3 05:43:35 2001 --- /tmp/strace-4.4/strace.c Fri Feb 22 12:40:26 2002 *************** int sig; *** 993,1050 **** #ifdef LINUX /* * Linux wrongly insists the child be stopped ! * 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 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 (waitpid(tcp->pid, &status, 0) < 0) { ! if (errno != ECHILD) ! perror("detach: waiting"); ! break; ! } ! if (!WIFSTOPPED(status)) { ! /* Au revoir, mon ami. */ ! break; ! } ! if (WSTOPSIG(status) == SIGSTOP) { ! if ((error = ptrace(PTRACE_DETACH, ! tcp->pid, (char *) 1, sig)) < 0) { ! if (errno != ESRCH) ! perror("detach: ptrace(PTRACE_DETACH, ...)"); ! /* I died trying. */ } - break; } ! if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1, ! WSTOPSIG(status) == SIGTRAP ? ! 0 : WSTOPSIG(status))) < 0) { if (errno != ESRCH) ! perror("detach: ptrace(PTRACE_CONT, ...)"); ! break; } } } ! #endif /* LINUX */ #if defined(SUNOS4) /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */ --- 993,1096 ---- #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 stop the process by sending it a SIGSTOP ! * signal. If the process is already stopped, this ! * is harmless. ! * ! * 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. ! * */ ! ! ! 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. ! */ ! if (waitpid (tcp->pid, &status, WUNTRACED) < 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; ! } ! } ! ! /* ! * 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) { 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) { + if (errno != ESRCH) + perror("detach: ptrace(PTRACE_CONT, ...)"); + break; } } ! #endif #if defined(SUNOS4) /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */