[PATCH 3/4] Split TCB_STARTUP into TCB_STARTUP and TCB_IGNORE_ONE_SIGSTOP bits

Denys Vlasenko dvlasenk at redhat.com
Fri Sep 2 14:17:15 UTC 2011


> Patch 3: Split TCB_STARTUP into TCB_STARTUP and TCB_IGNORE_ONE_SIGSTOP
> bits. This is required by SIEZE because with SIEZE, waiting for SIGSTOP
> is not necessary, but initialization is still needed.

diff -d -urpN strace.3/defs.h strace.4/defs.h
--- strace.3/defs.h	2011-09-01 20:17:13.712850718 +0200
+++ strace.4/defs.h	2011-09-02 11:23:45.242545628 +0200
@@ -436,8 +436,15 @@ struct tcb {
 };
 
 /* TCB flags */
-#define TCB_STARTUP	00001	/* We have just begun ptracing this process */
-#define TCB_INUSE	00002	/* This table entry is in use */
+#define TCB_INUSE		00001	/* This table entry is in use */
+/* We have attached to this process, but did not see it stopping yet.
+ * (If this bit is not set, we either didn't attach yet,
+ * or we did attach to it, already saw it stopping at least once,
+ * did some init work on it and cleared this bit. TODO: maybe it makes sense
+ * to split these two states?)
+ */
+#define TCB_STARTUP		00002
+#define TCB_IGNORE_ONE_SIGSTOP	00004	/* Next SIGSTOP is to be ignored */
 /*
  * Are we in system call entry or in syscall exit?
  *
@@ -456,8 +463,8 @@ struct tcb {
  *
  * Use entering(tcp) / exiting(tcp) to check this bit to make code more readable.
  */
-#define TCB_INSYSCALL	00004
-#define TCB_ATTACHED	00010	/* Process is not our own child */
+#define TCB_INSYSCALL	00010
+#define TCB_ATTACHED	00020	/* Process is not our own child */
 #define TCB_BPTSET	00100	/* "Breakpoint" set after fork(2) */
 #define TCB_SIGTRAPPED	00200	/* Process wanted to block SIGTRAP */
 #define TCB_REPRINT	01000	/* We should reprint this syscall on exit */
diff -d -urpN strace.3/process.c strace.4/process.c
--- strace.3/process.c	2011-09-01 18:30:57.848409673 +0200
+++ strace.4/process.c	2011-09-02 11:38:20.129919984 +0200
@@ -859,7 +859,7 @@ internal_fork(struct tcb *tcp)
 		}
 #endif /* !oldway */
 #endif /* SUNOS4 */
-		tcpchild->flags |= TCB_ATTACHED | TCB_STARTUP;
+		tcpchild->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
 		/* Child has BPT too, must be removed on first occasion */
 		if (bpt) {
 			tcpchild->flags |= TCB_BPTSET;
diff -d -urpN strace.3/strace.c strace.4/strace.c
--- strace.3/strace.c	2011-09-02 16:06:04.360190184 +0200
+++ strace.4/strace.c	2011-09-02 16:06:21.864293092 +0200
@@ -491,7 +491,7 @@ startup_attach(void)
 					cur_tcp = tcp;
 					if (tid != tcp->pid)
 						cur_tcp = alloctcb(tid);
-					cur_tcp->flags |= TCB_ATTACHED | TCB_STARTUP;
+					cur_tcp->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
 				}
 				closedir(dir);
 				if (interactive) {
@@ -512,6 +512,13 @@ startup_attach(void)
 : "Process %u attached - interrupt to quit\n",
 						tcp->pid, ntid);
 				}
+				if (!(tcp->flags & TCB_STARTUP)) {
+					/* -p PID, we failed to attach to PID itself
+					 * but did attach to some of its sibling threads.
+					 * Drop PID's tcp.
+					 */
+					droptcb(tcp);
+				}
 				continue;
 			} /* if (opendir worked) */
 		} /* if (-f) */
