]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_syswrap/syswrap-amd64-darwin.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / 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-2010 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 "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"
57
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"
62
63
64 #include <mach/mach.h>
65
66 static void x86_thread_state64_from_vex(x86_thread_state64_t *mach, 
67                                         VexGuestAMD64State *vex)
68 {
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;
87     /* GrP fixme
88     mach->__cs = vex->guest_CS;
89     mach->__fs = vex->guest_FS;
90     mach->__gs = vex->guest_GS;
91     */
92 }
93
94
95 static void x86_float_state64_from_vex(x86_float_state64_t *mach, 
96                                        VexGuestAMD64State *vex)
97 {
98    // DDD: #warning GrP fixme fp state
99
100    VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
101 }
102
103
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)
108 {
109    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
110
111    switch (flavor) {
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);
115       break;
116
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);
120       break;
121        
122    default:
123       vg_assert(0);
124    }
125 }
126
127
128 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach, 
129                                       VexGuestAMD64State *vex)
130 {
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;
150    /* GrP fixme 
151    vex->guest_CS = mach->__cs;
152    vex->guest_FS = mach->__fs;
153    vex->guest_GS = mach->__gs;
154    */
155 }
156
157 static void x86_float_state64_to_vex(const x86_float_state64_t *mach, 
158                                      VexGuestAMD64State *vex)
159 {
160    // DDD: #warning GrP fixme fp state
161
162    VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
163 }
164
165
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)
170 {
171    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
172    
173    switch(flavor) {
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);
177       break;
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);
181       break;
182
183    default:
184       vg_assert(0);
185       break;
186    }
187 }
188
189
190 ThreadState *build_thread(const thread_state_t state, 
191                           thread_state_flavor_t flavor, 
192                           mach_msg_type_number_t count)
193 {
194    ThreadId tid = VG_(alloc_ThreadState)();
195    ThreadState *tst = VG_(get_ThreadState)(tid);
196     
197    vg_assert(flavor == x86_THREAD_STATE64);
198    vg_assert(count == x86_THREAD_STATE64_COUNT);
199
200    // Initialize machine registers
201
202    thread_state_to_vex(state, flavor, count, &tst->arch.vex);
203
204    I_die_here;
205    // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
206
207    find_stack_segment(tid, tst->arch.vex.guest_RSP);
208
209    return tst;
210 }
211
212
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, 
219                          ThreadState *tst)
220 {
221    x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
222    char *stack;
223
224    vg_assert(flavor == x86_THREAD_STATE64);
225    vg_assert(count == x86_THREAD_STATE64_COUNT);
226
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
231
232    mach->__rdi = (uintptr_t)tst;          // arg1 = tst
233    mach->__rip = (uintptr_t)&start_thread_NORETURN;
234    mach->__rsp = (uintptr_t)stack;
235 }
236
237
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,
243                              Addr retaddr,
244                              void (*f)(Word),
245                              Word arg1 );
246 // %rdi == stack (must be 16-byte aligned)
247 // %rsi == retaddr
248 // %rdx == f
249 // %rcx == arg1
250 asm(
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
259 "   movq $0, %rbx\n"
260 "   movq $0, %rcx\n"
261 "   movq $0, %rdx\n"
262 "   movq $0, %rsi\n"
263 "   movq $0, %rbp\n"
264 "   movq $0, %r8\n"
265 "   movq $0, %r9\n"
266 "   movq $0, %r10\n"
267 "   movq $0, %r11\n"
268 "   movq $0, %r12\n"
269 "   movq $0, %r13\n"
270 "   movq $0, %r14\n"
271 "   movq $0, %r15\n"
272 "   ret\n"                 // jump to f
273 "   ud2\n"                 // should never get here
274 );
275
276 asm(
277 ".globl _pthread_hijack_asm\n"
278 "_pthread_hijack_asm:\n"
279 "   movq %rsp,%rbp\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"
285     );
286
287
288
289 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
290                     Addr stacksize, Addr flags, Addr sp)
291 {
292    vki_sigset_t blockall;
293    ThreadState *tst = (ThreadState *)func_arg;
294    VexGuestAMD64State *vex = &tst->arch.vex;
295
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);
297
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);
301
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);
306
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;
318    vex->guest_RSP = sp;
319
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");
324
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;
330
331       // pthread structure
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);
335       // stack contents
336       ML_(notify_core_and_tool_of_mmap)(
337             stack, stacksize, 
338             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
339       // guard page
340       ML_(notify_core_and_tool_of_mmap)(
341             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
342             0, VKI_MAP_PRIVATE, -1, 0);
343    } else {
344       // client allocated stack
345       find_stack_segment(tst->tid, sp);
346    }
347    ML_(sync_mappings)("after", "pthread_hijack", 0);
348
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 );
352
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
357
358    // Go!
359    call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
360                          start_thread_NORETURN, (Word)tst);
361
362    /*NOTREACHED*/
363    vg_assert(0);
364 }
365
366
367
368 asm(
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"
375     );
376
377
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 
381     interaction.
382     To handle this in valgrind, we create and destroy a valgrind 
383     thread for every work item.
384 */
385 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 
386                      Int reuse, Addr sp)
387 {
388    ThreadState *tst;
389    VexGuestAMD64State *vex;
390    Addr stack;
391    SizeT stacksize;
392    vki_sigset_t blockall;
393
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
401       lock. */
402    VG_(acquire_BigLock_LL)("wqthread_hijack");
403
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);
408
409    if (reuse) {
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);
417
418        tst = VG_(get_ThreadState)(tid);
419        vex = &tst->arch.vex;
420        vg_assert(tst->os_state.pthread == self);
421    }
422    else {
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);
428    }
429        
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;
439    vex->guest_R9  = 0;
440    vex->guest_RSP = sp;
441
442    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
443    stack = VG_PGROUNDUP(sp) - stacksize;
444
445    if (reuse) {
446       // Continue V's thread back in the scheduler. 
447       // The client thread is of course in another location entirely.
448
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
455          right now. */
456       VG_(release_BigLock_LL)("wqthread_hijack(1)");
457       ML_(wqthread_continue_NORETURN)(tst->tid);
458    } 
459    else {
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");
464       
465       // kernel allocated stack - needs mapping
466       tst->client_stack_highest_word = stack+stacksize;
467       tst->client_stack_szB = stacksize;
468
469       // GrP fixme scheduler lock?!
470       
471       // pthread structure
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);
475       // stack contents
476       // GrP fixme uninitialized!
477       ML_(notify_core_and_tool_of_mmap)(
478             stack, stacksize, 
479             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
480       // guard page
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);
485
486       ML_(sync_mappings)("after", "wqthread_hijack", 0);
487
488       // Go!
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.
493
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
497          possible, though? */
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);
501    }
502
503    /*NOTREACHED*/
504    vg_assert(0);
505 }
506
507 #endif // defined(VGP_amd64_darwin)
508
509 /*--------------------------------------------------------------------*/
510 /*--- end                                                          ---*/
511 /*--------------------------------------------------------------------*/