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-2011 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_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 
     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 
     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 
     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 
    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 
    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 
    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 
    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.
    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 
    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 */
    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    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