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