]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix 342040 Valgrind mishandles clone with CLONE_VFORK | CLONE_VM that clones to a...
authorPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Sun, 11 Dec 2016 21:39:23 +0000 (21:39 +0000)
committerPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Sun, 11 Dec 2016 21:39:23 +0000 (21:39 +0000)
Fix 373192 Calling posix_spawn in glibc 2.24 completely broken

Functionally, this patch just does the following 2 changes to the
fork clone handling:
* It does not mask anymore CLONE_VFORK :
  The only effect of this flag is to suspend the parent, waiting for
  the child to either exit or execve.
  If some applications depends on this synchronisation, better keep it,
  as it will not harm to suspend the parent valgrind waiting for the
  child valgrind to exit or execve.
* In case the guest calls the clone syscall providing a non zero client stack,
  set the child guest SP after the syscall, before executing guest instructions.
  Not setting the guest stack ptr was the source of the problem reported
  in the bugs.

This also adds a test case  none/tests/linux/clonev.
Before this patch, test gives a SEGV, which is fixed by the patch.

The patch is however a lot bigger : this fix was touching some (mostly
identical/duplicated) code in all the linux platforms.
So, the clone/fork code has been factorised as much as possible.
This removes about 1700 lines of code.

This has been tested on:
* amd64
* x86
* ppc64 be and le
* ppc32
* arm64

This has been compiled on but *not really tested* on:
* mips64 (not too clear how to properly build and run valgrind on gcc22)

It has *not* been compiled and *not* tested on:
* arm
* mips32
* tilegx
* darwin   (normally, no impact)
* solaris  (normally, no impact)

The changes are relatively mechanical, so it is not impossible that
it will compile and work out of the box on these platforms.
Otherwise, questions welcome.

A few points of interest:
* Some platforms did have a typedef void vki_modify_ldt_t,
  and some platforms had no definition for this type at all.
  To make it easier to factorise, for such platforms, the following has
  been used:
     typedef char vki_modify_ldt_t;
    When the sizeof vki_modify_ldt_t is > 1, then the arg syscall is checked.
  This is somewhat a hack, but was simplifying the factorisation.

* for mips32/mips64 and tilegx, there is a strange unconditional assignment
  of 0 to a register (guest_r2 on mips, guest_r0 on tilegx).
  Unclear what this is, in particular because this is assigned whatever
  the result of the syscall (success or not).

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16186

24 files changed:
NEWS
coregrind/m_syswrap/priv_syswrap-linux.h
coregrind/m_syswrap/syswrap-amd64-linux.c
coregrind/m_syswrap/syswrap-arm-linux.c
coregrind/m_syswrap/syswrap-arm64-linux.c
coregrind/m_syswrap/syswrap-linux.c
coregrind/m_syswrap/syswrap-mips32-linux.c
coregrind/m_syswrap/syswrap-mips64-linux.c
coregrind/m_syswrap/syswrap-ppc32-linux.c
coregrind/m_syswrap/syswrap-ppc64-linux.c
coregrind/m_syswrap/syswrap-s390x-linux.c
coregrind/m_syswrap/syswrap-tilegx-linux.c
coregrind/m_syswrap/syswrap-x86-linux.c
include/vki/vki-arm64-linux.h
include/vki/vki-mips32-linux.h
include/vki/vki-mips64-linux.h
include/vki/vki-ppc32-linux.h
include/vki/vki-ppc64-linux.h
include/vki/vki-s390x-linux.h
none/tests/linux/Makefile.am
none/tests/linux/clonev.c [new file with mode: 0644]
none/tests/linux/clonev.stderr.exp [new file with mode: 0644]
none/tests/linux/clonev.stdout.exp [new file with mode: 0644]
none/tests/linux/clonev.vgtest [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 5b7190f628b49b6c235d7e0951f1561baa789dbd..fe609aa3019558259f16ba739ca528c474d6ecca 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,7 +28,12 @@ X86/MacOSX 10.11/12, AMD64/MacOSX 10.11/12 and TILEGX/Linux.
 
 * ================== PLATFORM CHANGES =================
 
-  Support for demangling Rust symbols (n-i-bz)
+  - Support for demangling Rust symbols (n-i-bz)
+  
+  - On linux, clone handling was improved to honour the CLONE_VFORK flag
+    and setting a child stack. Note however that CLONE_VFORK | CLONE_VM
+    is handled like CLONE_VFORK (so removing CLONE_VM flag).
+    Applications that depends on CLONE_VM exact semantic will (still) not work.
 
 * ==================== TOOL CHANGES ====================
 
@@ -71,6 +76,8 @@ To see details of a given bug, visit
   https://bugs.kde.org/show_bug.cgi?id=XXXXXX
 where XXXXXX is the bug number as listed below.
 
+342040  Valgrind mishandles clone with CLONE_VFORK | CLONE_VM that clones
+        to a different stack.
 348616  Wine/valgrind: noted but unhandled ioctl 0x5390 [..] (DVD_READ_STRUCT)
 352395  Please provide SVN revision info in --version -v
 352767  Wine/valgrind: noted but unhandled ioctl 0x5307 [..] (CDROMSTOP)
@@ -83,6 +90,7 @@ where XXXXXX is the bug number as listed below.
 372504  Hanging on exit_group
 372600  process loops forever when fatal signals are arriving quickly
 373046  Stacks registered by core are never deregistered
+373192  Calling posix_spawn in glibc 2.24 completely broken
 
 Release 3.12.0 (20 October 2016)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 38fcd7b6253277e7d06d98b5ed7a2b3e558bdf7b..06ea7cde68bedffcc3a07db08ee56991bdd411aa 100644 (file)
@@ -39,12 +39,10 @@ extern Word ML_(start_thread_NORETURN) ( void* arg );
 extern Addr ML_(allocstack)            ( ThreadId tid );
 extern void ML_(call_on_new_stack_0_1) ( Addr stack, Addr retaddr,
                                         void (*f)(Word), Word arg1 );
-extern SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
-                                   Int* parent_tidptr, Int* child_tidptr );
-
 
 // Linux-specific (but non-arch-specific) syscalls
 
+DECL_TEMPLATE(linux, sys_clone)
 DECL_TEMPLATE(linux, sys_mount);
 DECL_TEMPLATE(linux, sys_oldumount);
 DECL_TEMPLATE(linux, sys_umount);
@@ -61,6 +59,10 @@ DECL_TEMPLATE(linux, sys_vmsplice);
 DECL_TEMPLATE(linux, sys_readahead);
 DECL_TEMPLATE(linux, sys_move_pages);
 
+// clone is similar enough between linux variants to have a generic
+// version, but which will call an extern defined in syswrap-<platform>-linux.c
+DECL_TEMPLATE(linux, sys_clone);
+
 // POSIX, but various sub-cases differ between Linux and Darwin.
 DECL_TEMPLATE(linux, sys_fcntl);
 DECL_TEMPLATE(linux, sys_fcntl64);
@@ -368,7 +370,83 @@ DECL_TEMPLATE(linux, sys_getpeername);
 DECL_TEMPLATE(linux, sys_socketpair);
 DECL_TEMPLATE(linux, sys_kcmp);
 
