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