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-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_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
65static 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
87static 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
96void 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
120static 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
142static 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
151void 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
175ThreadState *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.
201void 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))
228void 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
236asm(
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
259asm(
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
277void 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
357asm(
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*/
381void 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   if (reuse) {
405
406      /* For whatever reason, tst->os_state.pthread appear to have a
407         constant offset of 72 on 10.7, but zero on 10.6 and 10.5.  No
408         idea why. */
409#     if DARWIN_VERS <= DARWIN_10_6
410      UWord magic_delta = 0;
411#     elif DARWIN_VERS == DARWIN_10_7
412      UWord magic_delta = 0x48;
413#     endif
414
415      // This thread already exists; we're merely re-entering
416      // after leaving via workq_ops(WQOPS_THREAD_RETURN).
417      // Don't allocate any V thread resources.
418      // Do reset thread registers.
419      ThreadId tid = VG_(lwpid_to_vgtid)(kport);
420      vg_assert(VG_(is_valid_tid)(tid));
421      vg_assert(mach_thread_self() == kport);
422
423      tst = VG_(get_ThreadState)(tid);
424
425      if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, "
426                         "tst->os_state.pthread %#lx, self %#lx\n",
427                         tst->os_state.pthread == self ? "SAME" : "DIFF",
428                         tid, tst, tst->os_state.pthread, self);
429
430      vex = &tst->arch.vex;
431      vg_assert(tst->os_state.pthread - magic_delta == self);
432   }
433   else {
434      // This is a new thread.
435      tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
436      vex = &tst->arch.vex;
437      allocstack(tst->tid);
438      LibVEX_GuestX86_initialise(vex);
439      /* Tell threading tools the new thread exists.  FIXME: we need
440         to know the identity (tid) of the parent thread, in order
441         that threading tools can make a dependency edge from it to
442         this thread.  But we don't know what the parent thread is.
443         Hence pass 1 (the root thread).  This is completely wrong in
444         general, and could cause large numbers of false races to be
445         reported.  In fact, it's positively dangerous; we don't even
446         know if thread 1 is still alive, and the thread checkers are
447         likely to assert if it isn't. */
448      VG_TRACK(pre_thread_ll_create, 1/*BOGUS*/, tst->tid);
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_EIP = wqthread_starter;
455   vex->guest_EAX = self;
456   vex->guest_EBX = kport;
457   vex->guest_ECX = stackaddr;
458   vex->guest_EDX = workitem;
459   vex->guest_EDI = reuse;
460   vex->guest_ESI = 0;
461   vex->guest_ESP = sp;
462
463   stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
464   stack = VG_PGROUNDUP(sp) - stacksize;
465
466   VG_TRACK(workq_task_start, tst->tid, workitem);
467   if (reuse) {
468       // Continue V's thread back in the scheduler.
469       // The client thread is of course in another location entirely.
470
471      /* Drop the lock before going into
472         ML_(wqthread_continue_NORETURN).  The latter will immediately
473         attempt to reacquire it in non-LL mode, which is a bit
474         wasteful but I don't think is harmful.  A better solution
475         would be to not drop the lock but instead "upgrade" it from a
476         LL lock to a full lock, but that's too much like hard work
477         right now. */
478       VG_(release_BigLock_LL)("wqthread_hijack(1)");
479       ML_(wqthread_continue_NORETURN)(tst->tid);
480   }
481   else {
482      // Record thread's stack and Mach port and pthread struct
483      tst->os_state.pthread = self;
484      tst->os_state.lwpid = kport;
485      record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
486
487      // kernel allocated stack - needs mapping
488      tst->client_stack_highest_word = stack+stacksize;
489      tst->client_stack_szB = stacksize;
490
491      // tell the tool that we are at a point after the new thread
492      // has its registers set up (so we can take a stack snapshot),
493      // but before it has executed any instructions (or, really,
494      // before it has done any memory references).
495      VG_TRACK(pre_thread_first_insn, tst->tid);
496
497      // pthread structure
498      ML_(notify_core_and_tool_of_mmap)(
499            stack+stacksize, pthread_structsize,
500            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
501      // stack contents
502      // GrP fixme uninitialized!
503      ML_(notify_core_and_tool_of_mmap)(
504            stack, stacksize,
505            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
506      // guard page
507      // GrP fixme ban_mem_stack!
508      ML_(notify_core_and_tool_of_mmap)(
509            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
510            0, VKI_MAP_PRIVATE, -1, 0);
511
512      ML_(sync_mappings)("after", "wqthread_hijack", 0);
513
514      // Go!
515      /* Same comments as the 'release' in the then-clause.
516         start_thread_NORETURN calls run_thread_NORETURN calls
517         thread_wrapper which acquires the lock before continuing.
518         Let's hope nothing non-thread-local happens until that point.
519
520         DDD: I think this is plain wrong .. if we get to
521         thread_wrapper not holding the lock, and someone has recycled
522         this thread slot in the meantime, we're hosed.  Is that
523         possible, though? */
524      VG_(release_BigLock_LL)("wqthread_hijack(2)");
525      call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
526                            start_thread_NORETURN, (Word)tst);
527   }
528
529   /*NOTREACHED*/
530   vg_assert(0);
531}
532
533#endif // defined(VGP_x86_darwin)
534
535/*--------------------------------------------------------------------*/
536/*--- end                                                          ---*/
537/*--------------------------------------------------------------------*/
538