-#endif   // __PRIV_SYSWRAP_LINUX_H
+// Some arch specific functions called from syswrap-linux.c
+extern Int do_syscall_clone_x86_linux ( Word (*fn)(void *), 
+                                        void* stack, 
+                                        Int   flags, 
+                                        void* arg,
+                                        Int*  child_tid, 
+                                        Int*  parent_tid, 
+                                        void* tls_ptr);
+extern SysRes ML_(x86_sys_set_thread_area) ( ThreadId tid,
+                                             vki_modify_ldt_t* info );
+extern void ML_(x86_setup_LDT_GDT) ( /*OUT*/ ThreadArchState *child, 
+                                     /*IN*/  ThreadArchState *parent );
+
+extern Long do_syscall_clone_amd64_linux ( Word (*fn)(void *), 
+                                           void* stack, 
+                                           Long  flags, 
+                                           void* arg,
+                                           Int* child_tid, 
+                                           Int* parent_tid, 
+                                           void* tls_ptr);
+extern ULong do_syscall_clone_ppc32_linux ( Word (*fn)(void *), 
+                                            void* stack, 
+                                            Int   flags, 
+                                            void* arg,
+                                            Int*  child_tid, 
+                                            Int*  parent_tid, 
+                                            void* tls_ptr);
+extern ULong do_syscall_clone_ppc64_linux ( Word (*fn)(void *), 
+                                            void* stack, 
+                                            Int   flags, 
+                                            void* arg,
+                                            Int*  child_tid, 
+                                            Int*  parent_tid, 
+                                            void* tls_ptr );
+extern ULong do_syscall_clone_s390x_linux ( void  *stack,
+                                            ULong flags,
+                                            Int   *parent_tid,
+                                            Int   *child_tid,
+                                            void*  tls_ptr,
+                                            Word (*fn)(void *),
+                                            void  *arg);
+extern Long do_syscall_clone_arm64_linux ( Word (*fn)(void *), 
+                                           void* stack, 
+                                           Long  flags, 
+                                           void* arg,
+                                           Int*  child_tid,
+                                           Int*  parent_tid,
+                                           void* tls_ptr );
+extern ULong do_syscall_clone_arm_linux   ( Word (*fn)(void *), 
+                                            void* stack, 
+                                            Int   flags, 
+                                            void* arg,
+                                            Int*  child_tid,
+                                            Int*  parent_tid,
+                                            void* tls_ptr );
+extern ULong do_syscall_clone_mips64_linux ( Word (*fn) (void *),  /* a0 - 4 */
+                                             void* stack,          /* a1 - 5 */
+                                             Int   flags,          /* a2 - 6 */
+                                             void* arg,            /* a3 - 7 */
+                                             Int*  parent_tid,     /* a4 - 8 */
+                                             void* tls_ptr,        /* a5 - 9 */
+                                             Int*  child_tid );    /* a6 - 10 */
+extern UInt do_syscall_clone_mips_linux ( Word (*fn) (void *), //a0     0    32
+                                          void* stack,         //a1     4    36
+                                          Int   flags,         //a2     8    40
+                                          void* arg,           //a3     12   44
+                                          Int*  child_tid,     //stack  16   48
+                                          Int*  parent_tid,    //stack  20   52
+                                          void* tls_ptr);      //stack  24   56
+extern Long do_syscall_clone_tilegx_linux ( Word (*fn) (void *),  //r0
+                                            void* stack,          //r1
+                                            Long  flags,          //r2
+                                            void* arg,            //r3
+                                            Long* child_tid,      //r4
+                                            Long* parent_tid,     //r5
+                                            void* tls_ptr );      //r6
+ #endif   // __PRIV_SYSWRAP_LINUX_H
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
index 08e9a93f17ef06fce8629857d8627ef68a110e5e..3fe993825effe191d0f8d0ce8e0751f55b97b8f4 100644 (file)
@@ -130,14 +130,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-Long do_syscall_clone_amd64_linux ( Word (*fn)(void *), 
-                                    void* stack, 
-                                    Long  flags, 
-                                    void* arg,
-                                    Long* child_tid, 
-                                    Long* parent_tid, 
-                                    vki_modify_ldt_t * );
+// See priv_syswrap-linux.h for arg profile.
 asm(
 ".text\n"
 ".globl do_syscall_clone_amd64_linux\n"
@@ -183,126 +176,6 @@ asm(
 #undef __NR_EXIT
 
 
-// forward declaration
-static void setup_child ( ThreadArchState*, ThreadArchState* );
-
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for EIP, and a separate stack
-   for ESP.
- */
-static SysRes do_clone ( ThreadId ptid, 
-                         ULong flags, Addr rsp, 
-                         Long* parent_tidptr, 
-                         Long* child_tidptr, 
-                         Addr tlsaddr )
-{
-   static const Bool debug = False;
-
-   ThreadId     ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   UWord*       stack;
-   SysRes       res;
-   Long         rax;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-   /* Copy register state
-
-      Both parent and child return to the same place, and the code
-      following the clone syscall works out which is which, so we
-      don't need to worry about it.
-
-      The parent gets the child's new tid returned from clone, but the
-      child gets 0.
-
-      If the clone call specifies a NULL rsp for the new thread, then
-      it actually gets a copy of the parent's rsp.
-   */
-   setup_child( &ctst->arch, &ptst->arch );
-
-   /* Make sys_clone appear to have returned Success(0) in the
-      child. */
-   ctst->arch.vex.guest_RAX = 0;
-
-   if (rsp != 0)
-      ctst->arch.vex.guest_RSP = rsp;
-
-   ctst->os_state.parent = ptid;
-
-   /* inherit signal mask */
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (rsp, ctst);
-
-   /* Assume the clone will succeed, and tell any tool that wants to
-      know that this thread has come into existence.  If the clone
-      fails, we'll send out a ll_exit notification for it at the out:
-      label below, to clean up. */
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      if (debug)
-        VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr);
-      ctst->arch.vex.guest_FS_CONST = tlsaddr;
-   }
-
-   flags &= ~VKI_CLONE_SETTLS;
-
-   /* start the thread with everything blocked */
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   /* Create the new thread */
-   rax = do_syscall_clone_amd64_linux(
-            ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
-            child_tidptr, parent_tidptr, NULL
-         );
-   res = VG_(mk_SysRes_amd64_linux)( rax );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-  out:
-   if (sr_isError(res)) {
-      /* clone failed */
-      VG_(cleanup_thread)(&ctst->arch);
-      ctst->status = VgTs_Empty;
-      /* oops.  Better tell the tool the thread exited in a hurry :-) */
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-}
-
-
 /* ---------------------------------------------------------------------
    More thread stuff
    ------------------------------------------------------------------ */
@@ -311,16 +184,6 @@ void VG_(cleanup_thread) ( ThreadArchState *arch )
 {  
 }  
 
-void setup_child ( /*OUT*/ ThreadArchState *child, 
-                   /*IN*/  ThreadArchState *parent )
-{  
-   /* We inherit our parent's guest state. */
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}  
-
-
 /* ---------------------------------------------------------------------
    PRE/POST wrappers for AMD64/Linux-specific syscalls
    ------------------------------------------------------------------ */
@@ -333,7 +196,6 @@ void setup_child ( /*OUT*/ ThreadArchState *child,
    the right thing to do is to make these wrappers 'static' since they
    aren't visible outside this file, but that requires even more macro
    magic. */
-DECL_TEMPLATE(amd64_linux, sys_clone);
 DECL_TEMPLATE(amd64_linux, sys_rt_sigreturn);
 DECL_TEMPLATE(amd64_linux, sys_arch_prctl);
 DECL_TEMPLATE(amd64_linux, sys_ptrace);
@@ -342,108 +204,6 @@ DECL_TEMPLATE(amd64_linux, sys_mmap);
 DECL_TEMPLATE(amd64_linux, sys_syscall184);
 
 
-PRE(sys_clone)
-{
-   ULong cloneflags;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-   PRE_REG_READ2(int, "clone",
-                 unsigned long, flags,
-                 void *, child_stack);
-
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA3("clone", int *, parent_tidptr);
-      }
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG1 & VKI_CLONE_SETTLS) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA4("clone", vki_modify_ldt_t *, tlsinfo);
-      }
-      PRE_MEM_READ("clone(tlsinfo)", ARG4, sizeof(vki_modify_ldt_t));
-      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(vki_modify_ldt_t), 
-                                             VKI_PROT_READ)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA5("clone", int *, child_tidptr);
-      }
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG4, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(Int), VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-
-   cloneflags = ARG1;
-
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  ARG1,          /* flags */
-                  (Addr)ARG2,    /* child ESP */
-                  (Long *)ARG3,  /* parent_tidptr */
-                  (Long *)ARG4,  /* child_tidptr */
-                  (Addr)ARG5));  /* set_tls */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,      /* flags */
-                       (Int *)ARG3,     /* parent_tidptr */
-                       (Int *)ARG4));   /* child_tidptr */
-      break;
-
-   default:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg,
-                   "Unsupported clone() flags: 0x%lx\n", ARG1);
-      VG_(message)(Vg_UserMsg,
-                   "\n");
-      VG_(message)(Vg_UserMsg,
-                   "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg,
-                   " - via a threads library (LinuxThreads or NPTL)\n");
-      VG_(message)(Vg_UserMsg,
-                   " - via the implementation of fork or vfork\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG4, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_rt_sigreturn)
 {
    /* This isn't really a syscall at all - it's a misuse of the
@@ -761,7 +521,7 @@ static SyscallTableEntry syscall_table[] = {
    LINX_(__NR_setsockopt,        sys_setsockopt),     // 54
 
    LINXY(__NR_getsockopt,        sys_getsockopt),     // 55 
-   PLAX_(__NR_clone,             sys_clone),          // 56 
+   LINX_(__NR_clone,             sys_clone),          // 56 
    GENX_(__NR_fork,              sys_fork),           // 57 
    GENX_(__NR_vfork,             sys_fork),           // 58 treat as fork
    GENX_(__NR_execve,            sys_execve),         // 59 
index 3bbd109564f8188602de5d479b5e59d1b1b10242..b417428d67be992ae250b1e3dbcff27e3750cc83 100644 (file)
@@ -102,14 +102,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-ULong do_syscall_clone_arm_linux   ( Word (*fn)(void *), 
-                                     void* stack, 
-                                     Int   flags, 
-                                     void* arg,
-                                     Int*  child_tid,
-                                     Int*  parent_tid,
-                                     void* tls );
+// See priv_syswrap-linux.h for arg profile.
 asm(
 ".text\n"
 ".globl do_syscall_clone_arm_linux\n"
@@ -148,104 +141,8 @@ asm(
 #undef __NR_EXIT
 
 // forward declarations
-static void setup_child ( ThreadArchState*, ThreadArchState* );
-static void assign_guest_tls(ThreadId ctid, Addr tlsptr);
 static SysRes sys_set_tls ( ThreadId tid, Addr tlsptr );
             
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */
-static SysRes do_clone ( ThreadId ptid, 
-                         UInt flags, Addr sp, 
-                         Int *parent_tidptr, 
-                         Int *child_tidptr, 
-                         Addr child_tls)
-{
-   ThreadId ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   UInt r0;
-   UWord *stack;
-   SysRes res;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-
-   if(stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-   setup_child( &ctst->arch, &ptst->arch );
-
-   ctst->arch.vex.guest_R0 = 0;
-   if(sp != 0)
-      ctst->arch.vex.guest_R13 = sp;
-
-   ctst->os_state.parent = ptid;
-
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (sp, ctst);
-
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      /* Just assign the tls pointer in the guest TPIDRURO. */
-      assign_guest_tls(ctid, child_tls);
-   }
-    
-   flags &= ~VKI_CLONE_SETTLS;
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   r0 = do_syscall_clone_arm_linux(
-      ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
-      child_tidptr, parent_tidptr, NULL
-   );
-   //VG_(printf)("AFTER SYSCALL, %x and %x  CHILD: %d PARENT: %d\n",child_tidptr, parent_tidptr,*child_tidptr,*parent_tidptr);
-    
-   res = VG_(mk_SysRes_arm_linux)( r0 );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-out:
-   if (sr_isError(res)) {
-      VG_(cleanup_thread)(&ctst->arch);
-      ctst->status = VgTs_Empty;
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-}
-
-
-
 /* ---------------------------------------------------------------------
    More thread stuff
    ------------------------------------------------------------------ */
@@ -256,26 +153,13 @@ void VG_(cleanup_thread) ( ThreadArchState* arch )
 {
 }  
 
-void setup_child ( /*OUT*/ ThreadArchState *child,
-                   /*IN*/  ThreadArchState *parent )
-{
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}
-
-static void assign_guest_tls(ThreadId tid, Addr tlsptr)
-{
-   VG_(threads)[tid].arch.vex.guest_TPIDRURO = tlsptr;
-}
-
 /* Assigns tlsptr to the guest TPIDRURO.
    If needed for the specific hardware, really executes
    the set_tls syscall.
 */
 static SysRes sys_set_tls ( ThreadId tid, Addr tlsptr )
 {
-   assign_guest_tls(tid, tlsptr);
+   VG_(threads)[tid].arch.vex.guest_TPIDRURO = tlsptr;
 
    if (KernelVariantiS(KernelVariant_android_no_hw_tls,
                        VG_(clo_kernel_variant))) {
@@ -333,7 +217,6 @@ DECL_TEMPLATE(arm_linux, sys_stat64);
 DECL_TEMPLATE(arm_linux, sys_lstat64);
 DECL_TEMPLATE(arm_linux, sys_fstatat64);
 DECL_TEMPLATE(arm_linux, sys_fstat64);
-DECL_TEMPLATE(arm_linux, sys_clone);
 DECL_TEMPLATE(arm_linux, sys_sigreturn);
 DECL_TEMPLATE(arm_linux, sys_rt_sigreturn);
 DECL_TEMPLATE(arm_linux, sys_sigsuspend);
@@ -424,100 +307,6 @@ POST(sys_fstat64)
    POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
 }
 
-PRE(sys_clone)
-{
-    UInt cloneflags;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-   PRE_REG_READ5(int, "clone",
-                 unsigned long, flags,
-                 void *, child_stack,
-                 int *, parent_tidptr,
-                 void *, child_tls,
-                 int *, child_tidptr);
-
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG5, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG1 & VKI_CLONE_SETTLS) {
-      PRE_MEM_READ("clone(tls_user_desc)", ARG4, sizeof(vki_modify_ldt_t));
-      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(vki_modify_ldt_t), 
-                                             VKI_PROT_READ)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-
-   cloneflags = ARG1;
-
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  ARG1,         /* flags */
-                  (Addr)ARG2,   /* child ESP */
-                  (Int *)ARG3,  /* parent_tidptr */
-                  (Int *)ARG5,  /* child_tidptr */
-                  (Addr)ARG4)); /* set_tls */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,      /* flags */
-                       (Int *)ARG3,     /* parent_tidptr */
-                       (Int *)ARG5));   /* child_tidptr */
-      break;
-
-   default:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
-      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
-      VG_(message)(Vg_UserMsg, " - for the Quadrics Elan3 user-space driver\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG5, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_sigreturn)
 {
    /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
@@ -901,7 +690,7 @@ static SyscallTableEntry syscall_main_table[] = {
    GENX_(__NR_fsync,             sys_fsync),          // 118
    PLAX_(__NR_sigreturn,         sys_sigreturn),      // 119 ?/Linux
 
-   PLAX_(__NR_clone,             sys_clone),          // 120
+   LINX_(__NR_clone,             sys_clone),          // 120
 //zz    //   (__NR_setdomainname,     sys_setdomainname),  // 121 */*(?)
    GENXY(__NR_uname,             sys_newuname),       // 122
 //   PLAX_(__NR_modify_ldt,        sys_modify_ldt),     // 123
index 6b579e82593a69aafce4d16c00eb86b29228c064..1be66297df32a4c4c62f3f07ce4df08338383d4a 100644 (file)
@@ -138,14 +138,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-Long do_syscall_clone_arm64_linux ( Word (*fn)(void *), 
-                                    void* child_stack, 
-                                    Long  flags, 
-                                    void* arg,
-                                    Int*  child_tid,
-                                    Int*  parent_tid,
-                                    void* tls );
+// See priv_syswrap-linux.h for arg profile.
 asm(
 ".text\n"
 ".globl do_syscall_clone_arm64_linux\n"
@@ -196,121 +189,6 @@ static void setup_child ( ThreadArchState*, ThreadArchState* );
 static void assign_guest_tls(ThreadId ctid, Addr tlsptr);
 //ZZ static SysRes sys_set_tls ( ThreadId tid, Addr tlsptr );
             
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */
-static SysRes do_clone ( ThreadId ptid, 
-                         ULong flags,
-                         Addr  child_xsp, 
-                         Int*  parent_tidptr, 
-                         Int*  child_tidptr, 
-                         Addr  child_tls )
-{
-   ThreadId     ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   UWord*       stack;
-   SysRes       res;
-   ULong        x0;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-   /* Copy register state
-
-      Both parent and child return to the same place, and the code
-      following the clone syscall works out which is which, so we
-      don't need to worry about it.
-
-      The parent gets the child's new tid returned from clone, but the
-      child gets 0.
-
-      If the clone call specifies a NULL xsp for the new thread, then
-      it actually gets a copy of the parent's xsp.
-   */
-   setup_child( &ctst->arch, &ptst->arch );
-
-   /* Make sys_clone appear to have returned Success(0) in the
-      child. */
-   ctst->arch.vex.guest_X0 = 0;
-
-   if (child_xsp != 0)
-      ctst->arch.vex.guest_XSP = child_xsp;
-
-   ctst->os_state.parent = ptid;
-
-   /* inherit signal mask */
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack)(child_xsp, ctst);
-
-   /* Assume the clone will succeed, and tell any tool that wants to
-      know that this thread has come into existence.  If the clone
-      fails, we'll send out a ll_exit notification for it at the out:
-      label below, to clean up. */
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      /* Just assign the tls pointer in the guest TPIDR_EL0. */
-      assign_guest_tls(ctid, child_tls);
-   }
-    
-   flags &= ~VKI_CLONE_SETTLS;
-
-   /* start the thread with everything blocked */
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   x0 = do_syscall_clone_arm64_linux(
-      ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
-      child_tidptr, parent_tidptr, NULL
-   );
-    
-   res = VG_(mk_SysRes_arm64_linux)( x0 );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-  out:
-   if (sr_isError(res)) {
-      /* clone failed */
-      VG_(cleanup_thread)(&ctst->arch);
-      ctst->status = VgTs_Empty;
-      /* oops.  Better tell the tool the thread exited in a hurry :-) */
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-}
-
-
 /* ---------------------------------------------------------------------
    More thread stuff
    ------------------------------------------------------------------ */
@@ -397,7 +275,6 @@ DECL_TEMPLATE(arm64_linux, sys_mmap);
 //ZZ DECL_TEMPLATE(arm_linux, sys_lstat64);
 //ZZ DECL_TEMPLATE(arm_linux, sys_fstatat64);
 //ZZ DECL_TEMPLATE(arm_linux, sys_fstat64);
-DECL_TEMPLATE(arm64_linux, sys_clone);
 //ZZ DECL_TEMPLATE(arm_linux, sys_sigreturn);
 DECL_TEMPLATE(arm64_linux, sys_rt_sigreturn);
 //ZZ DECL_TEMPLATE(arm_linux, sys_sigsuspend);
@@ -512,110 +389,6 @@ PRE(sys_mmap)
 //ZZ    POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
 //ZZ }
 
-/* Aarch64 seems to use CONFIG_CLONE_BACKWARDS in the kernel.  See:
-      http://dev.gentoo.org/~vapier/aarch64/linux-3.12.6.config
-      http://people.redhat.com/wcohen/aarch64/aarch64_config
-   from linux-3.10.5/kernel/fork.c 
-    #ifdef CONFIG_CLONE_BACKWARDS
-    SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
-                     int __user *, parent_tidptr,
-                     int, tls_val,
-                     int __user *, child_tidptr)
-*/
-PRE(sys_clone)
-{
-   UInt cloneflags;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-   PRE_REG_READ5(int, "clone",
-                 unsigned long, flags,
-                 void *, child_stack,
-                 int *, parent_tidptr,
-                 void *, child_tls,
-                 int *, child_tidptr);
-
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-//ZZ    if (ARG1 & VKI_CLONE_SETTLS) {
-//ZZ       PRE_MEM_READ("clone(tls_user_desc)", ARG4, sizeof(vki_modify_ldt_t));
-//ZZ       if (!VG_(am_is_valid_for_client)(ARG4, sizeof(vki_modify_ldt_t), 
-//ZZ                                              VKI_PROT_READ)) {
-//ZZ          SET_STATUS_Failure( VKI_EFAULT );
-//ZZ          return;
-//ZZ       }
-//ZZ    }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG5, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-
-   cloneflags = ARG1;
-
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  ARG1,         /* flags */
-                  (Addr)ARG2,   /* child SP */
-                  (Int*)ARG3,   /* parent_tidptr */
-                  (Int*)ARG5,   /* child_tidptr */
-                  (Addr)ARG4)); /* tls_val */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,     /* flags */
-                       (Int*)ARG3,     /* parent_tidptr */
-                       (Int*)ARG5));   /* child_tidptr */
-      break;
-
-   default:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
-      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
-      VG_(message)(Vg_UserMsg, " - for the Quadrics Elan3 user-space driver\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG5, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 //ZZ PRE(sys_sigreturn)
 //ZZ {
 //ZZ    /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
@@ -1072,7 +845,7 @@ static SyscallTableEntry syscall_main_table[] = {
    LINX_(__NR_add_key,           sys_add_key),           // 217
 
    LINXY(__NR_keyctl,            sys_keyctl),            // 219
-   PLAX_(__NR_clone,             sys_clone),             // 220
+   LINX_(__NR_clone,             sys_clone),             // 220
    GENX_(__NR_execve,            sys_execve),            // 221
    PLAX_(__NR_mmap,              sys_mmap),              // 222
    PLAX_(__NR_fadvise64,         sys_fadvise64),         // 223
index b3ffdb1cbfaab3eb683b6620bc092d289ec6d3ce..aa00a5fd456c5bbd98acd92cf53aebaea6926ec0 100644 (file)
@@ -93,9 +93,8 @@ static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW)
    VG_TRACK(pre_thread_first_insn, tid);
 
    tst->os_state.lwpid = VG_(gettid)();
-   /* Set the threadgroup for real.  This overwrites the provisional
-      value set in do_clone() syswrap-*-linux.c.  See comments in
-      do_clone for background, also #226116. */
+   /* Set the threadgroup for real.  This overwrites the provisional value set
+      in do_clone().  See comments in do_clone for background, also #226116. */
    tst->os_state.threadgroup = VG_(getpid)();
 
    /* Thread created with all signals blocked; scheduler will set the
@@ -430,17 +429,327 @@ void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
    vg_assert(0);
 }
 
+/* Clone a new thread. Note that in the clone syscalls, we hard-code
+   tlsaddr argument as NULL : the guest TLS is emulated via guest
+   registers, and Valgrind itself has no thread local storage. */
+static SysRes clone_new_thread ( Word (*fn)(void *), 
+                                 void* stack, 
+                                 Word  flags, 
+                                 ThreadState* ctst,
+                                 Int* child_tidptr, 
+                                 Int* parent_tidptr)
+{
+   SysRes res;
+   /* Note that in all the below, we make sys_clone appear to have returned
+      Success(0) in the child, by assigning the relevant child guest
+      register(s) just before the clone syscall. */
+#if defined(VGP_x86_linux)
+   Int          eax;
+   ctst->arch.vex.guest_EAX = 0;
+   eax = do_syscall_clone_x86_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   res = VG_(mk_SysRes_x86_linux)( eax );
+#elif defined(VGP_amd64_linux)
+   Long         rax;
+   ctst->arch.vex.guest_RAX = 0;
+   rax = do_syscall_clone_amd64_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   res = VG_(mk_SysRes_amd64_linux)( rax );
+#elif defined(VGP_ppc32_linux)
+   ULong        word64;
+   UInt old_cr = LibVEX_GuestPPC32_get_CR( &ctst->arch.vex );
+   /* %r3 = 0 */
+   ctst->arch.vex.guest_GPR3 = 0;
+   /* %cr0.so = 0 */
+   LibVEX_GuestPPC32_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
+   word64 = do_syscall_clone_ppc32_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   /* High half word64 is syscall return value.  Low half is
+      the entire CR, from which we need to extract CR0.SO. */
+   /* VG_(printf)("word64 = 0x%llx\n", word64); */
+   res = VG_(mk_SysRes_ppc32_linux)(/*val*/(UInt)(word64 >> 32), 
+                                    /*errflag*/ (((UInt)word64) >> 28) & 1);
+#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
+   ULong        word64;
+   UInt old_cr = LibVEX_GuestPPC64_get_CR( &ctst->arch.vex );
+   /* %r3 = 0 */
+   ctst->arch.vex.guest_GPR3 = 0;
+   /* %cr0.so = 0 */
+   LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
+   word64 = do_syscall_clone_ppc64_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   /* Low half word64 is syscall return value.  Hi half is
+      the entire CR, from which we need to extract CR0.SO. */
+   /* VG_(printf)("word64 = 0x%llx\n", word64); */
+   res = VG_(mk_SysRes_ppc64_linux)
+      (/*val*/(UInt)(word64 & 0xFFFFFFFFULL), 
+       /*errflag*/ (UInt)((word64 >> (32+28)) & 1));
+#elif defined(VGP_s390x_linux)
+   ULong        r2;
+   ctst->arch.vex.guest_r2 = 0;
+   r2 = do_syscall_clone_s390x_linux
+      (stack, flags, parent_tidptr, child_tidptr, NULL,
+       ML_(start_thread_NORETURN), ctst);
+   res = VG_(mk_SysRes_s390x_linux)( r2 );
+#elif defined(VGP_arm64_linux)
+   ULong        x0;
+   ctst->arch.vex.guest_X0 = 0;
+   x0 = do_syscall_clone_arm64_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   res = VG_(mk_SysRes_arm64_linux)( x0 );
+#elif defined(VGP_arm_linux)
+   UInt r0;
+   ctst->arch.vex.guest_R0 = 0;
+   r0 = do_syscall_clone_arm_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   res = VG_(mk_SysRes_arm_linux)( r0 );
+#elif defined(VGP_mips64_linux)
+   UInt ret = 0;
+   ctst->arch.vex.guest_r2 = 0;
+   ctst->arch.vex.guest_r7 = 0;
+   ret = do_syscall_clone_mips64_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       parent_tidptr, NULL, child_tidptr);
+   res = VG_(mk_SysRes_mips64_linux)( /* val */ ret, 0, /* errflag */ 0);
+#elif defined(VGP_mips32_linux)
+   UInt ret = 0;
+   ctst->arch.vex.guest_r2 = 0;
+   ctst->arch.vex.guest_r7 = 0;
+   ret = do_syscall_clone_mips_linux
+      (ML_(start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   /* High half word64 is syscall return value.  Low half is
+      the entire CR, from which we need to extract CR0.SO. */ 
+   res = VG_ (mk_SysRes_mips32_linux) (/*val */ ret, 0, /*errflag */ 0);
+#elif defined(VGP_tilegx_linux)
+   Long ret = 0;
+   ctst->arch.vex.guest_r0 = 0;
+   ctst->arch.vex.guest_r3 = 0;
+   ret = do_syscall_clone_tilegx_linux
+      (ML_ (start_thread_NORETURN), stack, flags, ctst,
+       child_tidptr, parent_tidptr, NULL);
+   /* High half word64 is syscall return value. */
+   res = VG_(mk_SysRes_tilegx_linux) (/*val */ ret);
+#else
+# error Unknown platform
+#endif
+   return res;
+}
+
+static void setup_child ( /*OUT*/ ThreadArchState *child, 
+                          /*IN*/  ThreadArchState *parent )
+{  
+   /* We inherit our parent's guest state. */
+   child->vex = parent->vex;
+   child->vex_shadow1 = parent->vex_shadow1;
+   child->vex_shadow2 = parent->vex_shadow2;
 
-/* Do a clone which is really a fork() */
-SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
-                            Int* parent_tidptr, Int* child_tidptr )
+#if defined(VGP_x86_linux)
+   extern void ML_(x86_setup_LDT_GDT) ( /*OUT*/ ThreadArchState *child, 
+                                        /*IN*/  ThreadArchState *parent );
+   ML_(x86_setup_LDT_GDT)(child, parent);
+#endif
+}
+
+static SysRes setup_child_tls (ThreadId ctid, Addr tlsaddr)
+{
+   static const Bool debug = False;
+   ThreadState* ctst = VG_(get_ThreadState)(ctid);
+   // res is succesful by default, overriden if a real syscall is needed/done.
+   SysRes res = VG_(mk_SysRes_Success)(0);
+
+   if (debug)
+      VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr);
+
+#if defined(VGP_x86_linux)
+   vki_modify_ldt_t* tlsinfo = (vki_modify_ldt_t*)tlsaddr;
+   if (debug)
+      VG_(printf)("clone child has SETTLS: tls info at %p: idx=%u "
+                  "base=%#lx limit=%x; esp=%#x fs=%x gs=%x\n",
+                  tlsinfo, tlsinfo->entry_number, 
+                  tlsinfo->base_addr, tlsinfo->limit,
+                  ctst->arch.vex.guest_ESP,
+                  ctst->arch.vex.guest_FS, ctst->arch.vex.guest_GS);
+   res = ML_(x86_sys_set_thread_area)(ctid, tlsinfo);
+#elif defined(VGP_amd64_linux)
+   ctst->arch.vex.guest_FS_CONST = tlsaddr;
+#elif defined(VGP_ppc32_linux)
+   ctst->arch.vex.guest_GPR2 = tlsaddr;
+#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
+   ctst->arch.vex.guest_GPR13 = tlsaddr;
+#elif defined(VGP_s390x_linux)
+   ctst->arch.vex.guest_a0 = (UInt) (tlsaddr >> 32);
+   ctst->arch.vex.guest_a1 = (UInt) tlsaddr;
+#elif defined(VGP_arm64_linux)
+   /* Just assign the tls pointer in the guest TPIDR_EL0. */
+   ctst->arch.vex.guest_TPIDR_EL0 = tlsaddr;
+#elif defined(VGP_arm_linux)
+   /* Just assign the tls pointer in the guest TPIDRURO. */
+   ctst->arch.vex.guest_TPIDRURO = tlsaddr;
+#elif defined(VGP_mips64_linux)
+   ctst->arch.vex.guest_ULR = tlsaddr;
+   ctst->arch.vex.guest_r27 = tlsaddr;
+#elif defined(VGP_mips32_linux)
+   ctst->arch.vex.guest_ULR = tlsaddr;
+   ctst->arch.vex.guest_r27 = tlsaddr;
+#elif defined(VGP_tilegx_linux)
+   ctst->arch.vex.guest_r53 = tlsaddr;
+#else
+# error Unknown platform
+#endif
+   return res;
+} 
+
+/* 
+   When a client clones, we need to keep track of the new thread.  This means:
+   1. allocate a ThreadId+ThreadState+stack for the thread
+
+   2. initialize the thread's new VCPU state
+
+   3. create the thread using the same args as the client requested,
+   but using the scheduler entrypoint for EIP, and a separate stack
+   for ESP.
+ */
+static SysRes do_clone ( ThreadId ptid, 
+                         UWord flags, Addr sp, 
+                         Int* parent_tidptr, 
+                         Int* child_tidptr, 
+                         Addr tlsaddr)
+{
+   ThreadId     ctid = VG_(alloc_ThreadState)();
+   ThreadState* ptst = VG_(get_ThreadState)(ptid);
+   ThreadState* ctst = VG_(get_ThreadState)(ctid);
+   UWord*       stack;
+   SysRes       res;
+   vki_sigset_t blockall, savedmask;
+
+   VG_(sigfillset)(&blockall);
+
+   vg_assert(VG_(is_running_thread)(ptid));
+   vg_assert(VG_(is_valid_tid)(ctid));
+
+   stack = (UWord*)ML_(allocstack)(ctid);
+   if (stack == NULL) {
+      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
+      goto out;
+   }
+
+   /* Copy register state
+
+      Both parent and child return to the same place, and the code
+      following the clone syscall works out which is which, so we
+      don't need to worry about it.
+
+      The parent gets the child's new tid returned from clone, but the
+      child gets 0.
+
+      If the clone call specifies a NULL sp for the new thread, then
+      it actually gets a copy of the parent's sp.
+   */
+   setup_child( &ctst->arch, &ptst->arch );
+
+   if (sp != 0)
+      VG_(set_SP)(ctid, sp);
+
+   ctst->os_state.parent = ptid;
+
+   /* inherit signal mask */
+   ctst->sig_mask     = ptst->sig_mask;
+   ctst->tmp_sig_mask = ptst->sig_mask;
+
+   /* Start the child with its threadgroup being the same as the
+      parent's.  This is so that any exit_group calls that happen
+      after the child is created but before it sets its
+      os_state.threadgroup field for real (in thread_wrapper in
+      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
+      a race condition in which the thread is unkillable (via
+      exit_group) because its threadgroup is not set.  The race window
+      is probably only a few hundred or a few thousand cycles long.
+      See #226116. */
+   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+
+   ML_(guess_and_register_stack) (sp, ctst);
+   
+   /* Assume the clone will succeed, and tell any tool that wants to
+      know that this thread has come into existence.  We cannot defer
+      it beyond this point because setup_tls, just below,
+      causes checks to assert by making references to the new ThreadId
+      if we don't state the new thread exists prior to that point.
+      If the clone fails, we'll send out a ll_exit notification for it
+      at the out: label below, to clean up. */
+   vg_assert(VG_(owns_BigLock_LL)(ptid));
+   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
+
+   if (flags & VKI_CLONE_SETTLS) {
+      res = setup_child_tls(ctid, tlsaddr);
+      if (sr_isError(res))
+        goto out;
+   }
+   flags &= ~VKI_CLONE_SETTLS;
+
+   /* start the thread with everything blocked */
+   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
+
+   /* Create the new thread */
+   res = clone_new_thread ( ML_(start_thread_NORETURN), stack, flags, ctst,
+                            child_tidptr, parent_tidptr);
+
+   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
+
+  out:
+   if (sr_isError(res)) {
+      /* clone failed */
+      VG_(cleanup_thread)(&ctst->arch);
+      ctst->status = VgTs_Empty;
+      /* oops.  Better tell the tool the thread exited in a hurry :-) */
+      VG_TRACK( pre_thread_ll_exit, ctid );
+   }
+
+#if defined(VGP_mips64_linux) || defined(VGP_mips32_linux)
+   // ??? why do we set unconditionally r2 to 0, even when error out ???
+   ptst->arch.vex.guest_r2 = 0;
+#elif defined(VGP_tilegx_linux)
+   // ??? why do we set unconditionally r0 to 0, even when error out ???
+   ptst->arch.vex.guest_r0 = 0;
+#endif
+
+   return res;
+}
+
+/* Do a clone which is really a fork().
+   ML_(do_fork_clone) uses the clone syscall to fork a child process.
+   Note that this should not be called for a thread creation.
+   Also, some flags combinations are not supported, and such combinations
+   are handled either by masking the non supported flags or by asserting.
+
+   The CLONE_VFORK flag is accepted, as this just tells that the parent is
+   suspended till the child exits or calls execve. We better keep this flag,
+   just in case the guests parent/client code depends on this synchronisation.
+
+   We cannot keep the flag CLONE_VM, as Valgrind will do whatever host
+   instructions in the child process, that will mess up the parent host
+   memory. So, we hope for the best and assumes that the guest application does
+   not (really) depends on sharing the memory between parent and child in the
+   interval between clone and exits/execve.
+
+   If child_sp != 0, the child (guest) sp will be set to child_sp just after the
+   clone syscall, before child guest instructions are executed. */
+static SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
+                                   Int* parent_tidptr, Int* child_tidptr,
+                                   Addr child_sp)
 {
    vki_sigset_t fork_saved_mask;
    vki_sigset_t mask;
    SysRes       res;
 
    if (flags & (VKI_CLONE_SETTLS | VKI_CLONE_FS | VKI_CLONE_VM 
-                | VKI_CLONE_FILES | VKI_CLONE_VFORK))
+                | VKI_CLONE_FILES))
       return VG_(mk_SysRes_Error)( VKI_EINVAL );
 
    /* Block all signals during fork, so that we can fix things up in
@@ -476,6 +785,8 @@ SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
 
    if (!sr_isError(res) && sr_Res(res) == 0) {
       /* child */
