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-2010 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 "pub_core_basics.h"
34 #include "pub_core_vki.h"
35 #include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
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"
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"
64 #include <mach/mach.h>
66 static void x86_thread_state64_from_vex(x86_thread_state64_t *mach,
67 VexGuestAMD64State *vex)
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;
88 mach->__cs = vex->guest_CS;
89 mach->__fs = vex->guest_FS;
90 mach->__gs = vex->guest_GS;
95 static void x86_float_state64_from_vex(x86_float_state64_t *mach,
96 VexGuestAMD64State *vex)
98 // DDD: #warning GrP fixme fp state
100 VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
104 void thread_state_from_vex(thread_state_t mach_generic,
105 thread_state_flavor_t flavor,
106 mach_msg_type_number_t count,
107 VexGuestArchState *vex_generic)
109 VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
112 case x86_THREAD_STATE64:
113 vg_assert(count == x86_THREAD_STATE64_COUNT);
114 x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
117 case x86_FLOAT_STATE64:
118 vg_assert(count == x86_FLOAT_STATE64_COUNT);
119 x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
128 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach,
129 VexGuestAMD64State *vex)
131 LibVEX_GuestAMD64_initialise(vex);
132 vex->guest_RAX = mach->__rax;
133 vex->guest_RBX = mach->__rbx;
134 vex->guest_RCX = mach->__rcx;
135 vex->guest_RDX = mach->__rdx;
136 vex->guest_RDI = mach->__rdi;
137 vex->guest_RSI = mach->__rsi;
138 vex->guest_RBP = mach->__rbp;
139 vex->guest_RSP = mach->__rsp;
140 // DDD: #warning GrP fixme eflags
141 vex->guest_RIP = mach->__rip;
142 vex->guest_R8 = mach->__r8;
143 vex->guest_R9 = mach->__r9;
144 vex->guest_R10 = mach->__r10;
145 vex->guest_R11 = mach->__r11;
146 vex->guest_R12 = mach->__r12;
147 vex->guest_R13 = mach->__r13;
148 vex->guest_R14 = mach->__r14;
149 vex->guest_R15 = mach->__r15;
151 vex->guest_CS = mach->__cs;
152 vex->guest_FS = mach->__fs;
153 vex->guest_GS = mach->__gs;
157 static void x86_float_state64_to_vex(const x86_float_state64_t *mach,
158 VexGuestAMD64State *vex)
160 // DDD: #warning GrP fixme fp state
162 VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
166 void thread_state_to_vex(const thread_state_t mach_generic,
167 thread_state_flavor_t flavor,
168 mach_msg_type_number_t count,
169 VexGuestArchState *vex_generic)
171 VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
174 case x86_THREAD_STATE64:
175 vg_assert(count == x86_THREAD_STATE64_COUNT);
176 x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
178 case x86_FLOAT_STATE64:
179 vg_assert(count == x86_FLOAT_STATE64_COUNT);
180 x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
190 ThreadState *build_thread(const thread_state_t state,
191 thread_state_flavor_t flavor,
192 mach_msg_type_number_t count)
194 ThreadId tid = VG_(alloc_ThreadState)();
195 ThreadState *tst = VG_(get_ThreadState)(tid);
197 vg_assert(flavor == x86_THREAD_STATE64);
198 vg_assert(count == x86_THREAD_STATE64_COUNT);
200 // Initialize machine registers
202 thread_state_to_vex(state, flavor, count, &tst->arch.vex);
205 // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
207 find_stack_segment(tid, tst->arch.vex.guest_RSP);
213 // Edit the thread state to send to the real kernel.
214 // The real thread will run start_thread_NORETURN(tst)
215 // on a separate non-client stack.
216 void hijack_thread_state(thread_state_t mach_generic,
217 thread_state_flavor_t flavor,
218 mach_msg_type_number_t count,
221 x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
224 vg_assert(flavor == x86_THREAD_STATE64);
225 vg_assert(count == x86_THREAD_STATE64_COUNT);
227 stack = (char *)allocstack(tst->tid);
228 stack -= 64+320; // make room for top frame
229 memset(stack, 0, 64+320); // ...and clear it
230 *(uintptr_t *)stack = 0; // push fake return address
232 mach->__rdi = (uintptr_t)tst; // arg1 = tst
233 mach->__rip = (uintptr_t)&start_thread_NORETURN;
234 mach->__rsp = (uintptr_t)stack;
238 /* Call f(arg1), but first switch stacks, using 'stack' as the new
239 stack, and use 'retaddr' as f's return-to address. Also, clear all
240 the integer registers before entering f.*/
241 __attribute__((noreturn))
242 void call_on_new_stack_0_1 ( Addr stack,
246 // %rdi == stack (must be 16-byte aligned)
251 ".globl _call_on_new_stack_0_1\n"
252 "_call_on_new_stack_0_1:\n"
253 " movq %rsp, %rbp\n" // remember old stack pointer
254 " movq %rdi, %rsp\n" // set new stack
255 " movq %rcx, %rdi\n" // set arg1
256 " pushq %rsi\n" // retaddr to new stack
257 " pushq %rdx\n" // f to new stack
258 " movq $0, %rax\n" // zero all other GP regs
272 " ret\n" // jump to f
273 " ud2\n" // should never get here
277 ".globl _pthread_hijack_asm\n"
278 "_pthread_hijack_asm:\n"
280 " push $0\n" // alignment pad
281 " push %rbp\n" // original sp
282 // other values stay where they are in registers
283 " push $0\n" // fake return address
284 " jmp _pthread_hijack\n"
289 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
290 Addr stacksize, Addr flags, Addr sp)
292 vki_sigset_t blockall;
293 ThreadState *tst = (ThreadState *)func_arg;
294 VexGuestAMD64State *vex = &tst->arch.vex;
296 // 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);
298 // Wait for parent thread's permission.
299 // The parent thread holds V's lock on our behalf.
300 semaphore_wait(tst->os_state.child_go);
302 /* Start the thread with all signals blocked. VG_(scheduler) will
303 set the mask correctly when we finally get there. */
304 VG_(sigfillset)(&blockall);
305 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
307 // Set thread's registers
308 // Do this FIRST because some code below tries to collect a backtrace,
309 // which requires valid register data.
310 LibVEX_GuestAMD64_initialise(vex);
311 vex->guest_RIP = pthread_starter;
312 vex->guest_RDI = self;
313 vex->guest_RSI = kport;
314 vex->guest_RDX = func;
315 vex->guest_RCX = tst->os_state.func_arg;
316 vex->guest_R8 = stacksize;
317 vex->guest_R9 = flags;
320 // Record thread's stack and Mach port and pthread struct
321 tst->os_state.pthread = self;
322 tst->os_state.lwpid = kport;
323 record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
325 if ((flags & 0x01000000) == 0) {
326 // kernel allocated stack - needs mapping
327 Addr stack = VG_PGROUNDUP(sp) - stacksize;
328 tst->client_stack_highest_word = stack+stacksize;
329 tst->client_stack_szB = stacksize;
332 ML_(notify_core_and_tool_of_mmap)(
333 stack+stacksize, pthread_structsize,
334 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
336 ML_(notify_core_and_tool_of_mmap)(
338 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
340 ML_(notify_core_and_tool_of_mmap)(
341 stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
342 0, VKI_MAP_PRIVATE, -1, 0);
344 // client allocated stack
345 find_stack_segment(tst->tid, sp);
347 ML_(sync_mappings)("after", "pthread_hijack", 0);
349 // DDD: should this be here rather than in POST(sys_bsdthread_create)?
350 // But we don't have ptid here...
351 //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
353 // Tell parent thread's POST(sys_bsdthread_create) that we're done
354 // initializing registers and mapping memory.
355 semaphore_signal(tst->os_state.child_done);
356 // LOCK IS GONE BELOW THIS POINT
359 call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
360 start_thread_NORETURN, (Word)tst);
369 ".globl _wqthread_hijack_asm\n"
370 "_wqthread_hijack_asm:\n"
371 " movq %rsp,%r9\n" // original sp
372 // other values stay where they are in registers
373 " push $0\n" // fake return address
374 " jmp _wqthread_hijack\n"
378 /* wqthread note: The kernel may create or destroy pthreads in the
379 wqthread pool at any time with no userspace interaction,
380 and wqthread_start may be entered at any time with no userspace
382 To handle this in valgrind, we create and destroy a valgrind
383 thread for every work item.
385 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
389 VexGuestAMD64State *vex;
392 vki_sigset_t blockall;
394 /* When we enter here we hold no lock (!), so we better acquire it
395 pronto. Why do we hold no lock? Because (presumably) the only
396 way to get here is as a result of a SfMayBlock syscall
397 "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
398 lock. At least that's clear for the 'reuse' case. The
399 non-reuse case? Dunno, perhaps it's a new thread the kernel
400 pulled out of a hat. In any case we still need to take a
402 VG_(acquire_BigLock_LL)("wqthread_hijack");
404 /* Start the thread with all signals blocked. VG_(scheduler) will
405 set the mask correctly when we finally get there. */
406 VG_(sigfillset)(&blockall);
407 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
410 // This thread already exists; we're merely re-entering
411 // after leaving via workq_ops(WQOPS_THREAD_RETURN).
412 // Don't allocate any V thread resources.
413 // Do reset thread registers.
414 ThreadId tid = VG_(lwpid_to_vgtid)(kport);
415 vg_assert(VG_(is_valid_tid)(tid));
416 vg_assert(mach_thread_self() == kport);
418 tst = VG_(get_ThreadState)(tid);
419 vex = &tst->arch.vex;
420 vg_assert(tst->os_state.pthread == self);
423 // This is a new thread.
424 tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
425 vex = &tst->arch.vex;
426 allocstack(tst->tid);
427 LibVEX_GuestAMD64_initialise(vex);
430 // Set thread's registers
431 // Do this FIRST because some code below tries to collect a backtrace,
432 // which requires valid register data.
433 vex->guest_RIP = wqthread_starter;
434 vex->guest_RDI = self;
435 vex->guest_RSI = kport;
436 vex->guest_RDX = stackaddr;
437 vex->guest_RCX = workitem;
438 vex->guest_R8 = reuse;
442 stacksize = 512*1024; // wq stacks are always DEFAULT_STACK_SIZE
443 stack = VG_PGROUNDUP(sp) - stacksize;
446 // Continue V's thread back in the scheduler.
447 // The client thread is of course in another location entirely.
449 /* Drop the lock before going into
450 ML_(wqthread_continue_NORETURN). The latter will immediately
451 attempt to reacquire it in non-LL mode, which is a bit
452 wasteful but I don't think is harmful. A better solution
453 would be to not drop the lock but instead "upgrade" it from a
454 LL lock to a full lock, but that's too much like hard work
456 VG_(release_BigLock_LL)("wqthread_hijack(1)");
457 ML_(wqthread_continue_NORETURN)(tst->tid);
460 // Record thread's stack and Mach port and pthread struct
461 tst->os_state.pthread = self;
462 tst->os_state.lwpid = kport;
463 record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
465 // kernel allocated stack - needs mapping
466 tst->client_stack_highest_word = stack+stacksize;
467 tst->client_stack_szB = stacksize;
469 // GrP fixme scheduler lock?!
472 ML_(notify_core_and_tool_of_mmap)(
473 stack+stacksize, pthread_structsize,
474 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
476 // GrP fixme uninitialized!
477 ML_(notify_core_and_tool_of_mmap)(
479 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
481 // GrP fixme ban_mem_stack!
482 ML_(notify_core_and_tool_of_mmap)(
483 stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
484 0, VKI_MAP_PRIVATE, -1, 0);
486 ML_(sync_mappings)("after", "wqthread_hijack", 0);
489 /* Same comments as the 'release' in the then-clause.
490 start_thread_NORETURN calls run_thread_NORETURN calls
491 thread_wrapper which acquires the lock before continuing.
492 Let's hope nothing non-thread-local happens until that point.
494 DDD: I think this is plain wrong .. if we get to
495 thread_wrapper not holding the lock, and someone has recycled
496 this thread slot in the meantime, we're hosed. Is that
498 VG_(release_BigLock_LL)("wqthread_hijack(2)");
499 call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
500 start_thread_NORETURN, (Word)tst);
507 #endif // defined(VGP_amd64_darwin)
509 /*--------------------------------------------------------------------*/
511 /*--------------------------------------------------------------------*/