/* 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;
}
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;
}
示例#3
0
/* When a client clones, we need to keep track of the new thread. This means:
   1. allocate a ThreadId+ThreadState+stack for the 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;
   NSegment const *seg;
   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;
   seg = VG_(am_find_nsegment)((Addr)sp);

   if (seg && seg->kind != SkResvn) {
      ctst->client_stack_highest_word = sp;
      ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;
      VG_(register_stack)(seg->start, ctst->client_stack_highest_word);
      if (debug)
        VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
                    ctid, seg->start, sp /* VG_PGROUNDUP (sp) */ );
   } else {
      VG_(message)(Vg_UserMsg,
                    "!? New thread %d starts with sp+%#lx) unmapped\n",
                    ctid, sp);
      ctst->client_stack_szB = 0;
   }

   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;
}