| |
| /*--------------------------------------------------------------------*/ |
| /*--- Platform-specific syscalls stuff. syswrap-amd64-solaris.c ---*/ |
| /*--------------------------------------------------------------------*/ |
| |
| /* |
| This file is part of Valgrind, a dynamic binary instrumentation |
| framework. |
| |
| Copyright (C) 2014-2017 Petr Pavlu |
| setup@dagobah.cz |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 2 of the |
| License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| The GNU General Public License is contained in the file COPYING. |
| */ |
| |
| #if defined(VGP_amd64_solaris) |
| |
| #include "libvex_guest_offsets.h" |
| #include "pub_core_basics.h" |
| #include "pub_core_debuglog.h" |
| #include "pub_core_vki.h" |
| #include "pub_core_libcassert.h" |
| #include "pub_core_libcbase.h" |
| #include "pub_core_libcprint.h" |
| #include "pub_core_libcsignal.h" |
| #include "pub_core_tooliface.h" |
| #include "pub_core_syswrap.h" |
| |
| #include "priv_types_n_macros.h" |
| #include "priv_syswrap-generic.h" |
| #include "priv_syswrap-solaris.h" |
| |
| |
| /* Call f(arg1), but first switch stacks, using 'stack' as the new stack, and |
| use 'retaddr' as f's return-to address. Also, clear all the integer |
| registers before entering f. */ |
| __attribute__((noreturn)) |
| void ML_(call_on_new_stack_0_1)(Addr stack, /* %rdi */ |
| Addr retaddr, /* %rsi */ |
| void (*f)(Word), /* %rdx */ |
| Word arg1); /* %rcx */ |
| __asm__ ( |
| ".text\n" |
| ".globl vgModuleLocal_call_on_new_stack_0_1\n" |
| "vgModuleLocal_call_on_new_stack_0_1:\n" |
| " movq %rdi, %rsp\n" /* set stack */ |
| " movq %rcx, %rdi\n" /* set arg1 */ |
| " pushq %rsi\n" /* retaddr to stack */ |
| " pushq %rdx\n" /* f to stack */ |
| " movq $0, %rax\n" /* zero all GP regs (except %rdi) */ |
| " movq $0, %rbx\n" |
| " movq $0, %rcx\n" |
| " movq $0, %rdx\n" |
| " movq $0, %rsi\n" |
| " movq $0, %rbp\n" |
| " movq $0, %r8\n" |
| " movq $0, %r9\n" |
| " movq $0, %r10\n" |
| " movq $0, %r11\n" |
| " movq $0, %r12\n" |
| " movq $0, %r13\n" |
| " movq $0, %r14\n" |
| " movq $0, %r15\n" |
| " ret\n" /* jump to f */ |
| " ud2\n" /* should never get here */ |
| ".previous\n" |
| ); |
| |
| /* This function is called to setup a context of a new Valgrind thread (which |
| will run the client code). */ |
| void ML_(setup_start_thread_context)(ThreadId tid, vki_ucontext_t *uc) |
| { |
| ThreadState *tst = VG_(get_ThreadState)(tid); |
| UWord *stack = (UWord*)tst->os_state.valgrind_stack_init_SP; |
| |
| VG_(memset)(uc, 0, sizeof(*uc)); |
| uc->uc_flags = VKI_UC_CPU | VKI_UC_SIGMASK; |
| |
| /* Start the thread with everything blocked. */ |
| VG_(sigfillset)(&uc->uc_sigmask); |
| |
| /* Set up the stack, it should be always 16-byte aligned before doing |
| a function call, i.e. the first parameter is also 16-byte aligned. */ |
| vg_assert(VG_IS_16_ALIGNED(stack)); |
| stack -= 1; |
| stack[0] = 0; /* bogus return value */ |
| |
| /* Set up the registers. */ |
| uc->uc_mcontext.gregs[VKI_REG_RDI] = (UWord)tst; /* the parameter */ |
| uc->uc_mcontext.gregs[VKI_REG_RIP] = (UWord)ML_(start_thread_NORETURN); |
| uc->uc_mcontext.gregs[VKI_REG_RSP] = (UWord)stack; |
| } |
| |
| /* Architecture-specific part of VG_(save_context). */ |
| void ML_(save_machine_context)(ThreadId tid, vki_ucontext_t *uc, |
| CorePart part) |
| { |
| ThreadState *tst = VG_(get_ThreadState)(tid); |
| struct vki_fpchip_state *fs |
| = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state; |
| SizeT i; |
| |
| /* CPU */ |
| /* Common registers */ |
| uc->uc_mcontext.gregs[VKI_REG_RIP] = tst->arch.vex.guest_RIP; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RIP, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RIP], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RAX] = tst->arch.vex.guest_RAX; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RAX, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RAX], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RBX] = tst->arch.vex.guest_RBX; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RBX, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBX], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RCX] = tst->arch.vex.guest_RCX; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RCX, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RCX], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RDX] = tst->arch.vex.guest_RDX; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RDX, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDX], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RBP] = tst->arch.vex.guest_RBP; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RBP, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBP], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RSI] = tst->arch.vex.guest_RSI; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RSI, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSI], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RDI] = tst->arch.vex.guest_RDI; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RDI, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDI], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R8] = tst->arch.vex.guest_R8; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R8, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R8], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R9] = tst->arch.vex.guest_R9; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R9, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R9], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R10] = tst->arch.vex.guest_R10; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R10, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R10], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R11] = tst->arch.vex.guest_R11; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R11, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R11], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R12] = tst->arch.vex.guest_R12; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R12, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R12], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R13] = tst->arch.vex.guest_R13; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R13, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R13], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R14] = tst->arch.vex.guest_R14; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R14, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R14], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_R15] = tst->arch.vex.guest_R15; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R15, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R15], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_RSP] = tst->arch.vex.guest_RSP; |
| VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RSP, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSP], sizeof(UWord)); |
| |
| /* ERR and TRAPNO */ |
| uc->uc_mcontext.gregs[VKI_REG_ERR] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_ERR], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_TRAPNO] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_TRAPNO], sizeof(UWord)); |
| |
| /* Segment registers */ |
| /* Valgrind does not support moves from/to segment registers on AMD64. The |
| values returned below are the ones that are set by the kernel when |
| a program is started. */ |
| uc->uc_mcontext.gregs[VKI_REG_CS] = VKI_UCS_SEL; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_CS], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_DS] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_DS], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_SS] = VKI_UDS_SEL; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_SS], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_ES] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_ES], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_FS] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_FS], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_GS] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_GS], sizeof(UWord)); |
| |
| /* Segment bases */ |
| uc->uc_mcontext.gregs[VKI_REG_FSBASE] = tst->arch.vex.guest_FS_CONST; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_FSBASE], sizeof(UWord)); |
| uc->uc_mcontext.gregs[VKI_REG_GSBASE] = 0; |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_GSBASE], sizeof(UWord)); |
| |
| /* Handle rflags. Refer to the x86-solaris variant of this code for |
| a detailed description. */ |
| uc->uc_mcontext.gregs[VKI_REG_RFL] = |
| LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); |
| VG_TRACK(post_mem_write, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RFL], sizeof(UWord)); |
| VKI_UC_GUEST_CC_OP(uc) = tst->arch.vex.guest_CC_OP; |
| VKI_UC_GUEST_CC_NDEP(uc) = tst->arch.vex.guest_CC_NDEP; |
| VKI_UC_GUEST_CC_DEP1(uc) = tst->arch.vex.guest_CC_DEP1; |
| VG_TRACK(copy_reg_to_mem, part, tid, |
| offsetof(VexGuestAMD64State, guest_CC_DEP1), |
| (Addr)&VKI_UC_GUEST_CC_DEP1(uc), sizeof(UWord)); |
| VKI_UC_GUEST_CC_DEP2(uc) = tst->arch.vex.guest_CC_DEP2; |
| VG_TRACK(copy_reg_to_mem, part, tid, |
| offsetof(VexGuestAMD64State, guest_CC_DEP2), |
| (Addr)&VKI_UC_GUEST_CC_DEP2(uc), sizeof(UWord)); |
| VKI_UC_GUEST_RFLAGS_NEG(uc) = ~uc->uc_mcontext.gregs[VKI_REG_RFL]; |
| /* Calculate a checksum. */ |
| { |
| ULong buf[5]; |
| ULong checksum; |
| |
| buf[0] = VKI_UC_GUEST_CC_OP(uc); |
| buf[1] = VKI_UC_GUEST_CC_NDEP(uc); |
| buf[2] = VKI_UC_GUEST_CC_DEP1(uc); |
| buf[3] = VKI_UC_GUEST_CC_DEP2(uc); |
| buf[4] = uc->uc_mcontext.gregs[VKI_REG_RFL]; |
| checksum = ML_(fletcher64)((UInt*)&buf, sizeof(buf) / sizeof(UInt)); |
| VKI_UC_GUEST_RFLAGS_CHECKSUM(uc) = checksum; |
| } |
| |
| /* FPU */ |
| /* The fpregset_t structure on amd64 follows the layout that is used by the |
| FXSAVE instruction, therefore it is only necessary to call a VEX |
| function that simulates this instruction. */ |
| LibVEX_GuestAMD64_fxsave(&tst->arch.vex, (HWord)fs); |
| |
| /* Control word */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->cw, sizeof(fs->cw)); |
| /* Status word */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->sw, sizeof(fs->sw)); |
| /* Compressed tag word */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->fctw, sizeof(fs->fctw)); |
| /* Unused */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->__fx_rsvd, |
| sizeof(fs->__fx_rsvd)); |
| vg_assert(fs->__fx_rsvd == 0); |
| /* Last x87 opcode */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->fop, sizeof(fs->fop)); |
| vg_assert(fs->fop == 0); |
| /* Last x87 instruction pointer */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->rip, sizeof(fs->rip)); |
| vg_assert(fs->rip == 0); |
| /* Last x87 data pointer */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->rdp, sizeof(fs->rdp)); |
| vg_assert(fs->rdp == 0); |
| /* Media-instruction control and status register */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->mxcsr, sizeof(fs->mxcsr)); |
| /* Supported features in MXCSR */ |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->mxcsr_mask, |
| sizeof(fs->mxcsr_mask)); |
| |
| /* ST registers */ |
| for (i = 0; i < 8; i++) { |
| Addr addr = (Addr)&fs->st[i]; |
| /* x87 uses 80b FP registers but VEX uses only 64b registers, thus we |
| have to lie here. :< */ |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_FPREG[i]), addr, sizeof(ULong)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_FPREG[i]), addr + 8, sizeof(UShort)); |
| } |
| |
| /* XMM registers */ |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM0), (Addr)&fs->xmm[0], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM1), (Addr)&fs->xmm[1], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM2), (Addr)&fs->xmm[2], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM3), (Addr)&fs->xmm[3], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM4), (Addr)&fs->xmm[4], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM5), (Addr)&fs->xmm[5], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM6), (Addr)&fs->xmm[6], sizeof(U128)); |
| VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State, |
| guest_YMM7), (Addr)&fs->xmm[7], sizeof(U128)); |
| |
| /* Status word (sw) at exception */ |
| fs->status = 0; |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->status, sizeof(fs->status)); |
| |
| /* MXCSR at exception */ |
| fs->xstatus = 0; |
| VG_TRACK(post_mem_write, part, tid, (Addr)&fs->xstatus, |
| sizeof(fs->xstatus)); |
| } |
| |
| /* Architecture-specific part of VG_(restore_context). */ |
| void ML_(restore_machine_context)(ThreadId tid, vki_ucontext_t *uc, |
| CorePart part, Bool esp_is_thrptr) |
| { |
| ThreadState *tst = VG_(get_ThreadState)(tid); |
| struct vki_fpchip_state *fs |
| = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state; |
| |
| /* CPU */ |
| if (uc->uc_flags & VKI_UC_CPU) { |
| /* Common registers */ |
| tst->arch.vex.guest_RIP = uc->uc_mcontext.gregs[VKI_REG_RIP]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RIP], OFFSET_amd64_RIP, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RAX = uc->uc_mcontext.gregs[VKI_REG_RAX]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RAX], OFFSET_amd64_RAX, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RBX = uc->uc_mcontext.gregs[VKI_REG_RBX]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBX], OFFSET_amd64_RBX, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RCX = uc->uc_mcontext.gregs[VKI_REG_RCX]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RCX], OFFSET_amd64_RCX, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RDX = uc->uc_mcontext.gregs[VKI_REG_RDX]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDX], OFFSET_amd64_RDX, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RBP = uc->uc_mcontext.gregs[VKI_REG_RBP]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBP], OFFSET_amd64_RBP, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RSI = uc->uc_mcontext.gregs[VKI_REG_RSI]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSI], OFFSET_amd64_RSI, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RDI = uc->uc_mcontext.gregs[VKI_REG_RDI]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDI], OFFSET_amd64_RDI, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R8 = uc->uc_mcontext.gregs[VKI_REG_R8]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R8], OFFSET_amd64_R8, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R9 = uc->uc_mcontext.gregs[VKI_REG_R9]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R9], OFFSET_amd64_R9, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R10 = uc->uc_mcontext.gregs[VKI_REG_R10]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R10], OFFSET_amd64_R10, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R11 = uc->uc_mcontext.gregs[VKI_REG_R11]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R11], OFFSET_amd64_R11, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R12 = uc->uc_mcontext.gregs[VKI_REG_R12]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R12], OFFSET_amd64_R12, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R13 = uc->uc_mcontext.gregs[VKI_REG_R13]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R13], OFFSET_amd64_R13, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R14 = uc->uc_mcontext.gregs[VKI_REG_R14]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R14], OFFSET_amd64_R14, |
| sizeof(UWord)); |
| tst->arch.vex.guest_R15 = uc->uc_mcontext.gregs[VKI_REG_R15]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_R15], OFFSET_amd64_R15, |
| sizeof(UWord)); |
| tst->arch.vex.guest_RSP = uc->uc_mcontext.gregs[VKI_REG_RSP]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSP], OFFSET_amd64_RSP, |
| sizeof(UWord)); |
| |
| /* Ignore ERR and TRAPNO. */ |
| |
| /* Ignore segment registers. */ |
| |
| /* Segment bases */ |
| tst->arch.vex.guest_FS_CONST = uc->uc_mcontext.gregs[VKI_REG_FSBASE]; |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_FSBASE], |
| offsetof(VexGuestAMD64State, guest_FS_CONST), sizeof(UWord)); |
| |
| /* Rflags. Refer to the x86-solaris variant of this code for a detailed |
| description. */ |
| { |
| ULong rflags; |
| ULong orig_rflags; |
| ULong new_rflags; |
| Bool ok_restore = False; |
| |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.gregs[VKI_REG_RFL])", |
| (Addr)&uc->uc_mcontext.gregs[VKI_REG_RFL], sizeof(UWord)); |
| rflags = uc->uc_mcontext.gregs[VKI_REG_RFL]; |
| orig_rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); |
| new_rflags = rflags; |
| /* The kernel disallows the ID flag to be changed via the setcontext |
| call, thus do the same. */ |
| if (orig_rflags & VKI_RFLAGS_ID_BIT) |
| new_rflags |= VKI_RFLAGS_ID_BIT; |
| else |
| new_rflags &= ~VKI_RFLAGS_ID_BIT; |
| LibVEX_GuestAMD64_put_rflags(new_rflags, &tst->arch.vex); |
| VG_TRACK(post_reg_write, part, tid, |
| offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(UWord)); |
| VG_TRACK(post_reg_write, part, tid, |
| offsetof(VexGuestAMD64State, guest_CC_DEP2), sizeof(UWord)); |
| |
| if (rflags != ~VKI_UC_GUEST_RFLAGS_NEG(uc)) { |
| VG_(debugLog)(1, "syswrap-solaris", |
| "The rflags value was restored from an " |
| "explicitly set value in thread %u.\n", tid); |
| ok_restore = True; |
| } |
| else { |
| ULong buf[5]; |
| ULong checksum; |
| |
| buf[0] = VKI_UC_GUEST_CC_OP(uc); |
| buf[1] = VKI_UC_GUEST_CC_NDEP(uc); |
| buf[2] = VKI_UC_GUEST_CC_DEP1(uc); |
| buf[3] = VKI_UC_GUEST_CC_DEP2(uc); |
| buf[4] = rflags; |
| checksum = ML_(fletcher64)((UInt*)&buf, |
| sizeof(buf) / sizeof(UInt)); |
| if (checksum == VKI_UC_GUEST_RFLAGS_CHECKSUM(uc)) { |
| /* Check ok, the full restoration is possible. */ |
| VG_(debugLog)(1, "syswrap-solaris", |
| "The CC_* guest state values were fully " |
| "restored in thread %u.\n", tid); |
| ok_restore = True; |
| |
| tst->arch.vex.guest_CC_OP = VKI_UC_GUEST_CC_OP(uc); |
| tst->arch.vex.guest_CC_NDEP = VKI_UC_GUEST_CC_NDEP(uc); |
| tst->arch.vex.guest_CC_DEP1 = VKI_UC_GUEST_CC_DEP1(uc); |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&VKI_UC_GUEST_CC_DEP1(uc), |
| offsetof(VexGuestAMD64State, guest_CC_DEP1), |
| sizeof(UWord)); |
| tst->arch.vex.guest_CC_DEP2 = VKI_UC_GUEST_CC_DEP2(uc); |
| VG_TRACK(copy_mem_to_reg, part, tid, |
| (Addr)&VKI_UC_GUEST_CC_DEP2(uc), |
| offsetof(VexGuestAMD64State, guest_CC_DEP2), |
| sizeof(UWord)); |
| } |
| } |
| |
| if (!ok_restore) |
| VG_(debugLog)(1, "syswrap-solaris", |
| "Cannot fully restore the CC_* guest state " |
| "values, using approximate rflags in thread " |
| "%u.\n", tid); |
| } |
| } |
| |
| if (uc->uc_flags & VKI_UC_FPU) { |
| /* FPU */ |
| VexEmNote note; |
| SizeT i; |
| |
| /* x87 */ |
| /* Control word */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..cw)", |
| (Addr)&fs->cw, sizeof(fs->cw)); |
| /* Status word */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..sw)", |
| (Addr)&fs->sw, sizeof(fs->sw)); |
| /* Compressed tag word */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..fctw)", |
| (Addr)&fs->fctw, sizeof(fs->fctw)); |
| /* Last x87 opcode */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..fop)", |
| (Addr)&fs->fop, sizeof(fs->fop)); |
| /* Last x87 instruction pointer */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..rip)", |
| (Addr)&fs->rip, sizeof(fs->rip)); |
| /* Last x87 data pointer */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..rdp)", |
| (Addr)&fs->rdp, sizeof(fs->rdp)); |
| /* Media-instruction control and status register */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..mxcsr)", |
| (Addr)&fs->mxcsr, sizeof(fs->mxcsr)); |
| /* Supported features in MXCSR */ |
| VG_TRACK(pre_mem_read, part, tid, |
| "restore_machine_context(uc->uc_mcontext.fpregs..mxcsr_mask)", |
| (Addr)&fs->mxcsr_mask, sizeof(fs->mxcsr_mask)); |
| |
| /* ST registers */ |
| for (i = 0; i < 8; i++) { |
| Addr addr = (Addr)&fs->st[i]; |
| VG_TRACK(copy_mem_to_reg, part, tid, addr, |
| offsetof(VexGuestAMD64State, guest_FPREG[i]), sizeof(ULong)); |
| } |
| |
| /* XMM registers */ |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[0], |
| offsetof(VexGuestAMD64State, guest_YMM0), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[1], |
| offsetof(VexGuestAMD64State, guest_YMM1), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[2], |
| offsetof(VexGuestAMD64State, guest_YMM2), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[3], |
| offsetof(VexGuestAMD64State, guest_YMM3), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[4], |
| offsetof(VexGuestAMD64State, guest_YMM4), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[5], |
| offsetof(VexGuestAMD64State, guest_YMM5), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[6], |
| offsetof(VexGuestAMD64State, guest_YMM6), sizeof(U128)); |
| VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[7], |
| offsetof(VexGuestAMD64State, guest_YMM7), sizeof(U128)); |
| |
| note = LibVEX_GuestAMD64_fxrstor((HWord)fs, &tst->arch.vex); |
| if (note != EmNote_NONE) |
| VG_(message)(Vg_UserMsg, |
| "Error restoring FP state in thread %u: %s.\n", |
| tid, LibVEX_EmNote_string(note)); |
| } |
| } |
| |
| |
| /* --------------------------------------------------------------------- |
| PRE/POST wrappers for AMD64/Solaris-specific syscalls |
| ------------------------------------------------------------------ */ |
| |
| #define PRE(name) DEFN_PRE_TEMPLATE(amd64_solaris, name) |
| #define POST(name) DEFN_POST_TEMPLATE(amd64_solaris, name) |
| |
| /* implementation */ |
| |
| #undef PRE |
| #undef POST |
| |
| #endif // defined(VGP_amd64_solaris) |
| |
| /*--------------------------------------------------------------------*/ |
| /*--- end ---*/ |
| /*--------------------------------------------------------------------*/ |