+      if (child_sp != 0)
+          VG_(set_SP)(tid, child_sp);
       VG_(do_atfork_child)(tid);
 
       /* restore signal mask */
@@ -508,7 +819,6 @@ SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
    return res;
 }
 
-
 /* ---------------------------------------------------------------------
    PRE/POST wrappers for arch-generic, Linux-specific syscalls
    ------------------------------------------------------------------ */
@@ -519,6 +829,157 @@ SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
 #define PRE(name)       DEFN_PRE_TEMPLATE(linux, name)
 #define POST(name)      DEFN_POST_TEMPLATE(linux, name)
 
+PRE(sys_clone)
+{
+   UInt cloneflags;
+   Bool badarg = False;
+
+   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
+
+// Order of arguments differs between platforms.
+#if defined(VGP_x86_linux) \
+    || defined(VGP_ppc32_linux) \
+    || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)        \
+    || defined(VGP_arm_linux) || defined(VGP_mips32_linux) \
+    || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
+#define ARG_CHILD_TIDPTR ARG5
+#define PRA_CHILD_TIDPTR PRA5
+#define ARG_TLS          ARG4
+#define PRA_TLS          PRA4
+#elif defined(VGP_amd64_linux) || defined(VGP_tilegx_linux) \
+    || defined(VGP_s390x_linux)
+#define ARG_CHILD_TIDPTR ARG4
+#define PRA_CHILD_TIDPTR PRA4
+#define ARG_TLS          ARG5
+#define PRA_TLS          PRA5
+#else
+# error Unknown platform
+#endif
+// And s390x is even more special, and inverts flags and child stack args
+#if defined(VGP_s390x_linux)
+#define ARG_FLAGS       ARG2
+#define PRA_FLAGS       PRA2
+#define ARG_CHILD_STACK ARG1
+#define PRA_CHILD_STACK PRA1
+#else
+#define ARG_FLAGS       ARG1
+#define PRA_FLAGS       PRA1
+#define ARG_CHILD_STACK ARG2
+#define PRA_CHILD_STACK PRA2
+#endif
+
+   if (VG_(tdict).track_pre_reg_read) {
+      PRA_FLAGS("clone", unsigned long, flags);
+      PRA_CHILD_STACK("clone",  void *, child_stack);
+   }
+
+   if (ARG_FLAGS & VKI_CLONE_PARENT_SETTID) {
+      if (VG_(tdict).track_pre_reg_read) {
+         PRA3("clone", int *, parent_tidptr);
+      }
+      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
+      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
+                                             VKI_PROT_WRITE)) {
+         badarg = True;
+      }
+   }
+   if (ARG_FLAGS & VKI_CLONE_SETTLS) {
+      if (VG_(tdict).track_pre_reg_read) {
+         PRA_TLS("clone", vki_modify_ldt_t *, tlsinfo);
+      }
+      /* Not very clear what is vki_modify_ldt_t: for many platforms, it is a
+         dummy type (that we define as a char). We only dereference/check the
+         ARG_TLS pointer if the type looks like a real type, i.e. sizeof > 1. */
+      if (sizeof(vki_modify_ldt_t) > 1) {
+         PRE_MEM_READ("clone(tlsinfo)", ARG_TLS, sizeof(vki_modify_ldt_t));
+         if (!VG_(am_is_valid_for_client)(ARG_TLS, sizeof(vki_modify_ldt_t), 
+                                          VKI_PROT_READ)) {
+            badarg = True;
+         }
+      }
+   }
+   if (ARG_FLAGS & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
+      if (VG_(tdict).track_pre_reg_read) {
+         PRA_CHILD_TIDPTR("clone", int *, child_tidptr);
+      }
+      PRE_MEM_WRITE("clone(child_tidptr)", ARG_CHILD_TIDPTR, sizeof(Int));
+      if (!VG_(am_is_valid_for_client)(ARG_CHILD_TIDPTR, sizeof(Int), 
+                                             VKI_PROT_WRITE)) {
+         badarg = True;
+      }
+   }
+
+   if (badarg) {
+      SET_STATUS_Failure( VKI_EFAULT );
+      return;
+   }
+
+   cloneflags = ARG_FLAGS;
+
+   if (!ML_(client_signal_OK)(ARG_FLAGS & VKI_CSIGNAL)) {
+      SET_STATUS_Failure( VKI_EINVAL );
+      return;
+   }
+
+   /* Only look at the flags we really care about */
+   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
+                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
+   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
+      /* thread creation */
+      SET_STATUS_from_SysRes(
+         do_clone(tid,
+                  ARG_FLAGS,               /* flags */
+                  (Addr)ARG_CHILD_STACK,   /* child ESP */
+                  (Int*)ARG3,              /* parent_tidptr */
+                  (Int*)ARG_CHILD_TIDPTR,  /* child_tidptr */
+                  (Addr)ARG_TLS));         /* set_tls */
+      break;
+
+   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
+      // FALLTHROUGH - assume vfork (somewhat) == fork, see ML_(do_fork_clone).
+      cloneflags &= ~VKI_CLONE_VM;
+
+   case 0: /* plain fork */
+      SET_STATUS_from_SysRes(
+         ML_(do_fork_clone)(tid,
+                       cloneflags,      /* flags */
+                       (Int*)ARG3,     /* parent_tidptr */
+                       (Int*)ARG_CHILD_TIDPTR,     /* child_tidptr */
+                       (Addr)ARG_CHILD_STACK));
+      break;
+
+   default:
+      /* should we just ENOSYS? */
+      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG_FLAGS);
+      VG_(message)(Vg_UserMsg, "\n");
+      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
+      VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
+      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
+      VG_(unimplemented)
+         ("Valgrind does not support general clone().");
+   }
+
+   if (SUCCESS) {
+      if (ARG_FLAGS & VKI_CLONE_PARENT_SETTID)
+         POST_MEM_WRITE(ARG3, sizeof(Int));
+      if (ARG_FLAGS & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
+         POST_MEM_WRITE(ARG_CHILD_TIDPTR, sizeof(Int));
+
+      /* Thread creation was successful; let the child have the chance
+         to run */
+      *flags |= SfYieldAfter;
+   }
+
+#undef ARG_CHILD_TIDPTR
+#undef PRA_CHILD_TIDPTR
+#undef ARG_TLS
+#undef PRA_TLS
+#undef ARG_FLAGS
+#undef PRA_FLAGS
+#undef ARG_CHILD_STACK
+#undef PRA_CHILD_STACK
+}
+
 /* ---------------------------------------------------------------------
    *mount wrappers
    ------------------------------------------------------------------ */
