Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Sep 2004 11:46:25 +1000 (EST)
From:      Sam Lawrance <boris@brooknet.com.au>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/71749: [PATCH] truss -f causes circular wait when traced process vforks
Message-ID:  <20040915014625.2D021AAF@localhost>
Resent-Message-ID: <200409150150.i8F1oKdZ035961@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         71749
>Category:       bin
>Synopsis:       [PATCH] truss -f causes circular wait when traced process vforks
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 15 01:50:20 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Sam Lawrance
>Release:        FreeBSD 5.3-BETA4 i386
>Organization:
>Environment:
System: FreeBSD dirk.no.domain 5.3-BETA4 FreeBSD 5.3-BETA4 #1: Wed Sep 15 01:21:24 EST 2004 root@dirk.no.domain:/usr/src/sys/i386/compile/GENERIC i386

>Description:
Truss can't follow processes that vfork() because of a circular
wait condition.

Truss assumes calls to fork in the traced process return immediately
with the child PID. On return, truss forks a child truss to trace
the child process.

Unfortunately, vfork() doesn't return the PID until the child
has exited or exec'd.

The circular wait is as follows:
1. Truss waits for vfork to return, so it can examine the PID
   and start a child truss to trace the child process.
2. The child process meanwhile has been started with the same
   pfsflags as the parent, so it will have stopped at the first
   syscall waiting for the child truss to PIOCCONT it.
3. But the child truss hasn't been started yet... back to (1).

Apparently devel/strace had similar problems under linux. The
strace fix is to actually poke user data and change vforks
into forks.

>How-To-Repeat:
In any port directory,
	truss -f make clean
always does the trick for me.

>Fix:

--- truss-patch begins here ---
This patch adds and uses S_FWAIT, stop on fork/wait. This allows
tracing processes to be informed of the child PID before the
syscall returns, allowing them to take action where previously
they would be stuck waiting.

Index: sys/sys/pioctl.h
===================================================================
RCS file: /home/ncvs/FreeBSD/src/sys/sys/pioctl.h,v
retrieving revision 1.12
diff -u -u -r1.12 pioctl.h
--- sys/sys/pioctl.h	4 Aug 2002 01:06:58 -0000	1.12
+++ sys/sys/pioctl.h	15 Sep 2004 00:59:55 -0000
@@ -65,7 +65,8 @@
 # define	S_SCX	0x00000008	/* stop on syscall exit */
 # define	S_CORE	0x00000010	/* stop on coredump */
 # define	S_EXIT	0x00000020	/* stop on exit */
-# define	S_ALLSTOPS  0x003f	/* stop on all events */
+# define	S_FWAIT 0x00000040	/* stop on fork/wait (vfork) */
+# define	S_ALLSTOPS  0x007f	/* stop on all events */
 
 /*
  * If PF_LINGER is set in procp->p_pfsflags, then the last close
Index: sys/kern/kern_fork.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/sys/kern/kern_fork.c,v
retrieving revision 1.234.2.3
diff -u -u -r1.234.2.3 kern_fork.c
--- sys/kern/kern_fork.c	9 Sep 2004 10:03:19 -0000	1.234.2.3
+++ sys/kern/kern_fork.c	15 Sep 2004 00:57:31 -0000
@@ -716,6 +716,13 @@
 	 */
 	KNOTE_LOCKED(&p1->p_klist, NOTE_FORK | p2->p_pid);
 