@@ -521,7 +528,7 @@ startup_attach(void)
 			droptcb(tcp);
 			continue;
 		}
-		tcp->flags |= TCB_STARTUP;
+		tcp->flags |= TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
 		if (debug)
 			fprintf(stderr, "attach to pid %d (main) succeeded\n", tcp->pid);
 
@@ -707,7 +714,10 @@ startup_child(char **argv)
 
 	if (!daemonized_tracer) {
 		tcp = alloctcb(pid);
-		tcp->flags |= TCB_STARTUP;
+		if (!strace_vforked)
+			tcp->flags |= TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
+		else
+			tcp->flags |= TCB_STARTUP;
 	}
 	else {
 		/* With -D, *we* are child here, IOW: different pid. Fetch it: */
@@ -1677,11 +1687,11 @@ detach(struct tcb *tcp, int sig)
 #define PTRACE_DETACH PTRACE_SUNDETACH
 #endif
 	/*
-	 * On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
-	 * expected SIGSTOP.  We must catch exactly one as otherwise the
-	 * detached process would be left stopped (process state T).
+	 * We did PTRACE_ATTACH but possibly didn't see the expected SIGSTOP.
+	 * We must catch exactly one as otherwise the detached process
+	 * would be left stopped (process state T).
 	 */
-	catch_sigstop = (tcp->flags & TCB_STARTUP);
+	catch_sigstop = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
 	error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig);
 	if (error == 0) {
 		/* On a clear day, you can see forever. */
@@ -2411,7 +2421,7 @@ trace()
 				   child so that we know how to do clearbpt
 				   in the child.  */
 				tcp = alloctcb(pid);
-				tcp->flags |= TCB_ATTACHED | TCB_STARTUP;
+				tcp->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
 				if (!qflag)
 					fprintf(stderr, "Process %d attached\n",
 						pid);
@@ -2478,28 +2488,10 @@ trace()
 			continue;
 		}
 
-		if (status >> 16) {
-			/* Ptrace event (we ignore all of them for now) */
-			goto restart_tracee_with_sig_0;
-		}
-
-		sig = WSTOPSIG(status);
-
-		/*
-		 * Interestingly, the process may stop
-		 * with STOPSIG equal to some other signal
-		 * than SIGSTOP if we happend to attach
-		 * just before the process takes a signal.
-		 * A no-MMU vforked child won't send up a signal,
-		 * so skip the first (lost) execve notification.
-		 */
-		if ((tcp->flags & TCB_STARTUP) &&
-		    (sig == SIGSTOP || strace_vforked)) {
-			/*
-			 * This flag is there to keep us in sync.
-			 * Next time this process stops it should
-			 * really be entering a system call.
-			 */
+		/* Is this the very first time we see this tracee stopped? */
+		if (tcp->flags & TCB_STARTUP) {
+			if (debug)
+				fprintf(stderr, "pid %d has TCB_STARTUP, initializing it\n", tcp->pid);
 			tcp->flags &= ~TCB_STARTUP;
 			if (tcp->flags & TCB_BPTSET) {
 				/*
@@ -2525,6 +2517,25 @@ trace()
 				}
 			}
 #endif
+		}
+
+		if (((unsigned)status >> 16) != 0) {
+			/* Ptrace event (we ignore all of them for now) */
+			goto restart_tracee_with_sig_0;
+		}
+
+		sig = WSTOPSIG(status);
+
+		/* Is this post-attach SIGSTOP?
+		 * Interestingly, the process may stop
+		 * with STOPSIG equal to some other signal
+		 * than SIGSTOP if we happend to attach
+		 * just before the process takes a signal.
+		 */
+		if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
+			if (debug)
+				fprintf(stderr, "ignored SIGSTOP on pid %d\n", tcp->pid);
+			tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
 			goto restart_tracee_with_sig_0;
 		}
 






More information about the Strace-devel mailing list