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