+	/*
+	 * If fork in parent won't return before child exits,
+	 * inform tracing processes so they may act.
+	 */
+	if (flags & RFPPWAIT)
+		_STOPEVENT(p1, S_FWAIT, p2->p_pid);
+
 	PROC_UNLOCK(p1);
 
 	/*
Index: usr.bin/truss/alpha-fbsd.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/alpha-fbsd.c,v
retrieving revision 1.18
diff -u -u -r1.18 alpha-fbsd.c
--- usr.bin/truss/alpha-fbsd.c	17 Jul 2004 19:48:49 -0000	1.18
+++ usr.bin/truss/alpha-fbsd.c	15 Sep 2004 01:20:57 -0000
@@ -161,8 +161,7 @@
 
   if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
    && ((!strcmp(fsc.name, "fork")
-    || !strcmp(fsc.name, "rfork")
-    || !strcmp(fsc.name, "vfork"))))
+    || !strcmp(fsc.name, "rfork"))))
   {
     trussinfo->in_fork = 1;
   }
Index: usr.bin/truss/amd64-fbsd.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/amd64-fbsd.c,v
retrieving revision 1.3
diff -u -u -r1.3 amd64-fbsd.c
--- usr.bin/truss/amd64-fbsd.c	17 Jul 2004 19:48:49 -0000	1.3
+++ usr.bin/truss/amd64-fbsd.c	15 Sep 2004 01:20:57 -0000
@@ -160,8 +160,7 @@
 
   if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
    && ((!strcmp(fsc.name, "fork")
-    || !strcmp(fsc.name, "rfork")
-    || !strcmp(fsc.name, "vfork"))))
+    || !strcmp(fsc.name, "rfork"))))
   {
     trussinfo->in_fork = 1;
   }
Index: usr.bin/truss/i386-fbsd.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/i386-fbsd.c,v
retrieving revision 1.23
diff -u -u -r1.23 i386-fbsd.c
--- usr.bin/truss/i386-fbsd.c	8 Aug 2004 23:29:36 -0000	1.23
+++ usr.bin/truss/i386-fbsd.c	15 Sep 2004 01:20:57 -0000
@@ -166,8 +166,7 @@
 
   if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
    && ((!strcmp(fsc.name, "fork")
-    || !strcmp(fsc.name, "rfork")
-    || !strcmp(fsc.name, "vfork"))))
+    || !strcmp(fsc.name, "rfork"))))
   {
     trussinfo->in_fork = 1;
   }
Index: usr.bin/truss/i386-linux.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/i386-linux.c,v
retrieving revision 1.23
diff -u -u -r1.23 i386-linux.c
--- usr.bin/truss/i386-linux.c	17 Jul 2004 19:48:49 -0000	1.23
+++ usr.bin/truss/i386-linux.c	15 Sep 2004 01:20:57 -0000
@@ -140,8 +140,7 @@
   }
 
   if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
-   && ((!strcmp(fsc.name, "linux_fork")
-    || !strcmp(fsc.name, "linux_vfork"))))
+   && (!strcmp(fsc.name, "linux_fork")))
   {
     trussinfo->in_fork = 1;
   }
Index: usr.bin/truss/ia64-fbsd.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/ia64-fbsd.c,v
retrieving revision 1.7
diff -u -u -r1.7 ia64-fbsd.c
--- usr.bin/truss/ia64-fbsd.c	17 Jul 2004 19:48:49 -0000	1.7
+++ usr.bin/truss/ia64-fbsd.c	15 Sep 2004 01:20:57 -0000
@@ -155,8 +155,7 @@
 
   if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
    && ((!strcmp(fsc.name, "fork")
-    || !strcmp(fsc.name, "rfork")
-    || !strcmp(fsc.name, "vfork"))))
+    || !strcmp(fsc.name, "rfork"))))
   {
     trussinfo->in_fork = 1;
   }
Index: usr.bin/truss/main.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/main.c,v
retrieving revision 1.38
diff -u -u -r1.38 main.c
--- usr.bin/truss/main.c	17 Jul 2004 19:19:36 -0000	1.38
+++ usr.bin/truss/main.c	15 Sep 2004 01:20:57 -0000
@@ -43,6 +43,7 @@
 #include <sys/pioctl.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 #include <sys/resource.h>
 
 #include <ctype.h>
@@ -243,7 +244,8 @@
 
 START_TRACE:
   Procfd = start_tracing(
-		trussinfo->pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT |
+		trussinfo->pid,
+		S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | S_FWAIT |
 		((trussinfo->flags & NOSIGS) ? 0 : S_SIG),
 		((trussinfo->flags & FOLLOWFORKS) ? PF_FORK : 0));
   if (Procfd == -1)
@@ -303,6 +305,19 @@
 	}
 	funcs->exit_syscall(trussinfo, pfs.val);
 	break;
+      case S_FWAIT:
+        if (trussinfo->flags & FOLLOWFORKS) {
+          /* Fork ourself to trace child */
+          int forkpid = fork();
+          if (forkpid == 0) {
+            /* Child truss starts tracing */
+            trussinfo->pid = pfs.val;
+            goto START_TRACE;
+          }
+          /* Parent truss waits for child (so output prints in right order) */
+          waitpid(forkpid, NULL, 0);
+        }
+        break;
       case S_SIG:
 	signame = strsig(pfs.val);
 	fprintf(trussinfo->outfile, "SIGNAL %lu (%s)\n", pfs.val,
Index: usr.bin/truss/sparc64-fbsd.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/usr.bin/truss/sparc64-fbsd.c,v
retrieving revision 1.7
diff -u -u -r1.7 sparc64-fbsd.c
--- usr.bin/truss/sparc64-fbsd.c	17 Jul 2004 19:48:49 -0000	1.7
+++ usr.bin/truss/sparc64-fbsd.c	15 Sep 2004 01:20:57 -0000
@@ -162,8 +162,7 @@
 
   if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
    && ((!strcmp(fsc.name, "fork")
-    || !strcmp(fsc.name, "rfork")
-    || !strcmp(fsc.name, "vfork"))))
+    || !strcmp(fsc.name, "rfork"))))
   {
     trussinfo->in_fork = 1;
   }

--- truss-patch ends here ---

>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040915014625.2D021AAF>