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