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-2013 Apple Inc.
11      Greg Parker  gparker@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
67static 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
96static 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
120void 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
144static 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
173static 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
197void 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
221ThreadState *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.
247void 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))
273void 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
281asm(
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
307asm(
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
320void 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
399asm(
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*/
416void 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)(
436             "wqthread_hijack: self %#lx, kport %#lx, "
437	     "stackaddr %#lx, workitem %#lx, reuse/flags %x, sp %#lx\n",
438	     self, kport, stackaddr, workitem, reuse, sp);
439
440   /* Start the thread with all signals blocked.  VG_(scheduler) will
441      set the mask correctly when we finally get there. */
442   VG_(sigfillset)(&blockall);
443   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
444
445   /* For 10.7 and earlier, |reuse| appeared to be used as a simple
446      boolean.  In 10.8 and later its name changed to |flags| and has
447      various other bits OR-d into it too, so it's necessary to fish
448      out just the relevant parts.  Hence: */
449#  if DARWIN_VERS <= DARWIN_10_7
450   Bool is_reuse = reuse != 0;
451#  elif DARWIN_VERS == DARWIN_10_8
452   Bool is_reuse = (reuse & 0x20000 /* == WQ_FLAG_THREAD_REUSE */) != 0;
453#  endif
454
455   if (is_reuse) {
456
457     /* For whatever reason, tst->os_state.pthread appear to have a
458        constant offset of 96 on 10.7, but zero on 10.6 and 10.5.  No
459        idea why. */
460#      if DARWIN_VERS <= DARWIN_10_6
461       UWord magic_delta = 0;
462#      elif DARWIN_VERS >= DARWIN_10_7
463       UWord magic_delta = 0x60;
464#      endif
465
466       // This thread already exists; we're merely re-entering
467       // after leaving via workq_ops(WQOPS_THREAD_RETURN).
468       // Don't allocate any V thread resources.
469       // Do reset thread registers.
470       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
471       vg_assert(VG_(is_valid_tid)(tid));
472       vg_assert(mach_thread_self() == kport);
473
474       tst = VG_(get_ThreadState)(tid);
475
476       if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, "
477                          "tst->os_state.pthread %#lx\n",
478                          tst->os_state.pthread == self ? "SAME" : "DIFF",
479                          tid, tst, tst->os_state.pthread);
480
481       vex = &tst->arch.vex;
482       vg_assert(tst->os_state.pthread - magic_delta == self);
483   }
484   else {
485       // This is a new thread.
486       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
487       vex = &tst->arch.vex;
488       allocstack(tst->tid);
489       LibVEX_GuestAMD64_initialise(vex);
490   }
491
492   // Set thread's registers
493   // Do this FIRST because some code below tries to collect a backtrace,
494   // which requires valid register data.
495   vex->guest_RIP = wqthread_starter;
496   vex->guest_RDI = self;
497   vex->guest_RSI = kport;
498   vex->guest_RDX = stackaddr;
499   vex->guest_RCX = workitem;
500   vex->guest_R8  = reuse;
501   vex->guest_R9  = 0;
502   vex->guest_RSP = sp;
503
504   stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
505   stack = VG_PGROUNDUP(sp) - stacksize;
506
507   if (is_reuse) {
508      // Continue V's thread back in the scheduler.
509      // The client thread is of course in another location entirely.
510
511      /* Drop the lock before going into
512         ML_(wqthread_continue_NORETURN).  The latter will immediately
513         attempt to reacquire it in non-LL mode, which is a bit
514         wasteful but I don't think is harmful.  A better solution
515         would be to not drop the lock but instead "upgrade" it from a
516         LL lock to a full lock, but that's too much like hard work
517         right now. */
518      VG_(release_BigLock_LL)("wqthread_hijack(1)");
519      ML_(wqthread_continue_NORETURN)(tst->tid);
520   }
521   else {
522      // Record thread's stack and Mach port and pthread struct
523      tst->os_state.pthread = self;
524      tst->os_state.lwpid = kport;
525      record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
526
527      // kernel allocated stack - needs mapping
528      tst->client_stack_highest_word = stack+stacksize;
529      tst->client_stack_szB = stacksize;
530
531      // GrP fixme scheduler lock?!
532
533      // pthread structure
534      ML_(notify_core_and_tool_of_mmap)(
535            stack+stacksize, pthread_structsize,
536            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
537      // stack contents
538      // GrP fixme uninitialized!
539      ML_(notify_core_and_tool_of_mmap)(
540            stack, stacksize,
541            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
542      // guard page
543      // GrP fixme ban_mem_stack!
544      ML_(notify_core_and_tool_of_mmap)(
545            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
546            0, VKI_MAP_PRIVATE, -1, 0);
547
548      ML_(sync_mappings)("after", "wqthread_hijack", 0);
549
550      // Go!
551      /* Same comments as the 'release' in the then-clause.
552         start_thread_NORETURN calls run_thread_NORETURN calls
553         thread_wrapper which acquires the lock before continuing.
554         Let's hope nothing non-thread-local happens until that point.
555
556         DDD: I think this is plain wrong .. if we get to
557         thread_wrapper not holding the lock, and someone has recycled
558         this thread slot in the meantime, we're hosed.  Is that
559         possible, though? */
560      VG_(release_BigLock_LL)("wqthread_hijack(2)");
561      call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
562                            start_thread_NORETURN, (Word)tst);
563   }
564
565   /*NOTREACHED*/
566   vg_assert(0);
567}
568
569#endif // defined(VGP_amd64_darwin)
570
571/*--------------------------------------------------------------------*/
572/*--- end                                                          ---*/
573/*--------------------------------------------------------------------*/
574