Do not detach when we think tracee is going to die.

Current code plays some ungodly tricks, trying to not detach
thread group leader until all threads exit.

Also, it detaches from a tracee when signal delivery is detected
which will cause tracee to exit.
This operation is racy (not to mention the determination
whether signal is set to SIG_DFL is a horrible hack):
after we determined that this signal is indeed fatal
but before we detach and let process die,
*other thread* may set a handler to this signal, and
we will leak the process, falsely displaying it as killed!

I need to look in the past to figure out why we even do it.
First guess is that it's a workaround for old kernel bugs:
kernel used to deliver exit notifications to the tracer,
not to real parent. These workarounds are ancient
(internal_exit is from 1995).

The patch deletes the hacks. We no longer need tcp->nclone_threads,
TCB_EXITING and TCB_GROUP_EXITING. We also lose a few rather
ugly functions.

I also added a new message: "+++ exited with EXITCODE +++"
which shows exact moment strace got exit notification.
It is analogous to existing "+++ killed by SIG +++" message.

* defs.h: Delete struct tcb::nclone_threads field,
  TCB_EXITING and TCB_GROUP_EXITING constants,
  declarations of sigishandled() and internal_exit().
* process.c (internal_exit): Delete this function.
  (handle_new_child): Don't ++tcp->nclone_threads.
* signal.c (parse_sigset_t): Delete this function.
  (sigishandled): Delete this function.
* strace.c (startup_attach): Don't tcbtab[tcbi]->nclone_threads++.
  (droptcb): Don't delay dropping if tcp->nclone_threads > 0,
  don't drop parent if its nclone_threads reached 0:
  just drop (only) this tcb unconditionally.
  (detach): don't drop parent.
  (handle_group_exit): Delete this function.
  (handle_ptrace_event): Instead of handle_group_exit, just drop tcb;
  do not panic if we see WIFEXITED from an attached pid;
  print "+++ exited with EXITCODE +++" for every WIFEXITED pid.
* syscall.c (internal_syscall):	Do not treat sys_exit specially -
  don't call internal_exit on it.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
diff --git a/strace.c b/strace.c
index dd179c9..1106255 100644
--- a/strace.c
+++ b/strace.c
@@ -482,7 +482,6 @@
 						if (tid != tcbtab[tcbi]->pid) {
 							tcp = alloctcb(tid);
 							tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD;
-							tcbtab[tcbi]->nclone_threads++;
 							tcp->parent = tcbtab[tcbi];
 						}
 					}
@@ -1553,40 +1552,11 @@
 {
 	if (tcp->pid == 0)
 		return;
-#ifdef TCB_CLONE_THREAD
-	if (tcp->nclone_threads > 0) {
-		/* There are other threads left in this process, but this
-		   is the one whose PID represents the whole process.
-		   We need to keep this record around as a zombie until
-		   all the threads die.  */
-		tcp->flags |= TCB_EXITING;
-		return;
-	}
-#endif
+
 	nprocs--;
 	if (debug)
 		fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs);
-	tcp->pid = 0;
 
-	if (tcp->parent != NULL) {
-#ifdef TCB_CLONE_THREAD
-		if (tcp->flags & TCB_CLONE_THREAD)
-			tcp->parent->nclone_threads--;
-#endif
-#ifdef LINUX
-		/* Update fields like NCLONE_DETACHED, only
-		   for zombie group leader that has already reported
-		   and been short-circuited at the top of this
-		   function.  The same condition as at the top of DETACH.  */
-		if ((tcp->flags & TCB_CLONE_THREAD) &&
-		    tcp->parent->nclone_threads == 0 &&
-		    (tcp->parent->flags & TCB_EXITING))
-			droptcb(tcp->parent);
-#endif
-		tcp->parent = NULL;
-	}
-
-	tcp->flags = 0;
 	if (tcp->pfd != -1) {
 		close(tcp->pfd);
 		tcp->pfd = -1;
@@ -1601,14 +1571,15 @@
 		}
 #endif /* !FREEBSD */
 #ifdef USE_PROCFS
-		rebuild_pollv(); /* Note, flags needs to be cleared by now.  */
+		tcp->flags = 0; /* rebuild_pollv needs it */
+		rebuild_pollv();
 #endif
 	}
 
 	if (outfname && followfork > 1 && tcp->outf)
 		fclose(tcp->outf);
 
-	tcp->outf = 0;
+	memset(tcp, 0, sizeof(*tcp));
 }
 
 /* detach traced process; continue with sig
@@ -1622,14 +1593,6 @@
 	int error = 0;
 #ifdef LINUX
 	int status, catch_sigstop;
-	struct tcb *zombie = NULL;
-
-	/* If the group leader is lingering only because of this other
-	   thread now dying, then detach the leader as well.  */
-	if ((tcp->flags & TCB_CLONE_THREAD) &&
-	    tcp->parent->nclone_threads == 1 &&
-	    (tcp->parent->flags & TCB_EXITING))
-		zombie = tcp->parent;
 #endif
 
 	if (tcp->flags & TCB_BPTSET)
@@ -1732,13 +1695,6 @@
 
 	droptcb(tcp);
 
-#ifdef LINUX
-	if (zombie != NULL) {
-		/* TCP no longer exists therefore you must not detach() it.  */
-		droptcb(zombie);
-	}
-#endif
-
 	return error;
 }
 
