2 /*--------------------------------------------------------------------*/
3 /*--- Darwin-specific syscalls, etc. syswrap-amd64-darwin.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2005-2011 Apple Inc.
11 Greg Parker gparker@apple.com
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.
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.
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
28 The GNU General Public License is contained in the file COPYING.
31 #if defined(VGP_amd64_darwin)
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"
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"
65 #include <mach/mach.h>
67 static void x86_thread_state64_from_vex(x86_thread_state64_t *mach,
68 VexGuestAMD64State *vex)
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;
89 mach->__cs = vex->guest_CS;
90 mach->__fs = vex->guest_FS;
91 mach->__gs = vex->guest_GS;
96 static void x86_float_state64_from_vex(x86_float_state64_t *mach,
97 VexGuestAMD64State *vex)
99 // DDD: #warning GrP fixme fp state
101 VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
105 void thread_state_from_vex(thread_state_t mach_generic,
106 thread_state_flavor_t flavor,
107 mach_msg_type_number_t count,
108 VexGuestArchState *vex_generic)
110 VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
113 case x86_THREAD_STATE64:
114 vg_assert(count == x86_THREAD_STATE64_COUNT);
115 x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
118 case x86_FLOAT_STATE64:
119 vg_assert(count == x86_FLOAT_STATE64_COUNT);
120 x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
129 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach,
130 VexGuestAMD64State *vex)
132 LibVEX_GuestAMD64_initialise(vex);
133 vex->guest_RAX = mach->__rax;
134 vex->guest_RBX = mach->__rbx;
135 vex->guest_RCX = mach->__rcx;
136 vex->guest_RDX = mach->__rdx;
137 vex->guest_RDI = mach->__rdi;
138 vex->guest_RSI = mach->__rsi;
139 vex->guest_RBP = mach->__rbp;
140 vex->guest_RSP = mach->__rsp;
141 // DDD: #warning GrP fixme eflags
142 vex->guest_RIP = mach->__rip;
143 vex->guest_R8 = mach->__r8;
144 vex->guest_R9 = mach->__r9;
145 vex->guest_R10 = mach->__r10;
146 vex->guest_R11 = mach->__r11;
147 vex->guest_R12 = mach->__r12;
148 vex->guest_R13 = mach->__r13;
149 vex->guest_R14 = mach->__r14;
150 vex->guest_R15 = mach->__r15;
152 vex->guest_CS = mach->__cs;
153 vex->guest_FS = mach->__fs;
154 vex->guest_GS = mach->__gs;
158 static void x86_float_state64_to_vex(const x86_float_state64_t *mach,
159 VexGuestAMD64State *vex)
161 // DDD: #warning GrP fixme fp state
163 VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
167 void thread_state_to_vex(const thread_state_t mach_generic,
168 thread_state_flavor_t flavor,
169 mach_msg_type_number_t count,
170 VexGuestArchState *vex_generic)
172 VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
175 case x86_THREAD_STATE64:
176 vg_assert(count == x86_THREAD_STATE64_COUNT);
177 x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
179 case x86_FLOAT_STATE64:
180 vg_assert(count == x86_FLOAT_STATE64_COUNT);
181 x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
191 ThreadState *build_thread(const thread_state_t state,
192 thread_state_flavor_t flavor,
193 mach_msg_type_number_t count)
195 ThreadId tid = VG_(alloc_ThreadState)();
196 ThreadState *tst = VG_(get_ThreadState)(tid);
198 vg_assert(flavor == x86_THREAD_STATE64);
199 vg_assert(count == x86_THREAD_STATE64_COUNT);
201 // Initialize machine registers
203 thread_state_to_vex(state, flavor, count, &tst->arch.vex);
206 // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
208 find_stack_segment(tid, tst->arch.vex.guest_RSP);
214 // Edit the thread state to send to the real kernel.
215 // The real thread will run start_thread_NORETURN(tst)
216 // on a separate non-client stack.
217 void hijack_thread_state(thread_state_t mach_generic,
218 thread_state_flavor_t flavor,
219 mach_msg_type_number_t count,
222 x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
225 vg_assert(flavor == x86_THREAD_STATE64);
226 vg_assert(count == x86_THREAD_STATE64_COUNT);
228 stack = (char *)allocstack(tst->tid);
229 stack -= 64+320; // make room for top frame
230 memset(stack, 0, 64+320); // ...and clear it
231 *(uintptr_t *)stack = 0; // push fake return address
233 mach->__rdi = (uintptr_t)tst; // arg1 = tst
234 mach->__rip = (uintptr_t)&start_thread_NORETURN;
235 mach->__rsp = (uintptr_t)stack;
239 /* Call f(arg1), but first switch stacks, using 'stack' as the new
240 stack, and use 'retaddr' as f's return-to address. Also, clear all
241 the integer registers before entering f.*/
242 __attribute__((noreturn))
243 void call_on_new_stack_0_1 ( Addr stack,
247 // %rdi == stack (must be 16-byte aligned)
252 ".globl _call_on_new_stack_0_1\n"
253 "_call_on_new_stack_0_1:\n"
254 " movq %rsp, %rbp\n" // remember old stack pointer
255 " movq %rdi, %rsp\n" // set new stack
256 " movq %rcx, %rdi\n" // set arg1
257 " pushq %rsi\n" // retaddr to new stack
258 " pushq %rdx\n" // f to new stack
259 " movq $0, %rax\n" // zero all other GP regs
273 " ret\n" // jump to f
274 " ud2\n" // should never get here
278 ".globl _pthread_hijack_asm\n"
279 "_pthread_hijack_asm:\n"
281 " push $0\n" // alignment pad
282 " push %rbp\n" // original sp
283 // other values stay where they are in registers
284 " push $0\n" // fake return address
285 " jmp _pthread_hijack\n"
290 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
291 Addr stacksize, Addr flags, Addr sp)
293 vki_sigset_t blockall;
294 ThreadState *tst = (ThreadState *)func_arg;
295 VexGuestAMD64State *vex = &tst->arch.vex;
297 // 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);
299 // Wait for parent thread's permission.
300 // The parent thread holds V's lock on our behalf.
301 semaphore_wait(tst->os_state.child_go);
303 /* Start the thread with all signals blocked. VG_(scheduler) will
304 set the mask correctly when we finally get there. */
305 VG_(sigfillset)(&blockall);
306 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
308 // Set thread's registers
309 // Do this FIRST because some code below tries to collect a backtrace,
310 // which requires valid register data.
311 LibVEX_GuestAMD64_initialise(vex);
312 vex->guest_RIP = pthread_starter;
313 vex->guest_RDI = self;
314 vex->guest_RSI = kport;
315 vex->guest_RDX = func;
316 vex->guest_RCX = tst->os_state.func_arg;
317 vex->guest_R8 = stacksize;
318 vex->guest_R9 = flags;
321 // Record thread's stack and Mach port and pthread struct
322 tst->os_state.pthread = self;
323 tst->os_state.lwpid = kport;
324 record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
326 if ((flags & 0x01000000) == 0) {
327 // kernel allocated stack - needs mapping
328 Addr stack = VG_PGROUNDUP(sp) - stacksize;
329 tst->client_stack_highest_word = stack+stacksize;
330 tst->client_stack_szB = stacksize;
333 ML_(notify_core_and_tool_of_mmap)(
334 stack+stacksize, pthread_structsize,
335 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
337 ML_(notify_core_and_tool_of_mmap)(
339 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
341 ML_(notify_core_and_tool_of_mmap)(
342 stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
343 0, VKI_MAP_PRIVATE, -1, 0);
345 // client allocated stack
346 find_stack_segment(tst->tid, sp);
348 ML_(sync_mappings)("after", "pthread_hijack", 0);
350 // DDD: should this be here rather than in POST(sys_bsdthread_create)?
351 // But we don't have ptid here...
352 //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
354 // Tell parent thread's POST(sys_bsdthread_create) that we're done
355 // initializing registers and mapping memory.
356 semaphore_signal(tst->os_state.child_done);
357 // LOCK IS GONE BELOW THIS POINT
360 call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
361 start_thread_NORETURN, (Word)tst);
370 ".globl _wqthread_hijack_asm\n"
371 "_wqthread_hijack_asm:\n"
372 " movq %rsp,%r9\n" // original sp
373 // other values stay where they are in registers
374 " push $0\n" // fake return address
375 " jmp _wqthread_hijack\n"
379 /* wqthread note: The kernel may create or destroy pthreads in the
380 wqthread pool at any time with no userspace interaction,
381 and wqthread_start may be entered at any time with no userspace
383 To handle this in valgrind, we create and destroy a valgrind
384 thread for every work item.
386 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
390 VexGuestAMD64State *vex;
393 vki_sigset_t blockall;
395 /* When we enter here we hold no lock (!), so we better acquire it
396 pronto. Why do we hold no lock? Because (presumably) the only
397 way to get here is as a result of a SfMayBlock syscall
398 "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
399 lock. At least that's clear for the 'reuse' case. The
400 non-reuse case? Dunno, perhaps it's a new thread the kernel
401 pulled out of a hat. In any case we still need to take a
403 VG_(acquire_BigLock_LL)("wqthread_hijack");
405 if (0) VG_(printf)("wqthread_hijack: self %#lx, kport %#lx, "
406 "stackaddr %#lx, workitem %#lx, reuse %d, sp %#lx\n",
407 self, kport, stackaddr, workitem, reuse, sp);
409 /* Start the thread with all signals blocked. VG_(scheduler) will
410 set the mask correctly when we finally get there. */
411 VG_(sigfillset)(&blockall);
412 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
416 /* For whatever reason, tst->os_state.pthread appear to have a
417 constant offset of 96 on 10.7, but zero on 10.6 and 10.5. No
419 # if DARWIN_VERS <= DARWIN_10_6
420 UWord magic_delta = 0;
421 # elif DARWIN_VERS == DARWIN_10_7
422 UWord magic_delta = 0x60;
425 // This thread already exists; we're merely re-entering
426 // after leaving via workq_ops(WQOPS_THREAD_RETURN).
427 // Don't allocate any V thread resources.
428 // Do reset thread registers.
429 ThreadId tid = VG_(lwpid_to_vgtid)(kport);
430 vg_assert(VG_(is_valid_tid)(tid));
431 vg_assert(mach_thread_self() == kport);
433 tst = VG_(get_ThreadState)(tid);
435 if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, "
436 "tst->os_state.pthread %#lx\n",
437 tst->os_state.pthread == self ? "SAME" : "DIFF",
438 tid, tst, tst->os_state.pthread);
440 vex = &tst->arch.vex;
441 vg_assert(tst->os_state.pthread - magic_delta == self);
444 // This is a new thread.
445 tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
446 vex = &tst->arch.vex;
447 allocstack(tst->tid);
448 LibVEX_GuestAMD64_initialise(vex);
451 // Set thread's registers
452 // Do this FIRST because some code below tries to collect a backtrace,
453 // which requires valid register data.
454 vex->guest_RIP = wqthread_starter;
455 vex->guest_RDI = self;
456 vex->guest_RSI = kport;
457 vex->guest_RDX = stackaddr;
458 vex->guest_RCX = workitem;
459 vex->guest_R8 = reuse;
463 stacksize = 512*1024; // wq stacks are always DEFAULT_STACK_SIZE
464 stack = VG_PGROUNDUP(sp) - stacksize;
467 // Continue V's thread back in the scheduler.
468 // The client thread is of course in another location entirely.
470 /* Drop the lock before going into
471 ML_(wqthread_continue_NORETURN). The latter will immediately
472 attempt to reacquire it in non-LL mode, which is a bit
473 wasteful but I don't think is harmful. A better solution
474 would be to not drop the lock but instead "upgrade" it from a
475 LL lock to a full lock, but that's too much like hard work
477 VG_(release_BigLock_LL)("wqthread_hijack(1)");
478 ML_(wqthread_continue_NORETURN)(tst->tid);
481 // Record thread's stack and Mach port and pthread struct
482 tst->os_state.pthread = self;
483 tst->os_state.lwpid = kport;
484 record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
486 // kernel allocated stack - needs mapping
487 tst->client_stack_highest_word = stack+stacksize;
488 tst->client_stack_szB = stacksize;
490 // GrP fixme scheduler lock?!
493 ML_(notify_core_and_tool_of_mmap)(
494 stack+stacksize, pthread_structsize,
495 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
497 // GrP fixme uninitialized!
498 ML_(notify_core_and_tool_of_mmap)(
500 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
502 // GrP fixme ban_mem_stack!
503 ML_(notify_core_and_tool_of_mmap)(
504 stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
505 0, VKI_MAP_PRIVATE, -1, 0);
507 ML_(sync_mappings)("after", "wqthread_hijack", 0);
510 /* Same comments as the 'release' in the then-clause.
511 start_thread_NORETURN calls run_thread_NORETURN calls
512 thread_wrapper which acquires the lock before continuing.
513 Let's hope nothing non-thread-local happens until that point.
515 DDD: I think this is plain wrong .. if we get to
516 thread_wrapper not holding the lock, and someone has recycled
517 this thread slot in the meantime, we're hosed. Is that
519 VG_(release_BigLock_LL)("wqthread_hijack(2)");
520 call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
521 start_thread_NORETURN, (Word)tst);
528 #endif // defined(VGP_amd64_darwin)
530 /*--------------------------------------------------------------------*/
532 /*--------------------------------------------------------------------*/