]> granicus.if.org Git - strace/commitdiff
Begin work on supporting clone
authorWichert Akkerman <wichert@deephackmode.org>
Thu, 23 Dec 1999 15:08:17 +0000 (15:08 +0000)
committerWichert Akkerman <wichert@deephackmode.org>
Thu, 23 Dec 1999 15:08:17 +0000 (15:08 +0000)
ChangeLog
defs.h
process.c
syscall.c
util.c

index 959068c6ed46a30e8d6e2bb337cb2897b2820fd0..e7b1c8710703d9f917aa558a006f6cb9b9da628f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@ Thu Dec 23 15:01:37 CET 1999 Wichert Akkerman <wakkerma@debian.org>
 
   * Merge patch from ftp://oss.software.ibm.com/linux390/ to add
     support for Linux on the IBM S/390 architecture
+  * process.c: add internal_clone(), currently only shows the options
+  * syscall.c: use internal_clone to handle SYS_clone
 
 Mon Dec 20 00:27:50 CET 1999 Wichert Akkerman <wakkerma@debian.org>
 
diff --git a/defs.h b/defs.h
index d65fc152c061f444f97d000b754a134058beca73..cae320a14bb708b68bed274323b19cf32d979f7c 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -336,6 +336,9 @@ extern void call_summary P((FILE *));
 extern void fake_execve P((struct tcb *, char *, char *[], char *[]));
 extern void printtv32 P((struct tcb*, long));
 
+#ifdef LINUX
+extern int internal_clone P((struct tcb *));
+#endif
 extern int internal_fork P((struct tcb *));
 extern int internal_exec P((struct tcb *));
 extern int internal_wait P((struct tcb *));
index ea78824a9d1e1598a3836c309c2e9e41ef05a573..ae7b8e4a06c9b93d02d69d4649e2916e5400558f 100644 (file)
--- a/process.c
+++ b/process.c
@@ -78,7 +78,7 @@
 #define WCOREDUMP(status) ((status) & 0200)
 #endif
 
-/* WTA: this has `&& !defined(LINUXSPARC)', this seems unneeded though? */
+/* WTA: this was `&& !defined(LINUXSPARC)', this seems unneeded though? */
 #if defined(HAVE_PRCTL)
 static struct xlat prctl_options[] = {
 #ifdef PR_MAXPROCS
@@ -316,6 +316,35 @@ struct tcb *tcp;
 
 #else /* !SVR4 */
 
+#ifdef LINUX
+
+/* defines copied from linux/sched.h since we can't include that
+ * ourselves (it conflicts with *lots* of libc includes)
+ */
+#define CSIGNAL         0x000000ff      /* signal mask to be sent at exit */
+#define CLONE_VM        0x00000100      /* set if VM shared between processes */
+#define CLONE_FS        0x00000200      /* set if fs info shared between processes */
+#define CLONE_FILES     0x00000400      /* set if open files shared between processes */
+#define CLONE_SIGHAND   0x00000800      /* set if signal handlers shared */
+#define CLONE_PID       0x00001000      /* set if pid shared */
+#define CLONE_PTRACE    0x00002000      /* set if we want to let tracing continue on the child too */
+#define CLONE_VFORK     0x00004000      /* set if the parent wants the child to wake it up on mm_release */
+#define CLONE_PARENT    0x00008000      /* set if we want to have the same parent as the cloner */
+
+static struct xlat clone_flags[] = {
+    { CLONE_VM,                "CLONE_VM"      },
+    { CLONE_FS,                "CLONE_FS"      },
+    { CLONE_FILES,     "CLONE_FILES"   },
+    { CLONE_SIGHAND,   "CLONE_SIGHAND" },
+    { CLONE_PID,       "CLONE_PID"     },
+    { CLONE_PTRACE,    "CLONE_PTRACE"  },
+    { CLONE_VFORK,     "CLONE_VFORK"   },
+    { CLONE_PARENT,    "CLONE_PARENT"  },
+    { 0,               NULL            },
+};
+
+#endif
+
 int
 sys_fork(tcp)
 struct tcb *tcp;
@@ -325,6 +354,66 @@ struct tcb *tcp;
        return 0;
 }
 
