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
65static 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
94static 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
103void 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
127static 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
156static 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
165void 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
189ThreadState *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.
215void 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))
241void 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
249asm(
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
275asm(
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
288void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
289                    Addr stacksize, Addr flags, Addr sp)
290{
291   vki_sigset_t blockall;
292   ThreadState *tst = (ThreadState *)func_arg;
293   VexGuestAMD64State *vex = &tst->arch.vex;
294
295   // 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);
296
297   // Wait for parent thread's permission.
298   // The parent thread holds V's lock on our behalf.
299   semaphore_wait(tst->os_state.child_go);
300
301   /* Start the thread with all signals blocked.  VG_(scheduler) will
302      set the mask correctly when we finally get there. */
303   VG_(sigfillset)(&blockall);
304   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
305
306   // Set thread's registers
307   // Do this FIRST because some code below tries to collect a backtrace,
308   // which requires valid register data.
309   LibVEX_GuestAMD64_initialise(vex);
310   vex->guest_RIP = pthread_starter;
311   vex->guest_RDI = self;
312   vex->guest_RSI = kport;
313   vex->guest_RDX = func;
314   vex->guest_RCX = tst->os_state.func_arg;
315   vex->guest_R8  = stacksize;
316   vex->guest_R9  = flags;
317   vex->guest_RSP = sp;
318
319   // Record thread's stack and Mach port and pthread struct
320   tst->os_state.pthread = self;
321   tst->os_state.lwpid = kport;
322   record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
323
324   if ((flags & 0x01000000) == 0) {
325      // kernel allocated stack - needs mapping
326      Addr stack = VG_PGROUNDUP(sp) - stacksize;
327      tst->client_stack_highest_word = stack+stacksize;
328      tst->client_stack_szB = stacksize;
329
330      // pthread structure
331      ML_(notify_core_and_tool_of_mmap)(
332            stack+stacksize, pthread_structsize,
333            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
334      // stack contents
335      ML_(notify_core_and_tool_of_mmap)(
336            stack, stacksize,
337            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
338      // guard page
339      ML_(notify_core_and_tool_of_mmap)(
340            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
341            0, VKI_MAP_PRIVATE, -1, 0);
342   } else {
343      // client allocated stack
344      find_stack_segment(tst->tid, sp);
345   }
346   ML_(sync_mappings)("after", "pthread_hijack", 0);
347
348   // DDD: should this be here rather than in POST(sys_bsdthread_create)?
349   // But we don't have ptid here...
350   //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
351
352   // Tell parent thread's POST(sys_bsdthread_create) that we're done
353   // initializing registers and mapping memory.
354   semaphore_signal(tst->os_state.child_done);
355   // LOCK IS GONE BELOW THIS POINT
356
357   // Go!
358   call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
359                         start_thread_NORETURN, (Word)tst);
360
361   /*NOTREACHED*/
362   vg_assert(0);
363}
364
365
366
367asm(
368".globl _wqthread_hijack_asm\n"
369"_wqthread_hijack_asm:\n"
370"   movq %rsp,%r9\n"  // original sp
371                      // other values stay where they are in registers
372"   push $0\n"        // fake return address
373"   jmp _wqthread_hijack\n"
374    );
375
376
377/*  wqthread note: The kernel may create or destroy pthreads in the
378    wqthread pool at any time with no userspace interaction,
379    and wqthread_start may be entered at any time with no userspace
380    interaction.
381    To handle this in valgrind, we create and destroy a valgrind
382    thread for every work item.
383*/
384void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
385                     Int reuse, Addr sp)
386{
387   ThreadState *tst;
388   VexGuestAMD64State *vex;
389   Addr stack;
390   SizeT stacksize;
391   vki_sigset_t blockall;
392
393   /* When we enter here we hold no lock (!), so we better acquire it
394      pronto.  Why do we hold no lock?  Because (presumably) the only
395      way to get here is as a result of a SfMayBlock syscall
396      "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
397      lock.  At least that's clear for the 'reuse' case.  The
398      non-reuse case?  Dunno, perhaps it's a new thread the kernel
399      pulled out of a hat.  In any case we still need to take a
400      lock. */
401   VG_(acquire_BigLock_LL)("wqthread_hijack");
402
403   /* Start the thread with all signals blocked.  VG_(scheduler) will
404      set the mask correctly when we finally get there. */
405   VG_(sigfillset)(&blockall);
406   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
407
408   if (reuse) {
409       // This thread already exists; we're merely re-entering
410       // after leaving via workq_ops(WQOPS_THREAD_RETURN).
411       // Don't allocate any V thread resources.
412       // Do reset thread registers.
413       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
414       vg_assert(VG_(is_valid_tid)(tid));
415       vg_assert(mach_thread_self() == kport);
416
417       tst = VG_(get_ThreadState)(tid);
418       vex = &tst->arch.vex;
419       vg_assert(tst->os_state.pthread == self);
420   }
421   else {
422       // This is a new thread.
423       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
424       vex = &tst->arch.vex;
425       allocstack(tst->tid);
426       LibVEX_GuestAMD64_initialise(vex);
427   }
428
429   // Set thread's registers
430   // Do this FIRST because some code below tries to collect a backtrace,
431   // which requires valid register data.
432   vex->guest_RIP = wqthread_starter;
433   vex->guest_RDI = self;
434   vex->guest_RSI = kport;
435   vex->guest_RDX = stackaddr;
436   vex->guest_RCX = workitem;
437   vex->guest_R8  = reuse;
438   vex->guest_R9  = 0;
439   vex->guest_RSP = sp;
440
441   stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
442   stack = VG_PGROUNDUP(sp) - stacksize;
443
444   if (reuse) {
445      // Continue V's thread back in the scheduler.
446      // The client thread is of course in another location entirely.
447
448      /* Drop the lock before going into
449         ML_(wqthread_continue_NORETURN).  The latter will immediately
450         attempt to reacquire it in non-LL mode, which is a bit
451         wasteful but I don't think is harmful.  A better solution
452         would be to not drop the lock but instead "upgrade" it from a
453         LL lock to a full lock, but that's too much like hard work
454         right now. */
455      VG_(release_BigLock_LL)("wqthread_hijack(1)");
456      ML_(wqthread_continue_NORETURN)(tst->tid);
457   }
458   else {
459      // Record thread's stack and Mach port and pthread struct
460      tst->os_state.pthread = self;
461      tst->os_state.lwpid = kport;
462      record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
463
464      // kernel allocated stack - needs mapping
465      tst->client_stack_highest_word = stack+stacksize;
466      tst->client_stack_szB = stacksize;
467
468      // GrP fixme scheduler lock?!
469
470      // pthread structure
471      ML_(notify_core_and_tool_of_mmap)(
472            stack+stacksize, pthread_structsize,
473            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
474      // stack contents
475      // GrP fixme uninitialized!
476      ML_(notify_core_and_tool_of_mmap)(
477            stack, stacksize,
478            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
479      // guard page
480      // GrP fixme ban_mem_stack!
481      ML_(notify_core_and_tool_of_mmap)(
482            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
483            0, VKI_MAP_PRIVATE, -1, 0);
484
485      ML_(sync_mappings)("after", "wqthread_hijack", 0);
486
487      // Go!
488      /* Same comments as the 'release' in the then-clause.
489         start_thread_NORETURN calls run_thread_NORETURN calls
490         thread_wrapper which acquires the lock before continuing.
491         Let's hope nothing non-thread-local happens until that point.
492
493         DDD: I think this is plain wrong .. if we get to
494         thread_wrapper not holding the lock, and someone has recycled
495         this thread slot in the meantime, we're hosed.  Is that
496         possible, though? */
497      VG_(release_BigLock_LL)("wqthread_hijack(2)");
498      call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
499                            start_thread_NORETURN, (Word)tst);
500   }
501
502   /*NOTREACHED*/
503   vg_assert(0);
504}
505
506#endif // defined(VGP_amd64_darwin)
507
508/*--------------------------------------------------------------------*/
509/*--- end                                                          ---*/
510/*--------------------------------------------------------------------*/
511