--- /dev/null
+diff -durN strace-4.4.orig/strace.c strace-4.4/strace.c
+--- strace-4.4.orig/strace.c Fri Aug 3 13:43:35 2001
++++ strace-4.4/strace.c Thu Jul 4 10:41:55 2002
+@@ -993,58 +993,110 @@
+ #ifdef LINUX
+ /*
+ * Linux wrongly insists the child be stopped
+- * before detaching. Arghh. We go through hoops
+- * to make a clean break of things.
++ * 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.
++ *
+ */
+-#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 {
++ } else {
++
+ for (;;) {
+- if (waitpid(tcp->pid, &status, 0) < 0) {
+- if (errno != ECHILD)
++ 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) {
+ perror("detach: waiting");
+- break;
++ } 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) {
++ 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 /* LINUX */
++#endif
+
+ #if defined(SUNOS4)
+ /* PTRACE_DETACH won't respect `sig' argument, so we post it here. */