index 0aa85a16b03943f50440bf9bf8bfe298826d5d8a..09b13c1e6b1ca6f6afeea8f78ccaa5731045b96f 100644 (file)
@@ -144,14 +144,7 @@ asm (
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-//extern
-UInt do_syscall_clone_mips_linux (Word (*fn) (void *), //a0      0     32
-                                   void *stack,         //a1      4     36
-                                   Int flags,           //a2      8     40
-                                   void *arg,           //a3      12    44
-                                   Int * child_tid,     //stack   16    48
-                                   Int * parent_tid,    //stack   20    52
-                                   Int tls);          //stack   24    56
+// See priv_syswrap-linux.h for arg profile.
 asm (
 ".text\n" 
 "   .globl   do_syscall_clone_mips_linux\n" 
@@ -219,109 +212,10 @@ asm (
 #undef __NR_EXIT
 
 // forward declarations
-
-static void setup_child (ThreadArchState *, ThreadArchState *);
 static SysRes sys_set_tls (ThreadId tid, Addr tlsptr);
 static SysRes mips_PRE_sys_mmap (ThreadId tid,
                                  UWord arg1, UWord arg2, UWord arg3,
                                  UWord arg4, UWord arg5, Off64T arg6);
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-   2. initialize the thread's new VCPU state
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */ 
-
-static SysRes do_clone (ThreadId ptid, 
-                        UInt flags, Addr sp, 
-                        Int * parent_tidptr,
-                        Int * child_tidptr, 
-                        Addr child_tls) 
-{
-   const Bool debug = False;
-   ThreadId ctid = VG_ (alloc_ThreadState) ();
-   ThreadState * ptst = VG_ (get_ThreadState) (ptid);
-   ThreadState * ctst = VG_ (get_ThreadState) (ctid);
-   UInt ret = 0;
-   UWord * stack;
-   SysRes res;
-   vki_sigset_t blockall, savedmask;
-
-   VG_ (sigfillset) (&blockall);
-   vg_assert (VG_ (is_running_thread) (ptid));
-   vg_assert (VG_ (is_valid_tid) (ctid));
-   stack = (UWord *) ML_ (allocstack) (ctid);
-   if (stack == NULL) {
-      res = VG_ (mk_SysRes_Error) (VKI_ENOMEM);
-      goto out;
-   }
-   setup_child (&ctst->arch, &ptst->arch);
-
-   /* on MIPS we need to set V0 and A3 to zero */ 
-   ctst->arch.vex.guest_r2 = 0;
-   ctst->arch.vex.guest_r7 = 0;
-   if (sp != 0)
-      ctst->arch.vex.guest_r29 = sp;
-
-   ctst->os_state.parent = ptid;
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */ 
-
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (sp, ctst);
-
-   VG_TRACK (pre_thread_ll_create, ptid, ctid);
-   if (flags & VKI_CLONE_SETTLS) {
-      if (debug)
-        VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
-      ctst->arch.vex.guest_r27 = child_tls;
-      res = sys_set_tls(ctid, child_tls);
-      if (sr_isError(res))
-         goto out;
-      ctst->arch.vex.guest_r27 = child_tls;
-  }
-
-   flags &= ~VKI_CLONE_SETTLS;
-   VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
-   /* Create the new thread */ 
-   ret = do_syscall_clone_mips_linux (ML_ (start_thread_NORETURN),
-                                    stack, flags, &VG_ (threads)[ctid], 
-                                    child_tidptr, parent_tidptr,
-                                    0 /*child_tls*/);
-
-   /* High half word64 is syscall return value.  Low half is
-      the entire CR, from which we need to extract CR0.SO. */ 
-   if (debug)
-      VG_(printf)("ret: 0x%x\n", ret);
-
-   res = VG_ (mk_SysRes_mips32_linux) (/*val */ ret, 0, /*errflag */ 0);
-
-   VG_ (sigprocmask) (VKI_SIG_SETMASK, &savedmask, NULL);
-
-   out:
-   if (sr_isError (res)) {
-      VG_(cleanup_thread) (&ctst->arch);
-      ctst->status = VgTs_Empty;
-      VG_TRACK (pre_thread_ll_exit, ctid);
-   }
-   ptst->arch.vex.guest_r2 = 0;
-
-   return res;
-}
-
 /* ---------------------------------------------------------------------
    More thread stuff
    ------------------------------------------------------------------ */ 
@@ -331,16 +225,6 @@ static SysRes do_clone (ThreadId ptid,
 void
 VG_ (cleanup_thread) (ThreadArchState * arch) { } 
 
-void
-setup_child ( /*OUT*/ ThreadArchState * child,
-              /*IN*/ ThreadArchState * parent) 
-{
-   /* We inherit our parent's guest state. */ 
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}
-
 SysRes sys_set_tls ( ThreadId tid, Addr tlsptr )
 {
    VG_(threads)[tid].arch.vex.guest_ULR = tlsptr;
@@ -521,7 +405,6 @@ DECL_TEMPLATE (mips_linux, sys_lstat64);
 DECL_TEMPLATE (mips_linux, sys_fadvise64);
 DECL_TEMPLATE (mips_linux, sys_fstatat64);
 DECL_TEMPLATE (mips_linux, sys_fstat64);
-DECL_TEMPLATE (mips_linux, sys_clone);
 DECL_TEMPLATE (mips_linux, sys_sigreturn);
 DECL_TEMPLATE (mips_linux, sys_rt_sigreturn);
 DECL_TEMPLATE (mips_linux, sys_cacheflush);
@@ -636,96 +519,6 @@ POST(sys_fstat64)
   POST_MEM_WRITE (ARG2, sizeof (struct vki_stat64));
 } 
 
-PRE(sys_clone) 
-  {
-    Bool badarg = False;
-    UInt cloneflags;
-    PRINT ("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3,
-                                                        ARG4, ARG5);
-    PRE_REG_READ2 (int, "clone", unsigned long, flags,  void *, child_stack);
-    if (ARG1 & VKI_CLONE_PARENT_SETTID)
-      {
-        if (VG_ (tdict).track_pre_reg_read)
-          {
-            PRA3 ("clone", int *, parent_tidptr);
-          }
-        PRE_MEM_WRITE ("clone(parent_tidptr)", ARG3, sizeof (Int));
-        if (!VG_ (am_is_valid_for_client)(ARG3, sizeof (Int), VKI_PROT_WRITE))
-        {
-          badarg = True;
-        }
-      }
-    if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-      {
-        if (VG_ (tdict).track_pre_reg_read)
-          {
-            PRA5 ("clone", int *, child_tidptr);
-          }
-        PRE_MEM_WRITE ("clone(child_tidptr)", ARG5, sizeof (Int));
-        if (!VG_ (am_is_valid_for_client)(ARG5, sizeof (Int), VKI_PROT_WRITE))
-          {
-            badarg = True;
-          }
-      }
-    if (badarg)
-      {
-        SET_STATUS_Failure (VKI_EFAULT);
-        return;
-      }
-    cloneflags = ARG1;
-    if (!ML_ (client_signal_OK) (ARG1 & VKI_CSIGNAL))
-      {
-        SET_STATUS_Failure (VKI_EINVAL);
-        return;
-      }
-    /* Only look at the flags we really care about */ 
-    switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
-           |VKI_CLONE_FILES | VKI_CLONE_VFORK))
-      {
-        case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-        /* thread creation */ 
-        PRINT ("sys_clone1 ( %#lx, %#lx, %#lx, %#lx, %#lx )",
-               ARG1, ARG2, ARG3, ARG4, ARG5);
-        SET_STATUS_from_SysRes (do_clone (tid, 
-                                          ARG1, /* flags */ 
-                                          (Addr) ARG2, /* child SP */ 
-                                          (Int *) ARG3, /* parent_tidptr */ 
-                                          (Int *) ARG5, /* child_tidptr */ 
-                                          (Addr) ARG4));       /* child_tls */
-
-        break;
-        case VKI_CLONE_VFORK | VKI_CLONE_VM:   /* vfork */
-          /* FALLTHROUGH - assume vfork == fork */ 
-          cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-        case 0:  /* plain fork */
-          SET_STATUS_from_SysRes (ML_ (do_fork_clone) (tid,
-                                  cloneflags, /* flags */ 
-                                  (Int *) ARG3, /* parent_tidptr */ 
-                                  (Int *) ARG5));      /* child_tidptr */
-        break;
-        default:
-          /* should we just ENOSYS? */ 
-          VG_ (message) (Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-          VG_ (message) (Vg_UserMsg, "\n");
-          VG_ (message) (Vg_UserMsg, "The only supported clone() uses are:\n");
-          VG_ (message) (Vg_UserMsg, 
-                          " - via a threads library (LinuxThreads or NPTL)\n");
-          VG_ (message) (Vg_UserMsg,
-                          " - via the implementation of fork or vfork\n");
-          VG_ (unimplemented)("Valgrind does not support general clone().");
-    }
-    if (SUCCESS)
-      {
-        if (ARG1 & VKI_CLONE_PARENT_SETTID)
-          POST_MEM_WRITE (ARG3, sizeof (Int));
-        if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-          POST_MEM_WRITE (ARG5, sizeof (Int));
-        /* Thread creation was successful; let the child have the chance 
-         * to run */
-        *flags |= SfYieldAfter;
-      }
-}
-
 PRE(sys_sigreturn) 
 {
   PRINT ("sys_sigreturn ( )");
@@ -991,7 +784,7 @@ static SyscallTableEntry syscall_main_table[] = {
    LINXY (__NR_ipc,                    sys_ipc),                     // 117
    GENX_ (__NR_fsync,                  sys_fsync),                   // 118
    PLAX_ (__NR_sigreturn,              sys_sigreturn),               // 119
-   PLAX_ (__NR_clone,                  sys_clone),                   // 120
+   LINX_ (__NR_clone,                  sys_clone),                   // 120
    //..    //   (__NR_setdomainname,     sys_setdomainname),     // 121
    GENXY (__NR_uname,                  sys_newuname),                // 122
    //..    PLAX_(__NR_modify_ldt,        sys_modify_ldt),        // 123
index 6e3db740fbf0162de4bfaeb7b52dc10cb54e57c2..d3d70c5f417f3664d9b9989581d180016d36bdb3 100644 (file)
@@ -136,14 +136,7 @@ asm (
 #define __NR_CLONE        __NR_clone
 #define __NR_EXIT         __NR_exit
 
-ULong do_syscall_clone_mips64_linux ( Word (*fn) (void *),  /* a0 - 4 */
-                                      void* stack,          /* a1 - 5 */
-                                      Int   flags,          /* a2 - 6 */
-                                      void* arg,            /* a3 - 7 */
-                                      Int*  parent_tid,     /* a4 - 8 */
-                                      void* /* Int tls */,  /* a5 - 9 */
-                                      Int*  child_tid );    /* a6 - 10 */
-
+// See priv_syswrap-linux.h for arg profile.
 asm(
 ".text\n" 
 ".set noreorder\n"
@@ -199,104 +192,13 @@ asm(
 #undef __NR_EXIT
 
 /* forward declarations */
-static void setup_child ( ThreadArchState *, ThreadArchState *);
 static SysRes sys_set_tls ( ThreadId tid, Addr tlsptr);
 
-/* When a client clones, we need to keep track of the new thread. This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested, but using
-      the scheduler entrypoint for IP, and a separate stack for SP. */
-static SysRes do_clone ( ThreadId ptid,
-                         UInt flags, Addr sp,
-                         Int* parent_tidptr,
-                         Int* child_tidptr,
-                         Addr child_tls )
-{
-   const Bool debug = False;
-   ThreadId ctid = VG_ (alloc_ThreadState) ();
-   ThreadState * ptst = VG_ (get_ThreadState) (ptid);
-   ThreadState * ctst = VG_ (get_ThreadState) (ctid);
-   UInt ret = 0;
-   UWord * stack;
-   SysRes res;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-   stack = (UWord *)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)(VKI_ENOMEM);
-      goto out;
-   }
-   setup_child(&ctst->arch, &ptst->arch);
-
-   /* on MIPS we need to set V0 and A3 to zero */
-   ctst->arch.vex.guest_r2 = 0;
-   ctst->arch.vex.guest_r7 = 0;
-   if (sp != 0)
-      ctst->arch.vex.guest_r29 = sp;
-
-   ctst->os_state.parent = ptid;
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (sp, ctst);
-
-   VG_TRACK(pre_thread_ll_create, ptid, ctid);
-   if (flags & VKI_CLONE_SETTLS) {
-       if (debug)
-         VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
-       res = sys_set_tls(ctid, child_tls);
-       if (sr_isError(res))
-          goto out;
-       ctst->arch.vex.guest_r27 = child_tls;
-   }
-
-   flags &= ~VKI_CLONE_SETTLS;
-   VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
-   /* Create the new thread */
-   ret = do_syscall_clone_mips64_linux(ML_(start_thread_NORETURN),
-                                       stack, flags, &VG_(threads)[ctid],
-                                       parent_tidptr, NULL /*child_tls*/,
-                                       child_tidptr);
-   if (debug)
-     VG_(printf)("ret: 0x%x\n", ret);
-
-   res = VG_(mk_SysRes_mips64_linux)( /* val */ ret, 0, /* errflag */ 0);
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-   out:
-   if (sr_isError (res)) {
-      VG_ (cleanup_thread) (&ctst->arch);
-      ctst->status = VgTs_Empty;
-      VG_TRACK (pre_thread_ll_exit, ctid);
-   }
-   ptst->arch.vex.guest_r2 = 0;
-
-   return res;
-}
-
 /* ---------------------------------------------------------------------
                           More thread stuff
    ------------------------------------------------------------------ */
 void VG_(cleanup_thread) ( ThreadArchState * arch ) { };
 
-void setup_child ( /* OUT */ ThreadArchState * child,
-                   /* IN  */ ThreadArchState * parent )
-{
-   /* We inherit our parent's guest state. */
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}
-
 SysRes sys_set_tls ( ThreadId tid, Addr tlsptr )
 {
    VG_(threads)[tid].arch.vex.guest_ULR = tlsptr;
@@ -316,7 +218,6 @@ SysRes sys_set_tls ( ThreadId tid, Addr tlsptr )
    file, but that requires even more macro magic. */
 
 DECL_TEMPLATE (mips_linux, sys_set_thread_area);
-DECL_TEMPLATE (mips_linux, sys_clone);
 DECL_TEMPLATE (mips_linux, sys_tee);
 DECL_TEMPLATE (mips_linux, sys_splice);
 DECL_TEMPLATE (mips_linux, sys_vmsplice);
@@ -494,84 +395,6 @@ PRE(sys_mmap)
                                  (Off64T) ARG6);
    SET_STATUS_from_SysRes(r);
 }
-
-PRE(sys_clone)
-{
-   Bool badarg = False;
-   UInt cloneflags;
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3,
-                                                      ARG4, ARG5);
-   PRE_REG_READ2(int, "clone", unsigned long, flags, void *, child_stack);
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA3("clone", int *, parent_tidptr);
-      }
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
-         badarg = True;
-      }
-   }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA5("clone", int *, child_tidptr);
-      }
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof (Int));
-      if (!VG_(am_is_valid_for_client)(ARG5, sizeof (Int), VKI_PROT_WRITE))
-         badarg = True;
-   }
-   if (badarg) {
-      SET_STATUS_Failure(VKI_EFAULT);
-      return;
-   }
-   cloneflags = ARG1;
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure(VKI_EINVAL);
-      return;
-   }
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
-           |VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-      case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-         /* thread creation */
-         SET_STATUS_from_SysRes(do_clone(tid,
-                                         ARG1,          /* flags */
-                                         (Addr)ARG2,    /* child SP */
-                                         (Int *)ARG3,   /* parent_tidptr */
-                                         (Int *)ARG5,   /* child_tidptr */
-                                         (Addr)ARG4));  /* child_tls */
-         break;
-
-      case VKI_CLONE_VFORK | VKI_CLONE_VM:  /* vfork */
-         /* FALLTHROUGH - assume vfork == fork */
-         cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-      case 0:  /* plain fork */
-         SET_STATUS_from_SysRes(ML_(do_fork_clone)(tid,
-                                cloneflags,     /* flags */
-                                (Int *)ARG3,    /* parent_tidptr */
-                                (Int *)ARG5));  /* child_tidptr */
-         break;
-
-      default:
-         /* should we just ENOSYS? */
-         VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-         VG_(message)(Vg_UserMsg, "\n");
-         VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-         VG_(message)(Vg_UserMsg,
-                       " - via a threads library (LinuxThreads or NPTL)\n");
-         VG_(message)(Vg_UserMsg,
-                       " - via the implementation of fork or vfork\n");
-         VG_(unimplemented)("Valgrind does not support general clone().");
-   }
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG5, sizeof(Int));
-      /* Thread creation was successful; let the child have the chance to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_rt_sigreturn)
 {
    /* See comments on PRE(sys_rt_sigreturn) in syswrap-s390x-linux.c for
@@ -766,7 +589,7 @@ static SyscallTableEntry syscall_main_table[] = {
    LINXY (__NR_socketpair, sys_socketpair),
    LINX_ (__NR_setsockopt, sys_setsockopt),
    LINXY (__NR_getsockopt, sys_getsockopt),
-   PLAX_ (__NR_clone, sys_clone),
+   LINX_ (__NR_clone, sys_clone),
    GENX_ (__NR_fork, sys_fork),
    GENX_ (__NR_execve, sys_execve),
    GENX_ (__NR_exit, sys_exit),
index 379fcb383ea96054892e43ccf6db98041a1dbeda..a654a90b4e9f2179d875affa0062167b24e23baa 100644 (file)
@@ -146,14 +146,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-ULong do_syscall_clone_ppc32_linux ( Word (*fn)(void *), 
-                                     void* stack, 
-                                     Int   flags, 
-                                     void* arg,
-                                     Int*  child_tid, 
-                                     Int*  parent_tid, 
-                                     vki_modify_ldt_t * );
+// See priv_syswrap-linux.h for arg profile.
 asm(
 ".text\n"
 ".globl do_syscall_clone_ppc32_linux\n"
@@ -216,145 +209,6 @@ asm(
 #undef __NR_CLONE
 #undef __NR_EXIT
 
-// forward declarations
-static void setup_child ( ThreadArchState*, ThreadArchState* );
-
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */
-static SysRes do_clone ( ThreadId ptid, 
-                         UInt flags, Addr sp, 
-                         Int *parent_tidptr, 
-                         Int *child_tidptr, 
-                         Addr child_tls)
-{
-   const Bool debug = False;
-
-   ThreadId     ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   ULong        word64;
-   UWord*       stack;
-   SysRes       res;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-//?   /* make a stack frame */
-//?   stack -= 16;
-//?   *(UWord *)stack = 0;
-
-
-   /* Copy register state
-
-      Both parent and child return to the same place, and the code
-      following the clone syscall works out which is which, so we
-      don't need to worry about it.
-
-      The parent gets the child's new tid returned from clone, but the
-      child gets 0.
-
-      If the clone call specifies a NULL SP for the new thread, then
-      it actually gets a copy of the parent's SP.
-
-      The child's TLS register (r2) gets set to the tlsaddr argument
-      if the CLONE_SETTLS flag is set.
-   */
-   setup_child( &ctst->arch, &ptst->arch );
-
-   /* Make sys_clone appear to have returned Success(0) in the
-      child. */
-   { UInt old_cr = LibVEX_GuestPPC32_get_CR( &ctst->arch.vex );
-     /* %r3 = 0 */
-     ctst->arch.vex.guest_GPR3 = 0;
-     /* %cr0.so = 0 */
-     LibVEX_GuestPPC32_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
-   }
-
-   if (sp != 0)
-      ctst->arch.vex.guest_GPR1 = sp;
-
-   ctst->os_state.parent = ptid;
-
-   /* inherit signal mask */
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (sp, ctst);
-
-   /* Assume the clone will succeed, and tell any tool that wants to
-      know that this thread has come into existence.  If the clone
-      fails, we'll send out a ll_exit notification for it at the out:
-      label below, to clean up. */
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      if (debug)
-         VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
-      ctst->arch.vex.guest_GPR2 = child_tls;
-   }
-
-   flags &= ~VKI_CLONE_SETTLS;
-
-   /* start the thread with everything blocked */
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   /* Create the new thread */
-   word64 = do_syscall_clone_ppc32_linux(
-               ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
-               child_tidptr, parent_tidptr, NULL
-            );
-   /* High half word64 is syscall return value.  Low half is
-      the entire CR, from which we need to extract CR0.SO. */
-   /* VG_(printf)("word64 = 0x%llx\n", word64); */
-   res = VG_(mk_SysRes_ppc32_linux)( 
-            /*val*/(UInt)(word64 >> 32), 
-            /*errflag*/ (((UInt)word64) >> 28) & 1 
-         );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-  out:
-   if (sr_isError(res)) {
-      /* clone failed */
-      VG_(cleanup_thread)(&ctst->arch);
-      ctst->status = VgTs_Empty;
-      /* oops.  Better tell the tool the thread exited in a hurry :-) */
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-}
-
-
 
 /* ---------------------------------------------------------------------
    More thread stuff
@@ -364,16 +218,6 @@ void VG_(cleanup_thread) ( ThreadArchState* arch )
 {
 }  
 
-void setup_child ( /*OUT*/ ThreadArchState *child,
-                   /*IN*/  ThreadArchState *parent )
-{
-   /* We inherit our parent's guest state. */
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}
-
-
 /* ---------------------------------------------------------------------
    PRE/POST wrappers for ppc32/Linux-specific syscalls
    ------------------------------------------------------------------ */
