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_threadstate.h"
36 #include "pub_core_aspacemgr.h"
37 #include "pub_core_xarray.h"
38 #include "pub_core_clientstate.h"
39 #include "pub_core_debuglog.h"
40 #include "pub_core_debuginfo.h" // VG_(di_notify_*)
41 #include "pub_core_transtab.h" // VG_(discard_translations)
42 #include "pub_core_libcbase.h"
43 #include "pub_core_libcassert.h"
44 #include "pub_core_libcfile.h"
45 #include "pub_core_libcprint.h"
46 #include "pub_core_libcproc.h"
47 #include "pub_core_libcsignal.h"
48 #include "pub_core_mallocfree.h"
49 #include "pub_core_options.h"
50 #include "pub_core_scheduler.h"
51 #include "pub_core_sigframe.h" // For VG_(sigframe_destroy)()
52 #include "pub_core_signals.h"
53 #include "pub_core_syscall.h"
54 #include "pub_core_syswrap.h"
55 #include "pub_core_tooliface.h"
57 #include "priv_types_n_macros.h"
58 #include "priv_syswrap-generic.h" /* for decls of generic wrappers */
59 #include "priv_syswrap-darwin.h" /* for decls of darwin-ish wrappers */
60 #include "priv_syswrap-main.h"
63 #include <mach/mach.h>
65 static void x86_thread_state64_from_vex(x86_thread_state64_t *mach,
66 VexGuestAMD64State *vex)
68 mach->__rax = vex->guest_RAX;
69 mach->__rbx = vex->guest_RBX;
70 mach->__rcx = vex->guest_RCX;
71 mach->__rdx = vex->guest_RDX;
72 mach->__rdi = vex->guest_RDI;
73 mach->__rsi = vex->guest_RSI;
74 mach->__rbp = vex->guest_RBP;
75 mach->__rsp = vex->guest_RSP;
76 mach->__rflags = LibVEX_GuestAMD64_get_rflags(vex);
77 mach->__rip = vex->guest_RIP;
78 mach->__r8 = vex->guest_R8;
79 mach->__r9 = vex->guest_R9;
80 mach->__r10 = vex->guest_R10;
81 mach->__r11 = vex->guest_R11;
82 mach->__r12 = vex->guest_R12;
83 mach->__r13 = vex->guest_R13;
84 mach->__r14 = vex->guest_R14;
85 mach->__r15 = vex->guest_R15;
87 mach->__cs = vex->guest_CS;
88 mach->__fs = vex->guest_FS;
89 mach->__gs = vex->guest_GS;
94 static void x86_float_state64_from_vex(x86_float_state64_t *mach,
95 VexGuestAMD64State *vex)
97 // DDD: #warning GrP fixme fp state
99 VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
103 void thread_state_from_vex(thread_state_t mach_generic,
104 thread_state_flavor_t flavor,
105 mach_msg_type_number_t count,
106 VexGuestArchState *vex_generic)
108 VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
111 case x86_THREAD_STATE64:
112 vg_assert(count == x86_THREAD_STATE64_COUNT);
113 x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
116 case x86_FLOAT_STATE64:
117 vg_assert(count == x86_FLOAT_STATE64_COUNT);
118 x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
127 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach,
128 VexGuestAMD64State *vex)
130 LibVEX_GuestAMD64_initialise(vex);
131 vex->guest_RAX = mach->__rax;
132 vex->guest_RBX = mach->__rbx;
133 vex->guest_RCX = mach->__rcx;
134 vex->guest_RDX = mach->__rdx;
135 vex->guest_RDI = mach->__rdi;
136 vex->guest_RSI = mach->__rsi;
137 vex->guest_RBP = mach->__rbp;
138 vex->guest_RSP = mach->__rsp;
139 // DDD: #warning GrP fixme eflags
140 vex->guest_RIP = mach->__rip;
141 vex->guest_R8 = mach->__r8;
142 vex->guest_R9 = mach->__r9;
143 vex->guest_R10 = mach->__r10;
144 vex->guest_R11 = mach->__r11;
145 vex->guest_R12 = mach->__r12;
146 vex->guest_R13 = mach->__r13;
147 vex->guest_R14 = mach->__r14;
148 vex->guest_R15 = mach->__r15;
150 vex->guest_CS = mach->__cs;
151 vex->guest_FS = mach->__fs;
152 vex->guest_GS = mach->__gs;
156 static void x86_float_state64_to_vex(const x86_float_state64_t *mach,
157 VexGuestAMD64State *vex)
159 // DDD: #warning GrP fixme fp state
161 VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
165 void thread_state_to_vex(const thread_state_t mach_generic,
166 thread_state_flavor_t flavor,
167 mach_msg_type_number_t count,
168 VexGuestArchState *vex_generic)
170 VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
173 case x86_THREAD_STATE64:
174 vg_assert(count == x86_THREAD_STATE64_COUNT);
175 x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
177 case x86_FLOAT_STATE64:
178 vg_assert(count == x86_FLOAT_STATE64_COUNT);
179 x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
189 ThreadState *build_thread(const thread_state_t state,
190 thread_state_flavor_t flavor,
191 mach_msg_type_number_t count)
193 ThreadId tid = VG_(alloc_ThreadState)();
194 ThreadState *tst = VG_(get_ThreadState)(tid);
196 vg_assert(flavor == x86_THREAD_STATE64);
197 vg_assert(count == x86_THREAD_STATE64_COUNT);
199 // Initialize machine registers
201 thread_state_to_vex(state, flavor, count, &tst->arch.vex);
204 // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
206 find_stack_segment(tid, tst->arch.vex.guest_RSP);
212 // Edit the thread state to send to the real kernel.
213 // The real thread will run start_thread_NORETURN(tst)
214 // on a separate non-client stack.
215 void hijack_thread_state(thread_state_t mach_generic,
216 thread_state_flavor_t flavor,
217 mach_msg_type_number_t count,
220 x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
223 vg_assert(flavor == x86_THREAD_STATE64);
224 vg_assert(count == x86_THREAD_STATE64_COUNT);
226 stack = (char *)allocstack(tst->tid);
227 stack -= 64+320; // make room for top frame
228 memset(stack, 0, 64+320); // ...and clear it
229 *(uintptr_t *)stack = 0; // push fake return address
231 mach->__rdi = (uintptr_t)tst; // arg1 = tst
232 mach->__rip = (uintptr_t)&start_thread_NORETURN;
233 mach->__rsp = (uintptr_t)stack;
237 /* Call f(arg1), but first switch stacks, using 'stack' as the new
238 stack, and use 'retaddr' as f's return-to address. Also, clear all
239 the integer registers before entering f.*/
240 __attribute__((noreturn))
241 void call_on_new_stack_0_1 ( Addr stack,
245 // %rdi == stack (must be 16-byte aligned)
250 ".globl _call_on_new_stack_0_1\n"
251 "_call_on_new_stack_0_1:\n"
252 " movq %rsp, %rbp\n" // remember old stack pointer
253 " movq %rdi, %rsp\n" // set new stack
254 " movq %rcx, %rdi\n" // set arg1
255 " pushq %rsi\n" // retaddr to new stack
256 " pushq %rdx\n" // f to new stack
257 " movq $0, %rax\n" // zero all other GP regs
271 " ret\n" // jump to f
272 " ud2\n" // should never get here
276 ".globl _pthread_hijack_asm\n"
277 "_pthread_hijack_asm:\n"
279 " push $0\n" // alignment pad
280 " push %rbp\n" // original sp
281 // other values stay where they are in registers
282 " push $0\n" // fake return address
283 " jmp _pthread_hijack\n"
288 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
289 Addr stacksize, Addr flags, Addr sp)
291 ThreadState *tst = (ThreadState *)func_arg;
292 VexGuestAMD64State *vex = &tst->arch.vex;
294 // 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);
296 // Wait for parent thread's permission.
297 // The parent thread holds V's lock on our behalf.
298 semaphore_wait(tst->os_state.child_go);
300 // Set thread's registers
301 // Do this FIRST because some code below tries to collect a backtrace,
302 // which requires valid register data.
303 LibVEX_GuestAMD64_initialise(vex);
304 vex->guest_RIP = pthread_starter;
305 vex->guest_RDI = self;
306 vex->guest_RSI = kport;
307 vex->guest_RDX = func;
308 vex->guest_RCX = tst->os_state.func_arg;
309 vex->guest_R8 = stacksize;
310 vex->guest_R9 = flags;
313 // Record thread's stack and Mach port and pthread struct
314 tst->os_state.pthread = self;
315 tst->os_state.lwpid = kport;
316 record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
318 if ((flags & 0x01000000) == 0) {
319 // kernel allocated stack - needs mapping
320 Addr stack = VG_PGROUNDUP(sp) - stacksize;
321 tst->client_stack_highest_word = stack+stacksize;
322 tst->client_stack_szB = stacksize;
325 ML_(notify_core_and_tool_of_mmap)(
326 stack+stacksize, pthread_structsize,
327 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
329 ML_(notify_core_and_tool_of_mmap)(
331 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
333 ML_(notify_core_and_tool_of_mmap)(
334 stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
336 // client allocated stack
337 find_stack_segment(tst->tid, sp);
339 VG_(am_do_sync_check)("after", "pthread_hijack", 0);
341 // Tell parent thread's POST(sys_bsdthread_create) that we're done
342 // initializing registers and mapping memory.
343 semaphore_signal(tst->os_state.child_done);
344 // LOCK IS GONE BELOW THIS POINT
347 call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
348 start_thread_NORETURN, (Word)tst);
357 ".globl _wqthread_hijack_asm\n"
358 "_wqthread_hijack_asm:\n"
359 " movq %rsp,%r9\n" // original sp
360 // other values stay where they are in registers
361 " push $0\n" // fake return address
362 " jmp _wqthread_hijack\n"
367 wqthread note: The kernel may create or destroy pthreads in the
368 wqthread pool at any time with no userspace interaction,
369 and wqthread_start may be entered at any time with no userspace
371 To handle this in valgrind, we create and destroy a valgrind
372 thread for every work item.
374 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
378 VexGuestAMD64State *vex;
383 // This thread already exists; we're merely re-entering
384 // after leaving via workq_ops(WQOPS_THREAD_RETURN).
385 // Don't allocate any V thread resources.
386 // Do reset thread registers.
387 ThreadId tid = VG_(lwpid_to_vgtid)(kport);
388 vg_assert(VG_(is_valid_tid)(tid));
389 vg_assert(mach_thread_self() == kport);
391 tst = VG_(get_ThreadState)(tid);
392 vex = &tst->arch.vex;
393 vg_assert(tst->os_state.pthread == self);
396 // This is a new thread.
397 tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
398 vex = &tst->arch.vex;
399 allocstack(tst->tid);
400 LibVEX_GuestAMD64_initialise(vex);
403 // Set thread's registers
404 // Do this FIRST because some code below tries to collect a backtrace,
405 // which requires valid register data.
406 vex->guest_RIP = wqthread_starter;
407 vex->guest_RDI = self;
408 vex->guest_RSI = kport;
409 vex->guest_RDX = stackaddr;
410 vex->guest_RCX = workitem;
411 vex->guest_R8 = reuse;
415 stacksize = 512*1024; // wq stacks are always DEFAULT_STACK_SIZE
416 stack = VG_PGROUNDUP(sp) - stacksize;
419 // Continue V's thread back in the scheduler.
420 // The client thread is of course in another location entirely.
421 ML_(wqthread_continue_NORETURN)(tst->tid);
425 // Record thread's stack and Mach port and pthread struct
426 tst->os_state.pthread = self;
427 tst->os_state.lwpid = kport;
428 record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
430 // kernel allocated stack - needs mapping
431 tst->client_stack_highest_word = stack+stacksize;
432 tst->client_stack_szB = stacksize;
434 // GrP fixme scheduler lock?!
437 ML_(notify_core_and_tool_of_mmap)(
438 stack+stacksize, pthread_structsize,
439 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
441 // GrP fixme uninitialized!
442 ML_(notify_core_and_tool_of_mmap)(
444 VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
446 // GrP fixme ban_mem_stack!
447 ML_(notify_core_and_tool_of_mmap)(
448 stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
450 VG_(am_do_sync_check)("after", "wqthread_hijack", 0);
453 call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
454 start_thread_NORETURN, (Word)tst);
461 #endif // defined(VGP_amd64_darwin)
463 /*--------------------------------------------------------------------*/
465 /*--------------------------------------------------------------------*/