@@ -2260,62 +2216,6 @@
 
 #else /* !USE_PROCFS */
 
-#ifdef TCB_GROUP_EXITING
-/* Handle an exit detach or death signal that is taking all the
-   related clone threads with it.  This is called in three circumstances:
-   SIG == -1	TCP has already died (TCB_ATTACHED is clear, strace is parent).
-   SIG == 0	Continuing TCP will perform an exit_group syscall.
-   SIG == other	Continuing TCP with SIG will kill the process.
-*/
-static int
-handle_group_exit(struct tcb *tcp, int sig)
-{
-	/* We need to locate our records of all the clone threads
-	   related to TCP, either its children or siblings.  */
-	struct tcb *leader = NULL;
-
-	if (tcp->flags & TCB_CLONE_THREAD)
-		leader = tcp->parent;
-
-	if (sig < 0) {
-		if (leader != NULL && leader != tcp
-		 && !(leader->flags & TCB_GROUP_EXITING)
-		 && !(tcp->flags & TCB_STARTUP)
-		) {
-			fprintf(stderr,
-				"PANIC: handle_group_exit: %d leader %d\n",
-				tcp->pid, leader ? leader->pid : -1);
-		}
-		/* TCP no longer exists therefore you must not detach() it.  */
-		droptcb(tcp);	/* Already died.  */
-	}
-	else {
-		/* Mark that we are taking the process down.  */
-		tcp->flags |= TCB_EXITING | TCB_GROUP_EXITING;
-		if (tcp->flags & TCB_ATTACHED) {
-			detach(tcp, sig);
-			if (leader != NULL && leader != tcp)
-				leader->flags |= TCB_GROUP_EXITING;
-		} else {
-			if (ptrace_restart(PTRACE_CONT, tcp, sig) < 0) {
-				cleanup();
-				return -1;
-			}
-			if (leader != NULL) {
-				leader->flags |= TCB_GROUP_EXITING;
-				if (leader != tcp)
-					droptcb(tcp);
-			}
-			/* The leader will report to us as parent now,
-			   and then we'll get to the SIG==-1 case.  */
-			return 0;
-		}
-	}
-
-	return 0;
-}
-#endif
-
 #ifdef LINUX
 static int
 handle_ptrace_event(int status, struct tcb *tcp)
@@ -2522,37 +2422,24 @@
 #endif
 				printtrailer();
 			}
-#ifdef TCB_GROUP_EXITING
-			handle_group_exit(tcp, -1);
-#else
 			droptcb(tcp);
-#endif
 			continue;
 		}
 		if (WIFEXITED(status)) {
 			if (pid == strace_child)
 				exit_code = WEXITSTATUS(status);
-			if ((tcp->flags & (TCB_ATTACHED|TCB_STARTUP)) == TCB_ATTACHED
-#ifdef TCB_GROUP_EXITING
-			    && !(tcp->parent && (tcp->parent->flags & TCB_GROUP_EXITING))
-			    && !(tcp->flags & TCB_GROUP_EXITING)
-#endif
-			) {
-				fprintf(stderr,
-					"PANIC: attached pid %u exited with %d\n",
-					pid, WEXITSTATUS(status));
-			}
 			if (tcp == tcp_last) {
 				if ((tcp->flags & (TCB_INSYSCALL|TCB_REPRINT)) == TCB_INSYSCALL)
 					tprintf(" <unfinished ... exit status %d>\n",
 						WEXITSTATUS(status));
 				tcp_last = NULL;
 			}
-#ifdef TCB_GROUP_EXITING
-			handle_group_exit(tcp, -1);
-#else
+			if (!cflag /* && (qual_flags[WTERMSIG(status)] & QUAL_SIGNAL) */ ) {
+				printleader(tcp);
+				tprintf("+++ exited with %d +++", WEXITSTATUS(status));
+				printtrailer();
+			}
 			droptcb(tcp);
-#endif
 			continue;
 		}
 		if (!WIFSTOPPED(status)) {
@@ -2657,16 +2544,6 @@
 						PC_FORMAT_ARG);
 				printtrailer();
 			}
-			if (((tcp->flags & TCB_ATTACHED) ||
-			     tcp->nclone_threads > 0) &&
-				!sigishandled(tcp, WSTOPSIG(status))) {
-#ifdef TCB_GROUP_EXITING
-				handle_group_exit(tcp, WSTOPSIG(status));
-#else
-				detach(tcp, WSTOPSIG(status));
-#endif
-				continue;
-			}
 			if (ptrace_restart(PTRACE_SYSCALL, tcp, WSTOPSIG(status)) < 0) {
 				cleanup();
 				return -1;
@@ -2702,22 +2579,6 @@
 			}
 			continue;
 		}
-		if (tcp->flags & TCB_EXITING) {
-#ifdef TCB_GROUP_EXITING
-			if (tcp->flags & TCB_GROUP_EXITING) {
-				if (handle_group_exit(tcp, 0) < 0)
-					return -1;
-				continue;
-			}
-#endif
-			if (tcp->flags & TCB_ATTACHED)
-				detach(tcp, 0);
-			else if (ptrace_restart(PTRACE_CONT, tcp, 0) < 0) {
-				cleanup();
-				return -1;
-			}
-			continue;
-		}
 		if (tcp->flags & TCB_SUSPENDED) {
 			if (!qflag)
 				fprintf(stderr, "Process %u suspended\n", pid);