@@ -393,7 +237,6 @@ DECL_TEMPLATE(ppc32_linux, sys_stat64);
 DECL_TEMPLATE(ppc32_linux, sys_lstat64);
 DECL_TEMPLATE(ppc32_linux, sys_fstatat64);
 DECL_TEMPLATE(ppc32_linux, sys_fstat64);
-DECL_TEMPLATE(ppc32_linux, sys_clone);
 DECL_TEMPLATE(ppc32_linux, sys_sigreturn);
 DECL_TEMPLATE(ppc32_linux, sys_rt_sigreturn);
 DECL_TEMPLATE(ppc32_linux, sys_sigsuspend);
@@ -530,91 +373,6 @@ POST(sys_fstat64)
 //..    }
 //.. }
 
-PRE(sys_clone)
-{
-   UInt cloneflags;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-   PRE_REG_READ5(int, "clone",
-                 unsigned long, flags,
-                 void *,        child_stack,
-                 int *,         parent_tidptr,
-                 void *,        child_tls,
-                 int *,         child_tidptr);
-
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG5, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-
-   cloneflags = ARG1;
-
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  ARG1,         /* flags */
-                  (Addr)ARG2,   /* child SP */
-                  (Int *)ARG3,  /* parent_tidptr */
-                  (Int *)ARG5,  /* child_tidptr */
-                  (Addr)ARG4)); /* child_tls */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,      /* flags */
-                       (Int *)ARG3,     /* parent_tidptr */
-                       (Int *)ARG5));   /* child_tidptr */
-      break;
-
-   default:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
-      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG5, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_sigreturn)
 {
    /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
@@ -999,7 +757,7 @@ static SyscallTableEntry syscall_table[] = {
    GENX_(__NR_fsync,             sys_fsync),             // 118
    PLAX_(__NR_sigreturn,         sys_sigreturn),         // 119 ?/Linux
 //.. 
-   PLAX_(__NR_clone,             sys_clone),             // 120
+   LINX_(__NR_clone,             sys_clone),             // 120
 //..    //   (__NR_setdomainname,     sys_setdomainname),     // 121 */*(?)
    GENXY(__NR_uname,             sys_newuname),          // 122
 //..    PLAX_(__NR_modify_ldt,        sys_modify_ldt),        // 123
index 1ae445474f767a3bf1fa14ef7c17f508f443f6b0..f90140d957818271f4141f1d6f7c9d927b4060e6 100644 (file)
@@ -209,14 +209,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-ULong do_syscall_clone_ppc64_linux ( Word (*fn)(void *), 
-                                     void* stack, 
-                                     Int   flags, 
-                                     void* arg,
-                                     Int*  child_tid, 
-                                     Int*  parent_tid, 
-                                     void/*vki_modify_ldt_t*/ * );
+// See priv_syswrap-linux.h for arg profile.
 asm(
 #if defined(VGP_ppc64be_linux)
 "   .align   2\n"
@@ -366,148 +359,6 @@ asm(
 #undef __NR_CLONE
 #undef __NR_EXIT
 
-// forward declarations
-static void setup_child ( ThreadArchState*, ThreadArchState* );
-
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */
-static SysRes do_clone ( ThreadId ptid, 
-                         UInt flags, Addr sp, 
-                         Int *parent_tidptr, 
-                         Int *child_tidptr, 
-                         Addr child_tls)
-{
-   const Bool debug = False;
-
-   ThreadId     ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   ULong        word64;
-   UWord*       stack;
-   SysRes       res;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-//?   /* make a stack frame */
-//?   stack -= 16;
-//?   *(UWord *)stack = 0;
-
-
-   /* Copy register state
-
-      Both parent and child return to the same place, and the code
-      following the clone syscall works out which is which, so we
-      don't need to worry about it.
-
-      The parent gets the child's new tid returned from clone, but the
-      child gets 0.
-
-      If the clone call specifies a NULL SP for the new thread, then
-      it actually gets a copy of the parent's SP.
-
-      The child's TLS register (r2) gets set to the tlsaddr argument
-      if the CLONE_SETTLS flag is set.
-   */
-   setup_child( &ctst->arch, &ptst->arch );
-
-   /* Make sys_clone appear to have returned Success(0) in the
-      child. */
-   { UInt old_cr = LibVEX_GuestPPC64_get_CR( &ctst->arch.vex );
-     /* %r3 = 0 */
-     ctst->arch.vex.guest_GPR3 = 0;
-     /* %cr0.so = 0 */
-     LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), &ctst->arch.vex );
-   }
-
-   if (sp != 0)
-      ctst->arch.vex.guest_GPR1 = sp;
-
-   ctst->os_state.parent = ptid;
-
-   /* inherit signal mask */
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (sp, ctst);
-
-   /* Assume the clone will succeed, and tell any tool that wants to
-      know that this thread has come into existence.  If the clone
-      fails, we'll send out a ll_exit notification for it at the out:
-      label below, to clean up. */
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      if (debug)
-         VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
-      ctst->arch.vex.guest_GPR13 = child_tls;
-   }
-
-   flags &= ~VKI_CLONE_SETTLS;
-
-   /* start the thread with everything blocked */
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   /* Create the new thread */
-   word64 = do_syscall_clone_ppc64_linux(
-               ML_(start_thread_NORETURN),
-               stack, flags, &VG_(threads)[ctid],
-               child_tidptr, parent_tidptr, NULL
-            );
-
-   /* Low half word64 is syscall return value.  Hi half is
-      the entire CR, from which we need to extract CR0.SO. */
-   /* VG_(printf)("word64 = 0x%llx\n", word64); */
-   res = VG_(mk_SysRes_ppc64_linux)( 
-            /*val*/(UInt)(word64 & 0xFFFFFFFFULL), 
-            /*errflag*/ (UInt)((word64 >> (32+28)) & 1)
-         );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-  out:
-   if (sr_isError(res)) {
-      /* clone failed */
-      VG_(cleanup_thread)(&ctst->arch);
-      ctst->status = VgTs_Empty;
-      /* oops.  Better tell the tool the thread exited in a hurry :-) */
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-}
-
-
-
 /* ---------------------------------------------------------------------
    More thread stuff
    ------------------------------------------------------------------ */
@@ -516,16 +367,6 @@ void VG_(cleanup_thread) ( ThreadArchState* arch )
 {
 }  
 
-void setup_child ( /*OUT*/ ThreadArchState *child,
-                   /*IN*/  ThreadArchState *parent )
-{
-   /* We inherit our parent's guest state. */
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}
-
-
 /* ---------------------------------------------------------------------
    PRE/POST wrappers for ppc64/Linux-specific syscalls
    ------------------------------------------------------------------ */
@@ -544,7 +385,6 @@ DECL_TEMPLATE(ppc64_linux, sys_mmap);
 //zz DECL_TEMPLATE(ppc64_linux, sys_stat64);
 //zz DECL_TEMPLATE(ppc64_linux, sys_lstat64);
 //zz DECL_TEMPLATE(ppc64_linux, sys_fstat64);
-DECL_TEMPLATE(ppc64_linux, sys_clone);
 //zz DECL_TEMPLATE(ppc64_linux, sys_sigreturn);
 DECL_TEMPLATE(ppc64_linux, sys_rt_sigreturn);
 DECL_TEMPLATE(ppc64_linux, sys_fadvise64);
@@ -629,92 +469,6 @@ PRE(sys_mmap)
 //zz   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
 //zz }
 
-
-PRE(sys_clone)
-{
-   UInt cloneflags;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-   PRE_REG_READ5(int, "clone",
-                 unsigned long, flags,
-                 void *,        child_stack,
-                 int *,         parent_tidptr,
-                 void *,        child_tls,
-                 int *,         child_tidptr);
-
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG5, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-
-   cloneflags = ARG1;
-
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  ARG1,         /* flags */
-                  (Addr)ARG2,   /* child SP */
-                  (Int *)ARG3,  /* parent_tidptr */
-                  (Int *)ARG5,  /* child_tidptr */
-                  (Addr)ARG4)); /* child_tls */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,      /* flags */
-                       (Int *)ARG3,     /* parent_tidptr */
-                       (Int *)ARG5));   /* child_tidptr */
-      break;
-
-   default:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
-      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG5, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_fadvise64)
 {
    PRINT("sys_fadvise64 ( %ld, %ld, %lu, %ld )",  SARG1, SARG2, SARG3, SARG4);
@@ -922,7 +676,7 @@ static SyscallTableEntry syscall_table[] = {
    GENX_(__NR_fsync,             sys_fsync),              // 118
 // _____(__NR_sigreturn,         sys_sigreturn),          // 119
 
-   PLAX_(__NR_clone,             sys_clone),              // 120
+   LINX_(__NR_clone,             sys_clone),              // 120
 // _____(__NR_setdomainname,     sys_setdomainname),      // 121
    GENXY(__NR_uname,             sys_newuname),           // 122
 // _____(__NR_modify_ldt,        sys_modify_ldt),         // 123
index ebb8295fb2cdf66147c038db5db603003152e340..f59634124bf86e2f0d59676aef6422c9a7896c66 100644 (file)
@@ -138,14 +138,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-ULong do_syscall_clone_s390x_linux ( void  *stack,
-                                     ULong flags,
-                                     Int   *parent_tid,
-                                     Int   *child_tid,
-                                     Addr  tlsaddr,
-                                     Word (*fn)(void *),
-                                     void  *arg);
+// See priv_syswrap-linux.h for arg profile.
 asm(
    "   .text\n"
    "   .align  4\n"
@@ -182,126 +175,6 @@ void VG_(cleanup_thread) ( ThreadArchState* arch )
   /* only used on x86 for descriptor tables */
 }
 
-static void setup_child ( /*OUT*/ ThreadArchState *child,
-                   /*IN*/  ThreadArchState *parent )
-{
-   /* We inherit our parent's guest state. */
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-}
-
-
-/*
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */
-static SysRes do_clone ( ThreadId ptid,
-                         Addr sp, ULong flags,
-                         Int *parent_tidptr,
-                         Int *child_tidptr,
-                         Addr tlsaddr)
-{
-   static const Bool debug = False;
-
-   ThreadId     ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   UWord*       stack;
-   SysRes       res;
-   ULong        r2;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-   /* Copy register state
-
-      Both parent and child return to the same place, and the code
-      following the clone syscall works out which is which, so we
-      don't need to worry about it.
-
-      The parent gets the child's new tid returned from clone, but the
-      child gets 0.
-
-      If the clone call specifies a NULL sp for the new thread, then
-      it actually gets a copy of the parent's sp.
-   */
-   setup_child( &ctst->arch, &ptst->arch );
-
-   /* Make sys_clone appear to have returned Success(0) in the
-      child. */
-   ctst->arch.vex.guest_r2 = 0;
-
-   if (sp != 0)
-      ctst->arch.vex.guest_SP = sp;
-
-   ctst->os_state.parent = ptid;
-
-   /* inherit signal mask */
-   ctst->sig_mask = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* have the parents thread group */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (sp, ctst);
-
-   /* Assume the clone will succeed, and tell any tool that wants to
-      know that this thread has come into existence.  If the clone
-      fails, we'll send out a ll_exit notification for it at the out:
-      label below, to clean up. */
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      if (debug)
-        VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr);
-      ctst->arch.vex.guest_a0 = (UInt) (tlsaddr >> 32);
-      ctst->arch.vex.guest_a1 = (UInt) tlsaddr;
-   }
-   flags &= ~VKI_CLONE_SETTLS;
-
-   /* start the thread with everything blocked */
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   /* Create the new thread */
-   r2 = do_syscall_clone_s390x_linux(
-            stack, flags, parent_tidptr, child_tidptr, tlsaddr,
-            ML_(start_thread_NORETURN), &VG_(threads)[ctid]);
-
-   res = VG_(mk_SysRes_s390x_linux)( r2 );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-  out:
-   if (sr_isError(res)) {
-      /* clone failed */
-      ctst->status = VgTs_Empty;
-      /* oops.  Better tell the tool the thread exited in a hurry :-) */
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-
-}
-
-
-
 /* ---------------------------------------------------------------------
    PRE/POST wrappers for s390x/Linux-specific syscalls
    ------------------------------------------------------------------ */
@@ -317,7 +190,6 @@ static SysRes do_clone ( ThreadId ptid,
 
 DECL_TEMPLATE(s390x_linux, sys_ptrace);
 DECL_TEMPLATE(s390x_linux, sys_mmap);
-DECL_TEMPLATE(s390x_linux, sys_clone);
 DECL_TEMPLATE(s390x_linux, sys_sigreturn);
 DECL_TEMPLATE(s390x_linux, sys_rt_sigreturn);
 DECL_TEMPLATE(s390x_linux, sys_fadvise64);
@@ -452,99 +324,6 @@ PRE(sys_mmap)
    SET_STATUS_from_SysRes(r);
 }
 
-PRE(sys_clone)
-{
-   UInt cloneflags;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4, ARG5);
-   PRE_REG_READ2(int, "clone",
-                 void *,        child_stack,
-                 unsigned long, flags);
-
-   if (ARG2 & VKI_CLONE_PARENT_SETTID) {
-      if (VG_(tdict).track_pre_reg_read)
-         PRA3("clone(parent_tidptr)", int *, parent_tidptr);
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int),
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-   if (ARG2 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      if (VG_(tdict).track_pre_reg_read)
-         PRA4("clone(child_tidptr)", int *, child_tidptr);
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG4, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(Int),
-                                             VKI_PROT_WRITE)) {
-         SET_STATUS_Failure( VKI_EFAULT );
-         return;
-      }
-   }
-
-   /* The kernel simply copies reg6 (ARG5) into AR0 and AR1, no checks */
-   if (ARG2 & VKI_CLONE_SETTLS) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA5("clone", Addr, tlsinfo);
-      }
-   }
-
-   cloneflags = ARG2;
-
-   if (!ML_(client_signal_OK)(ARG2 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  (Addr)ARG1,   /* child SP */
-                  ARG2,         /* flags */
-                  (Int *)ARG3,  /* parent_tidptr */
-                  (Int *)ARG4, /* child_tidptr */
-                  (Addr)ARG5)); /*  tlsaddr */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,      /* flags */
-                       (Int *)ARG3,     /* parent_tidptr */
-                       (Int *)ARG4));   /* child_tidptr */
-      break;
-
-   default:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG2);
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg, " - via a threads library (NPTL)\n");
-      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG2 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG2 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG4, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_sigreturn)
 {
    ThreadState* tst;
@@ -775,7 +554,7 @@ static SyscallTableEntry syscall_table[] = {
    GENX_(__NR_fsync,  sys_fsync),                                     // 118
    PLAX_(__NR_sigreturn, sys_sigreturn),                              // 119
 
-   PLAX_(__NR_clone,  sys_clone),                                     // 120
+   LINX_(__NR_clone,  sys_clone),                                     // 120
 // ?????(__NR_setdomainname, ),                                       // 121
    GENXY(__NR_uname, sys_newuname),                                   // 122
    GENX_(123, sys_ni_syscall), /* unimplemented (by the kernel) */    // 123
index 7501b20eea9e729a1486b593d39c59174c68edca..05d81e833b7b16cf88bc1e64cec2cc3642a9476e 100644 (file)
@@ -224,14 +224,7 @@ void ML_(call_on_new_stack_0_1) (Addr stack, Addr retaddr,
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-Long do_syscall_clone_tilegx_linux ( Word (*fn) (void *),  //r0
-                                     void *stack,          //r1
-                                     Long flags,           //r2
-                                     void *arg,            //r3
-                                     Long * child_tid,     //r4
-                                     Long * parent_tid,    //r5
-                                     Long   tls );         //r6
-    /*
+   /*
       stack
       high -> 4  r29
       3
@@ -239,6 +232,7 @@ Long do_syscall_clone_tilegx_linux ( Word (*fn) (void *),  //r0
       1  r10
       low  -> 0  lr    <- sp
     */
+// See priv_syswrap-linux.h for arg profile.
      asm (
        ".text\n"
        "   .globl   do_syscall_clone_tilegx_linux\n"
@@ -315,101 +309,6 @@ Long do_syscall_clone_tilegx_linux ( Word (*fn) (void *),  //r0
 #undef __NR_EXIT
 
 // forward declarations
-static void setup_child ( ThreadArchState *, ThreadArchState * );
-static SysRes sys_set_tls ( ThreadId tid, Addr tlsptr );
- /*
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-   2. initialize the thread's new VCPU state
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for IP, and a separate stack
-   for SP.
- */
-static SysRes do_clone ( ThreadId ptid,
-                         Long flags, Addr sp,
-                         Long * parent_tidptr,
-                         Long * child_tidptr,
-                         Addr child_tls )
-{
-  const Bool debug = False;
-  ThreadId ctid = VG_ (alloc_ThreadState) ();
-  ThreadState * ptst = VG_ (get_ThreadState) (ptid);
-  ThreadState * ctst = VG_ (get_ThreadState) (ctid);
-  Long ret = 0;
-  Long * stack;
-  SysRes res;
-  vki_sigset_t blockall, savedmask;
-
-  VG_ (sigfillset) (&blockall);
-  vg_assert (VG_ (is_running_thread) (ptid));
-  vg_assert (VG_ (is_valid_tid) (ctid));
-  stack = (Long *) ML_ (allocstack) (ctid);
-  if (stack == NULL) {
-    res = VG_ (mk_SysRes_Error) (VKI_ENOMEM);
-    goto out;
-  }
-  setup_child (&ctst->arch, &ptst->arch);
-
-  /* On TILEGX we need to set r0 and r3 to zero */
-  ctst->arch.vex.guest_r0 = 0;
-  ctst->arch.vex.guest_r3 = 0;
-  if (sp != 0)
-    ctst->arch.vex.guest_r54 = sp;
-
-  ctst->os_state.parent = ptid;
-  ctst->sig_mask = ptst->sig_mask;
-  ctst->tmp_sig_mask = ptst->sig_mask;
-
-  /* Start the child with its threadgroup being the same as the
-     parent's.  This is so that any exit_group calls that happen
-     after the child is created but before it sets its
-     os_state.threadgroup field for real (in thread_wrapper in
-     syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-     a race condition in which the thread is unkillable (via
-     exit_group) because its threadgroup is not set.  The race window
-     is probably only a few hundred or a few thousand cycles long.
-     See #226116. */
-
-  ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-  ML_(guess_and_register_stack) (sp, ctst);
-
-  VG_TRACK (pre_thread_ll_create, ptid, ctid);
-  if (flags & VKI_CLONE_SETTLS) {
-    if (debug)
-      VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
-    ctst->arch.vex.guest_r53 = child_tls;
-    res = sys_set_tls(ctid, child_tls);
-    if (sr_isError(res))
-      goto out;
-  }
-
-  flags &= ~VKI_CLONE_SETTLS;
-  VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
-  /* Create the new thread */
-  ret = do_syscall_clone_tilegx_linux (ML_ (start_thread_NORETURN),
-                                       stack, flags, &VG_ (threads)[ctid],
-                                       child_tidptr, parent_tidptr,
-                                       (Long)NULL /*child_tls*/);
-
-  /* High half word64 is syscall return value. */
-  if (debug)
-    VG_(printf)("ret: 0x%llx\n", (ULong)ret);
-
-  res = VG_(mk_SysRes_tilegx_linux) (/*val */ ret);
-
-  VG_ (sigprocmask) (VKI_SIG_SETMASK, &savedmask, NULL);
-
- out:
-  if (sr_isError (res)) {
-    VG_(cleanup_thread) (&ctst->arch);
-    ctst->status = VgTs_Empty;
-    VG_TRACK (pre_thread_ll_exit, ctid);
-  }
-  ptst->arch.vex.guest_r0 = 0;
-
-  return res;
-}
-
 extern Addr do_brk ( Addr newbrk );
 
 extern
@@ -428,23 +327,6 @@ extern Bool linux_kernel_2_6_22(void);
 void
 VG_ (cleanup_thread) ( ThreadArchState * arch ) { }
 
-void
-setup_child ( /*OUT*/ ThreadArchState * child,
-              /*IN*/ ThreadArchState * parent )
-{
-  /* We inherit our parent's guest state. */
-  child->vex = parent->vex;
-  child->vex_shadow1 = parent->vex_shadow1;
-  child->vex_shadow2 = parent->vex_shadow2;
-}
-
-SysRes sys_set_tls ( ThreadId tid, Addr tlsptr )
-{
-  VG_(threads)[tid].arch.vex.guest_r53 = tlsptr;
-  return VG_(mk_SysRes_Success)( 0 );
-}
-
-
 /* ---------------------------------------------------------------------
    PRE/POST wrappers for tilegx/Linux-specific syscalls
    ------------------------------------------------------------------ */
@@ -457,7 +339,6 @@ SysRes sys_set_tls ( ThreadId tid, Addr tlsptr )
    aren't visible outside this file, but that requires even more macro
    magic. */
 
-DECL_TEMPLATE (tilegx_linux, sys_clone);
 DECL_TEMPLATE (tilegx_linux, sys_rt_sigreturn);
 DECL_TEMPLATE (tilegx_linux, sys_socket);
 DECL_TEMPLATE (tilegx_linux, sys_setsockopt);
@@ -496,94 +377,6 @@ DECL_TEMPLATE (tilegx_linux, sys_syscall184);
 DECL_TEMPLATE (tilegx_linux, sys_cacheflush);
 DECL_TEMPLATE (tilegx_linux, sys_set_dataplane);
 
-PRE(sys_clone)
-{
-  ULong cloneflags;
-
-  PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-  PRE_REG_READ5(int, "clone",
-                unsigned long, flags,
-                void *, child_stack,
-                int *, parent_tidptr,
-                int *, child_tidptr,
-                void *, tlsaddr);
-
-  if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-    PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-    if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
-      SET_STATUS_Failure( VKI_EFAULT );
-      return;
-    }
-  }
-  if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-    PRE_MEM_WRITE("clone(child_tidptr)", ARG4, sizeof(Int));
-    if (!VG_(am_is_valid_for_client)(ARG4, sizeof(Int), VKI_PROT_WRITE)) {
-      SET_STATUS_Failure( VKI_EFAULT );
-      return;
-    }
-  }
-
-  cloneflags = ARG1;
-
-  if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-    SET_STATUS_Failure( VKI_EINVAL );
-    return;
-  }
-
-  /* Only look at the flags we really care about */
-  switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
-                        | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-  case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-    /* thread creation */
-    SET_STATUS_from_SysRes(
-      do_clone(tid,
-               ARG1,          /* flags */
-               (Addr)ARG2,    /* child ESP */
-               (Long *)ARG3,  /* parent_tidptr */
-               (Long *)ARG4,  /* child_tidptr */
-               (Addr)ARG5));  /* set_tls */
-    break;
-
-  case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-    /* FALLTHROUGH - assume vfork == fork */
-    cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-  case 0: /* plain fork */
-    SET_STATUS_from_SysRes(
-      ML_(do_fork_clone)(tid,
-                         cloneflags,      /* flags */
-                         (Int *)ARG3,     /* parent_tidptr */
-                         (Int *)ARG4));   /* child_tidptr */
-    break;
-
-  default:
-    /* should we just ENOSYS? */
-    VG_(message)(Vg_UserMsg,
-                 "Unsupported clone() flags: 0x%lx\n", ARG1);
-    VG_(message)(Vg_UserMsg,
-                 "\n");
-    VG_(message)(Vg_UserMsg,
-                 "The only supported clone() uses are:\n");
-    VG_(message)(Vg_UserMsg,
-                 " - via a threads library (LinuxThreads or NPTL)\n");
-    VG_(message)(Vg_UserMsg,
-                 " - via the implementation of fork or vfork\n");
-    VG_(unimplemented)
-      ("Valgrind does not support general clone().");
-  }
-
-  if (SUCCESS) {
-    if (ARG1 & VKI_CLONE_PARENT_SETTID)
-      POST_MEM_WRITE(ARG3, sizeof(Int));
-    if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-      POST_MEM_WRITE(ARG4, sizeof(Int));
-
-    /* Thread creation was successful; let the child have the chance
-       to run */
-    *flags |= SfYieldAfter;
-  }
-}
-
 PRE(sys_rt_sigreturn)
 {
   /* This isn't really a syscall at all - it's a misuse of the
@@ -1344,7 +1137,7 @@ static SyscallTableEntry syscall_table[] = {
   LINX_(__NR_add_key,           sys_add_key),              // 217
   LINX_(__NR_request_key,       sys_request_key),          // 218
   LINXY(__NR_keyctl,            sys_keyctl),               // 219
-  PLAX_(__NR_clone,             sys_clone),                // 220
+  LINX_(__NR_clone,             sys_clone),                // 220
   GENX_(__NR_execve,            sys_execve),               // 221
   PLAX_(__NR_mmap,              sys_mmap),                 // 222
   GENXY(__NR_mprotect,          sys_mprotect),             // 226
index 0e5af9830fbf5b44014a70859aa693fca5391760..f8c4eb42c895445372564282dcc9bc86245e40b3 100644 (file)
@@ -131,14 +131,7 @@ asm(
 #define __NR_CLONE        VG_STRINGIFY(__NR_clone)
 #define __NR_EXIT         VG_STRINGIFY(__NR_exit)
 
-extern
-Int do_syscall_clone_x86_linux ( Word (*fn)(void *), 
-                                 void* stack, 
-                                 Int   flags, 
-                                 void* arg,
-                                 Int*  child_tid, 
-                                 Int*  parent_tid, 
-                                 vki_modify_ldt_t * );
+// See priv_syswrap-linux.h for arg profile.
 asm(
 ".text\n"
 ".globl do_syscall_clone_x86_linux\n"
@@ -191,141 +184,6 @@ asm(
 #undef __NR_EXIT
 
 
-// forward declarations
-static void setup_child ( ThreadArchState*, ThreadArchState*, Bool );
-static SysRes sys_set_thread_area ( ThreadId, vki_modify_ldt_t* );
-
-/* 
-   When a client clones, we need to keep track of the new thread.  This means:
-   1. allocate a ThreadId+ThreadState+stack for the thread
-
-   2. initialize the thread's new VCPU state
-
-   3. create the thread using the same args as the client requested,
-   but using the scheduler entrypoint for EIP, and a separate stack
-   for ESP.
- */
-static SysRes do_clone ( ThreadId ptid, 
-                         UInt flags, Addr esp, 
-                         Int* parent_tidptr, 
-                         Int* child_tidptr, 
-                         vki_modify_ldt_t *tlsinfo)
-{
-   static const Bool debug = False;
-
-   ThreadId     ctid = VG_(alloc_ThreadState)();
-   ThreadState* ptst = VG_(get_ThreadState)(ptid);
-   ThreadState* ctst = VG_(get_ThreadState)(ctid);
-   UWord*       stack;
-   SysRes       res;
-   Int          eax;
-   vki_sigset_t blockall, savedmask;
-
-   VG_(sigfillset)(&blockall);
-
-   vg_assert(VG_(is_running_thread)(ptid));
-   vg_assert(VG_(is_valid_tid)(ctid));
-
-   stack = (UWord*)ML_(allocstack)(ctid);
-   if (stack == NULL) {
-      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
-      goto out;
-   }
-
-   /* Copy register state
-
-      Both parent and child return to the same place, and the code
-      following the clone syscall works out which is which, so we
-      don't need to worry about it.
-
-      The parent gets the child's new tid returned from clone, but the
-      child gets 0.
-
-      If the clone call specifies a NULL esp for the new thread, then
-      it actually gets a copy of the parent's esp.
-   */
-   /* Note: the clone call done by the Quadrics Elan3 driver specifies
-      clone flags of 0xF00, and it seems to rely on the assumption
-      that the child inherits a copy of the parent's GDT.  
-      setup_child takes care of setting that up. */
-   setup_child( &ctst->arch, &ptst->arch, True );
-
-   /* Make sys_clone appear to have returned Success(0) in the
-      child. */
-   ctst->arch.vex.guest_EAX = 0;
-
-   if (esp != 0)
-      ctst->arch.vex.guest_ESP = esp;
-
-   ctst->os_state.parent = ptid;
-
-   /* inherit signal mask */
-   ctst->sig_mask     = ptst->sig_mask;
-   ctst->tmp_sig_mask = ptst->sig_mask;
-
-   /* Start the child with its threadgroup being the same as the
-      parent's.  This is so that any exit_group calls that happen
-      after the child is created but before it sets its
-      os_state.threadgroup field for real (in thread_wrapper in
-      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
-      a race condition in which the thread is unkillable (via
-      exit_group) because its threadgroup is not set.  The race window
-      is probably only a few hundred or a few thousand cycles long.
-      See #226116. */
-   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
-
-   ML_(guess_and_register_stack) (esp, ctst);
-   
-   /* Assume the clone will succeed, and tell any tool that wants to
-      know that this thread has come into existence.  We cannot defer
-      it beyond this point because sys_set_thread_area, just below,
-      causes tCheck to assert by making references to the new ThreadId
-      if we don't state the new thread exists prior to that point.
-      If the clone fails, we'll send out a ll_exit notification for it
-      at the out: label below, to clean up. */
-   vg_assert(VG_(owns_BigLock_LL)(ptid));
-   VG_TRACK ( pre_thread_ll_create, ptid, ctid );
-
-   if (flags & VKI_CLONE_SETTLS) {
-      if (debug)
-        VG_(printf)("clone child has SETTLS: tls info at %p: idx=%u "
-                     "base=%#lx limit=%x; esp=%#x fs=%x gs=%x\n",
-                    tlsinfo, tlsinfo->entry_number, 
-                     tlsinfo->base_addr, tlsinfo->limit,
-                    ptst->arch.vex.guest_ESP,
-                    ctst->arch.vex.guest_FS, ctst->arch.vex.guest_GS);
-      res = sys_set_thread_area(ctid, tlsinfo);
-      if (sr_isError(res))
-        goto out;
-   }
-
-   flags &= ~VKI_CLONE_SETTLS;
-
-   /* start the thread with everything blocked */
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
-
-   /* Create the new thread */
-   eax = do_syscall_clone_x86_linux(
-            ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
-            child_tidptr, parent_tidptr, NULL
-         );
-   res = VG_(mk_SysRes_x86_linux)( eax );
-
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
-
-  out:
-   if (sr_isError(res)) {
-      /* clone failed */
-      VG_(cleanup_thread)(&ctst->arch);
-      ctst->status = VgTs_Empty;
-      /* oops.  Better tell the tool the thread exited in a hurry :-) */
-      VG_TRACK( pre_thread_ll_exit, ctid );
-   }
-
-   return res;
-}
-
-
 /* ---------------------------------------------------------------------
    LDT/GDT simulation
    ------------------------------------------------------------------ */
@@ -630,7 +488,7 @@ static SysRes sys_modify_ldt ( ThreadId tid,
 }
 
 
-static SysRes sys_set_thread_area ( ThreadId tid, vki_modify_ldt_t* info )
+SysRes ML_(x86_sys_set_thread_area) ( ThreadId tid, vki_modify_ldt_t* info )
 {
    Int                  idx;
    VexGuestX86SegDescr* gdt;
@@ -738,15 +596,9 @@ void VG_(cleanup_thread) ( ThreadArchState* arch )
 }  
 
 
-static void setup_child ( /*OUT*/ ThreadArchState *child, 
-                          /*IN*/  ThreadArchState *parent,
-                          Bool inherit_parents_GDT )
+void ML_(x86_setup_LDT_GDT) ( /*OUT*/ ThreadArchState *child, 
+                              /*IN*/  ThreadArchState *parent )
 {
-   /* We inherit our parent's guest state. */
-   child->vex = parent->vex;
-   child->vex_shadow1 = parent->vex_shadow1;
-   child->vex_shadow2 = parent->vex_shadow2;
-
    /* We inherit our parent's LDT. */
    if (parent->vex.guest_LDT == (HWord)NULL) {
       /* We hope this is the common case. */
@@ -763,7 +615,7 @@ static void setup_child ( /*OUT*/ ThreadArchState *child,
       only). */
    child->vex.guest_GDT = (HWord)NULL;
 
-   if (inherit_parents_GDT && parent->vex.guest_GDT != (HWord)NULL) {
+   if (parent->vex.guest_GDT != (HWord)NULL) {
       child->vex.guest_GDT = (HWord)alloc_zeroed_x86_GDT();
       copy_GDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_GDT,
                         (VexGuestX86SegDescr*)child->vex.guest_GDT );
@@ -787,7 +639,6 @@ DECL_TEMPLATE(x86_linux, sys_stat64);
 DECL_TEMPLATE(x86_linux, sys_fstatat64);
 DECL_TEMPLATE(x86_linux, sys_fstat64);
 DECL_TEMPLATE(x86_linux, sys_lstat64);
-DECL_TEMPLATE(x86_linux, sys_clone);
 DECL_TEMPLATE(x86_linux, old_mmap);
 DECL_TEMPLATE(x86_linux, sys_mmap2);
 DECL_TEMPLATE(x86_linux, sys_sigreturn);
@@ -835,137 +686,6 @@ PRE(old_select)
    }
 }
 
-PRE(sys_clone)
-{
-   UInt cloneflags;
-   Bool badarg = False;
-
-   PRINT("sys_clone ( %lx, %#lx, %#lx, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
-   PRE_REG_READ2(int, "clone",
-                 unsigned long, flags,
-                 void *, child_stack);
-
-   if (ARG1 & VKI_CLONE_PARENT_SETTID) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA3("clone", int *, parent_tidptr);
-      }
-      PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         badarg = True;
-      }
-   }
-   if (ARG1 & VKI_CLONE_SETTLS) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA4("clone", vki_modify_ldt_t *, tlsinfo);
-      }
-      PRE_MEM_READ("clone(tlsinfo)", ARG4, sizeof(vki_modify_ldt_t));
-      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(vki_modify_ldt_t), 
-                                             VKI_PROT_READ)) {
-         badarg = True;
-      }
-   }
-   if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
-      if (VG_(tdict).track_pre_reg_read) {
-         PRA5("clone", int *, child_tidptr);
-      }
-      PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
-      if (!VG_(am_is_valid_for_client)(ARG5, sizeof(Int), 
-                                             VKI_PROT_WRITE)) {
-         badarg = True;
-      }
-   }
-
-   if (badarg) {
-      SET_STATUS_Failure( VKI_EFAULT );
-      return;
-   }
-
-   cloneflags = ARG1;
-
-   if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
-      SET_STATUS_Failure( VKI_EINVAL );
-      return;
-   }
-
-   /* Be ultra-paranoid and filter out any clone-variants we don't understand:
-      - ??? specifies clone flags of 0x100011
-      - ??? specifies clone flags of 0x1200011.
-      - NPTL specifies clone flags of 0x7D0F00.
-      - The Quadrics Elan3 driver specifies clone flags of 0xF00.
-      - Newer Quadrics Elan3 drivers with NTPL support specify 0x410F00.
-      Everything else is rejected. 
-   */
-   if (
-        1 ||
-        /* 11 Nov 05: for the time being, disable this ultra-paranoia.
-           The switch below probably does a good enough job. */
-          (cloneflags == 0x100011 || cloneflags == 0x1200011
-                                  || cloneflags == 0x7D0F00
-                                  || cloneflags == 0x790F00
-                                  || cloneflags == 0x3D0F00
-                                  || cloneflags == 0x410F00
-                                  || cloneflags == 0xF00
-                                  || cloneflags == 0xF21)) {
-     /* OK */
-   }
-   else {
-      /* Nah.  We don't like it.  Go away. */
-      goto reject;
-   }
-
-   /* Only look at the flags we really care about */
-   switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS 
-                         | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
-   case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
-      /* thread creation */
-      SET_STATUS_from_SysRes(
-         do_clone(tid,
-                  ARG1,         /* flags */
-                  (Addr)ARG2,   /* child ESP */
-                  (Int *)ARG3,  /* parent_tidptr */
-                  (Int *)ARG5,  /* child_tidptr */
-                  (vki_modify_ldt_t *)ARG4)); /* set_tls */
-      break;
-
-   case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
-      /* FALLTHROUGH - assume vfork == fork */
-      cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
-
-   case 0: /* plain fork */
-      SET_STATUS_from_SysRes(
-         ML_(do_fork_clone)(tid,
-                       cloneflags,      /* flags */
-                       (Int *)ARG3,     /* parent_tidptr */
-                       (Int *)ARG5));   /* child_tidptr */
-      break;
-
-   default:
-   reject:
-      /* should we just ENOSYS? */
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "Unsupported clone() flags: 0x%lx\n", ARG1);
-      VG_(message)(Vg_UserMsg, "\n");
-      VG_(message)(Vg_UserMsg, "The only supported clone() uses are:\n");
-      VG_(message)(Vg_UserMsg, " - via a threads library (LinuxThreads or NPTL)\n");
-      VG_(message)(Vg_UserMsg, " - via the implementation of fork or vfork\n");
-      VG_(message)(Vg_UserMsg, " - for the Quadrics Elan3 user-space driver\n");
-      VG_(unimplemented)
-         ("Valgrind does not support general clone().");
-   }
-
-   if (SUCCESS) {
-      if (ARG1 & VKI_CLONE_PARENT_SETTID)
-         POST_MEM_WRITE(ARG3, sizeof(Int));
-      if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
-         POST_MEM_WRITE(ARG5, sizeof(Int));
-
-      /* Thread creation was successful; let the child have the chance
-         to run */
-      *flags |= SfYieldAfter;
-   }
-}
-
 PRE(sys_sigreturn)
 {
    /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
@@ -1063,7 +783,7 @@ PRE(sys_set_thread_area)
    PRE_MEM_READ( "set_thread_area(u_info)", ARG1, sizeof(vki_modify_ldt_t) );
 
    /* "do" the syscall ourselves; the kernel never sees it */
-   SET_STATUS_from_SysRes( sys_set_thread_area( tid, (void *)ARG1 ) );
+   SET_STATUS_from_SysRes( ML_(x86_sys_set_thread_area)( tid, (void *)ARG1 ) );
 }
 
 PRE(sys_get_thread_area)
