]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_syswrap/syswrap-amd64-darwin.c
70c5a9087623954f576a01fd5db586597942c084
[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_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"
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_state64_from_vex(x86_thread_state64_t *mach, 
66                                         VexGuestAMD64State *vex)
67 {
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;
86     /* GrP fixme
87     mach->__cs = vex->guest_CS;
88     mach->__fs = vex->guest_FS;
89     mach->__gs = vex->guest_GS;
90     */
91 }
92
93
94 static void x86_float_state64_from_vex(x86_float_state64_t *mach, 
95                                        VexGuestAMD64State *vex)
96 {
97    // DDD: #warning GrP fixme fp state
98
99    VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
100 }
101
102
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)
107 {
108    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
109
110    switch (flavor) {
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);
114       break;
115
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);
119       break;
120        
121    default:
122       vg_assert(0);
123    }
124 }
125
126
127 static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach, 
128                                       VexGuestAMD64State *vex)
129 {
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;
149    /* GrP fixme 
150    vex->guest_CS = mach->__cs;
151    vex->guest_FS = mach->__fs;
152    vex->guest_GS = mach->__gs;
153    */
154 }
155
156 static void x86_float_state64_to_vex(const x86_float_state64_t *mach, 
157                                      VexGuestAMD64State *vex)
158 {
159    // DDD: #warning GrP fixme fp state
160
161    VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
162 }
163
164
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)
169 {
170    VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
171    
172    switch(flavor) {
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);
176       break;
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);
180       break;
181
182    default:
183       vg_assert(0);
184       break;
185    }
186 }
187
188
189 ThreadState *build_thread(const thread_state_t state, 
190                           thread_state_flavor_t flavor, 
191                           mach_msg_type_number_t count)
192 {
193    ThreadId tid = VG_(alloc_ThreadState)();
194    ThreadState *tst = VG_(get_ThreadState)(tid);
195     
196    vg_assert(flavor == x86_THREAD_STATE64);
197    vg_assert(count == x86_THREAD_STATE64_COUNT);
198
199    // Initialize machine registers
200
201    thread_state_to_vex(state, flavor, count, &tst->arch.vex);
202
203    I_die_here;
204    // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
205
206    find_stack_segment(tid, tst->arch.vex.guest_RSP);
207
208    return tst;
209 }
210
211
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, 
218                          ThreadState *tst)
219 {
220    x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
221    char *stack;
222
223    vg_assert(flavor == x86_THREAD_STATE64);
224    vg_assert(count == x86_THREAD_STATE64_COUNT);
225
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
230
231    mach->__rdi = (uintptr_t)tst;          // arg1 = tst
232    mach->__rip = (uintptr_t)&start_thread_NORETURN;
233    mach->__rsp = (uintptr_t)stack;
234 }
235
236
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,
242                              Addr retaddr,
243                              void (*f)(Word),
244                              Word arg1 );
245 // %rdi == stack (must be 16-byte aligned)
246 // %rsi == retaddr
247 // %rdx == f
248 // %rcx == arg1
249 asm(
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
258 "   movq $0, %rbx\n"
259 "   movq $0, %rcx\n"
260 "   movq $0, %rdx\n"
261 "   movq $0, %rsi\n"
262 "   movq $0, %rbp\n"
263 "   movq $0, %r8\n"
264 "   movq $0, %r9\n"
265 "   movq $0, %r10\n"
266 "   movq $0, %r11\n"
267 "   movq $0, %r12\n"
268 "   movq $0, %r13\n"
269 "   movq $0, %r14\n"
270 "   movq $0, %r15\n"
271 "   ret\n"                 // jump to f
272 "   ud2\n"                 // should never get here
273 );
274
275 asm(
276 ".globl _pthread_hijack_asm\n"
277 "_pthread_hijack_asm:\n"
278 "   movq %rsp,%rbp\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"
284     );
285
286
287
288 void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
289                     Addr stacksize, Addr flags, Addr sp)
290 {
291    ThreadState *tst = (ThreadState *)func_arg;
292    VexGuestAMD64State *vex = &tst->arch.vex;
293
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);
295
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);
299
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;
311    vex->guest_RSP = sp;
312
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");
317
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;
323
324       // pthread structure
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);
328       // stack contents
329       ML_(notify_core_and_tool_of_mmap)(
330             stack, stacksize, 
331             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
332       // guard page
333       ML_(notify_core_and_tool_of_mmap)(
334             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
335    } else {
336       // client allocated stack
337       find_stack_segment(tst->tid, sp);
338    }
339    VG_(am_do_sync_check)("after", "pthread_hijack", 0);
340
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
345
346    // Go!
347    call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
348                          start_thread_NORETURN, (Word)tst);
349
350    /*NOTREACHED*/
351    vg_assert(0);
352 }
353
354
355
356 asm(
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"
363     );
364
365
366 /*
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 
370     interaction.
371     To handle this in valgrind, we create and destroy a valgrind 
372     thread for every work item.
373 */
374 void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 
375                      Int reuse, Addr sp)
376 {
377    ThreadState *tst;
378    VexGuestAMD64State *vex;
379    Addr stack;
380    SizeT stacksize;
381
382    if (reuse) {
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);
390
391        tst = VG_(get_ThreadState)(tid);
392        vex = &tst->arch.vex;
393        vg_assert(tst->os_state.pthread == self);
394    }
395    else {
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);
401    }
402        
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;
412    vex->guest_R9  = 0;
413    vex->guest_RSP = sp;
414
415    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
416    stack = VG_PGROUNDUP(sp) - stacksize;
417
418    if (reuse) {
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);
422    } 
423    else {
424
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");
429       
430       // kernel allocated stack - needs mapping
431       tst->client_stack_highest_word = stack+stacksize;
432       tst->client_stack_szB = stacksize;
433
434       // GrP fixme scheduler lock?!
435       
436       // pthread structure
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);
440       // stack contents
441       // GrP fixme uninitialized!
442       ML_(notify_core_and_tool_of_mmap)(
443             stack, stacksize, 
444             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
445       // guard page
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);
449
450       VG_(am_do_sync_check)("after", "wqthread_hijack", 0);
451
452       // Go!
453       call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
454                             start_thread_NORETURN, (Word)tst);
455    }
456
457    /*NOTREACHED*/
458    vg_assert(0);
459 }
460
461 #endif // defined(VGP_amd64_darwin)
462
463 /*--------------------------------------------------------------------*/
464 /*--- end                                                          ---*/
465 /*--------------------------------------------------------------------*/