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