+#ifdef SYS_clone
+int
+internal_clone(tcp)
+struct tcb *tcp;
+{
+       if (entering(tcp)) {
+               tprintf("fn=%#lx, child_stack=%#lx, flags=",
+                               tcp->u_arg[0], tcp->u_arg[1]);
+               if (printflags(clone_flags, tcp->u_arg[2]) == 0)
+                       tprintf("0");
+               tprintf(", args=%#lx", tcp->u_arg[3]);
+
+               /* For now we don't follow clone yet.. we're just preparing the code */
+               dont_follow = 1;
+
+               if (!followfork || dont_follow)
+                       return 0;
+               if (nprocs == MAX_PROCS) {
+                       tcp->flags &= ~TCB_FOLLOWFORK;
+                       fprintf(stderr, "sys_fork: tcb table full\n");
+                       return 0;
+               }
+               tcp->flags |= TCB_FOLLOWFORK;
+
+               /* XXX 
+               /* We will take the simple approach and add CLONE_PTRACE to the clone
+                * options. This only works on Linux 2.2.x and later. This means that
+                * we break all programs using clone on older kernels..
+                * We should try to fallback to the bpt-trick if this fails, but right
+                * now we don't.
+                */
+
+               /* TODO: actually change the flags */
+       } else {
+               if (!(tcp->flags & TCB_FOLLOWFORK))
+                       return 0;
+
+               if (syserror(tcp))
+                       return 0;
+
+               pid = tcp->u_rval;
+               if ((tcpchild = alloctcb(pid)) == NULL) {
+                       fprintf(stderr, " [tcb table full]\n");
+                       kill(pid, SIGKILL); /* XXX */
+                       return 0;
+               }
+
+               /* For fork we need to re-attach, but thanks to CLONE_PTRACE we're
+                * already attached.
+                */
+               tcphild->flags |= TCB_ATTACHED;
+               newoutf(tcpfhild);
+               tcp->nchildren++;
+               if (!qflag)
+                       fprintf(stderr, "Process %d attached\n", pid);
+       }
+       return 0;
+}
+#endif
+
 int
 internal_fork(tcp)
 struct tcb *tcp;
@@ -349,9 +438,17 @@ struct tcb *tcp;
 #endif
 #ifdef SYS_clone
        /* clone can do many things, not all of which we know how to handle.
-          Don't do it for now. */
-       if (tcp->scno == SYS_clone)
+          Don't do much for now. */
+       if (tcp->scno == SYS_clone) {
+               if (entering(tcp)) {
+                       tprintf("fn=%#lx, child_stack=%#lx, flags=",
+                                       tcp->u_arg[0], tcp->u_arg[1]);
+                       if (printflags(clone_flags, tcp->u_arg[2]) == 0)
+                           tprintf("0");
+                       tprintf(", args=%#lx", tcp->u_arg[3]);
+               }
                dont_follow = 1;
+       }
 #endif
        if (entering(tcp)) {
                if (!followfork || dont_follow)
@@ -364,7 +461,7 @@ struct tcb *tcp;
                tcp->flags |= TCB_FOLLOWFORK;
                if (setbpt(tcp) < 0)
                        return 0;
-       }
+       }
        else {
                int bpt = tcp->flags & TCB_BPTSET;
 
index 2b23471da0efa2a2c4db18930c7866c8bf0c6bae..19739a87ea903fd92ab17fff2971490c6a8afc92 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -531,12 +531,13 @@ struct tcb *tcp;
 #ifdef SYS_vfork
        case SYS_vfork:
 #endif
+               internal_fork(tcp);
+               break;
 #ifdef SYS_clone
        case SYS_clone:
-#endif
-               internal_fork(tcp);
+               internal_clone(tcp);
                break;
-
+#endif
 #ifdef SYS_execv
        case SYS_execv:
 #endif
diff --git a/util.c b/util.c
index 5c38e66be6298ff9bd888d4f687032b71f41cea2..2d55f8ed771763fc5aed126f978e358841e00991 100644 (file)
--- a/util.c
+++ b/util.c
@@ -871,7 +871,6 @@ struct tcb *tcp;
 
 #ifdef LINUX
        long pc;
-
 #if defined(I386)
        if (upeek(tcp->pid, 4*EIP, &pc) < 0)
                return -1;
@@ -897,9 +896,7 @@ struct tcb *tcp;
        pc = regs.r_pc;
 #elif defined(S390)
        if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
-               return -1;
-
-#else
+#endif
        return pc;
 #endif /* LINUX */