@@ -1553,7 +1273,7 @@ static SyscallTableEntry syscall_table[] = {
    GENX_(__NR_fsync,             sys_fsync),          // 118
    PLAX_(__NR_sigreturn,         sys_sigreturn),      // 119 ?/Linux
 
-   PLAX_(__NR_clone,             sys_clone),          // 120
+   LINX_(__NR_clone,             sys_clone),          // 120
 //zz    //   (__NR_setdomainname,     sys_setdomainname),  // 121 */*(?)
    GENXY(__NR_uname,             sys_newuname),       // 122
    PLAX_(__NR_modify_ldt,        sys_modify_ldt),     // 123
index df34dd6c0d68edc1e3e7acc262e842d550418a8a..5a3b08faec08d80aa257c5268a752faa640961a1 100644 (file)
@@ -586,7 +586,8 @@ struct vki_ucontext {
 //ZZ };
 //ZZ 
 //ZZ // [[Nb: for our convenience within Valgrind, use a more specific name]]
-//ZZ typedef struct vki_user_desc vki_modify_ldt_t;
+
+typedef char vki_modify_ldt_t;
 
 //----------------------------------------------------------------------
 // From linux-3.10.5/include/asm-generic/ipcbuf.h
index 5be8e156256195769795d9f2622923e6d40b8ce7..b6c991405fdd632836d2a8c940530444b4f6b606 100644 (file)
@@ -679,7 +679,7 @@ struct vki_ucontext {
 };
 
 // CAB: TODO
-typedef void vki_modify_ldt_t;
+typedef char vki_modify_ldt_t;
 
 //----------------------------------------------------------------------
 // From linux-2.6.35.5/include/asm-mips/ipcbuf.h
index 26b8e9f982e576ad639cea666c507bc20e0baaf7..ca49b10b07aec3834c1d790e94dd7b8f1aa2eaae 100644 (file)
@@ -710,6 +710,7 @@ struct vki_ucontext {
        vki_sigset_t           uc_sigmask;  /* mask last for extensibility */
 };
 
+typedef char vki_modify_ldt_t;
 //----------------------------------------------------------------------
 // From linux-2.6.35.9/include/asm-mips/ipcbuf.h
 //----------------------------------------------------------------------
index 70c2835ee1afdb090c26f2e46a850035933b5acf..0fd3c798d689f14f285f2565ba369fe3e1465d24 100644 (file)
@@ -811,10 +811,9 @@ struct vki_ucontext {
 //.. };
 //.. 
 //.. // [[Nb: for our convenience within Valgrind, use a more specific name]]
-//.. typedef struct vki_user_desc vki_modify_ldt_t;
 
 // CAB: TODO
-typedef void vki_modify_ldt_t;
+typedef char vki_modify_ldt_t;
 
 
 //----------------------------------------------------------------------
index b4106637bb35e7483a6b95b423f68d27d0ee6840..fd5cea63a48739576d36d25114d2f0362760e002 100644 (file)
@@ -685,6 +685,9 @@ struct vki_ucontext {
   struct vki_sigcontext uc_mcontext;  /* last for extensibility */
 };
 
+// CAB: TODO
+typedef char vki_modify_ldt_t;
+
 //----------------------------------------------------------------------
 // From linux-2.6.13/include/asm-ppc64/ipcbuf.h
 //----------------------------------------------------------------------
index c3f6d00478823f5e5873084209eeb546b4c62c52..1ef5cf7647deacac6a2d5c247767db33a915f3e7 100644 (file)
@@ -822,6 +822,8 @@ struct vki_ucontext {
        vki_sigset_t          uc_sigmask; /* mask last for extensibility */
 };
 
+typedef char vki_modify_ldt_t;
+
 //----------------------------------------------------------------------
 // From linux-2.6.16.60/include/asm-s390/ipcbuf.h
 //----------------------------------------------------------------------
index f407cb473abe485b3065abd179e673e96450127c..ddc988ab687203b7418659478d3d68ee01b87c52 100644 (file)
@@ -7,6 +7,7 @@ EXTRA_DIST = \
        blockfault.stderr.exp blockfault.vgtest \
        brk-overflow1.stderr.exp brk-overflow1.vgtest \
        brk-overflow2.stderr.exp brk-overflow2.vgtest \
+       clonev.stderr.exp clonev.vgtest \
        mremap.stderr.exp mremap.stderr.exp-glibc27 mremap.stdout.exp \
            mremap.vgtest \
        mremap2.stderr.exp mremap2.stdout.exp mremap2.vgtest \
@@ -21,6 +22,7 @@ check_PROGRAMS = \
        blockfault \
        brk-overflow1 \
        brk-overflow2 \
+       clonev \
        mremap \
        mremap2 \
        mremap3 \
@@ -35,6 +37,7 @@ AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
 AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
 # Special needs
+clonev_LDADD = -lpthread
 pthread_stack_LDADD = -lpthread
 
 stack_overflow_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ \
diff --git a/none/tests/linux/clonev.c b/none/tests/linux/clonev.c
new file mode 100644 (file)
index 0000000..b37cc8d
--- /dev/null
@@ -0,0 +1,77 @@
+#define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+// Based on a test by Steven Stewart-Gallus, see 342040
+int fork_routine(void *arg)
+{
+        write(1, "fork_routine\n", 13);
+       _Exit(EXIT_SUCCESS);
+}
+
+int main(void)
+{
+       long page_size = sysconf(_SC_PAGE_SIZE);
+       assert(page_size != -1);
+
+       /* We need an extra page for signals */
+       long stack_size = sysconf(_SC_THREAD_STACK_MIN) + page_size;
+       assert(stack_size != -1);
+
+       size_t stack_and_guard_size = page_size + stack_size + page_size;
+       void *child_stack = mmap(
+           NULL, stack_and_guard_size, PROT_READ | PROT_WRITE,
+           MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
+       if (NULL == child_stack) {
+               perror("mmap");
+               return EXIT_FAILURE;
+       }
+
+       /* Guard pages are shared between the stacks */
+       if (-1 == mprotect((char *)child_stack, page_size, PROT_NONE)) {
+               perror("mprotect");
+               return EXIT_FAILURE;
+       }
+
+       if (-1 == mprotect((char *)child_stack + page_size + stack_size,
+                          page_size, PROT_NONE)) {
+               perror("mprotect");
+               return EXIT_FAILURE;
+       }
+
+       void *stack_start = (char *)child_stack + page_size + stack_size;
+        if (0)
+           printf("stack_start %p page_size %d stack_size %d\n",
+                  stack_start, (int)page_size, (int)stack_size);
+        write(1, "parent before clone\n", 20);
+       pid_t child =
+           clone(fork_routine, stack_start,
+                 SIGCHLD | CLONE_VFORK | CLONE_VM, NULL);
+        write(1, "parent after clone\n", 19);
+       if (-1 == child) {
+               perror("clone");
+               return EXIT_FAILURE;
+       }
+
+       for (;;) {
+               int xx;
+               switch (waitpid(child, &xx, 0)) {
+               case -1:
+                       switch (errno) {
+                       case EINTR:
+                               continue;
+                       default:
+                               perror("waitpid");
+                               return EXIT_FAILURE;
+                       }
+
+               default:
+                       return EXIT_SUCCESS;
+               }
+       }
+}
diff --git a/none/tests/linux/clonev.stderr.exp b/none/tests/linux/clonev.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/none/tests/linux/clonev.stdout.exp b/none/tests/linux/clonev.stdout.exp
new file mode 100644 (file)
index 0000000..2410e69
--- /dev/null
@@ -0,0 +1,3 @@
+parent before clone
+fork_routine
+parent after clone
diff --git a/none/tests/linux/clonev.vgtest b/none/tests/linux/clonev.vgtest
new file mode 100644 (file)
index 0000000..61ed15c
--- /dev/null
@@ -0,0 +1,2 @@
+prog: clonev
+vgopts: -q