• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2013 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 
x86_thread_state32_from_vex(i386_thread_state_t * mach,VexGuestX86State * vex)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 
x86_float_state32_from_vex(i386_float_state_t * mach,VexGuestX86State * vex)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 
thread_state_from_vex(thread_state_t mach_generic,thread_state_flavor_t flavor,mach_msg_type_number_t count,VexGuestArchState * vex_generic)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 
x86_thread_state32_to_vex(const i386_thread_state_t * mach,VexGuestX86State * vex)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 
x86_float_state32_to_vex(const i386_float_state_t * mach,VexGuestX86State * vex)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 
thread_state_to_vex(const thread_state_t mach_generic,thread_state_flavor_t flavor,mach_msg_type_number_t count,VexGuestArchState * vex_generic)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 
build_thread(const thread_state_t state,thread_state_flavor_t flavor,mach_msg_type_number_t count)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.
hijack_thread_state(thread_state_t mach_generic,thread_state_flavor_t flavor,mach_msg_type_number_t count,ThreadState * tst)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 
pthread_hijack(Addr self,Addr kport,Addr func,Addr func_arg,Addr stacksize,Addr flags,Addr sp)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 */
wqthread_hijack(Addr self,Addr kport,Addr stackaddr,Addr workitem,Int reuse,Addr sp)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 
407       /* For whatever reason, tst->os_state.pthread appear to have a
408          constant offset of 72 on 10.7, but zero on 10.6 and 10.5.  No
409          idea why. */
410 #     if DARWIN_VERS <= DARWIN_10_6
411       UWord magic_delta = 0;
412 #     elif DARWIN_VERS >= DARWIN_10_7
413       UWord magic_delta = 0x48;
414 #     endif
415 
416       // This thread already exists; we're merely re-entering
417       // after leaving via workq_ops(WQOPS_THREAD_RETURN).
418       // Don't allocate any V thread resources.
419       // Do reset thread registers.
420       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
421       vg_assert(VG_(is_valid_tid)(tid));
422       vg_assert(mach_thread_self() == kport);
423 
424       tst = VG_(get_ThreadState)(tid);
425 
426       if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, "
427                          "tst->os_state.pthread %#lx, self %#lx\n",
428                          tst->os_state.pthread == self ? "SAME" : "DIFF",
429                          tid, tst, tst->os_state.pthread, self);
430 
431       vex = &tst->arch.vex;
432       vg_assert(tst->os_state.pthread - magic_delta == self);
433    }
434    else {
435       // This is a new thread.
436       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
437       vex = &tst->arch.vex;
438       allocstack(tst->tid);
439       LibVEX_GuestX86_initialise(vex);
440    }
441 
442    // Set thread's registers
443    // Do this FIRST because some code below tries to collect a backtrace,
444    // which requires valid register data.
445    vex->guest_EIP = wqthread_starter;
446    vex->guest_EAX = self;
447    vex->guest_EBX = kport;
448    vex->guest_ECX = stackaddr;
449    vex->guest_EDX = workitem;
450    vex->guest_EDI = reuse;
451    vex->guest_ESI = 0;
452    vex->guest_ESP = sp;
453 
454    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
455    stack = VG_PGROUNDUP(sp) - stacksize;
456 
457    if (reuse) {
458        // Continue V's thread back in the scheduler.
459        // The client thread is of course in another location entirely.
460 
461       /* Drop the lock before going into
462          ML_(wqthread_continue_NORETURN).  The latter will immediately
463          attempt to reacquire it in non-LL mode, which is a bit
464          wasteful but I don't think is harmful.  A better solution
465          would be to not drop the lock but instead "upgrade" it from a
466          LL lock to a full lock, but that's too much like hard work
467          right now. */
468        VG_(release_BigLock_LL)("wqthread_hijack(1)");
469        ML_(wqthread_continue_NORETURN)(tst->tid);
470    }
471    else {
472       // Record thread's stack and Mach port and pthread struct
473       tst->os_state.pthread = self;
474       tst->os_state.lwpid = kport;
475       record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
476 
477       // kernel allocated stack - needs mapping
478       tst->client_stack_highest_word = stack+stacksize;
479       tst->client_stack_szB = stacksize;
480 
481       // GrP fixme scheduler lock?!
482 
483       // pthread structure
484       ML_(notify_core_and_tool_of_mmap)(
485             stack+stacksize, pthread_structsize,
486             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
487       // stack contents
488       // GrP fixme uninitialized!
489       ML_(notify_core_and_tool_of_mmap)(
490             stack, stacksize,
491             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
492       // guard page
493       // GrP fixme ban_mem_stack!
494       ML_(notify_core_and_tool_of_mmap)(
495             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
496             0, VKI_MAP_PRIVATE, -1, 0);
497 
498       ML_(sync_mappings)("after", "wqthread_hijack", 0);
499 
500       // Go!
501       /* Same comments as the 'release' in the then-clause.
502          start_thread_NORETURN calls run_thread_NORETURN calls
503          thread_wrapper which acquires the lock before continuing.
504          Let's hope nothing non-thread-local happens until that point.
505 
506          DDD: I think this is plain wrong .. if we get to
507          thread_wrapper not holding the lock, and someone has recycled
508          this thread slot in the meantime, we're hosed.  Is that
509          possible, though? */
510       VG_(release_BigLock_LL)("wqthread_hijack(2)");
511       call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
512                             start_thread_NORETURN, (Word)tst);
513    }
514 
515    /*NOTREACHED*/
516    vg_assert(0);
517 }
518 
519 #endif // defined(VGP_x86_darwin)
520 
521 /*--------------------------------------------------------------------*/
522 /*--- end                                                          ---*/
523 /*--------------------------------------------------------------------*/
524