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-2012 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 
    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