0863abfa852c5c083ec4db865befa9909ab6c0fc
[sdk/tools/upstream/valgrind.git] / coregrind / m_syswrap / syswrap-amd64-darwin.c
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-2011 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
67 static 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
96 static void x86_float_state64_from_vex(x86_float_state64_t *mach, 
97                                        VexGuestAMD64State *vex)
98 {
99    // DDD: #warning GrP fixme fp state
100
101    VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
102 }
103
104
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)
109 {
110    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
111
112    switch (flavor) {
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);
116       break;
117
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);
121       break;
122        
123    default:
124       vg_assert(0);
125    }
126 }
127
128
129 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach, 
130                                       VexGuestAMD64State *vex)
131 {
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;
151    /* GrP fixme 
152    vex->guest_CS = mach->__cs;
153    vex->guest_FS = mach->__fs;
154    vex->guest_GS = mach->__gs;
155    */
156 }
157
158 static void x86_float_state64_to_vex(const x86_float_state64_t *mach, 
159                                      VexGuestAMD64State *vex)
160 {
161    // DDD: #warning GrP fixme fp state
162
163    VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
164 }
165
166
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)
171 {
172    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
173    
174    switch(flavor) {
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);
178       break;
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);
182       break;
183
184    default:
185       vg_assert(0);
186       break;
187    }
188 }
189
190
191 ThreadState *build_thread(const thread_state_t state, 
192                           thread_state_flavor_t flavor, 
193                           mach_msg_type_number_t count)
194 {
195    ThreadId tid = VG_(alloc_ThreadState)();
196    ThreadState *tst = VG_(get_ThreadState)(tid);
197     
198    vg_assert(flavor == x86_THREAD_STATE64);
199    vg_assert(count == x86_THREAD_STATE64_COUNT);
200
201    // Initialize machine registers
202
203    thread_state_to_vex(state, flavor, count, &tst->arch.vex);
204
205    I_die_here;
206    // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
207
208    find_stack_segment(tid, tst->arch.vex.guest_RSP);
209
210    return tst;
211 }
212
213
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, 
220                          ThreadState *tst)
221 {
222    x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
223    char *stack;
224
225    vg_assert(flavor == x86_THREAD_STATE64);
226    vg_assert(count == x86_THREAD_STATE64_COUNT);
227
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
232
233    mach->__rdi = (uintptr_t)tst;          // arg1 = tst
234    mach->__rip = (uintptr_t)&start_thread_NORETURN;
235    mach->__rsp = (uintptr_t)stack;
236 }
237
238
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,
244                              Addr retaddr,
245                              void (*f)(Word),
246                              Word arg1 );
247 // %rdi == stack (must be 16-byte aligned)
248 // %rsi == retaddr
249 // %rdx == f
250 // %rcx == arg1
251 asm(
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
260 "   movq $0, %rbx\n"
261 "   movq $0, %rcx\n"
262 "   movq $0, %rdx\n"
263 "   movq $0, %rsi\n"
264 "   movq $0, %rbp\n"
265 "   movq $0, %r8\n"
266 "   movq $0, %r9\n"
267 "   movq $0, %r10\n"
268 "   movq $0, %r11\n"
269 "   movq $0, %r12\n"
270 "   movq $0, %r13\n"
271 "   movq $0, %r14\n"
272 "   movq $0, %r15\n"
273 "   ret\n"                 // jump to f
274 "   ud2\n"                 // should never get here
275 );
276
277 asm(
278 ".globl _pthread_hijack_asm\n"
279 "_pthread_hijack_asm:\n"
280 "   movq %rsp,%rbp\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"
286 );
287
288
289
290 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
291                     Addr stacksize, Addr flags, Addr sp)
292 {
293    vki_sigset_t blockall;
294    ThreadState *tst = (ThreadState *)func_arg;
295    VexGuestAMD64State *vex = &tst->arch.vex;
296
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);
298
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);
302
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);
307
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;
319    vex->guest_RSP = sp;
320
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");
325
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;
331
332       // pthread structure
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);
336       // stack contents
337       ML_(notify_core_and_tool_of_mmap)(
338             stack, stacksize, 
339             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
340       // guard page
341       ML_(notify_core_and_tool_of_mmap)(
342             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
343             0, VKI_MAP_PRIVATE, -1, 0);
344    } else {
345       // client allocated stack
346       find_stack_segment(tst->tid, sp);
347    }
348    ML_(sync_mappings)("after", "pthread_hijack", 0);
349
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 );
353
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
358
359    // Go!
360    call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
361                          start_thread_NORETURN, (Word)tst);
362
363    /*NOTREACHED*/
364    vg_assert(0);
365 }
366
367
368
369 asm(
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"
376 );
377
378
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 
382     interaction.
383     To handle this in valgrind, we create and destroy a valgrind 
384     thread for every work item.
385 */
386 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 
387                      Int reuse, Addr sp)
388 {
389    ThreadState *tst;
390    VexGuestAMD64State *vex;
391    Addr stack;
392    SizeT stacksize;
393    vki_sigset_t blockall;
394
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
402       lock. */
403    VG_(acquire_BigLock_LL)("wqthread_hijack");
404
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);
408
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);
413
414    if (reuse) {
415
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
418         idea why. */
419 #      if DARWIN_VERS <= DARWIN_10_6
420        UWord magic_delta = 0;
421 #      elif DARWIN_VERS == DARWIN_10_7
422        UWord magic_delta = 0x60;
423 #      endif
424
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);
432
433        tst = VG_(get_ThreadState)(tid);
434
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);
439
440        vex = &tst->arch.vex;
441        vg_assert(tst->os_state.pthread - magic_delta == self);
442    }
443    else {
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);
449    }
450        
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;
460    vex->guest_R9  = 0;
461    vex->guest_RSP = sp;
462
463    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
464    stack = VG_PGROUNDUP(sp) - stacksize;
465
466    if (reuse) {
467       // Continue V's thread back in the scheduler. 
468       // The client thread is of course in another location entirely.
469
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
476          right now. */
477       VG_(release_BigLock_LL)("wqthread_hijack(1)");
478       ML_(wqthread_continue_NORETURN)(tst->tid);
479    } 
480    else {
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");
485       
486       // kernel allocated stack - needs mapping
487       tst->client_stack_highest_word = stack+stacksize;
488       tst->client_stack_szB = stacksize;
489
490       // GrP fixme scheduler lock?!
491       
492       // pthread structure
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);
496       // stack contents
497       // GrP fixme uninitialized!
498       ML_(notify_core_and_tool_of_mmap)(
499             stack, stacksize, 
500             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
501       // guard page
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);
506
507       ML_(sync_mappings)("after", "wqthread_hijack", 0);
508
509       // Go!
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.
514
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
518          possible, though? */
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);
522    }
523
524    /*NOTREACHED*/
525    vg_assert(0);
526 }
527
528 #endif // defined(VGP_amd64_darwin)
529
530 /*--------------------------------------------------------------------*/
531 /*--- end                                                          ---*/
532 /*--------------------------------------------------------------------*/