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-2015 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_byte = stack+stacksize-1;
    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    if (0) VG_(printf)(
    400              "wqthread_hijack: self %#lx, kport %#lx, "
    401              "stackaddr %#lx, workitem %#lx, reuse/flags %x, sp %#lx\n",
    402              self, kport, stackaddr, workitem, reuse, sp);
    403 
    404    /* Start the thread with all signals blocked.  VG_(scheduler) will
    405       set the mask correctly when we finally get there. */
    406    VG_(sigfillset)(&blockall);
    407    VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
    408 
    409    /* For 10.7 and earlier, |reuse| appeared to be used as a simple
    410       boolean.  In 10.8 and later its name changed to |flags| and has
    411       various other bits OR-d into it too, so it's necessary to fish
    412       out just the relevant parts.  Hence: */
    413 #  if DARWIN_VERS <= DARWIN_10_7
    414    Bool is_reuse = reuse != 0;
    415 #  elif DARWIN_VERS > DARWIN_10_7
    416    Bool is_reuse = (reuse & 0x20000 /* == WQ_FLAG_THREAD_REUSE */) != 0;
    417 #  else
    418 #    error "Unsupported Darwin version"
    419 #  endif
    420 
    421    if (is_reuse) {
    422 
    423       /* For whatever reason, tst->os_state.pthread appear to have a
    424          constant offset of 72 on 10.7, but zero on 10.6 and 10.5.  No
    425          idea why. */
    426 #     if DARWIN_VERS <= DARWIN_10_6
    427       UWord magic_delta = 0;
    428 #     elif DARWIN_VERS == DARWIN_10_7 || DARWIN_VERS == DARWIN_10_8
    429       UWord magic_delta = 0x48;
    430 #     elif DARWIN_VERS == DARWIN_10_9 || DARWIN_VERS == DARWIN_10_10
    431       UWord magic_delta = 0xB0;
    432 #     elif DARWIN_VERS == DARWIN_10_11
    433       UWord magic_delta = 0x100;
    434 #     else
    435 #       error "magic_delta: to be computed on new OS version"
    436         // magic_delta = tst->os_state.pthread - self
    437 #     endif
    438 
    439       // This thread already exists; we're merely re-entering
    440       // after leaving via workq_ops(WQOPS_THREAD_RETURN).
    441       // Don't allocate any V thread resources.
    442       // Do reset thread registers.
    443       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
    444       vg_assert(VG_(is_valid_tid)(tid));
    445       vg_assert(mach_thread_self() == kport);
    446 
    447       tst = VG_(get_ThreadState)(tid);
    448 
    449       if (0) VG_(printf)("wqthread_hijack reuse %s: tid %u, tst %p, "
    450                          "tst->os_state.pthread %#lx, self %#lx\n",
    451                          tst->os_state.pthread == self ? "SAME" : "DIFF",
    452                          tid, tst, tst->os_state.pthread, self);
    453 
    454       vex = &tst->arch.vex;
    455       vg_assert(tst->os_state.pthread - magic_delta == self);
    456    }
    457    else {
    458       // This is a new thread.
    459       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
    460       vex = &tst->arch.vex;
    461       allocstack(tst->tid);
    462       LibVEX_GuestX86_initialise(vex);
    463    }
    464 
    465    // Set thread's registers
    466    // Do this FIRST because some code below tries to collect a backtrace,
    467    // which requires valid register data.
    468    vex->guest_EIP = wqthread_starter;
    469    vex->guest_EAX = self;
    470    vex->guest_EBX = kport;
    471    vex->guest_ECX = stackaddr;
    472    vex->guest_EDX = workitem;
    473    vex->guest_EDI = reuse;
    474    vex->guest_ESI = 0;
    475    vex->guest_ESP = sp;
    476 
    477    stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
    478    stack = VG_PGROUNDUP(sp) - stacksize;
    479 
    480    if (is_reuse) {
    481        // Continue V's thread back in the scheduler.
    482        // The client thread is of course in another location entirely.
    483 
    484       /* Drop the lock before going into
    485          ML_(wqthread_continue_NORETURN).  The latter will immediately
    486          attempt to reacquire it in non-LL mode, which is a bit
    487          wasteful but I don't think is harmful.  A better solution
    488          would be to not drop the lock but instead "upgrade" it from a
    489          LL lock to a full lock, but that's too much like hard work
    490          right now. */
    491        VG_(release_BigLock_LL)("wqthread_hijack(1)");
    492        ML_(wqthread_continue_NORETURN)(tst->tid);
    493    }
    494    else {
    495       // Record thread's stack and Mach port and pthread struct
    496       tst->os_state.pthread = self;
    497       tst->os_state.lwpid = kport;
    498       record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
    499 
    500       // kernel allocated stack - needs mapping
    501       tst->client_stack_highest_byte = stack+stacksize-1;
    502       tst->client_stack_szB = stacksize;
    503 
    504       // GrP fixme scheduler lock?!
    505 
    506       // pthread structure
    507       ML_(notify_core_and_tool_of_mmap)(
    508             stack+stacksize, pthread_structsize,
    509             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
    510       // stack contents
    511       // GrP fixme uninitialized!
    512       ML_(notify_core_and_tool_of_mmap)(
    513             stack, stacksize,
    514             VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
    515       // guard page
    516       // GrP fixme ban_mem_stack!
    517       ML_(notify_core_and_tool_of_mmap)(
    518             stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
    519             0, VKI_MAP_PRIVATE, -1, 0);
    520 
    521       ML_(sync_mappings)("after", "wqthread_hijack", 0);
    522 
    523       // Go!
    524       /* Same comments as the 'release' in the then-clause.
    525          start_thread_NORETURN calls run_thread_NORETURN calls
    526          thread_wrapper which acquires the lock before continuing.
    527          Let's hope nothing non-thread-local happens until that point.
    528 
    529          DDD: I think this is plain wrong .. if we get to
    530          thread_wrapper not holding the lock, and someone has recycled
    531          this thread slot in the meantime, we're hosed.  Is that
    532          possible, though? */
    533       VG_(release_BigLock_LL)("wqthread_hijack(2)");
    534       call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
    535                             start_thread_NORETURN, (Word)tst);
    536    }
    537 
    538    /*NOTREACHED*/
    539    vg_assert(0);
    540 }
    541 
    542 #endif // defined(VGP_x86_darwin)
    543 
    544 /*--------------------------------------------------------------------*/
    545 /*--- end                                                          ---*/
    546 /*--------------------------------------------------------------------*/
    547