[PATCH/v2] Add support for Linux/no-mmu with vfork

Mike Frysinger vapier at gentoo.org
Thu Oct 23 09:47:27 UTC 2008


Systems that lack a MMU cannot use fork() to create the child process.
First we detect if the toolchain has the fork() symbol and if it does not,
we just always use vfork().  If it does, then we try that first.  If it
fails due to ENOSYS, we fall back to using vfork().

Since fork() gets used in a few places, create a strace_fork() macro.
It cannot be a function due to the fun "children of a vfork share the
stack of the parent", so returning from the function the child was
spawned from would clobber the stack when the parent tried to return.

Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
Previous version had a typo in strace_vforked handling for MMU.

 configure.ac |    2 +-
 strace.c     |   30 +++++++++++++++++++++++++++---
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 3554ab6..530c116 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,7 +196,7 @@ if test x$opsys != xlinux; then
 AC_CHECK_LIB(nsl, main)
 fi
 
-AC_CHECK_FUNCS(sigaction strerror strsignal pread sys_siglist _sys_siglist getdents mctl prctl sendmsg inet_ntop if_indextoname)
+AC_CHECK_FUNCS(sigaction strerror strsignal pread sys_siglist _sys_siglist getdents mctl prctl sendmsg inet_ntop if_indextoname fork)
 AC_CHECK_HEADERS([sys/reg.h sys/filio.h sys/acl.h sys/asynch.h sys/door.h stropts.h sys/conf.h sys/stream.h sys/tihdr.h sys/tiuser.h sys/sysconfig.h ioctls.h sys/ioctl.h sys/ptrace.h termio.h linux/ptrace.h asm/reg.h sys/uio.h sys/aio.h poll.h sys/poll.h sys/vfs.h asm/sysmips.h linux/utsname.h sys/nscsys.h mqueue.h sys/epoll.h libaio.h inttypes.h], [], [])
 AC_CHECK_HEADERS([linux/icmp.h linux/in6.h linux/netlink.h linux/if_packet.h],
                  [], [], [#include <stddef.h>
diff --git a/strace.c b/strace.c
index bb59e96..33a85a7 100644
--- a/strace.c
+++ b/strace.c
@@ -191,6 +191,27 @@ foobar()
 #endif /* MIPS */
 #endif /* SVR4 */
 
+/*
+ * Glue for systems without a MMU that cannot provide fork().  Cannot
+ * be a real function as vfork()-ed children may not return from the
+ * function in which they were created (due to shared stack w/parent).
+ */
+#ifdef HAVE_FORK
+static bool strace_vforked = false;
+#define strace_fork() \
+({ \
+	pid_t __child_pid = fork(); \
+	if (__child_pid == -1 && errno == ENOSYS) { \
+		strace_vforked = true; \
+		__child_pid = vfork(); \
+	} \
+	__child_pid; \
+})
+#else
+# define strace_vforked false
+# define strace_fork() vfork()
+#endif
+
 static int
 set_cloexec_flag(int fd)
 {
@@ -293,7 +314,7 @@ strace_popen(const char *command)
 		return NULL;
 	}
 
-	if ((popen_pid = fork()) == -1)
+	if ((popen_pid = strace_fork()) == -1)
 	{
 		fprintf(stderr, "%s: fork: %s\n",
 			progname, strerror(errno));
@@ -523,7 +544,7 @@ startup_child (char **argv)
 			progname, filename);
 		exit(1);
 	}
-	switch (pid = fork()) {
+	switch (pid = strace_fork()) {
 	case -1:
 		perror("strace: fork");
 		cleanup();
@@ -590,8 +611,11 @@ startup_child (char **argv)
 		 * Induce an immediate stop so that the parent
 		 * will resume us with PTRACE_SYSCALL and display
 		 * this execve call normally.
+		 * Unless of course we're on a no-MMU system where
+		 * we vfork()-ed, so we cannot stop the child.
 		 */
-		kill(getpid(), SIGSTOP);
+		if (!strace_vforked)
+			kill(getpid(), SIGSTOP);
 #endif /* !USE_PROCFS */
 
 		execv(pathname, argv);
-- 
1.6.0.2





More information about the Strace-devel mailing list