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