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
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_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
100663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // JRS: what about the YMMHI bits?  Are they important?
101663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm0,  &vex->guest_YMM0,   sizeof(mach->__fpu_xmm0));
102663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm1,  &vex->guest_YMM1,   sizeof(mach->__fpu_xmm1));
103663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm2,  &vex->guest_YMM2,   sizeof(mach->__fpu_xmm2));
104663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm3,  &vex->guest_YMM3,   sizeof(mach->__fpu_xmm3));
105663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm4,  &vex->guest_YMM4,   sizeof(mach->__fpu_xmm4));
106663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm5,  &vex->guest_YMM5,   sizeof(mach->__fpu_xmm5));
107663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm6,  &vex->guest_YMM6,   sizeof(mach->__fpu_xmm6));
108663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm7,  &vex->guest_YMM7,   sizeof(mach->__fpu_xmm7));
109663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm8,  &vex->guest_YMM8,   sizeof(mach->__fpu_xmm8));
110663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm9,  &vex->guest_YMM9,   sizeof(mach->__fpu_xmm9));
111663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm10, &vex->guest_YMM10,  sizeof(mach->__fpu_xmm10));
112663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm11, &vex->guest_YMM11,  sizeof(mach->__fpu_xmm11));
113663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm12, &vex->guest_YMM12,  sizeof(mach->__fpu_xmm12));
114663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm13, &vex->guest_YMM13,  sizeof(mach->__fpu_xmm13));
115663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm14, &vex->guest_YMM14,  sizeof(mach->__fpu_xmm14));
116663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&mach->__fpu_xmm15, &vex->guest_YMM15,  sizeof(mach->__fpu_xmm15));
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid thread_state_from_vex(thread_state_t mach_generic,
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           thread_state_flavor_t flavor,
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mach_msg_type_number_t count,
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           VexGuestArchState *vex_generic)
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (flavor) {
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case x86_THREAD_STATE64:
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(count == x86_THREAD_STATE64_COUNT);
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case x86_FLOAT_STATE64:
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(count == x86_FLOAT_STATE64_COUNT);
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void x86_thread_state64_to_vex(const x86_thread_state64_t *mach,
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      VexGuestAMD64State *vex)
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestAMD64_initialise(vex);
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RAX = mach->__rax;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RBX = mach->__rbx;
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RCX = mach->__rcx;
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RDX = mach->__rdx;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RDI = mach->__rdi;
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RSI = mach->__rsi;
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RBP = mach->__rbp;
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RSP = mach->__rsp;
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: #warning GrP fixme eflags
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RIP = mach->__rip;
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R8  = mach->__r8;
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R9  = mach->__r9;
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R10 = mach->__r10;
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R11 = mach->__r11;
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R12 = mach->__r12;
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R13 = mach->__r13;
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R14 = mach->__r14;
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R15 = mach->__r15;
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* GrP fixme
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_CS = mach->__cs;
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_FS = mach->__fs;
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_GS = mach->__gs;
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void x86_float_state64_to_vex(const x86_float_state64_t *mach,
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     VexGuestAMD64State *vex)
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: #warning GrP fixme fp state
177663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // JRS: what about the YMMHI bits?  Are they important?
178663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM0,  &mach->__fpu_xmm0,  sizeof(mach->__fpu_xmm0));
179663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM1,  &mach->__fpu_xmm1,  sizeof(mach->__fpu_xmm1));
180663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM2,  &mach->__fpu_xmm2,  sizeof(mach->__fpu_xmm2));
181663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM3,  &mach->__fpu_xmm3,  sizeof(mach->__fpu_xmm3));
182663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM4,  &mach->__fpu_xmm4,  sizeof(mach->__fpu_xmm4));
183663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM5,  &mach->__fpu_xmm5,  sizeof(mach->__fpu_xmm5));
184663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM6,  &mach->__fpu_xmm6,  sizeof(mach->__fpu_xmm6));
185663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM7,  &mach->__fpu_xmm7,  sizeof(mach->__fpu_xmm7));
186663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM8,  &mach->__fpu_xmm8,  sizeof(mach->__fpu_xmm8));
187663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM9,  &mach->__fpu_xmm9,  sizeof(mach->__fpu_xmm9));
188663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM10, &mach->__fpu_xmm10, sizeof(mach->__fpu_xmm10));
189663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM11, &mach->__fpu_xmm11, sizeof(mach->__fpu_xmm11));
190663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM12, &mach->__fpu_xmm12, sizeof(mach->__fpu_xmm12));
191663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM13, &mach->__fpu_xmm13, sizeof(mach->__fpu_xmm13));
192663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM14, &mach->__fpu_xmm14, sizeof(mach->__fpu_xmm14));
193663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memcpy)(&vex->guest_YMM15, &mach->__fpu_xmm15, sizeof(mach->__fpu_xmm15));
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid thread_state_to_vex(const thread_state_t mach_generic,
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         thread_state_flavor_t flavor,
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mach_msg_type_number_t count,
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         VexGuestArchState *vex_generic)
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch(flavor) {
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case x86_THREAD_STATE64:
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(count == x86_THREAD_STATE64_COUNT);
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case x86_FLOAT_STATE64:
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(count == x86_FLOAT_STATE64_COUNT);
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownThreadState *build_thread(const thread_state_t state,
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          thread_state_flavor_t flavor,
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mach_msg_type_number_t count)
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId tid = VG_(alloc_ThreadState)();
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst = VG_(get_ThreadState)(tid);
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(flavor == x86_THREAD_STATE64);
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(count == x86_THREAD_STATE64_COUNT);
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Initialize machine registers
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread_state_to_vex(state, flavor, count, &tst->arch.vex);
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I_die_here;
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   find_stack_segment(tid, tst->arch.vex.guest_RSP);
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tst;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Edit the thread state to send to the real kernel.
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The real thread will run start_thread_NORETURN(tst)
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// on a separate non-client stack.
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid hijack_thread_state(thread_state_t mach_generic,
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         thread_state_flavor_t flavor,
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mach_msg_type_number_t count,
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         ThreadState *tst)
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char *stack;
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(flavor == x86_THREAD_STATE64);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(count == x86_THREAD_STATE64_COUNT);
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack = (char *)allocstack(tst->tid);
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack -= 64+320;                       // make room for top frame
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(stack, 0, 64+320);              // ...and clear it
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *(uintptr_t *)stack = 0;               // push fake return address
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mach->__rdi = (uintptr_t)tst;          // arg1 = tst
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mach->__rip = (uintptr_t)&start_thread_NORETURN;
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mach->__rsp = (uintptr_t)stack;
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Call f(arg1), but first switch stacks, using 'stack' as the new
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack, and use 'retaddr' as f's return-to address.  Also, clear all
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the integer registers before entering f.*/
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noreturn))
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid call_on_new_stack_0_1 ( Addr stack,
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			     Addr retaddr,
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			     void (*f)(Word),
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             Word arg1 );
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rdi == stack (must be 16-byte aligned)
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rsi == retaddr
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rdx == f
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// %rcx == arg1
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownasm(
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown".globl _call_on_new_stack_0_1\n"
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"_call_on_new_stack_0_1:\n"
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq  %rsp, %rbp\n"     // remember old stack pointer
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq  %rdi, %rsp\n"     // set new stack
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq  %rcx, %rdi\n"     // set arg1
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   pushq %rsi\n"           // retaddr to new stack
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   pushq %rdx\n"           // f to new stack
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %rax\n"        // zero all other GP regs
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %rbx\n"
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %rcx\n"
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %rdx\n"
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %rsi\n"
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %rbp\n"
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r8\n"
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r9\n"
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r10\n"
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r11\n"
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r12\n"
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r13\n"
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r14\n"
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq $0, %r15\n"
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   ret\n"                 // jump to f
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   ud2\n"                 // should never get here
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown);
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownasm(
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown".globl _pthread_hijack_asm\n"
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"_pthread_hijack_asm:\n"
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq %rsp,%rbp\n"
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   push $0\n"    // alignment pad
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   push %rbp\n"  // original sp
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // other values stay where they are in registers
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   push $0\n"    // fake return address
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   jmp _pthread_hijack\n"
316b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov);
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Addr stacksize, Addr flags, Addr sp)
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_sigset_t blockall;
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst = (ThreadState *)func_arg;
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State *vex = &tst->arch.vex;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff 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);
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Wait for parent thread's permission.
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // The parent thread holds V's lock on our behalf.
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   semaphore_wait(tst->os_state.child_go);
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Start the thread with all signals blocked.  VG_(scheduler) will
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      set the mask correctly when we finally get there. */
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigfillset)(&blockall);
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Set thread's registers
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Do this FIRST because some code below tries to collect a backtrace,
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // which requires valid register data.
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestAMD64_initialise(vex);
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RIP = pthread_starter;
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RDI = self;
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RSI = kport;
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RDX = func;
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RCX = tst->os_state.func_arg;
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R8  = stacksize;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R9  = flags;
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RSP = sp;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Record thread's stack and Mach port and pthread struct
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.pthread = self;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->os_state.lwpid = kport;
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((flags & 0x01000000) == 0) {
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // kernel allocated stack - needs mapping
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr stack = VG_PGROUNDUP(sp) - stacksize;
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->client_stack_highest_word = stack+stacksize;
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->client_stack_szB = stacksize;
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // pthread structure
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(notify_core_and_tool_of_mmap)(
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stack+stacksize, pthread_structsize,
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack contents
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(notify_core_and_tool_of_mmap)(
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stack, stacksize,
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // guard page
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(notify_core_and_tool_of_mmap)(
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            0, VKI_MAP_PRIVATE, -1, 0);
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // client allocated stack
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      find_stack_segment(tst->tid, sp);
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ML_(sync_mappings)("after", "pthread_hijack", 0);
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: should this be here rather than in POST(sys_bsdthread_create)?
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // But we don't have ptid here...
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Tell parent thread's POST(sys_bsdthread_create) that we're done
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // initializing registers and mapping memory.
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   semaphore_signal(tst->os_state.child_done);
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // LOCK IS GONE BELOW THIS POINT
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Go!
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         start_thread_NORETURN, (Word)tst);
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownasm(
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown".globl _wqthread_hijack_asm\n"
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"_wqthread_hijack_asm:\n"
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   movq %rsp,%r9\n"  // original sp
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      // other values stay where they are in registers
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   push $0\n"        // fake return address
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   jmp _wqthread_hijack\n"
406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov);
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*  wqthread note: The kernel may create or destroy pthreads in the
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    wqthread pool at any time with no userspace interaction,
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    and wqthread_start may be entered at any time with no userspace
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    interaction.
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    To handle this in valgrind, we create and destroy a valgrind
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    thread for every work item.
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int reuse, Addr sp)
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState *tst;
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State *vex;
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr stack;
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT stacksize;
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_sigset_t blockall;
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* When we enter here we hold no lock (!), so we better acquire it
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pronto.  Why do we hold no lock?  Because (presumably) the only
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      way to get here is as a result of a SfMayBlock syscall
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lock.  At least that's clear for the 'reuse' case.  The
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      non-reuse case?  Dunno, perhaps it's a new thread the kernel
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pulled out of a hat.  In any case we still need to take a
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lock. */
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(acquire_BigLock_LL)("wqthread_hijack");
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
435436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (0) VG_(printf)(
436436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             "wqthread_hijack: self %#lx, kport %#lx, "
437436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	     "stackaddr %#lx, workitem %#lx, reuse/flags %x, sp %#lx\n",
438436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	     self, kport, stackaddr, workitem, reuse, sp);
439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Start the thread with all signals blocked.  VG_(scheduler) will
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      set the mask correctly when we finally get there. */
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigfillset)(&blockall);
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
445436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* For 10.7 and earlier, |reuse| appeared to be used as a simple
446436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      boolean.  In 10.8 and later its name changed to |flags| and has
447436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      various other bits OR-d into it too, so it's necessary to fish
448436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      out just the relevant parts.  Hence: */
449436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if DARWIN_VERS <= DARWIN_10_7
450436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Bool is_reuse = reuse != 0;
451436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif DARWIN_VERS == DARWIN_10_8
452436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Bool is_reuse = (reuse & 0x20000 /* == WQ_FLAG_THREAD_REUSE */) != 0;
453436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  endif
454436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
455436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (is_reuse) {
456b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     /* For whatever reason, tst->os_state.pthread appear to have a
458b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        constant offset of 96 on 10.7, but zero on 10.6 and 10.5.  No
459b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        idea why. */
460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#      if DARWIN_VERS <= DARWIN_10_6
461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       UWord magic_delta = 0;
462663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#      elif DARWIN_VERS >= DARWIN_10_7
463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       UWord magic_delta = 0x60;
464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#      endif
465b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // This thread already exists; we're merely re-entering
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // after leaving via workq_ops(WQOPS_THREAD_RETURN).
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // Don't allocate any V thread resources.
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // Do reset thread registers.
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vg_assert(VG_(is_valid_tid)(tid));
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vg_assert(mach_thread_self() == kport);
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       tst = VG_(get_ThreadState)(tid);
475b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
476b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       if (0) VG_(printf)("wqthread_hijack reuse %s: tid %d, tst %p, "
477b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          "tst->os_state.pthread %#lx\n",
478b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          tst->os_state.pthread == self ? "SAME" : "DIFF",
479b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                          tid, tst, tst->os_state.pthread);
480b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vex = &tst->arch.vex;
482b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       vg_assert(tst->os_state.pthread - magic_delta == self);
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // This is a new thread.
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vex = &tst->arch.vex;
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       allocstack(tst->tid);
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       LibVEX_GuestAMD64_initialise(vex);
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Set thread's registers
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Do this FIRST because some code below tries to collect a backtrace,
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // which requires valid register data.
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RIP = wqthread_starter;
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RDI = self;
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RSI = kport;
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RDX = stackaddr;
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RCX = workitem;
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R8  = reuse;
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_R9  = 0;
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex->guest_RSP = sp;
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack = VG_PGROUNDUP(sp) - stacksize;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
507436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (is_reuse) {
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Continue V's thread back in the scheduler.
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // The client thread is of course in another location entirely.
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Drop the lock before going into
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(wqthread_continue_NORETURN).  The latter will immediately
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         attempt to reacquire it in non-LL mode, which is a bit
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wasteful but I don't think is harmful.  A better solution
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         would be to not drop the lock but instead "upgrade" it from a
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         LL lock to a full lock, but that's too much like hard work
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         right now. */
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(release_BigLock_LL)("wqthread_hijack(1)");
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(wqthread_continue_NORETURN)(tst->tid);
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Record thread's stack and Mach port and pthread struct
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->os_state.pthread = self;
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->os_state.lwpid = kport;
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // kernel allocated stack - needs mapping
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->client_stack_highest_word = stack+stacksize;
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tst->client_stack_szB = stacksize;
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme scheduler lock?!
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // pthread structure
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(notify_core_and_tool_of_mmap)(
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stack+stacksize, pthread_structsize,
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack contents
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme uninitialized!
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(notify_core_and_tool_of_mmap)(
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stack, stacksize,
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // guard page
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme ban_mem_stack!
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(notify_core_and_tool_of_mmap)(
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            0, VKI_MAP_PRIVATE, -1, 0);
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(sync_mappings)("after", "wqthread_hijack", 0);
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Go!
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Same comments as the 'release' in the then-clause.
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         start_thread_NORETURN calls run_thread_NORETURN calls
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thread_wrapper which acquires the lock before continuing.
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Let's hope nothing non-thread-local happens until that point.
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DDD: I think this is plain wrong .. if we get to
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thread_wrapper not holding the lock, and someone has recycled
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this thread slot in the meantime, we're hosed.  Is that
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         possible, though? */
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(release_BigLock_LL)("wqthread_hijack(2)");
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            start_thread_NORETURN, (Word)tst);
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGP_amd64_darwin)
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
574