2004-06-03  Roland McGrath  <roland@redhat.com>

	* strace.c (main) [LINUX]: Expand TCBTAB as necessary for threads
	attached.  Attach threads only under -f.  Set TCB_FOLLOWFORK in them.
	(expand_tcbtab): New function, broken out of ...
	* process.c (fork_tcb): ... here, call that.
	* defs.h: Declare expand_tcbtab.
diff --git a/defs.h b/defs.h
index 6d22d34..95cd897 100644
--- a/defs.h
+++ b/defs.h
@@ -413,6 +413,7 @@
 extern struct tcb *alloctcb P((int));
 extern struct tcb *pid2tcb P((int));
 extern void droptcb P((struct tcb *));
+extern int expand_tcbtab P((void));
 
 extern void set_sortby P((char *));
 extern void set_overhead P((int));
diff --git a/process.c b/process.c
index 038fc14..7764725 100644
--- a/process.c
+++ b/process.c
@@ -402,27 +402,10 @@
 fork_tcb(struct tcb *tcp)
 {
 	if (nprocs == tcbtabsize) {
-		/* Allocate some more TCBs and expand the table.
-		   We don't want to relocate the TCBs because our
-		   callers have pointers and it would be a pain.
-		   So tcbtab is a table of pointers.  Since we never
-		   free the TCBs, we allocate a single chunk of many.  */
-		struct tcb **newtab = (struct tcb **)
-			realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
-		struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
-							    sizeof *newtcbs);
-		int i;
-		if (newtab == NULL || newtcbs == NULL) {
-			if (newtab != NULL)
-				free(newtab);
+		if (expand_tcbtab()) {
 			tcp->flags &= ~TCB_FOLLOWFORK;
 			fprintf(stderr, "sys_fork: tcb table full\n");
-			return 1;
 		}
-		for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
-			newtab[i] = &newtcbs[i - tcbtabsize];
-		tcbtabsize *= 2;
-		tcbtab = newtab;
 	}
 
 	tcp->flags |= TCB_FOLLOWFORK;
diff --git a/strace.c b/strace.c
index a8a1e40..5fc640d 100644
--- a/strace.c
+++ b/strace.c
@@ -403,7 +403,7 @@
 # ifdef LINUX
 		if (tcp->flags & TCB_CLONE_THREAD)
 			continue;
-		{
+		if (followfork) {
 			char procdir[MAXPATHLEN];
 			DIR *dir;
 			sprintf(procdir, "/proc/%d/task", tcp->pid);
@@ -424,13 +424,17 @@
 						   (char *) 1, 0) < 0)
 						++nerr;
 					else if (tid != tcbtab[c]->pid) {
-						tcp = alloctcb(tid);
+						if (nprocs == tcbtabsize &&
+						    expand_tcbtab())
+							tcp = NULL;
+						else
+							tcp = alloctcb(tid);
 						if (tcp == NULL) {
 							fprintf(stderr, "%s: out of memory\n",
 								progname);
 							exit(1);
 						}
-						tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED;
+						tcp->flags |= TCB_ATTACHED|TCB_CLONE_THREAD|TCB_CLONE_DETACHED|TCB_FOLLOWFORK;
 						tcbtab[c]->nchildren++;
 						tcbtab[c]->nclone_threads++;
 						tcbtab[c]->nclone_detached++;
@@ -688,6 +692,33 @@
 	return;
 }
 
+int
+expand_tcbtab()
+{
+	/* Allocate some more TCBs and expand the table.
+	   We don't want to relocate the TCBs because our
+	   callers have pointers and it would be a pain.
+	   So tcbtab is a table of pointers.  Since we never
+	   free the TCBs, we allocate a single chunk of many.  */
+	struct tcb **newtab = (struct tcb **)
+		realloc(tcbtab, 2 * tcbtabsize * sizeof tcbtab[0]);
+	struct tcb *newtcbs = (struct tcb *) calloc(tcbtabsize,
+						    sizeof *newtcbs);
+	int i;
+	if (newtab == NULL || newtcbs == NULL) {
+		if (newtab != NULL)
+			free(newtab);
+		return 1;
+	}
+	for (i = tcbtabsize; i < 2 * tcbtabsize; ++i)
+		newtab[i] = &newtcbs[i - tcbtabsize];
+	tcbtabsize *= 2;
+	tcbtab = newtab;
+
+	return 0;
+}
+
+
 struct tcb *
 alloctcb(pid)
 int pid;