1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Darwin-specific syscalls, etc. syswrap-amd64-darwin.c ---*/ 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of Valgrind, a dynamic binary instrumentation 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown framework. 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Copyright (C) 2005-2011 Apple Inc. 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Greg Parker gparker@apple.com 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_amd64_darwin) 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 33b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "config.h" // DARWIN_VERS 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h" 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h" 36b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h" 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h" 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h" 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clientstate.h" 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuglog.h" 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuginfo.h" // VG_(di_notify_*) 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_transtab.h" // VG_(discard_translations) 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h" 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h" 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcfile.h" 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h" 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h" 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcsignal.h" 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mallocfree.h" 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h" 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_scheduler.h" 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_sigframe.h" // For VG_(sigframe_destroy)() 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_signals.h" 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h" 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syswrap.h" 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h" 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_types_n_macros.h" 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_syswrap-generic.h" /* for decls of generic wrappers */ 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_syswrap-darwin.h" /* for decls of darwin-ish wrappers */ 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_syswrap-main.h" 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <mach/mach.h> 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void x86_thread_state64_from_vex(x86_thread_state64_t *mach, 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex) 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rax = vex->guest_RAX; 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rbx = vex->guest_RBX; 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rcx = vex->guest_RCX; 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rdx = vex->guest_RDX; 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rdi = vex->guest_RDI; 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rsi = vex->guest_RSI; 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rbp = vex->guest_RBP; 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rsp = vex->guest_RSP; 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rflags = LibVEX_GuestAMD64_get_rflags(vex); 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rip = vex->guest_RIP; 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r8 = vex->guest_R8; 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r9 = vex->guest_R9; 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r10 = vex->guest_R10; 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r11 = vex->guest_R11; 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r12 = vex->guest_R12; 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r13 = vex->guest_R13; 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r14 = vex->guest_R14; 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__r15 = vex->guest_R15; 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* GrP fixme 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__cs = vex->guest_CS; 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__fs = vex->guest_FS; 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__gs = vex->guest_GS; 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void x86_float_state64_from_vex(x86_float_state64_t *mach, 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex) 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme fp state 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0)); 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid thread_state_from_vex(thread_state_t mach_generic, 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_state_flavor_t flavor, 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_msg_type_number_t count, 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestArchState *vex_generic) 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic; 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (flavor) { 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case x86_THREAD_STATE64: 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(count == x86_THREAD_STATE64_COUNT); 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex); 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case x86_FLOAT_STATE64: 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(count == x86_FLOAT_STATE64_COUNT); 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex); 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(0); 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void x86_thread_state64_to_vex(const x86_thread_state64_t *mach, 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex) 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LibVEX_GuestAMD64_initialise(vex); 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RAX = mach->__rax; 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RBX = mach->__rbx; 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RCX = mach->__rcx; 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RDX = mach->__rdx; 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RDI = mach->__rdi; 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RSI = mach->__rsi; 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RBP = mach->__rbp; 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RSP = mach->__rsp; 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme eflags 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RIP = mach->__rip; 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R8 = mach->__r8; 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R9 = mach->__r9; 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R10 = mach->__r10; 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R11 = mach->__r11; 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R12 = mach->__r12; 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R13 = mach->__r13; 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R14 = mach->__r14; 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R15 = mach->__r15; 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* GrP fixme 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_CS = mach->__cs; 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_FS = mach->__fs; 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_GS = mach->__gs; 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void x86_float_state64_to_vex(const x86_float_state64_t *mach, 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex) 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: #warning GrP fixme fp state 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0)); 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid thread_state_to_vex(const thread_state_t mach_generic, 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_state_flavor_t flavor, 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_msg_type_number_t count, 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestArchState *vex_generic) 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic; 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch(flavor) { 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case x86_THREAD_STATE64: 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(count == x86_THREAD_STATE64_COUNT); 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex); 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case x86_FLOAT_STATE64: 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(count == x86_FLOAT_STATE64_COUNT); 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex); 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(0); 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownThreadState *build_thread(const thread_state_t state, 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_state_flavor_t flavor, 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_msg_type_number_t count) 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadId tid = VG_(alloc_ThreadState)(); 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadState *tst = VG_(get_ThreadState)(tid); 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(flavor == x86_THREAD_STATE64); 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(count == x86_THREAD_STATE64_COUNT); 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Initialize machine registers 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_state_to_vex(state, flavor, count, &tst->arch.vex); 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown I_die_here; 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown find_stack_segment(tid, tst->arch.vex.guest_RSP); 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return tst; 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Edit the thread state to send to the real kernel. 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The real thread will run start_thread_NORETURN(tst) 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// on a separate non-client stack. 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid hijack_thread_state(thread_state_t mach_generic, 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_state_flavor_t flavor, 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach_msg_type_number_t count, 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadState *tst) 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic; 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown char *stack; 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(flavor == x86_THREAD_STATE64); 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(count == x86_THREAD_STATE64_COUNT); 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack = (char *)allocstack(tst->tid); 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack -= 64+320; // make room for top frame 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown memset(stack, 0, 64+320); // ...and clear it 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *(uintptr_t *)stack = 0; // push fake return address 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rdi = (uintptr_t)tst; // arg1 = tst 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rip = (uintptr_t)&start_thread_NORETURN; 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mach->__rsp = (uintptr_t)stack; 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Call f(arg1), but first switch stacks, using 'stack' as the new 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack, and use 'retaddr' as f's return-to address. Also, clear all 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the integer registers before entering f.*/ 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noreturn)) 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid call_on_new_stack_0_1 ( Addr stack, 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr retaddr, 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void (*f)(Word), 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Word arg1 ); 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rdi == stack (must be 16-byte aligned) 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rsi == retaddr 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rdx == f 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rcx == arg1 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownasm( 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown".globl _call_on_new_stack_0_1\n" 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"_call_on_new_stack_0_1:\n" 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq %rsp, %rbp\n" // remember old stack pointer 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq %rdi, %rsp\n" // set new stack 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq %rcx, %rdi\n" // set arg1 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" pushq %rsi\n" // retaddr to new stack 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" pushq %rdx\n" // f to new stack 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %rax\n" // zero all other GP regs 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %rbx\n" 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %rcx\n" 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %rdx\n" 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %rsi\n" 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %rbp\n" 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r8\n" 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r9\n" 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r10\n" 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r11\n" 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r12\n" 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r13\n" 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r14\n" 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq $0, %r15\n" 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" ret\n" // jump to f 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" ud2\n" // should never get here 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown); 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownasm( 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown".globl _pthread_hijack_asm\n" 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"_pthread_hijack_asm:\n" 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq %rsp,%rbp\n" 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" push $0\n" // alignment pad 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" push %rbp\n" // original sp 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // other values stay where they are in registers 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" push $0\n" // fake return address 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" jmp _pthread_hijack\n" 286b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov); 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr stacksize, Addr flags, Addr sp) 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vki_sigset_t blockall; 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadState *tst = (ThreadState *)func_arg; 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex = &tst->arch.vex; 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 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); 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Wait for parent thread's permission. 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The parent thread holds V's lock on our behalf. 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown semaphore_wait(tst->os_state.child_go); 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Start the thread with all signals blocked. VG_(scheduler) will 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set the mask correctly when we finally get there. */ 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigfillset)(&blockall); 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL); 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Set thread's registers 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Do this FIRST because some code below tries to collect a backtrace, 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // which requires valid register data. 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LibVEX_GuestAMD64_initialise(vex); 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RIP = pthread_starter; 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RDI = self; 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RSI = kport; 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RDX = func; 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RCX = tst->os_state.func_arg; 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R8 = stacksize; 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R9 = flags; 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RSP = sp; 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Record thread's stack and Mach port and pthread struct 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->os_state.pthread = self; 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->os_state.lwpid = kport; 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p"); 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((flags & 0x01000000) == 0) { 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // kernel allocated stack - needs mapping 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr stack = VG_PGROUNDUP(sp) - stacksize; 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->client_stack_highest_word = stack+stacksize; 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->client_stack_szB = stacksize; 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // pthread structure 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(notify_core_and_tool_of_mmap)( 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack+stacksize, pthread_structsize, 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0); 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // stack contents 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(notify_core_and_tool_of_mmap)( 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack, stacksize, 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0); 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // guard page 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(notify_core_and_tool_of_mmap)( 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, VKI_MAP_PRIVATE, -1, 0); 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // client allocated stack 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown find_stack_segment(tst->tid, sp); 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(sync_mappings)("after", "pthread_hijack", 0); 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // DDD: should this be here rather than in POST(sys_bsdthread_create)? 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // But we don't have ptid here... 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid ); 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Tell parent thread's POST(sys_bsdthread_create) that we're done 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // initializing registers and mapping memory. 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown semaphore_signal(tst->os_state.child_done); 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // LOCK IS GONE BELOW THIS POINT 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Go! 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start_thread_NORETURN, (Word)tst); 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*NOTREACHED*/ 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(0); 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownasm( 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown".globl _wqthread_hijack_asm\n" 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"_wqthread_hijack_asm:\n" 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" movq %rsp,%r9\n" // original sp 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // other values stay where they are in registers 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" push $0\n" // fake return address 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown" jmp _wqthread_hijack\n" 376b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov); 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* wqthread note: The kernel may create or destroy pthreads in the 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown wqthread pool at any time with no userspace interaction, 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and wqthread_start may be entered at any time with no userspace 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interaction. 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown To handle this in valgrind, we create and destroy a valgrind 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread for every work item. 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int reuse, Addr sp) 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadState *tst; 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VexGuestAMD64State *vex; 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr stack; 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SizeT stacksize; 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vki_sigset_t blockall; 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* When we enter here we hold no lock (!), so we better acquire it 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pronto. Why do we hold no lock? Because (presumably) the only 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown way to get here is as a result of a SfMayBlock syscall 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lock. At least that's clear for the 'reuse' case. The 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown non-reuse case? Dunno, perhaps it's a new thread the kernel 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pulled out of a hat. In any case we still need to take a 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lock. */ 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(acquire_BigLock_LL)("wqthread_hijack"); 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 405b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (0) VG_(printf)("wqthread_hijack: self %#lx, kport %#lx, " 406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "stackaddr %#lx, workitem %#lx, reuse %d, sp %#lx\n", 407b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov self, kport, stackaddr, workitem, reuse, sp); 408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Start the thread with all signals blocked. VG_(scheduler) will 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown set the mask correctly when we finally get there. */ 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigfillset)(&blockall); 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL); 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (reuse) { 415b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* For whatever reason, tst->os_state.pthread appear to have a 417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov constant offset of 96 on 10.7, but zero on 10.6 and 10.5. No 418b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov idea why. */ 419b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# if DARWIN_VERS <= DARWIN_10_6 420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UWord magic_delta = 0; 421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# elif DARWIN_VERS == DARWIN_10_7 422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov UWord magic_delta = 0x60; 423b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov# endif 424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // This thread already exists; we're merely re-entering 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // after leaving via workq_ops(WQOPS_THREAD_RETURN). 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Don't allocate any V thread resources. 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Do reset thread registers. 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ThreadId tid = VG_(lwpid_to_vgtid)(kport); 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(VG_(is_valid_tid)(tid)); 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(mach_thread_self() == kport); 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst = VG_(get_ThreadState)(tid); 434b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 435b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, " 436b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "tst->os_state.pthread %#lx\n", 437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tst->os_state.pthread == self ? "SAME" : "DIFF", 438b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tid, tst, tst->os_state.pthread); 439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex = &tst->arch.vex; 441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov vg_assert(tst->os_state.pthread - magic_delta == self); 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else { 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // This is a new thread. 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)()); 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex = &tst->arch.vex; 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown allocstack(tst->tid); 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LibVEX_GuestAMD64_initialise(vex); 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Set thread's registers 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Do this FIRST because some code below tries to collect a backtrace, 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // which requires valid register data. 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RIP = wqthread_starter; 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RDI = self; 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RSI = kport; 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RDX = stackaddr; 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RCX = workitem; 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R8 = reuse; 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_R9 = 0; 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vex->guest_RSP = sp; 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stacksize = 512*1024; // wq stacks are always DEFAULT_STACK_SIZE 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack = VG_PGROUNDUP(sp) - stacksize; 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (reuse) { 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Continue V's thread back in the scheduler. 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The client thread is of course in another location entirely. 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Drop the lock before going into 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(wqthread_continue_NORETURN). The latter will immediately 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown attempt to reacquire it in non-LL mode, which is a bit 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown wasteful but I don't think is harmful. A better solution 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown would be to not drop the lock but instead "upgrade" it from a 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LL lock to a full lock, but that's too much like hard work 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown right now. */ 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(release_BigLock_LL)("wqthread_hijack(1)"); 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(wqthread_continue_NORETURN)(tst->tid); 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else { 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Record thread's stack and Mach port and pthread struct 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->os_state.pthread = self; 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->os_state.lwpid = kport; 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p"); 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // kernel allocated stack - needs mapping 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->client_stack_highest_word = stack+stacksize; 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tst->client_stack_szB = stacksize; 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme scheduler lock?! 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // pthread structure 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(notify_core_and_tool_of_mmap)( 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack+stacksize, pthread_structsize, 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0); 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // stack contents 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme uninitialized! 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(notify_core_and_tool_of_mmap)( 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack, stacksize, 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0); 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // guard page 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // GrP fixme ban_mem_stack! 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(notify_core_and_tool_of_mmap)( 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, VKI_MAP_PRIVATE, -1, 0); 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ML_(sync_mappings)("after", "wqthread_hijack", 0); 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Go! 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Same comments as the 'release' in the then-clause. 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start_thread_NORETURN calls run_thread_NORETURN calls 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_wrapper which acquires the lock before continuing. 513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Let's hope nothing non-thread-local happens until that point. 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DDD: I think this is plain wrong .. if we get to 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown thread_wrapper not holding the lock, and someone has recycled 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown this thread slot in the meantime, we're hosed. Is that 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown possible, though? */ 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(release_BigLock_LL)("wqthread_hijack(2)"); 520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown start_thread_NORETURN, (Word)tst); 522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*NOTREACHED*/ 525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(0); 526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGP_amd64_darwin) 529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end ---*/ 532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 533