diff options
author | Ben Pye <ben@curlybracket.co.uk> | 2015-07-01 15:10:09 +0100 |
---|---|---|
committer | Ben Pye <ben@curlybracket.co.uk> | 2015-07-24 16:45:35 +0100 |
commit | 9cd8273572260317c6acc126333e5a6e56aaeb06 (patch) | |
tree | f125e83a6908151322aa20940b63c64c621c1169 /src/pal/src/arch | |
parent | acca43b33dcd97d1dc5d92147a3047a3bdfaf1ce (diff) | |
download | coreclr-9cd8273572260317c6acc126333e5a6e56aaeb06.tar.gz coreclr-9cd8273572260317c6acc126333e5a6e56aaeb06.tar.bz2 coreclr-9cd8273572260317c6acc126333e5a6e56aaeb06.zip |
Add ARM target for CoreCLR on Linux.
c_runtime/vprintf/test1 is disabled as casting NULL to va_list is
against the C specification.
Fix SetFilePointer tests on 32 bit platforms.
Define _FILE_OFFSET_BITS=64 so that we have long file support on 32 bit
platforms.
Implement context capture/restore for ARM.
Link libgcc_s before libunwind on ARM so C++ exceptions work.
Translate armasm to gas syntax.
Specify Thumb, VFPv3, ARMv7 for the ARM target.
Add ARM configuration to mscorlib build
Implement GetLogicalProcessorCacheSizeFromOS in PAL.
Set UNWIND_CONTEXT_IS_UCONTEXT_T from configure check.
Diffstat (limited to 'src/pal/src/arch')
-rw-r--r-- | src/pal/src/arch/arm/context2.S | 217 | ||||
-rw-r--r-- | src/pal/src/arch/arm/processor.cpp | 43 | ||||
-rw-r--r-- | src/pal/src/arch/i386/context.cpp | 1225 |
3 files changed, 260 insertions, 1225 deletions
diff --git a/src/pal/src/arch/arm/context2.S b/src/pal/src/arch/arm/context2.S new file mode 100644 index 0000000000..88aee3b321 --- /dev/null +++ b/src/pal/src/arch/arm/context2.S @@ -0,0 +1,217 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// +// Implementation of _CONTEXT_CaptureContext for the ARM platform. +// This function is processor dependent. It is used by exception handling, +// and is always apply to the current thread. +// + +#include "unixasmmacros.inc" + +.syntax unified +.thumb + +#define CONTEXT_ARM 0x00200000 + +#define CONTEXT_CONTROL 1 // Sp, Lr, Pc, Cpsr +#define CONTEXT_INTEGER 2 // R0-R12 +#define CONTEXT_SEGMENTS 4 // +#define CONTEXT_FLOATING_POINT 8 +#define CONTEXT_DEBUG_REGISTERS 16 // + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) + +#define CONTEXT_ContextFlags 0 +#define CONTEXT_R0 CONTEXT_ContextFlags+4 +#define CONTEXT_R1 CONTEXT_R0+4 +#define CONTEXT_R2 CONTEXT_R1+4 +#define CONTEXT_R3 CONTEXT_R2+4 +#define CONTEXT_R4 CONTEXT_R3+4 +#define CONTEXT_R5 CONTEXT_R4+4 +#define CONTEXT_R6 CONTEXT_R5+4 +#define CONTEXT_R7 CONTEXT_R6+4 +#define CONTEXT_R8 CONTEXT_R7+4 +#define CONTEXT_R9 CONTEXT_R8+4 +#define CONTEXT_R10 CONTEXT_R9+4 +#define CONTEXT_R11 CONTEXT_R10+4 +#define CONTEXT_R12 CONTEXT_R11+4 +#define CONTEXT_Sp CONTEXT_R12+4 +#define CONTEXT_Lr CONTEXT_Sp+4 +#define CONTEXT_Pc CONTEXT_Lr+4 +#define CONTEXT_Cpsr CONTEXT_Pc+4 +#define CONTEXT_Fpscr CONTEXT_Cpsr+4 +#define CONTEXT_Padding CONTEXT_Fpscr+4 +#define CONTEXT_D0 CONTEXT_Padding+4 +#define CONTEXT_D1 CONTEXT_D0+8 +#define CONTEXT_D2 CONTEXT_D1+8 +#define CONTEXT_D3 CONTEXT_D2+8 +#define CONTEXT_D4 CONTEXT_D3+8 +#define CONTEXT_D5 CONTEXT_D4+8 +#define CONTEXT_D6 CONTEXT_D5+8 +#define CONTEXT_D7 CONTEXT_D6+8 +#define CONTEXT_D8 CONTEXT_D7+8 +#define CONTEXT_D9 CONTEXT_D8+8 +#define CONTEXT_D10 CONTEXT_D9+8 +#define CONTEXT_D11 CONTEXT_D10+8 +#define CONTEXT_D12 CONTEXT_D11+8 +#define CONTEXT_D13 CONTEXT_D12+8 +#define CONTEXT_D14 CONTEXT_D13+8 +#define CONTEXT_D15 CONTEXT_D14+8 +#define CONTEXT_D16 CONTEXT_D15+8 +#define CONTEXT_D17 CONTEXT_D16+8 +#define CONTEXT_D18 CONTEXT_D17+8 +#define CONTEXT_D19 CONTEXT_D18+8 +#define CONTEXT_D20 CONTEXT_D19+8 +#define CONTEXT_D21 CONTEXT_D20+8 +#define CONTEXT_D22 CONTEXT_D21+8 +#define CONTEXT_D23 CONTEXT_D22+8 +#define CONTEXT_D24 CONTEXT_D23+8 +#define CONTEXT_D25 CONTEXT_D24+8 +#define CONTEXT_D26 CONTEXT_D25+8 +#define CONTEXT_D27 CONTEXT_D26+8 +#define CONTEXT_D28 CONTEXT_D27+8 +#define CONTEXT_D29 CONTEXT_D28+8 +#define CONTEXT_D30 CONTEXT_D29+8 +#define CONTEXT_D31 CONTEXT_D30+8 + +// Incoming: +// r0: Context* +// +LEAF_ENTRY CONTEXT_CaptureContext, _TEXT + // Ensure we save these registers + push {r4-r11} + // Save processor flags before calling any of the following 'test' instructions + // because they will modify state of some flags + push {r1} + mrs r1, apsr // Get APSR - equivalent to eflags + push {r1} // Save APSR + END_PROLOGUE + + push {r2} + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_INTEGER) + pop {r2} + + // Add 4 to stack so we point at R1, pop, then sub 8 to point at APSR + add sp, sp, #4 + pop {r1} + sub sp, sp, #8 + + itttt ne + strne r0, [r0, #(CONTEXT_R0)] + addne r0, CONTEXT_R1 + stmiane r0, {r1-r12} + subne r0, CONTEXT_R1 + + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_CONTROL) + + ittt ne + addne sp, sp, #(10*4) // This needs to put the stack in the same state as it started + strne sp, [r0, #(CONTEXT_Sp)] + subne sp, sp, #(10*4) + + itt ne + strne lr, [r0, #(CONTEXT_Lr)] + strne lr, [r0, #(CONTEXT_Pc)] + + // Get the APSR pushed onto the stack at the start + pop {r1} + it ne + strne r1, [r0, #(CONTEXT_Cpsr)] + + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_FLOATING_POINT) + + itt ne + vmrsne r3, fpscr + strne r3, [r0, #(CONTEXT_Fpscr)] + + itttt ne + addne r0, CONTEXT_D0 + vstmiane r0!, {d0-d15} + vstmiane r0!, {d16-d31} + subne r0, CONTEXT_D31 + + // Make sure sp is restored + add sp, sp, #4 + + // Restore callee saved registers + pop {r4-r11} + bx lr +LEAF_END CONTEXT_CaptureContext, _TEXT + +// Incoming: +// R0: Context* +// +LEAF_ENTRY RtlCaptureContext, _TEXT + push {r1} + mov r1, #0 + orr r1, r1, #CONTEXT_ARM + orr r1, r1, #CONTEXT_INTEGER + orr r1, r1, #CONTEXT_CONTROL + orr r1, r1, #CONTEXT_FLOATING_POINT + str r1, [r0, #(CONTEXT_ContextFlags)] + pop {r1} + b C_FUNC(CONTEXT_CaptureContext) +LEAF_END RtlCaptureContext, _TEXT + +// Incoming: +// r0: Context* +// r1: Exception* +// +LEAF_ENTRY RtlRestoreContext, _TEXT + END_PROLOGUE + + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_FLOATING_POINT) + + itttt ne + addne r0, CONTEXT_D0 + vldmiane r0!, {d0-d15} + vldmiane r0, {d16-d31} + subne r0, CONTEXT_D16 + + itt ne + ldrne r3, [r0, #(CONTEXT_Fpscr)] + vmrsne r3, FPSCR + + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_CONTROL) + + it eq + beq LOCAL_LABEL(No_Restore_CONTEXT_CONTROL) + + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_INTEGER) + + it eq + beq LOCAL_LABEL(No_Restore_CONTEXT_INTEGER) + + ldr R2, [r0, #(CONTEXT_Cpsr)] + msr APSR, r2 + + add r0, CONTEXT_R0 + ldmia r0, {r0-r12, sp, lr, pc} + +LOCAL_LABEL(No_Restore_CONTEXT_INTEGER): + + ldr r2, [r0, #(CONTEXT_Cpsr)] + msr APSR, r2 + + add r0, CONTEXT_Sp + ldmia r0, {sp, lr, pc} + +LOCAL_LABEL(No_Restore_CONTEXT_CONTROL): + ldr r2, [r0, #(CONTEXT_ContextFlags)] + tst r2, #(CONTEXT_INTEGER) + + itt ne + addne r0, CONTEXT_R0 + ldmiane r0, {r0-r12} + + sub sp, sp, #4 + bx lr +LEAF_END RtlRestoreContext, _TEXT
\ No newline at end of file diff --git a/src/pal/src/arch/arm/processor.cpp b/src/pal/src/arch/arm/processor.cpp new file mode 100644 index 0000000000..b7973486e0 --- /dev/null +++ b/src/pal/src/arch/arm/processor.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +/*++ + + + +Module Name: + + processor.cpp + +Abstract: + + Implementation of processor related functions for the ARM + platform. These functions are processor dependent. + + + +--*/ + +#include "pal/palinternal.h" + +/*++ +Function: +YieldProcessor + +The YieldProcessor function signals to the processor to give resources +to threads that are waiting for them. This macro is only effective on +processors that support technology allowing multiple threads running +on a single processor, such as Intel's Hyper-Threading technology. + +--*/ +void +PALAPI +YieldProcessor( + VOID) +{ + // Pretty sure ARM has no useful function here? + return; +} + diff --git a/src/pal/src/arch/i386/context.cpp b/src/pal/src/arch/i386/context.cpp deleted file mode 100644 index 14a96bb9b0..0000000000 --- a/src/pal/src/arch/i386/context.cpp +++ /dev/null @@ -1,1225 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -/*++ - - - -Module Name: - - context.c - -Abstract: - - Implementation of GetThreadContext/SetThreadContext/DebugBreak functions for - the Intel x86 platform. These functions are processor dependent. - - - ---*/ - -#include "pal/palinternal.h" -#include "pal/dbgmsg.h" -#include "pal/context.h" -#include "pal/debug.h" -#include "pal/thread.hpp" - -#include <sys/ptrace.h> -#include <errno.h> -#include <unistd.h> - -SET_DEFAULT_DEBUG_CHANNEL(DEBUG); - -// in context2.S -extern void CONTEXT_CaptureContext(LPCONTEXT lpContext); - -#ifdef _X86_ -#define CONTEXT_ALL_FLOATING (CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS) -#elif defined(_AMD64_) -#define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT -#else -#error Unexpected architecture. -#endif - -#if !HAVE_MACH_EXCEPTIONS - -#if HAVE_BSD_REGS_T -#include <machine/reg.h> -#include <machine/npx.h> -#endif // HAVE_BSD_REGS_T -#if HAVE_PT_REGS -#include <asm/ptrace.h> -#endif // HAVE_PT_REGS - -#ifdef BIT64 -#define ASSIGN_CONTROL_REGS \ - ASSIGN_REG(Rbp) \ - ASSIGN_REG(Rip) \ - ASSIGN_REG(SegCs) \ - ASSIGN_REG(EFlags) \ - ASSIGN_REG(Rsp) \ - -#define ASSIGN_INTEGER_REGS \ - ASSIGN_REG(Rdi) \ - ASSIGN_REG(Rsi) \ - ASSIGN_REG(Rbx) \ - ASSIGN_REG(Rdx) \ - ASSIGN_REG(Rcx) \ - ASSIGN_REG(Rax) \ - ASSIGN_REG(R8) \ - ASSIGN_REG(R9) \ - ASSIGN_REG(R10) \ - ASSIGN_REG(R11) \ - ASSIGN_REG(R12) \ - ASSIGN_REG(R13) \ - ASSIGN_REG(R14) \ - ASSIGN_REG(R15) \ - -#else // BIT64 -#define ASSIGN_CONTROL_REGS \ - ASSIGN_REG(Ebp) \ - ASSIGN_REG(Eip) \ - ASSIGN_REG(SegCs) \ - ASSIGN_REG(EFlags) \ - ASSIGN_REG(Esp) \ - ASSIGN_REG(SegSs) \ - -#define ASSIGN_INTEGER_REGS \ - ASSIGN_REG(Edi) \ - ASSIGN_REG(Esi) \ - ASSIGN_REG(Ebx) \ - ASSIGN_REG(Edx) \ - ASSIGN_REG(Ecx) \ - ASSIGN_REG(Eax) \ - -#endif //BIT64 - -#define ASSIGN_ALL_REGS \ - ASSIGN_CONTROL_REGS \ - ASSIGN_INTEGER_REGS \ - -/*++ -Function: - CONTEXT_GetRegisters - -Abstract - retrieve the machine registers value of the indicated process. - -Parameter - processId: process ID - registers: reg structure in which the machine registers value will be returned. -Return - returns TRUE if it succeeds, FALSE otherwise ---*/ -BOOL CONTEXT_GetRegisters(DWORD processId, ucontext_t *registers) -{ -#if HAVE_BSD_REGS_T - int regFd = -1; -#endif // HAVE_BSD_REGS_T - BOOL bRet = FALSE; - - if (processId == GetCurrentProcessId()) - { -#if HAVE_GETCONTEXT - if (getcontext(registers) != 0) - { - ASSERT("getcontext() failed %d (%s)\n", errno, strerror(errno)); - return FALSE; - } -#elif HAVE_BSD_REGS_T - char buf[MAX_PATH]; - struct reg bsd_registers; - - sprintf_s(buf, sizeof(buf), "/proc/%d/regs", processId); - - if ((regFd = PAL__open(buf, O_RDONLY)) == -1) - { - ASSERT("PAL__open() failed %d (%s) \n", errno, strerror(errno)); - return FALSE; - } - - if (lseek(regFd, 0, 0) == -1) - { - ASSERT("lseek() failed %d (%s)\n", errno, strerror(errno)); - goto EXIT; - } - - if (read(regFd, &bsd_registers, sizeof(bsd_registers)) != sizeof(bsd_registers)) - { - ASSERT("read() failed %d (%s)\n", errno, strerror(errno)); - goto EXIT; - } - -#define ASSIGN_REG(reg) MCREG_##reg(registers->uc_mcontext) = BSDREG_##reg(bsd_registers); - ASSIGN_ALL_REGS -#undef ASSIGN_REG - -#else -#error "Don't know how to get current context on this platform!" -#endif - } - else - { -#if HAVE_PT_REGS - struct pt_regs ptrace_registers; - if (ptrace((__ptrace_request)PT_GETREGS, processId, (caddr_t) &ptrace_registers, 0) == -1) -#elif HAVE_BSD_REGS_T - struct reg ptrace_registers; - if (ptrace(PT_GETREGS, processId, (caddr_t) &ptrace_registers, 0) == -1) -#endif - { - ASSERT("Failed ptrace(PT_GETREGS, processId:%d) errno:%d (%s)\n", - processId, errno, strerror(errno)); - } - -#if HAVE_PT_REGS -#define ASSIGN_REG(reg) MCREG_##reg(registers->uc_mcontext) = PTREG_##reg(ptrace_registers); -#elif HAVE_BSD_REGS_T -#define ASSIGN_REG(reg) MCREG_##reg(registers->uc_mcontext) = BSDREG_##reg(ptrace_registers); -#endif - ASSIGN_ALL_REGS -#undef ASSIGN_REG - } - - bRet = TRUE; -#if HAVE_BSD_REGS_T -EXIT : - if (regFd != -1) - { - close(regFd); - } -#endif // HAVE_BSD_REGS_T - return bRet; -} - -/*++ -Function: - GetThreadContext - -See MSDN doc. ---*/ -BOOL -CONTEXT_GetThreadContext( - DWORD dwProcessId, - pthread_t self, - DWORD dwLwpId, - LPCONTEXT lpContext) -{ - BOOL ret = FALSE; - ucontext_t registers; - - if (lpContext == NULL) - { - ERROR("Invalid lpContext parameter value\n"); - SetLastError(ERROR_NOACCESS); - goto EXIT; - } - - /* How to consider the case when self is different from the current - thread of its owner process. Machine registers values could be retreived - by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content. - Unfortunately, these two methods only depend on process ID, not on - thread ID. */ - - if (dwProcessId == GetCurrentProcessId()) - { - if (self != pthread_self()) - { - DWORD flags; - // There aren't any APIs for this. We can potentially get the - // context of another thread by using per-thread signals, but - // on FreeBSD signal handlers that are called as a result - // of signals raised via pthread_kill don't get a valid - // sigcontext or ucontext_t. But we need this to return TRUE - // to avoid an assertion in the CLR in code that manages to - // cope reasonably well without a valid thread context. - // Given that, we'll zero out our structure and return TRUE. - ERROR("GetThreadContext on a thread other than the current " - "thread is returning TRUE\n"); - flags = lpContext->ContextFlags; - memset(lpContext, 0, sizeof(*lpContext)); - lpContext->ContextFlags = flags; - ret = TRUE; - goto EXIT; - } - - } - - if (lpContext->ContextFlags & - (CONTEXT_CONTROL | CONTEXT_INTEGER)) - { - if (CONTEXT_GetRegisters(dwProcessId, ®isters) == FALSE) - { - SetLastError(ERROR_INTERNAL_ERROR); - goto EXIT; - } - - CONTEXTFromNativeContext(®isters, lpContext, lpContext->ContextFlags); - } - - ret = TRUE; - -EXIT: - return ret; -} - -/*++ -Function: - SetThreadContext - -See MSDN doc. ---*/ -BOOL -CONTEXT_SetThreadContext( - DWORD dwProcessId, - pthread_t self, - DWORD dwLwpId, - CONST CONTEXT *lpContext) -{ - BOOL ret = FALSE; - -#if HAVE_PT_REGS - struct pt_regs ptrace_registers; -#elif HAVE_BSD_REGS_T - struct reg ptrace_registers; -#endif - - if (lpContext == NULL) - { - ERROR("Invalid lpContext parameter value\n"); - SetLastError(ERROR_NOACCESS); - goto EXIT; - } - - /* How to consider the case when self is different from the current - thread of its owner process. Machine registers values could be retreived - by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content. - Unfortunately, these two methods only depend on process ID, not on - thread ID. */ - - if (dwProcessId == GetCurrentProcessId()) - { -#ifdef FEATURE_PAL_SXS - // Need to implement SetThreadContext(current thread) for the IX architecture; look at common_signal_handler. - _ASSERT(FALSE); -#endif // FEATURE_PAL_SXS - ASSERT("SetThreadContext should be called for cross-process only.\n"); - SetLastError(ERROR_INVALID_PARAMETER); - goto EXIT; - } - - if (lpContext->ContextFlags & - (CONTEXT_CONTROL | CONTEXT_INTEGER)) - { -#if HAVE_PT_REGS - if (ptrace((__ptrace_request)PT_GETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) -#elif HAVE_BSD_REGS_T - if (ptrace(PT_GETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) -#endif - { - ASSERT("Failed ptrace(PT_GETREGS, processId:%d) errno:%d (%s)\n", - dwProcessId, errno, strerror(errno)); - SetLastError(ERROR_INTERNAL_ERROR); - goto EXIT; - } - -#if HAVE_PT_REGS -#define ASSIGN_REG(reg) PTREG_##reg(ptrace_registers) = lpContext->reg; -#elif HAVE_BSD_REGS_T -#define ASSIGN_REG(reg) BSDREG_##reg(ptrace_registers) = lpContext->reg; -#endif - if (lpContext->ContextFlags & CONTEXT_CONTROL) - { - ASSIGN_CONTROL_REGS - } - if (lpContext->ContextFlags & CONTEXT_INTEGER) - { - ASSIGN_INTEGER_REGS - } -#undef ASSIGN_REG - -#if HAVE_PT_REGS - if (ptrace((__ptrace_request)PT_SETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) -#elif HAVE_BSD_REGS_T - if (ptrace(PT_SETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1) -#endif - { - ASSERT("Failed ptrace(PT_SETREGS, processId:%d) errno:%d (%s)\n", - dwProcessId, errno, strerror(errno)); - SetLastError(ERROR_INTERNAL_ERROR); - goto EXIT; - } - } - - ret = TRUE; - EXIT: - return ret; -} - -/*++ -Function : - CONTEXTToNativeContext - - Converts a CONTEXT record to a native context. - -Parameters : - CONST CONTEXT *lpContext : CONTEXT to convert - native_context_t *native : native context to fill in - ULONG contextFlags : flags that determine which registers are valid in - lpContext and which ones to set in native - -Return value : - None - ---*/ -void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native) -{ -#define ASSIGN_REG(reg) MCREG_##reg(native->uc_mcontext) = lpContext->reg; - if ((lpContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - ASSIGN_CONTROL_REGS - } - - if ((lpContext->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - ASSIGN_INTEGER_REGS - } -#undef ASSIGN_REG - - if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { - FPREG_ControlWord(native) = lpContext->FltSave.ControlWord; - FPREG_StatusWord(native) = lpContext->FltSave.StatusWord; - FPREG_TagWord(native) = lpContext->FltSave.TagWord; - FPREG_ErrorOffset(native) = lpContext->FltSave.ErrorOffset; - FPREG_ErrorSelector(native) = lpContext->FltSave.ErrorSelector; - FPREG_DataOffset(native) = lpContext->FltSave.DataOffset; - FPREG_DataSelector(native) = lpContext->FltSave.DataSelector; - FPREG_MxCsr(native) = lpContext->FltSave.MxCsr; - FPREG_MxCsr_Mask(native) = lpContext->FltSave.MxCsr_Mask; - - for (int i = 0; i < 8; i++) - { - FPREG_St(native, i) = ((M128U*)lpContext->FltSave.FloatRegisters)[i]; - } - - for (int i = 0; i < 16; i++) - { - FPREG_Xmm(native, i) = ((M128U*)lpContext->FltSave.XmmRegisters)[i]; - } - } -} - -/*++ -Function : - CONTEXTFromNativeContext - - Converts a native context to a CONTEXT record. - -Parameters : - const native_context_t *native : native context to convert - LPCONTEXT lpContext : CONTEXT to fill in - ULONG contextFlags : flags that determine which registers are valid in - native and which ones to set in lpContext - -Return value : - None - ---*/ -void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext, - ULONG contextFlags) -{ - lpContext->ContextFlags = contextFlags; - -#define ASSIGN_REG(reg) lpContext->reg = MCREG_##reg(native->uc_mcontext); - if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - ASSIGN_CONTROL_REGS - } - - if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - ASSIGN_INTEGER_REGS - } -#undef ASSIGN_REG - - if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { - lpContext->FltSave.ControlWord = FPREG_ControlWord(native); - lpContext->FltSave.StatusWord = FPREG_StatusWord(native); - lpContext->FltSave.TagWord = FPREG_TagWord(native); - lpContext->FltSave.ErrorOffset = FPREG_ErrorOffset(native); - lpContext->FltSave.ErrorSelector = FPREG_ErrorSelector(native); - lpContext->FltSave.DataOffset = FPREG_DataOffset(native); - lpContext->FltSave.DataSelector = FPREG_DataSelector(native); - lpContext->FltSave.MxCsr = FPREG_MxCsr(native); - lpContext->FltSave.MxCsr_Mask = FPREG_MxCsr_Mask(native); - - for (int i = 0; i < 8; i++) - { - ((M128U*)lpContext->FltSave.FloatRegisters)[i] = FPREG_St(native, i); - } - - for (int i = 0; i < 16; i++) - { - ((M128U*)lpContext->FltSave.XmmRegisters)[i] = FPREG_Xmm(native, i); - } - } -} - -/*++ -Function : - CONTEXTGetPC - - Returns the program counter from the native context. - -Parameters : - const native_context_t *native : native context - -Return value : - The program counter from the native context. - ---*/ -LPVOID CONTEXTGetPC(const native_context_t *context) -{ -#ifdef BIT64 - return (LPVOID)MCREG_Rip(context->uc_mcontext); -#else - return (LPVOID) MCREG_Eip(context->uc_mcontext); -#endif // BIT64 -} - -/*++ -Function : - CONTEXTGetExceptionCodeForSignal - - Translates signal and context information to a Win32 exception code. - -Parameters : - const siginfo_t *siginfo : signal information from a signal handler - const native_context_t *context : context information - -Return value : - The Win32 exception code that corresponds to the signal and context - information. - ---*/ -#ifdef ILL_ILLOPC -// If si_code values are available for all signals, use those. -DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo, - const native_context_t *context) -{ - switch (siginfo->si_signo) - { - case SIGILL: - switch (siginfo->si_code) - { - case ILL_ILLOPC: // Illegal opcode - case ILL_ILLOPN: // Illegal operand - case ILL_ILLADR: // Illegal addressing mode - case ILL_ILLTRP: // Illegal trap - case ILL_COPROC: // Co-processor error - return EXCEPTION_ILLEGAL_INSTRUCTION; - case ILL_PRVOPC: // Privileged opcode - case ILL_PRVREG: // Privileged register - return EXCEPTION_PRIV_INSTRUCTION; - case ILL_BADSTK: // Internal stack error - return EXCEPTION_STACK_OVERFLOW; - default: - break; - } - break; - case SIGFPE: - switch (siginfo->si_code) - { - case FPE_INTDIV: - return EXCEPTION_INT_DIVIDE_BY_ZERO; - case FPE_INTOVF: - return EXCEPTION_INT_OVERFLOW; - case FPE_FLTDIV: - return EXCEPTION_FLT_DIVIDE_BY_ZERO; - case FPE_FLTOVF: - return EXCEPTION_FLT_OVERFLOW; - case FPE_FLTUND: - return EXCEPTION_FLT_UNDERFLOW; - case FPE_FLTRES: - return EXCEPTION_FLT_INEXACT_RESULT; - case FPE_FLTINV: - return EXCEPTION_FLT_INVALID_OPERATION; - case FPE_FLTSUB: - return EXCEPTION_FLT_INVALID_OPERATION; - default: - break; - } - break; - case SIGSEGV: - switch (siginfo->si_code) - { - case SI_USER: // User-generated signal, sometimes sent - // for SIGSEGV under normal circumstances - case SEGV_MAPERR: // Address not mapped to object - case SEGV_ACCERR: // Invalid permissions for mapped object - return EXCEPTION_ACCESS_VIOLATION; - default: - break; - } - break; - case SIGBUS: - switch (siginfo->si_code) - { - case BUS_ADRALN: // Invalid address alignment - return EXCEPTION_DATATYPE_MISALIGNMENT; - case BUS_ADRERR: // Non-existent physical address - return EXCEPTION_ACCESS_VIOLATION; - case BUS_OBJERR: // Object-specific hardware error - default: - break; - } - case SIGTRAP: - switch (siginfo->si_code) - { - case SI_KERNEL: - case SI_USER: - case TRAP_BRKPT: // Process breakpoint - return EXCEPTION_BREAKPOINT; - case TRAP_TRACE: // Process trace trap - return EXCEPTION_SINGLE_STEP; - default: - // We don't want to use ASSERT here since it raises SIGTRAP and we - // might again end up here resulting in an infinite loop! - // so, we print out an error message and return - DBG_PRINTF(DLI_ASSERT, defdbgchan, TRUE) - ("Got unknown SIGTRAP signal (%d) with code %d\n", SIGTRAP, siginfo->si_code); - - return EXCEPTION_ILLEGAL_INSTRUCTION; - } - default: - break; - } - ASSERT("Got unknown signal number %d with code %d\n", - siginfo->si_signo, siginfo->si_code); - return EXCEPTION_ILLEGAL_INSTRUCTION; -} -#else // ILL_ILLOPC -DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo, - const native_context_t *context) -{ - int trap; - - if (siginfo->si_signo == SIGFPE) - { - // Floating point exceptions are mapped by their si_code. - switch (siginfo->si_code) - { - case FPE_INTDIV : - TRACE("Got signal SIGFPE:FPE_INTDIV; raising " - "EXCEPTION_INT_DIVIDE_BY_ZERO\n"); - return EXCEPTION_INT_DIVIDE_BY_ZERO; - break; - case FPE_INTOVF : - TRACE("Got signal SIGFPE:FPE_INTOVF; raising " - "EXCEPTION_INT_OVERFLOW\n"); - return EXCEPTION_INT_OVERFLOW; - break; - case FPE_FLTDIV : - TRACE("Got signal SIGFPE:FPE_FLTDIV; raising " - "EXCEPTION_FLT_DIVIDE_BY_ZERO\n"); - return EXCEPTION_FLT_DIVIDE_BY_ZERO; - break; - case FPE_FLTOVF : - TRACE("Got signal SIGFPE:FPE_FLTOVF; raising " - "EXCEPTION_FLT_OVERFLOW\n"); - return EXCEPTION_FLT_OVERFLOW; - break; - case FPE_FLTUND : - TRACE("Got signal SIGFPE:FPE_FLTUND; raising " - "EXCEPTION_FLT_UNDERFLOW\n"); - return EXCEPTION_FLT_UNDERFLOW; - break; - case FPE_FLTRES : - TRACE("Got signal SIGFPE:FPE_FLTRES; raising " - "EXCEPTION_FLT_INEXACT_RESULT\n"); - return EXCEPTION_FLT_INEXACT_RESULT; - break; - case FPE_FLTINV : - TRACE("Got signal SIGFPE:FPE_FLTINV; raising " - "EXCEPTION_FLT_INVALID_OPERATION\n"); - return EXCEPTION_FLT_INVALID_OPERATION; - break; - case FPE_FLTSUB :/* subscript out of range */ - TRACE("Got signal SIGFPE:FPE_FLTSUB; raising " - "EXCEPTION_FLT_INVALID_OPERATION\n"); - return EXCEPTION_FLT_INVALID_OPERATION; - break; - default: - ASSERT("Got unknown signal code %d\n", siginfo->si_code); - break; - } - } - - trap = context->uc_mcontext.mc_trapno; - switch (trap) - { - case T_PRIVINFLT : /* privileged instruction */ - TRACE("Trap code T_PRIVINFLT mapped to EXCEPTION_PRIV_INSTRUCTION\n"); - return EXCEPTION_PRIV_INSTRUCTION; - case T_BPTFLT : /* breakpoint instruction */ - TRACE("Trap code T_BPTFLT mapped to EXCEPTION_BREAKPOINT\n"); - return EXCEPTION_BREAKPOINT; - case T_ARITHTRAP : /* arithmetic trap */ - TRACE("Trap code T_ARITHTRAP maps to floating point exception...\n"); - return 0; /* let the caller pick an exception code */ -#ifdef T_ASTFLT - case T_ASTFLT : /* system forced exception : ^C, ^\. SIGINT signal - handler shouldn't be calling this function, since - it doesn't need an exception code */ - ASSERT("Trap code T_ASTFLT received, shouldn't get here\n"); - return 0; -#endif // T_ASTFLT - case T_PROTFLT : /* protection fault */ - TRACE("Trap code T_PROTFLT mapped to EXCEPTION_ACCESS_VIOLATION\n"); - return EXCEPTION_ACCESS_VIOLATION; - case T_TRCTRAP : /* debug exception (sic) */ - TRACE("Trap code T_TRCTRAP mapped to EXCEPTION_SINGLE_STEP\n"); - return EXCEPTION_SINGLE_STEP; - case T_PAGEFLT : /* page fault */ - TRACE("Trap code T_PAGEFLT mapped to EXCEPTION_ACCESS_VIOLATION\n"); - return EXCEPTION_ACCESS_VIOLATION; - case T_ALIGNFLT : /* alignment fault */ - TRACE("Trap code T_ALIGNFLT mapped to EXCEPTION_DATATYPE_MISALIGNMENT\n"); - return EXCEPTION_DATATYPE_MISALIGNMENT; - case T_DIVIDE : - TRACE("Trap code T_DIVIDE mapped to EXCEPTION_INT_DIVIDE_BY_ZERO\n"); - return EXCEPTION_INT_DIVIDE_BY_ZERO; - case T_NMI : /* non-maskable trap */ - TRACE("Trap code T_NMI mapped to EXCEPTION_ILLEGAL_INSTRUCTION\n"); - return EXCEPTION_ILLEGAL_INSTRUCTION; - case T_OFLOW : - TRACE("Trap code T_OFLOW mapped to EXCEPTION_INT_OVERFLOW\n"); - return EXCEPTION_INT_OVERFLOW; - case T_BOUND : /* bound instruction fault */ - TRACE("Trap code T_BOUND mapped to EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n"); - return EXCEPTION_ARRAY_BOUNDS_EXCEEDED; - case T_DNA : /* device not available fault */ - TRACE("Trap code T_DNA mapped to EXCEPTION_ILLEGAL_INSTRUCTION\n"); - return EXCEPTION_ILLEGAL_INSTRUCTION; - case T_DOUBLEFLT : /* double fault */ - TRACE("Trap code T_DOUBLEFLT mapped to EXCEPTION_ILLEGAL_INSTRUCTION\n"); - return EXCEPTION_ILLEGAL_INSTRUCTION; - case T_FPOPFLT : /* fp coprocessor operand fetch fault */ - TRACE("Trap code T_FPOPFLT mapped to EXCEPTION_FLT_INVALID_OPERATION\n"); - return EXCEPTION_FLT_INVALID_OPERATION; - case T_TSSFLT : /* invalid tss fault */ - TRACE("Trap code T_TSSFLT mapped to EXCEPTION_ILLEGAL_INSTRUCTION\n"); - return EXCEPTION_ILLEGAL_INSTRUCTION; - case T_SEGNPFLT : /* segment not present fault */ - TRACE("Trap code T_SEGNPFLT mapped to EXCEPTION_ACCESS_VIOLATION\n"); - return EXCEPTION_ACCESS_VIOLATION; - case T_STKFLT : /* stack fault */ - TRACE("Trap code T_STKFLT mapped to EXCEPTION_STACK_OVERFLOW\n"); - return EXCEPTION_STACK_OVERFLOW; - case T_MCHK : /* machine check trap */ - TRACE("Trap code T_MCHK mapped to EXCEPTION_ILLEGAL_INSTRUCTION\n"); - return EXCEPTION_ILLEGAL_INSTRUCTION; - case T_RESERVED : /* reserved (unknown) */ - TRACE("Trap code T_RESERVED mapped to EXCEPTION_ILLEGAL_INSTRUCTION\n"); - return EXCEPTION_ILLEGAL_INSTRUCTION; - default: - ASSERT("Got unknown trap code %d\n", trap); - break; - } - return EXCEPTION_ILLEGAL_INSTRUCTION; -} -#endif // ILL_ILLOPC - -#else // !HAVE_MACH_EXCEPTIONS - -#include <mach/message.h> -#include <mach/thread_act.h> -#include "../../exception/machexception.h" - -/*++ -Function: - CONTEXT_GetThreadContextFromPort - - Helper for GetThreadContext that uses a mach_port ---*/ -kern_return_t -CONTEXT_GetThreadContextFromPort( - mach_port_t Port, - LPCONTEXT lpContext) -{ - // Extract the CONTEXT from the Mach thread. - - kern_return_t MachRet = KERN_SUCCESS; - mach_msg_type_number_t StateCount; - thread_state_flavor_t StateFlavor; - - if (lpContext->ContextFlags & (CONTEXT_CONTROL|CONTEXT_INTEGER)) - { -#ifdef _X86_ - x86_thread_state32_t State; - StateFlavor = x86_THREAD_STATE32; -#elif defined(_AMD64_) - x86_thread_state64_t State; - StateFlavor = x86_THREAD_STATE64; -#else -#error Unexpected architecture. -#endif - - StateCount = sizeof(State) / sizeof(natural_t); - - MachRet = thread_get_state(Port, - StateFlavor, - (thread_state_t)&State, - &StateCount); - if (MachRet != KERN_SUCCESS) - { - ASSERT("thread_get_state(THREAD_STATE) failed: %d\n", MachRet); - goto EXIT; - } - - // Copy in the GPRs and the various other control registers -#ifdef _X86_ - lpContext->Eax = State.eax; - lpContext->Ebx = State.ebx; - lpContext->Ecx = State.ecx; - lpContext->Edx = State.edx; - lpContext->Edi = State.edi; - lpContext->Esi = State.esi; - lpContext->Ebp = State.ebp; - lpContext->Esp = State.esp; - lpContext->SegSs = State.ss; - lpContext->EFlags = State.eflags; - lpContext->Eip = State.eip; - lpContext->SegCs = State.cs; - lpContext->SegDs_PAL_Undefined = State.ds; - lpContext->SegEs_PAL_Undefined = State.es; - lpContext->SegFs_PAL_Undefined = State.fs; - lpContext->SegGs_PAL_Undefined = State.gs; -#elif defined(_AMD64_) - lpContext->Rax = State.__rax; - lpContext->Rbx = State.__rbx; - lpContext->Rcx = State.__rcx; - lpContext->Rdx = State.__rdx; - lpContext->Rdi = State.__rdi; - lpContext->Rsi = State.__rsi; - lpContext->Rbp = State.__rbp; - lpContext->Rsp = State.__rsp; - lpContext->R8 = State.__r8; - lpContext->R9 = State.__r9; - lpContext->R10 = State.__r10; - lpContext->R11 = State.__r11; - lpContext->R12 = State.__r12; - lpContext->R13 = State.__r13; - lpContext->R14 = State.__r14; - lpContext->R15 = State.__r15; -// lpContext->SegSs = State.ss; // no such state? - lpContext->EFlags = State.__rflags; - lpContext->Rip = State.__rip; - lpContext->SegCs = State.__cs; -// lpContext->SegDs_PAL_Undefined = State.ds; // no such state? -// lpContext->SegEs_PAL_Undefined = State.es; // no such state? - lpContext->SegFs = State.__fs; - lpContext->SegGs = State.__gs; -#else -#error Unexpected architecture. -#endif - } - - if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING) { -#ifdef _X86_ - x86_float_state32_t State; - StateFlavor = x86_FLOAT_STATE32; -#elif defined(_AMD64_) - x86_float_state64_t State; - StateFlavor = x86_FLOAT_STATE64; -#else -#error Unexpected architecture. -#endif - StateCount = sizeof(State) / sizeof(natural_t); - - MachRet = thread_get_state(Port, - StateFlavor, - (thread_state_t)&State, - &StateCount); - if (MachRet != KERN_SUCCESS) - { - ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet); - goto EXIT; - } - - if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT) - { - // Copy the FPRs -#ifdef _X86_ - lpContext->FloatSave.ControlWord = *(DWORD*)&State.fpu_fcw; - lpContext->FloatSave.StatusWord = *(DWORD*)&State.fpu_fsw; - lpContext->FloatSave.TagWord = State.fpu_ftw; - lpContext->FloatSave.ErrorOffset = State.fpu_ip; - lpContext->FloatSave.ErrorSelector = State.fpu_cs; - lpContext->FloatSave.DataOffset = State.fpu_dp; - lpContext->FloatSave.DataSelector = State.fpu_ds; - lpContext->FloatSave.Cr0NpxState = State.fpu_mxcsr; - - // Windows stores the floating point registers in a packed layout (each 10-byte register end to end - // for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably for - // alignment purposes). So we can't just memcpy the registers over in a single block, we need to copy - // them individually. - for (int i = 0; i < 8; i++) - memcpy(&lpContext->FloatSave.RegisterArea[i * 10], (&State.fpu_stmm0)[i].mmst_reg, 10); -#elif defined(_AMD64_) - lpContext->FltSave.ControlWord = *(DWORD*)&State.__fpu_fcw; - lpContext->FltSave.StatusWord = *(DWORD*)&State.__fpu_fsw; - lpContext->FltSave.TagWord = State.__fpu_ftw; - lpContext->FltSave.ErrorOffset = State.__fpu_ip; - lpContext->FltSave.ErrorSelector = State.__fpu_cs; - lpContext->FltSave.DataOffset = State.__fpu_dp; - lpContext->FltSave.DataSelector = State.__fpu_ds; - lpContext->FltSave.MxCsr = State.__fpu_mxcsr; - lpContext->FltSave.MxCsr_Mask = State.__fpu_mxcsrmask; // note: we don't save the mask for x86 - - // Windows stores the floating point registers in a packed layout (each 10-byte register end to end - // for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably for - // alignment purposes). So we can't just memcpy the registers over in a single block, we need to copy - // them individually. - for (int i = 0; i < 8; i++) - memcpy(&lpContext->FltSave.FloatRegisters[i], (&State.__fpu_stmm0)[i].__mmst_reg, 10); - - // AMD64's FLOATING_POINT includes the xmm registers. - memcpy(&lpContext->Xmm0, &State.__fpu_xmm0, 8 * 16); -#else -#error Unexpected architecture. -#endif - } - -#ifdef _X86_ - if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS) { - // The only extended register information that Mach will tell us about are the xmm register values. - // Both Windows and Mach store the registers in a packed layout (each of the 8 registers is 16 bytes) - // so we can simply memcpy them across. - memcpy(lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, &State.fpu_xmm0, 8 * 16); - } -#endif - } - -EXIT: - return MachRet; -} - -/*++ -Function: - GetThreadContext - -See MSDN doc. ---*/ -BOOL -CONTEXT_GetThreadContext( - DWORD dwProcessId, - pthread_t self, - DWORD dwLwpId, - LPCONTEXT lpContext) -{ - BOOL ret = FALSE; - - if (lpContext == NULL) - { - ERROR("Invalid lpContext parameter value\n"); - SetLastError(ERROR_NOACCESS); - goto EXIT; - } - - if (GetCurrentProcessId() == dwProcessId) - { - if (self != pthread_self()) - { - // the target thread is in the current process, but isn't - // the current one: extract the CONTEXT from the Mach thread. - mach_port_t mptPort; - mptPort = pthread_mach_thread_np(self); - - ret = (CONTEXT_GetThreadContextFromPort(mptPort, lpContext) == KERN_SUCCESS); - } - else - { - CONTEXT_CaptureContext(lpContext); - ret = TRUE; - } - } - else - { - ASSERT("Cross-process GetThreadContext() is not supported on this platform\n"); - SetLastError(ERROR_NOACCESS); - } - -EXIT: - return ret; -} - -/*++ -Function: - SetThreadContextOnPort - - Helper for CONTEXT_SetThreadContext ---*/ -kern_return_t -CONTEXT_SetThreadContextOnPort( - mach_port_t Port, - IN CONST CONTEXT *lpContext) -{ - kern_return_t MachRet = KERN_SUCCESS; - mach_msg_type_number_t StateCount; - thread_state_flavor_t StateFlavor; - - if (lpContext->ContextFlags & (CONTEXT_CONTROL|CONTEXT_INTEGER)) - { -#ifdef _X86_ - x86_thread_state32_t State; - StateFlavor = x86_THREAD_STATE32; - - State.eax = lpContext->Eax; - State.ebx = lpContext->Ebx; - State.ecx = lpContext->Ecx; - State.edx = lpContext->Edx; - State.edi = lpContext->Edi; - State.esi = lpContext->Esi; - State.ebp = lpContext->Ebp; - State.esp = lpContext->Esp; - State.ss = lpContext->SegSs; - State.eflags = lpContext->EFlags; - State.eip = lpContext->Eip; - State.cs = lpContext->SegCs; - State.ds = lpContext->SegDs_PAL_Undefined; - State.es = lpContext->SegEs_PAL_Undefined; - State.fs = lpContext->SegFs_PAL_Undefined; - State.gs = lpContext->SegGs_PAL_Undefined; -#elif defined(_AMD64_) - x86_thread_state64_t State; - StateFlavor = x86_THREAD_STATE64; - - State.__rax = lpContext->Rax; - State.__rbx = lpContext->Rbx; - State.__rcx = lpContext->Rcx; - State.__rdx = lpContext->Rdx; - State.__rdi = lpContext->Rdi; - State.__rsi = lpContext->Rsi; - State.__rbp = lpContext->Rbp; - State.__rsp = lpContext->Rsp; - State.__r8 = lpContext->R8; - State.__r9 = lpContext->R9; - State.__r10 = lpContext->R10; - State.__r11 = lpContext->R11; - State.__r12 = lpContext->R12; - State.__r13 = lpContext->R13; - State.__r14 = lpContext->R14; - State.__r15 = lpContext->R15; -// State.ss = lpContext->SegSs; - State.__rflags = lpContext->EFlags; - State.__rip = lpContext->Rip; - State.__cs = lpContext->SegCs; -// State.ds = lpContext->SegDs_PAL_Undefined; -// State.es = lpContext->SegEs_PAL_Undefined; - State.__fs = lpContext->SegFs; - State.__gs = lpContext->SegGs; -#else -#error Unexpected architecture. -#endif - - StateCount = sizeof(State) / sizeof(natural_t); - - MachRet = thread_set_state(Port, - StateFlavor, - (thread_state_t)&State, - StateCount); - if (MachRet != KERN_SUCCESS) - { - ASSERT("thread_set_state(THREAD_STATE) failed: %d\n", MachRet); - goto EXIT; - } - } - - if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING) - { - -#ifdef _X86_ - x86_float_state32_t State; - StateFlavor = x86_FLOAT_STATE32; -#elif defined(_AMD64_) - x86_float_state64_t State; - StateFlavor = x86_FLOAT_STATE64; -#else -#error Unexpected architecture. -#endif - - StateCount = sizeof(State) / sizeof(natural_t); - - // If we're setting only one of the floating point or extended registers (of which Mach supports only - // the xmm values) then we don't have values for the other set. This is a problem since Mach only - // supports setting both groups as a single unit. So in this case we'll need to fetch the current - // values first. - if ((lpContext->ContextFlags & CONTEXT_ALL_FLOATING) != - CONTEXT_ALL_FLOATING) - { - mach_msg_type_number_t StateCountGet = StateCount; - MachRet = thread_get_state(Port, - StateFlavor, - (thread_state_t)&State, - &StateCountGet); - if (MachRet != KERN_SUCCESS) - { - ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet); - goto EXIT; - } - _ASSERTE(StateCountGet == StateCount); - } - - if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT) - { -#ifdef _X86_ - *(DWORD*)&State.fpu_fcw = lpContext->FloatSave.ControlWord; - *(DWORD*)&State.fpu_fsw = lpContext->FloatSave.StatusWord; - State.fpu_ftw = lpContext->FloatSave.TagWord; - State.fpu_ip = lpContext->FloatSave.ErrorOffset; - State.fpu_cs = lpContext->FloatSave.ErrorSelector; - State.fpu_dp = lpContext->FloatSave.DataOffset; - State.fpu_ds = lpContext->FloatSave.DataSelector; - State.fpu_mxcsr = lpContext->FloatSave.Cr0NpxState; - - // Windows stores the floating point registers in a packed layout (each 10-byte register end to - // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably - // for alignment purposes). So we can't just memcpy the registers over in a single block, we need - // to copy them individually. - for (int i = 0; i < 8; i++) - memcpy((&State.fpu_stmm0)[i].mmst_reg, &lpContext->FloatSave.RegisterArea[i * 10], 10); -#elif defined(_AMD64_) - *(DWORD*)&State.__fpu_fcw = lpContext->FltSave.ControlWord; - *(DWORD*)&State.__fpu_fsw = lpContext->FltSave.StatusWord; - State.__fpu_ftw = lpContext->FltSave.TagWord; - State.__fpu_ip = lpContext->FltSave.ErrorOffset; - State.__fpu_cs = lpContext->FltSave.ErrorSelector; - State.__fpu_dp = lpContext->FltSave.DataOffset; - State.__fpu_ds = lpContext->FltSave.DataSelector; - State.__fpu_mxcsr = lpContext->FltSave.MxCsr; - State.__fpu_mxcsrmask = lpContext->FltSave.MxCsr_Mask; // note: we don't save the mask for x86 - - // Windows stores the floating point registers in a packed layout (each 10-byte register end to - // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably - // for alignment purposes). So we can't just memcpy the registers over in a single block, we need - // to copy them individually. - for (int i = 0; i < 8; i++) - memcpy((&State.__fpu_stmm0)[i].__mmst_reg, &lpContext->FltSave.FloatRegisters[i], 10); - - memcpy(&State.__fpu_xmm0, &lpContext->Xmm0, 8 * 16); -#else -#error Unexpected architecture. -#endif - } - -#ifdef _X86_ - if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS) - { - // The only extended register information that Mach will tell us about are the xmm register - // values. Both Windows and Mach store the registers in a packed layout (each of the 8 registers - // is 16 bytes) so we can simply memcpy them across. - memcpy(&State.fpu_xmm0, lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, 8 * 16); - } -#endif // _X86_ - - MachRet = thread_set_state(Port, - StateFlavor, - (thread_state_t)&State, - StateCount); - if (MachRet != KERN_SUCCESS) - { - ASSERT("thread_set_state(FLOAT_STATE) failed: %d\n", MachRet); - goto EXIT; - } - } - -EXIT: - return MachRet; -} - -/*++ -Function: - SetThreadContext - -See MSDN doc. ---*/ -BOOL -CONTEXT_SetThreadContext( - DWORD dwProcessId, - pthread_t self, - DWORD dwLwpId, - CONST CONTEXT *lpContext) -{ - BOOL ret = FALSE; - - if (lpContext == NULL) - { - ERROR("Invalid lpContext parameter value\n"); - SetLastError(ERROR_NOACCESS); - goto EXIT; - } - - if (dwProcessId != GetCurrentProcessId()) - { - // GetThreadContext() of a thread in another process - ASSERT("Cross-process GetThreadContext() is not supported\n"); - SetLastError(ERROR_NOACCESS); - goto EXIT; - } - - if (self != pthread_self()) - { - // hThread is in the current process, but isn't the current - // thread. Extract the CONTEXT from the Mach thread. - - mach_port_t mptPort; - - mptPort = pthread_mach_thread_np(self); - - ret = (CONTEXT_SetThreadContextOnPort(mptPort, lpContext) == KERN_SUCCESS); - } - else - { - MachSetThreadContext(const_cast<CONTEXT *>(lpContext)); - ASSERT("MachSetThreadContext should never return\n"); - } - -EXIT: - return ret; -} - -#endif // !HAVE_MACH_EXCEPTIONS - -/*++ -Function: - DBG_DebugBreak: same as DebugBreak - -See MSDN doc. ---*/ -VOID -DBG_DebugBreak() -{ - __asm__ __volatile__("int $3"); -} - - -/*++ -Function: - DBG_FlushInstructionCache: processor-specific portion of - FlushInstructionCache - -See MSDN doc. ---*/ -BOOL -DBG_FlushInstructionCache( - IN LPCVOID lpBaseAddress, - IN SIZE_T dwSize) -{ - // Intel x86 hardware has cache coherency, so nothing needs to be done. - return TRUE; -} |