Home | History | Annotate | Download | only in m_syswrap
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Darwin-specific syscalls, etc.        syswrap-amd64-darwin.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2005-2012 Apple Inc.
     11       Greg Parker  gparker (at) apple.com
     12 
     13    This program is free software; you can redistribute it and/or
     14    modify it under the terms of the GNU General Public License as
     15    published by the Free Software Foundation; either version 2 of the
     16    License, or (at your option) any later version.
     17 
     18    This program is distributed in the hope that it will be useful, but
     19    WITHOUT ANY WARRANTY; without even the implied warranty of
     20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21    General Public License for more details.
     22 
     23    You should have received a copy of the GNU General Public License
     24    along with this program; if not, write to the Free Software
     25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     26    02111-1307, USA.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     31 #if defined(VGP_amd64_darwin)
     32 
     33 #include "config.h"                // DARWIN_VERS
     34 #include "pub_core_basics.h"
     35 #include "pub_core_vki.h"
     36 #include "pub_core_libcsetjmp.h"   // to keep _threadstate.h happy
     37 #include "pub_core_threadstate.h"
     38 #include "pub_core_aspacemgr.h"
     39 #include "pub_core_xarray.h"
     40 #include "pub_core_clientstate.h"
     41 #include "pub_core_debuglog.h"
     42 #include "pub_core_debuginfo.h"    // VG_(di_notify_*)
     43 #include "pub_core_transtab.h"     // VG_(discard_translations)
     44 #include "pub_core_libcbase.h"
     45 #include "pub_core_libcassert.h"
     46 #include "pub_core_libcfile.h"
     47 #include "pub_core_libcprint.h"
     48 #include "pub_core_libcproc.h"
     49 #include "pub_core_libcsignal.h"
     50 #include "pub_core_mallocfree.h"
     51 #include "pub_core_options.h"
     52 #include "pub_core_scheduler.h"
     53 #include "pub_core_sigframe.h"      // For VG_(sigframe_destroy)()
     54 #include "pub_core_signals.h"
     55 #include "pub_core_syscall.h"
     56 #include "pub_core_syswrap.h"
     57 #include "pub_core_tooliface.h"
     58 
     59 #include "priv_types_n_macros.h"
     60 #include "priv_syswrap-generic.h"   /* for decls of generic wrappers */
     61 #include "priv_syswrap-darwin.h"    /* for decls of darwin-ish wrappers */
     62 #include "priv_syswrap-main.h"
     63 
     64 
     65 #include <mach/mach.h>
     66 
     67 static void x86_thread_state64_from_vex(x86_thread_state64_t *mach,
     68                                         VexGuestAMD64State *vex)
     69 {
     70     mach->__rax = vex->guest_RAX;
     71     mach->__rbx = vex->guest_RBX;
     72     mach->__rcx = vex->guest_RCX;
     73     mach->__rdx = vex->guest_RDX;
     74     mach->__rdi = vex->guest_RDI;
     75     mach->__rsi = vex->guest_RSI;
     76     mach->__rbp = vex->guest_RBP;
     77     mach->__rsp = vex->guest_RSP;
     78     mach->__rflags = LibVEX_GuestAMD64_get_rflags(vex);
     79     mach->__rip = vex->guest_RIP;
     80     mach->__r8  = vex->guest_R8;
     81     mach->__r9  = vex->guest_R9;
     82     mach->__r10 = vex->guest_R10;
     83     mach->__r11 = vex->guest_R11;
     84     mach->__r12 = vex->guest_R12;
     85     mach->__r13 = vex->guest_R13;
     86     mach->__r14 = vex->guest_R14;
     87     mach->__r15 = vex->guest_R15;
     88     /* GrP fixme
     89     mach->__cs = vex->guest_CS;
     90     mach->__fs = vex->guest_FS;
     91     mach->__gs = vex->guest_GS;
     92     */
     93 }
     94 
     95 
     96 static void x86_float_state64_from_vex(x86_float_state64_t *mach,
     97                                        VexGuestAMD64State *vex)
     98 {
     99    // DDD: #warning GrP fixme fp state
    100    // JRS: what about the YMMHI bits?  Are they important?
    101    VG_(memcpy)(&mach->__fpu_xmm0,  &vex->guest_YMM0,   sizeof(mach->__fpu_xmm0));
    102    VG_(memcpy)(&mach->__fpu_xmm1,  &vex->guest_YMM1,   sizeof(mach->__fpu_xmm1));
    103    VG_(memcpy)(&mach->__fpu_xmm2,  &vex->guest_YMM2,   sizeof(mach->__fpu_xmm2));
    104    VG_(memcpy)(&mach->__fpu_xmm3,  &vex->guest_YMM3,   sizeof(mach->__fpu_xmm3));
    105    VG_(memcpy)(&mach->__fpu_xmm4,  &vex->guest_YMM4,   sizeof(mach->__fpu_xmm4));
    106    VG_(memcpy)(&mach->__fpu_xmm5,  &vex->guest_YMM5,   sizeof(mach->__fpu_xmm5));
    107    VG_(memcpy)(&mach->__fpu_xmm6,  &vex->guest_YMM6,   sizeof(mach->__fpu_xmm6));
    108    VG_(memcpy)(&mach->__fpu_xmm7,  &vex->guest_YMM7,   sizeof(mach->__fpu_xmm7));
    109    VG_(memcpy)(&mach->__fpu_xmm8,  &vex->guest_YMM8,   sizeof(mach->__fpu_xmm8));
    110    VG_(memcpy)(&mach->__fpu_xmm9,  &vex->guest_YMM9,   sizeof(mach->__fpu_xmm9));
    111    VG_(memcpy)(&mach->__fpu_xmm10, &vex->guest_YMM10,  sizeof(mach->__fpu_xmm10));
    112    VG_(memcpy)(&mach->__fpu_xmm11, &vex->guest_YMM11,  sizeof(mach->__fpu_xmm11));
    113    VG_(memcpy)(&mach->__fpu_xmm12, &vex->guest_YMM12,  sizeof(mach->__fpu_xmm12));
    114    VG_(memcpy)(&mach->__fpu_xmm13, &vex->guest_YMM13,  sizeof(mach->__fpu_xmm13));
    115    VG_(memcpy)(&mach->__fpu_xmm14, &vex->guest_YMM14,  sizeof(mach->__fpu_xmm14));
    116    VG_(memcpy)(&mach->__fpu_xmm15, &vex->guest_YMM15,  sizeof(mach->__fpu_xmm15));
    117 }
    118 
    119 
    120 void thread_state_from_vex(thread_state_t mach_generic,
    121                            thread_state_flavor_t flavor,
    122                            mach_msg_type_number_t count,
    123                            VexGuestArchState *vex_generic)
    124 {
    125    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
    126 
    127    switch (flavor) {
    128    case x86_THREAD_STATE64:
    129       vg_assert(count == x86_THREAD_STATE64_COUNT);
    130       x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
    131       break;
    132 
    133    case x86_FLOAT_STATE64:
    134       vg_assert(count == x86_FLOAT_STATE64_COUNT);
    135       x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
    136       break;
    137 
    138    default:
    139       vg_assert(0);
    140    }
    141 }
    142 
    143 
    144 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach,
    145                                       VexGuestAMD64State *vex)
    146 {
    147    LibVEX_GuestAMD64_initialise(vex);
    148    vex->guest_RAX = mach->__rax;
    149    vex->guest_RBX = mach->__rbx;
    150    vex->guest_RCX = mach->__rcx;
    151    vex->guest_RDX = mach->__rdx;
    152    vex->guest_RDI = mach->__rdi;
    153    vex->guest_RSI = mach->__rsi;
    154    vex->guest_RBP = mach->__rbp;
    155    vex->guest_RSP = mach->__rsp;
    156    // DDD: #warning GrP fixme eflags
    157    vex->guest_RIP = mach->__rip;
    158    vex->guest_R8  = mach->__r8;
    159    vex->guest_R9  = mach->__r9;
    160    vex->guest_R10 = mach->__r10;
    161    vex->guest_R11 = mach->__r11;
    162    vex->guest_R12 = mach->__r12;
    163    vex->guest_R13 = mach->__r13;
    164    vex->guest_R14 = mach->__r14;
    165    vex->guest_R15 = mach->__r15;
    166    /* GrP fixme
    167    vex->guest_CS = mach->__cs;
    168    vex->guest_FS = mach->__fs;
    169    vex->guest_GS = mach->__gs;
    170    */
    171 }
    172 
    173 static void x86_float_state64_to_vex(const x86_float_state64_t *mach,
    174                                      VexGuestAMD64State *vex)
    175 {
    176    // DDD: #warning GrP fixme fp state
    177    // JRS: what about the YMMHI bits?  Are they important?
    178    VG_(memcpy)(&vex->guest_YMM0,  &mach->__fpu_xmm0,  sizeof(mach->__fpu_xmm0));
    179    VG_(memcpy)(&vex->guest_YMM1,  &mach->__fpu_xmm1,  sizeof(mach->__fpu_xmm1));
    180    VG_(memcpy)(&vex->guest_YMM2,  &mach->__fpu_xmm2,  sizeof(mach->__fpu_xmm2));
    181    VG_(memcpy)(&vex->guest_YMM3,  &mach->__fpu_xmm3,  sizeof(mach->__fpu_xmm3));
    182    VG_(memcpy)(&vex->guest_YMM4,  &mach->__fpu_xmm4,  sizeof(mach->__fpu_xmm4));
    183    VG_(memcpy)(&vex->guest_YMM5,  &mach->__fpu_xmm5,  sizeof(mach->__fpu_xmm5));
    184    VG_(memcpy)(&vex->guest_YMM6,  &mach->__fpu_xmm6,  sizeof(mach->__fpu_xmm6));
    185    VG_(memcpy)(&vex->guest_YMM7,  &mach->__fpu_xmm7,  sizeof(mach->__fpu_xmm7));
    186    VG_(memcpy)(&vex->guest_YMM8,  &mach->__fpu_xmm8,  sizeof(mach->__fpu_xmm8));
    187    VG_(memcpy)(&vex->guest_YMM9,  &mach->__fpu_xmm9,  sizeof(mach->__fpu_xmm9));
    188    VG_(memcpy)(&vex->guest_YMM10, &mach->__fpu_xmm10, sizeof(mach->__fpu_xmm10));
    189    VG_(memcpy)(&vex->guest_YMM11, &mach->__fpu_xmm11, sizeof(mach->__fpu_xmm11));
    190    VG_(memcpy)(&vex->guest_YMM12, &mach->__fpu_xmm12, sizeof(mach->__fpu_xmm12));
    191    VG_(memcpy)(&vex->guest_YMM13, &mach->__fpu_xmm13, sizeof(mach->__fpu_xmm13));
    192    VG_(memcpy)(&vex->guest_YMM14, &mach->__fpu_xmm14, sizeof(mach->__fpu_xmm14));
    193    VG_(memcpy)(&vex->guest_YMM15, &mach->__fpu_xmm15, sizeof(mach->__fpu_xmm15));
    194 }
    195 
    196 
    197 void thread_state_to_vex(const thread_state_t mach_generic,
    198                          thread_state_flavor_t flavor,
    199                          mach_msg_type_number_t count,
    200                          VexGuestArchState *vex_generic)
    201 {
    202    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
    203 
    204    switch(flavor) {
    205    case x86_THREAD_STATE64:
    206       vg_assert(count == x86_THREAD_STATE64_COUNT);
    207       x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
    208       break;
    209    case x86_FLOAT_STATE64:
    210       vg_assert(count == x86_FLOAT_STATE64_COUNT);
    211       x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
    212       break;
    213 
    214    default:
    215       vg_assert(0);
    216       break;
    217    }
    218 }
    219 
    220 
    221 ThreadState *build_thread(const thread_state_t state,
    222                           thread_state_flavor_t flavor,
    223                           mach_msg_type_number_t count)
    224 {
    225    ThreadId tid = VG_(alloc_ThreadState)();
    226    ThreadState *tst = VG_(get_ThreadState)(tid);
    227 
    228    vg_assert(flavor == x86_THREAD_STATE64);
    229    vg_assert(count == x86_THREAD_STATE64_COUNT);
    230 
    231    // Initialize machine registers
    232 
    233    thread_state_to_vex(state, flavor, count, &tst->arch.vex);
    234 
    235    I_die_here;
    236    // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
    237 
    238    find_stack_segment(tid, tst->arch.vex.guest_RSP);
    239 
    240    return tst;
    241 }
    242 
    243 
    244 // Edit the thread state to send to the real kernel.
    245 // The real thread will run start_thread_NORETURN(tst)
    246 // on a separate non-client stack.
    247 void hijack_thread_state(thread_state_t mach_generic,
    248                          thread_state_flavor_t flavor,
    249                          mach_msg_type_number_t count,
    250                          ThreadState *tst)
    251 {
    252    x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
    253    char *stack;
    254 
    255    vg_assert(flavor == x86_THREAD_STATE64);
    256    vg_assert(count == x86_THREAD_STATE64_COUNT);
    257 
    258    stack = (char *)allocstack(tst->tid);
    259    stack -= 64+320;                       // make room for top frame
    260    memset(stack, 0, 64+320);              // ...and clear it
    261    *(uintptr_t *)stack = 0;               // push fake return address
    262 
    263    mach->__rdi = (uintptr_t)tst;          // arg1 = tst
    264    mach->__rip = (uintptr_t)&start_thread_NORETURN;
    265    mach->__rsp = (uintptr_t)stack;
    266 }
    267 
    268 
    269 /* Call f(arg1), but first switch stacks, using 'stack' as the new
    270    stack, and use 'retaddr' as f's return-to address.  Also, clear all
    271    the integer registers before entering f.*/
    272 __attribute__((noreturn))
    273 void call_on_new_stack_0_1 ( Addr stack,
    274 			     Addr retaddr,
    275 			     void (*f)(Word),
    276                              Word arg1 );
    277 // %rdi == stack (must be 16-byte aligned)
    278 // %rsi == retaddr
    279 // %rdx == f
    280 // %rcx == arg1
    281 asm(
    282 ".globl _call_on_new_stack_0_1\n"
    283 "_call_on_new_stack_0_1:\n"
    284 "   movq  %rsp, %rbp\n"     // remember old stack pointer
    285 "   movq  %rdi, %rsp\n"     // set new stack
    286 "   movq  %rcx, %rdi\n"     // set arg1
    287 "   pushq %rsi\n"           // retaddr to new stack
    288 "   pushq %rdx\n"           // f to new stack
    289 "   movq $0, %rax\n"        // zero all other GP regs
    290 "   movq $0, %rbx\n"
    291 "   movq $0, %rcx\n"
    292 "   movq $0, %rdx\n"
    293 "   movq $0, %rsi\n"
    294 "   movq $0, %rbp\n"
    295 "   movq $0, %r8\n"
    296 "   movq $0, %r9\n"
    297 "   movq $0, %r10\n"
    298 "   movq $0, %r11\n"
    299 "   movq $0, %r12\n"
    300 "   movq $0, %r13\n"
    301 "   movq $0, %r14\n"
    302 "   movq $0, %r15\n"
    303 "   ret\n"                 // jump to f
    304 "   ud2\n"                 // should never get here
    305 );
    306 
    307 asm(
    308 ".globl _pthread_hijack_asm\n"
    309 "_pthread_hijack_asm:\n"
    310 "   movq %rsp,%rbp\n"
    311 "   push $0\n"    // alignment pad
    312 "   push %rbp\n"  // original sp
    313                   // other values stay where they are in registers
    314 "   push $0\n"    // fake return address
    315 "   jmp _pthread_hijack\n"
    316 );
    317 
    318 
    319 
    320 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
    321                     Addr stacksize, Addr flags, Addr sp)
    322 {
    323    vki_sigset_t blockall;
    324    ThreadState *tst = (ThreadState *)func_arg;
    325    VexGuestAMD64State *vex = &tst->arch.vex;
    326 
    327    // VG_(printf)("pthread_hijack pthread %p, machthread %p, func %p, arg %p, stack %p, flags %p, stack %p\n", self, kport, func, func_arg, stacksize, flags, sp);
    328 
    329    // Wait for parent thread's permission.
    330    // The parent thread holds V's lock on our behalf.
    331    semaphore_wait(tst->os_state.child_go);
    332 
    333    /* Start the thread with all signals blocked.  VG_(scheduler) will
    334       set the mask correctly when we finally get there. */
    335    VG_(sigfillset)(&blockall);
    336    VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
    337 
    338    // Set thread's registers
    339    // Do this FIRST because some code below tries to collect a backtrace,
    340    // which requires valid register data.
    341    LibVEX_GuestAMD64_initialise(vex);
    342    vex->guest_RIP = pthread_starter;
    343    vex->guest_RDI = self;
    344    vex->guest_RSI = kport;
    345    vex->guest_RDX = func;
    346    vex->guest_RCX = tst->os_state.func_arg;
    347    vex->guest_R8  = stacksize;
    348    vex->guest_R9  = flags;
    349    vex->guest_RSP = sp;
    350 
    351    // Record thread's stack and Mach port and pthread struct
    352    tst->os_state.pthread = self;
    353    tst->os_state.lwpid = kport;
    354    record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
    355 
    356    if ((flags & 0x01000000) == 0) {
    357       // kernel allocated stack - needs mapping
    358       Addr stack = VG_PGROUNDUP(sp) - stacksize;
    359       tst->client_stack_highest_word = stack+stacksize;
    360       tst->client_stack_szB = stacksize;
    361 
    362       // pthread structure
    363       ML_(notify_core_and_tool_of_mmap)(
    364             stack+stacksize, pthread_structsize,
    365             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
    366       // stack contents
    367       ML_(notify_core_and_tool_of_mmap)(
    368             stack, stacksize,
    369             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
    370       // guard page
    371       ML_(notify_core_and_tool_of_mmap)(
    372             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
    373             0, VKI_MAP_PRIVATE, -1, 0);
    374    } else {
    375       // client allocated stack
    376       find_stack_segment(tst->tid, sp);
    377    }
    378    ML_(sync_mappings)("after", "pthread_hijack", 0);
    379 
    380    // DDD: should this be here rather than in POST(sys_bsdthread_create)?
    381    // But we don't have ptid here...
    382    //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
    383 
    384    // Tell parent thread's POST(sys_bsdthread_create) that we're done
    385    // initializing registers and mapping memory.
    386    semaphore_signal(tst->os_state.child_done);
    387    // LOCK IS GONE BELOW THIS POINT
    388 
    389    // Go!
    390    call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
    391                          start_thread_NORETURN, (Word)tst);
    392 
    393    /*NOTREACHED*/
    394    vg_assert(0);
    395 }
    396 
    397 
    398 
    399 asm(
    400 ".globl _wqthread_hijack_asm\n"
    401 "_wqthread_hijack_asm:\n"
    402 "   movq %rsp,%r9\n"  // original sp
    403                       // other values stay where they are in registers
    404 "   push $0\n"        // fake return address
    405 "   jmp _wqthread_hijack\n"
    406 );
    407 
    408 
    409 /*  wqthread note: The kernel may create or destroy pthreads in the
    410     wqthread pool at any time with no userspace interaction,
    411     and wqthread_start may be entered at any time with no userspace
    412     interaction.
    413     To handle this in valgrind, we create and destroy a valgrind
    414     thread for every work item.
    415 */
    416 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
    417                      Int reuse, Addr sp)
    418 {
    419    ThreadState *tst;
    420    VexGuestAMD64State *vex;
    421    Addr stack;
    422    SizeT stacksize;
    423    vki_sigset_t blockall;
    424 
    425    /* When we enter here we hold no lock (!), so we better acquire it
    426       pronto.  Why do we hold no lock?  Because (presumably) the only
    427       way to get here is as a result of a SfMayBlock syscall
    428       "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
    429       lock.  At least that's clear for the 'reuse' case.  The
    430       non-reuse case?  Dunno, perhaps it's a new thread the kernel
    431       pulled out of a hat.  In any case we still need to take a
    432       lock. */
    433    VG_(acquire_BigLock_LL)("wqthread_hijack");
    434 
    435    if (0) VG_(printf)("wqthread_hijack: self %#lx, kport %#lx, "
    436                       "stackaddr %#lx, workitem %#lx, reuse %d, sp %#lx\n",
    437                       self, kport, stackaddr, workitem, reuse, sp);
    438 
    439    /* Start the thread with all signals blocked.  VG_(scheduler) will
    440       set the mask correctly when we finally get there. */
    441    VG_(sigfillset)(&blockall);
    442    VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
    443 
    444    if (reuse) {
    445 
    446      /* For whatever reason, tst->os_state.pthread appear to have a
    447         constant offset of 96 on 10.7, but zero on 10.6 and 10.5.  No
    448         idea why. */
    449 #      if DARWIN_VERS <= DARWIN_10_6
    450        UWord magic_delta = 0;
    451 #      elif DARWIN_VERS >= DARWIN_10_7
    452        UWord magic_delta = 0x60;
    453 #      endif
    454 
    455        // This thread already exists; we're merely re-entering
    456        // after leaving via workq_ops(WQOPS_THREAD_RETURN).
    457        // Don't allocate any V thread resources.
    458        // Do reset thread registers.
    459        ThreadId tid = VG_(lwpid_to_vgtid)(kport);
    460        vg_assert(VG_(is_valid_tid)(tid));
    461        vg_assert(mach_thread_self() == kport);
    462 
    463        tst = VG_(get_ThreadState)(tid);
    464 
    465        if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, "
    466                           "tst->os_state.pthread %#lx\n",
    467                           tst->os_state.pthread == self ? "SAME" : "DIFF",
    468                           tid, tst, tst->os_state.pthread);
    469 
    470        vex = &tst->arch.vex;
    471        vg_assert(tst->os_state.pthread - magic_delta == self);
    472    }
    473    else {
    474        // This is a new thread.
    475        tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
    476        vex = &tst->arch.vex;
    477        allocstack(tst->tid);
    478        LibVEX_GuestAMD64_initialise(vex);
    479    }
    480 
    481    // Set thread's registers
    482    // Do this FIRST because some code below tries to collect a backtrace,
    483    // which requires valid register data.
    484    vex->guest_RIP = wqthread_starter;
    485    vex->guest_RDI = self;
    486    vex->guest_RSI = kport;
    487    vex->guest_RDX = stackaddr;
    488    vex->guest_RCX = workitem;
    489    vex->guest_R8  = reuse;
    490    vex->guest_R9  = 0;
    491    vex->guest_RSP = sp;
    492 
    493    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
    494    stack = VG_PGROUNDUP(sp) - stacksize;
    495 
    496    if (reuse) {
    497       // Continue V's thread back in the scheduler.
    498       // The client thread is of course in another location entirely.
    499 
    500       /* Drop the lock before going into
    501          ML_(wqthread_continue_NORETURN).  The latter will immediately
    502          attempt to reacquire it in non-LL mode, which is a bit
    503          wasteful but I don't think is harmful.  A better solution
    504          would be to not drop the lock but instead "upgrade" it from a
    505          LL lock to a full lock, but that's too much like hard work
    506          right now. */
    507       VG_(release_BigLock_LL)("wqthread_hijack(1)");
    508       ML_(wqthread_continue_NORETURN)(tst->tid);
    509    }
    510    else {
    511       // Record thread's stack and Mach port and pthread struct
    512       tst->os_state.pthread = self;
    513       tst->os_state.lwpid = kport;
    514       record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
    515 
    516       // kernel allocated stack - needs mapping
    517       tst->client_stack_highest_word = stack+stacksize;
    518       tst->client_stack_szB = stacksize;
    519 
    520       // GrP fixme scheduler lock?!
    521 
    522       // pthread structure
    523       ML_(notify_core_and_tool_of_mmap)(
    524             stack+stacksize, pthread_structsize,
    525             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
    526       // stack contents
    527       // GrP fixme uninitialized!
    528       ML_(notify_core_and_tool_of_mmap)(
    529             stack, stacksize,
    530             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
    531       // guard page
    532       // GrP fixme ban_mem_stack!
    533       ML_(notify_core_and_tool_of_mmap)(
    534             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
    535             0, VKI_MAP_PRIVATE, -1, 0);
    536 
    537       ML_(sync_mappings)("after", "wqthread_hijack", 0);
    538 
    539       // Go!
    540       /* Same comments as the 'release' in the then-clause.
    541          start_thread_NORETURN calls run_thread_NORETURN calls
    542          thread_wrapper which acquires the lock before continuing.
    543          Let's hope nothing non-thread-local happens until that point.
    544 
    545          DDD: I think this is plain wrong .. if we get to
    546          thread_wrapper not holding the lock, and someone has recycled
    547          this thread slot in the meantime, we're hosed.  Is that
    548          possible, though? */
    549       VG_(release_BigLock_LL)("wqthread_hijack(2)");
    550       call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
    551                             start_thread_NORETURN, (Word)tst);
    552    }
    553 
    554    /*NOTREACHED*/
    555    vg_assert(0);
    556 }
    557 
    558 #endif // defined(VGP_amd64_darwin)
    559 
    560 /*--------------------------------------------------------------------*/
    561 /*--- end                                                          ---*/
    562 /*--------------------------------------------------------------------*/
    563