[PATCH 2/2] Trace fork series calls using PTRACE_SETOPTIONS on linux

Wang Chao wang.chao at cn.fujitsu.com
Wed Sep 1 09:17:56 UTC 2010


* defs.h: Variable declaration.
* process.c (internal_fork): Do nothing if using PTRACE_SETOPTIONS
  to trace fork series calls.
* strace.c (trace): Set ptrace options and handle trap with flag
  PTRACE_EVENT_{CLONE,VFORK,FORK}.

Signed-off-by: Wang Chao <wang.chao at cn.fujitsu.com>
---
 defs.h    |    1 +
 process.c |    5 ++++-
 strace.c  |   53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletions(-)

diff --git a/defs.h b/defs.h
index a813f5b..3642fce 100644
--- a/defs.h
+++ b/defs.h
@@ -470,6 +470,7 @@ typedef enum {
 extern struct tcb **tcbtab;
 extern int *qual_flags;
 extern int debug, followfork;
+extern int ptrace_setoptions;
 extern int dtime, xflag, qflag;
 extern cflag_t cflag;
 extern int acolumn;
diff --git a/process.c b/process.c
index 7f9353a..9365495 100644
--- a/process.c
+++ b/process.c
@@ -837,13 +837,16 @@ internal_fork(struct tcb *tcp)
 		if (!followfork)
 			return 0;
 		fork_tcb(tcp);
-		if (setbpt(tcp) < 0)
+		if (ptrace_setoptions || setbpt(tcp) < 0)
 			return 0;
 	} else {
 		struct tcb *tcpchild;
 		int pid;
 		int bpt;
 
+		if (ptrace_setoptions)
+			return 0;
+
 		if (!(tcp->flags & TCB_FOLLOWFORK))
 			return 0;
 
diff --git a/strace.c b/strace.c
index c1d6539..70b9222 100644
--- a/strace.c
+++ b/strace.c
@@ -82,6 +82,8 @@ extern int optind;
 extern char *optarg;
 
 
+/* use PTRACE_SETOPTIONS to trace fork series calls. */
+int ptrace_setoptions = 0;
 int debug = 0, followfork = 0;
 int dtime = 0, xflag = 0, qflag = 0;
 cflag_t cflag = CFLAG_NONE;
@@ -2454,6 +2456,51 @@ Process %d attached (waiting for parent)\n",
 			fprintf(stderr, "pid %u stopped, [%s]\n",
 				pid, signame(WSTOPSIG(status)));
 
+		if (ptrace_setoptions &&
+		    (status >> 16 == PTRACE_EVENT_VFORK ||
+		     status >> 16 == PTRACE_EVENT_CLONE ||
+		     status >> 16 == PTRACE_EVENT_FORK)) {
+			struct tcb *tcpchild = NULL;
+			int childpid;
+
+			ptrace(PTRACE_GETEVENTMSG, pid, NULL, &childpid);
+			tcpchild = pid2tcb(childpid);
+			if (tcpchild == NULL) {
+				tcpchild = alloctcb(childpid);
+			}
+			else if ((tcpchild->flags
+				 & (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED))
+				!= (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED))
+					fprintf(stderr,
+						"[preattached child %d of %d in weird state!]\n",
+						childpid, tcp->pid);
+
+			tcpchild->flags |= TCB_ATTACHED;
+			if (tcpchild->flags & TCB_SUSPENDED) {
+				tcpchild->flags &= ~TCB_SUSPENDED;
+				if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0) {
+					fprintf(stderr, "Restart suspended child %d with error\n",
+						tcpchild->pid);
+					goto tracing;
+				}
+
+				if (!qflag)
+					fprintf(stderr,
+						"Process %u resumed (parent %d ready)\n",
+						childpid, tcp->pid);
+			}
+			else {
+				if (!qflag)
+					fprintf(stderr, "Process %d attached\n", childpid);
+			}
+			tcpchild->parent = tcp;
+			++tcp->nchildren;
+#ifdef TCB_CLONE_THREAD
+			reparent(tcp, tcpchild);
+#endif
+			goto tracing;
+		}
+
 		/*
 		 * Interestingly, the process may stop
 		 * with STOPSIG equal to some other signal
@@ -2481,6 +2528,12 @@ Process %d attached (waiting for parent)\n",
 					return -1;
 				}
 			}
+#ifdef LINUX
+			if (followfork && tcp->parent == NULL &&
+			    ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL,
+			           PTRACE_O_TRACEFORK|PTRACE_O_TRACEVFORK|PTRACE_O_TRACECLONE) == 0)
+				ptrace_setoptions = 1;
+#endif
 			goto tracing;
 		}
 
-- 
1.6.5.2





More information about the Strace-devel mailing list