]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_syswrap/syswrap-x86-darwin.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_syswrap / syswrap-x86-darwin.c
1
2 /*--------------------------------------------------------------------*/
3 /*--- Darwin-specific syscalls, etc.          syswrap-x86-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_x86_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_signals.h"
53 #include "pub_core_syscall.h"
54 #include "pub_core_syswrap.h"
55 #include "pub_core_tooliface.h"
56
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"
61
62
63 #include <mach/mach.h>
64
65 static void x86_thread_state32_from_vex(i386_thread_state_t *mach, 
66                                         VexGuestX86State *vex)
67 {
68     mach->__eax = vex->guest_EAX;
69     mach->__ebx = vex->guest_EBX;
70     mach->__ecx = vex->guest_ECX;
71     mach->__edx = vex->guest_EDX;
72     mach->__edi = vex->guest_EDI;
73     mach->__esi = vex->guest_ESI;
74     mach->__ebp = vex->guest_EBP;
75     mach->__esp = vex->guest_ESP;
76     mach->__ss = vex->guest_SS;
77     mach->__eflags = LibVEX_GuestX86_get_eflags(vex);
78     mach->__eip = vex->guest_EIP;
79     mach->__cs = vex->guest_CS;
80     mach->__ds = vex->guest_DS;
81     mach->__es = vex->guest_ES;
82     mach->__fs = vex->guest_FS;
83     mach->__gs = vex->guest_GS;
84 }
85
86
87 static void x86_float_state32_from_vex(i386_float_state_t *mach, 
88                                        VexGuestX86State *vex)
89 {
90    // DDD: #warning GrP fixme fp state
91
92    VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 8 * sizeof(mach->__fpu_xmm0));
93 }
94
95
96 void thread_state_from_vex(thread_state_t mach_generic, 
97                            thread_state_flavor_t flavor, 
98                            mach_msg_type_number_t count, 
99                            VexGuestArchState *vex_generic)
100 {
101    VexGuestX86State *vex = (VexGuestX86State *)vex_generic;
102
103    switch (flavor) {
104    case i386_THREAD_STATE:
105       vg_assert(count == i386_THREAD_STATE_COUNT);
106       x86_thread_state32_from_vex((i386_thread_state_t *)mach_generic, vex);
107       break;
108
109    case i386_FLOAT_STATE:
110       vg_assert(count == i386_FLOAT_STATE_COUNT);
111       x86_float_state32_from_vex((i386_float_state_t *)mach_generic, vex);
112       break;
113        
114    default:
115       vg_assert(0);
116    }
117 }
118
119
120 static void x86_thread_state32_to_vex(const i386_thread_state_t *mach, 
121                                       VexGuestX86State *vex)
122 {
123    LibVEX_GuestX86_initialise(vex);
124    vex->guest_EAX = mach->__eax;
125    vex->guest_EBX = mach->__ebx;
126    vex->guest_ECX = mach->__ecx;
127    vex->guest_EDX = mach->__edx;
128    vex->guest_EDI = mach->__edi;
129    vex->guest_ESI = mach->__esi;
130    vex->guest_EBP = mach->__ebp;
131    vex->guest_ESP = mach->__esp;
132    vex->guest_SS = mach->__ss;
133    // DDD: #warning GrP fixme eflags
134    vex->guest_EIP = mach->__eip;
135    vex->guest_CS = mach->__cs;
136    vex->guest_DS = mach->__ds;
137    vex->guest_ES = mach->__es;
138    vex->guest_FS = mach->__fs;
139    vex->guest_GS = mach->__gs;
140 }
141
142 static void x86_float_state32_to_vex(const i386_float_state_t *mach, 
143                                      VexGuestX86State *vex)
144 {
145    // DDD: #warning GrP fixme fp state
146
147    VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 8 * sizeof(mach->__fpu_xmm0));
148 }
149
150
151 void thread_state_to_vex(const thread_state_t mach_generic, 
152                          thread_state_flavor_t flavor, 
153                          mach_msg_type_number_t count, 
154                          VexGuestArchState *vex_generic)
155 {
156    VexGuestX86State *vex = (VexGuestX86State *)vex_generic;
157    
158    switch(flavor) {
159    case i386_THREAD_STATE:
160       vg_assert(count == i386_THREAD_STATE_COUNT);
161       x86_thread_state32_to_vex((const i386_thread_state_t*)mach_generic,vex);
162       break;
163    case i386_FLOAT_STATE:
164       vg_assert(count == i386_FLOAT_STATE_COUNT);
165       x86_float_state32_to_vex((const i386_float_state_t*)mach_generic,vex);
166       break;
167
168    default:
169       vg_assert(0);
170       break;
171    }
172 }
173
174
175 ThreadState *build_thread(const thread_state_t state, 
176                           thread_state_flavor_t flavor, 
177                           mach_msg_type_number_t count)
178 {
179    ThreadId tid = VG_(alloc_ThreadState)();
180    ThreadState *tst = VG_(get_ThreadState)(tid);
181     
182    vg_assert(flavor == i386_THREAD_STATE);
183    vg_assert(count == i386_THREAD_STATE_COUNT);
184
185    // Initialize machine registers
186
187    thread_state_to_vex(state, flavor, count, &tst->arch.vex);
188
189    I_die_here;
190    // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
191
192    find_stack_segment(tid, tst->arch.vex.guest_ESP);
193
194    return tst;
195 }
196
197
198 // Edit the thread state to send to the real kernel.
199 // The real thread will run start_thread_NORETURN(tst)
200 // on a separate non-client stack.
201 void hijack_thread_state(thread_state_t mach_generic, 
202                          thread_state_flavor_t flavor, 
203                          mach_msg_type_number_t count, 
204                          ThreadState *tst)
205 {
206    i386_thread_state_t *mach = (i386_thread_state_t *)mach_generic;
207    char *stack;
208
209    vg_assert(flavor == i386_THREAD_STATE);
210    vg_assert(count == i386_THREAD_STATE_COUNT);
211
212    stack = (char *)allocstack(tst->tid);
213    stack -= 64+320;                       // make room for top frame
214    memset(stack, 0, 64+320);              // ...and clear it
215    *(uintptr_t *)stack = (uintptr_t)tst;  // set parameter
216    stack -= sizeof(uintptr_t);
217    *(uintptr_t *)stack = 0;               // push fake return address
218
219    mach->__eip = (uintptr_t)&start_thread_NORETURN;
220    mach->__esp = (uintptr_t)stack;
221 }
222
223
224 /* Call f(arg1), but first switch stacks, using 'stack' as the new
225    stack, and use 'retaddr' as f's return-to address.  Also, clear all
226    the integer registers before entering f.*/
227 __attribute__((noreturn))
228 void call_on_new_stack_0_1 ( Addr stack,
229                              Addr retaddr,
230                              void (*f)(Word),
231                              Word arg1 );
232 //  4(%esp) == stack (must be 16-byte aligned)
233 //  8(%esp) == retaddr
234 // 12(%esp) == f
235 // 16(%esp) == arg1
236 asm(
237 ".globl _call_on_new_stack_0_1\n"
238 "_call_on_new_stack_0_1:\n"
239 "   movl %esp, %esi\n"     // remember old stack pointer
240 "   movl 4(%esi), %esp\n"  // set new stack
241 "   pushl $0\n"            // align stack
242 "   pushl $0\n"            // align stack
243 "   pushl $0\n"            // align stack
244 "   pushl 16(%esi)\n"      // arg1 to stack
245 "   pushl  8(%esi)\n"      // retaddr to stack
246 "   pushl 12(%esi)\n"      // f to stack
247 "   movl $0, %eax\n"       // zero all GP regs
248 "   movl $0, %ebx\n"
249 "   movl $0, %ecx\n"
250 "   movl $0, %edx\n"
251 "   movl $0, %esi\n"
252 "   movl $0, %edi\n"
253 "   movl $0, %ebp\n"
254 "   ret\n"                 // jump to f
255 "   ud2\n"                 // should never get here
256 );
257
258
259 asm(
260 ".globl _pthread_hijack_asm\n"
261 "_pthread_hijack_asm:\n"
262 "   movl %esp,%ebp\n"
263 "   push $0\n"    // alignment pad
264 "   push %ebp\n"  // original sp
265 "   push %esi\n"  // flags
266 "   push %edi\n"  // stacksize
267 "   push %edx\n"  // func_arg
268 "   push %ecx\n"  // func
269 "   push %ebx\n"  // kport
270 "   push %eax\n"  // self
271 "   push $0\n"    // fake return address
272 "   jmp _pthread_hijack\n"
273     );
274
275
276
277 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
278                     Addr stacksize, Addr flags, Addr sp)
279 {
280    vki_sigset_t blockall;
281    ThreadState *tst = (ThreadState *)func_arg;
282    VexGuestX86State *vex = &tst->arch.vex;
283
284    // 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);
285
286    // Wait for parent thread's permission.
287    // The parent thread holds V's lock on our behalf.
288    semaphore_wait(tst->os_state.child_go);
289
290    /* Start the thread with all signals blocked.  VG_(scheduler) will
291       set the mask correctly when we finally get there. */
292    VG_(sigfillset)(&blockall);
293    VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
294
295    // Set thread's registers
296    // Do this FIRST because some code below tries to collect a backtrace, 
297    // which requires valid register data.
298    // DDD: need to do post_reg_write events here?
299    LibVEX_GuestX86_initialise(vex);
300    vex->guest_EIP = pthread_starter;
301    vex->guest_EAX = self;
302    vex->guest_EBX = kport;
303    vex->guest_ECX = func;
304    vex->guest_EDX = tst->os_state.func_arg;
305    vex->guest_EDI = stacksize;
306    vex->guest_ESI = flags;
307    vex->guest_ESP = sp;
308
309    // Record thread's stack and Mach port and pthread struct
310    tst->os_state.pthread = self;
311    tst->os_state.lwpid = kport;
312    record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
313
314    if ((flags & 0x01000000) == 0) {
315       // kernel allocated stack - needs mapping
316       Addr stack = VG_PGROUNDUP(sp) - stacksize;
317       tst->client_stack_highest_word = stack+stacksize;
318       tst->client_stack_szB = stacksize;
319
320       // pthread structure
321       ML_(notify_core_and_tool_of_mmap)(
322             stack+stacksize, pthread_structsize, 
323             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
324       // stack contents
325       ML_(notify_core_and_tool_of_mmap)(
326             stack, stacksize, 
327             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
328       // guard page
329       ML_(notify_core_and_tool_of_mmap)(
330             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 
331             0, VKI_MAP_PRIVATE, -1, 0);
332    } else {
333       // client allocated stack
334       find_stack_segment(tst->tid, sp);
335    }
336    ML_(sync_mappings)("after", "pthread_hijack", 0);
337
338    // DDD: should this be here rather than in POST(sys_bsdthread_create)?
339    // But we don't have ptid here...
340    //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
341
342    // Tell parent thread's POST(sys_bsdthread_create) that we're done 
343    // initializing registers and mapping memory.
344    semaphore_signal(tst->os_state.child_done);
345    // LOCK IS GONE BELOW THIS POINT
346
347    // Go!
348    call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
349                          start_thread_NORETURN, (Word)tst);
350
351    /*NOTREACHED*/
352    vg_assert(0);
353 }
354
355
356
357 asm(
358 ".globl _wqthread_hijack_asm\n"
359 "_wqthread_hijack_asm:\n"
360 "   movl %esp,%ebp\n"
361 "   push $0\n"    // alignment
362 "   push $0\n"    // alignment
363 "   push %ebp\n"  // original sp
364 "   push %edi\n"  // reuse
365 "   push %edx\n"  // workitem
366 "   push %ecx\n"  // stackaddr
367 "   push %ebx\n"  // kport
368 "   push %eax\n"  // self
369 "   push $0\n"    // fake return address
370 "   jmp _wqthread_hijack\n"
371     );
372
373
374 /*  wqthread note: The kernel may create or destroy pthreads in the 
375     wqthread pool at any time with no userspace interaction, 
376     and wqthread_start may be entered at any time with no userspace 
377     interaction.
378     To handle this in valgrind, we create and destroy a valgrind 
379     thread for every work item.
380 */
381 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 
382                      Int reuse, Addr sp)
383 {
384    ThreadState *tst;
385    VexGuestX86State *vex;
386    Addr stack;
387    SizeT stacksize;
388    vki_sigset_t blockall;
389
390    /* When we enter here we hold no lock (!), so we better acquire it
391       pronto.  Why do we hold no lock?  Because (presumably) the only
392       way to get here is as a result of a SfMayBlock syscall
393       "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
394       lock.  At least that's clear for the 'reuse' case.  The
395       non-reuse case?  Dunno, perhaps it's a new thread the kernel
396       pulled out of a hat.  In any case we still need to take a
397       lock. */
398    VG_(acquire_BigLock_LL)("wqthread_hijack");
399
400    /* Start the thread with all signals blocked.  VG_(scheduler) will
401       set the mask correctly when we finally get there. */
402    VG_(sigfillset)(&blockall);
403    VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
404
405    if (reuse) {
406       // This thread already exists; we're merely re-entering 
407       // after leaving via workq_ops(WQOPS_THREAD_RETURN). 
408       // Don't allocate any V thread resources.
409       // Do reset thread registers.
410       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
411       vg_assert(VG_(is_valid_tid)(tid));
412       vg_assert(mach_thread_self() == kport);
413
414       tst = VG_(get_ThreadState)(tid);
415       vex = &tst->arch.vex;
416       vg_assert(tst->os_state.pthread == self);
417    }
418    else {
419       // This is a new thread.
420       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());        
421       vex = &tst->arch.vex;
422       allocstack(tst->tid);
423       LibVEX_GuestX86_initialise(vex);
424    }
425         
426    // Set thread's registers
427    // Do this FIRST because some code below tries to collect a backtrace, 
428    // which requires valid register data.
429    vex->guest_EIP = wqthread_starter;
430    vex->guest_EAX = self;
431    vex->guest_EBX = kport;
432    vex->guest_ECX = stackaddr;
433    vex->guest_EDX = workitem;
434    vex->guest_EDI = reuse;
435    vex->guest_ESI = 0;
436    vex->guest_ESP = sp;
437
438    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
439    stack = VG_PGROUNDUP(sp) - stacksize;
440
441    if (reuse) {
442        // Continue V's thread back in the scheduler. 
443        // The client thread is of course in another location entirely.
444
445       /* Drop the lock before going into
446          ML_(wqthread_continue_NORETURN).  The latter will immediately
447          attempt to reacquire it in non-LL mode, which is a bit
448          wasteful but I don't think is harmful.  A better solution
449          would be to not drop the lock but instead "upgrade" it from a
450          LL lock to a full lock, but that's too much like hard work
451          right now. */
452        VG_(release_BigLock_LL)("wqthread_hijack(1)");
453        ML_(wqthread_continue_NORETURN)(tst->tid);
454    } 
455    else {
456       // Record thread's stack and Mach port and pthread struct
457       tst->os_state.pthread = self;
458       tst->os_state.lwpid = kport;
459       record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
460       
461       // kernel allocated stack - needs mapping
462       tst->client_stack_highest_word = stack+stacksize;
463       tst->client_stack_szB = stacksize;
464
465       // GrP fixme scheduler lock?!
466       
467       // pthread structure
468       ML_(notify_core_and_tool_of_mmap)(
469             stack+stacksize, pthread_structsize, 
470             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
471       // stack contents
472       // GrP fixme uninitialized!
473       ML_(notify_core_and_tool_of_mmap)(
474             stack, stacksize, 
475             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
476       // guard page
477       // GrP fixme ban_mem_stack!
478       ML_(notify_core_and_tool_of_mmap)(
479             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 
480             0, VKI_MAP_PRIVATE, -1, 0);
481
482       ML_(sync_mappings)("after", "wqthread_hijack", 0);
483
484       // Go!
485       /* Same comments as the 'release' in the then-clause.
486          start_thread_NORETURN calls run_thread_NORETURN calls
487          thread_wrapper which acquires the lock before continuing.
488          Let's hope nothing non-thread-local happens until that point.
489
490          DDD: I think this is plain wrong .. if we get to
491          thread_wrapper not holding the lock, and someone has recycled
492          this thread slot in the meantime, we're hosed.  Is that
493          possible, though? */
494       VG_(release_BigLock_LL)("wqthread_hijack(2)");
495       call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
496                             start_thread_NORETURN, (Word)tst);
497    }
498
499    /*NOTREACHED*/
500    vg_assert(0);
501 }
502
503 #endif // defined(VGP_x86_darwin)
504
505 /*--------------------------------------------------------------------*/
506 /*--- end                                                          ---*/
507 /*--------------------------------------------------------------------*/