1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Implementation of GetThreadContext/SetThreadContext/DebugBreak.
16 There are a lot of architecture specifics here.
22 #include "pal/dbgmsg.h"
23 SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
25 #include "pal/palinternal.h"
26 #include "pal/context.h"
27 #include "pal/debug.h"
28 #include "pal/thread.hpp"
29 #include "pal/utils.h"
30 #include "pal/virtual.h"
32 #include <sys/ptrace.h>
36 extern PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode;
38 #define CONTEXT_AREA_MASK 0xffff
40 #define CONTEXT_ALL_FLOATING (CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS)
41 #elif defined(_AMD64_)
42 #define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT
44 #define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT
45 #elif defined(_ARM64_)
46 #define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT
48 #error Unexpected architecture.
51 #if !HAVE_MACH_EXCEPTIONS
54 typedef int __ptrace_request;
57 #if HAVE_MACHINE_REG_H
58 #include <machine/reg.h>
59 #endif // HAVE_MACHINE_REG_H
60 #if HAVE_MACHINE_NPX_H
61 #include <machine/npx.h>
62 #endif // HAVE_MACHINE_NPX_H
65 #include <asm/ptrace.h>
66 #endif // HAVE_PT_REGS
69 #define ASSIGN_CONTROL_REGS \
76 #define ASSIGN_INTEGER_REGS \
93 #define ASSIGN_CONTROL_REGS \
101 #define ASSIGN_INTEGER_REGS \
110 #define ASSIGN_CONTROL_REGS \
116 #define ASSIGN_INTEGER_REGS \
130 #elif defined(_ARM64_)
131 #define ASSIGN_CONTROL_REGS \
138 #define ASSIGN_INTEGER_REGS \
170 #error Don't know how to assign registers on this architecture
173 #define ASSIGN_ALL_REGS \
174 ASSIGN_CONTROL_REGS \
175 ASSIGN_INTEGER_REGS \
182 retrieve the machine registers value of the indicated process.
185 processId: process ID
186 lpContext: context structure in which the machine registers value will be returned.
188 returns TRUE if it succeeds, FALSE otherwise
190 BOOL CONTEXT_GetRegisters(DWORD processId, LPCONTEXT lpContext)
194 #endif // HAVE_BSD_REGS_T
197 if (processId == GetCurrentProcessId())
199 CONTEXT_CaptureContext(lpContext);
203 ucontext_t registers;
205 struct pt_regs ptrace_registers;
206 if (ptrace((__ptrace_request)PT_GETREGS, processId, (caddr_t) &ptrace_registers, 0) == -1)
207 #elif HAVE_BSD_REGS_T
208 struct reg ptrace_registers;
209 if (PAL_PTRACE(PT_GETREGS, processId, &ptrace_registers, 0) == -1)
212 ASSERT("Failed ptrace(PT_GETREGS, processId:%d) errno:%d (%s)\n",
213 processId, errno, strerror(errno));
217 #define ASSIGN_REG(reg) MCREG_##reg(registers.uc_mcontext) = PTREG_##reg(ptrace_registers);
218 #elif HAVE_BSD_REGS_T
219 #define ASSIGN_REG(reg) MCREG_##reg(registers.uc_mcontext) = BSDREG_##reg(ptrace_registers);
221 #define ASSIGN_REG(reg)
222 ASSERT("Don't know how to get the context of another process on this platform!");
228 CONTEXTFromNativeContext(®isters, lpContext, lpContext->ContextFlags);
237 #endif // HAVE_BSD_REGS_T
248 CONTEXT_GetThreadContext(
255 if (lpContext == NULL)
257 ERROR("Invalid lpContext parameter value\n");
258 SetLastError(ERROR_NOACCESS);
262 /* How to consider the case when self is different from the current
263 thread of its owner process. Machine registers values could be retreived
264 by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content.
265 Unfortunately, these two methods only depend on process ID, not on
268 if (dwProcessId == GetCurrentProcessId())
270 if (self != pthread_self())
273 // There aren't any APIs for this. We can potentially get the
274 // context of another thread by using per-thread signals, but
275 // on FreeBSD signal handlers that are called as a result
276 // of signals raised via pthread_kill don't get a valid
277 // sigcontext or ucontext_t. But we need this to return TRUE
278 // to avoid an assertion in the CLR in code that manages to
279 // cope reasonably well without a valid thread context.
280 // Given that, we'll zero out our structure and return TRUE.
281 ERROR("GetThreadContext on a thread other than the current "
282 "thread is returning TRUE\n");
283 flags = lpContext->ContextFlags;
284 memset(lpContext, 0, sizeof(*lpContext));
285 lpContext->ContextFlags = flags;
292 if (lpContext->ContextFlags &
293 (CONTEXT_CONTROL | CONTEXT_INTEGER) & CONTEXT_AREA_MASK)
295 if (CONTEXT_GetRegisters(dwProcessId, lpContext) == FALSE)
297 SetLastError(ERROR_INTERNAL_ERROR);
315 CONTEXT_SetThreadContext(
318 CONST CONTEXT *lpContext)
323 struct pt_regs ptrace_registers;
324 #elif HAVE_BSD_REGS_T
325 struct reg ptrace_registers;
328 if (lpContext == NULL)
330 ERROR("Invalid lpContext parameter value\n");
331 SetLastError(ERROR_NOACCESS);
335 /* How to consider the case when self is different from the current
336 thread of its owner process. Machine registers values could be retreived
337 by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content.
338 Unfortunately, these two methods only depend on process ID, not on
341 if (dwProcessId == GetCurrentProcessId())
343 #ifdef FEATURE_PAL_SXS
344 // Need to implement SetThreadContext(current thread) for the IX architecture; look at common_signal_handler.
346 #endif // FEATURE_PAL_SXS
347 ASSERT("SetThreadContext should be called for cross-process only.\n");
348 SetLastError(ERROR_INVALID_PARAMETER);
352 if (lpContext->ContextFlags &
353 (CONTEXT_CONTROL | CONTEXT_INTEGER) & CONTEXT_AREA_MASK)
356 if (ptrace((__ptrace_request)PT_GETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1)
357 #elif HAVE_BSD_REGS_T
358 if (PAL_PTRACE(PT_GETREGS, dwProcessId, &ptrace_registers, 0) == -1)
361 ASSERT("Failed ptrace(PT_GETREGS, processId:%d) errno:%d (%s)\n",
362 dwProcessId, errno, strerror(errno));
363 SetLastError(ERROR_INTERNAL_ERROR);
368 #define ASSIGN_REG(reg) PTREG_##reg(ptrace_registers) = lpContext->reg;
369 #elif HAVE_BSD_REGS_T
370 #define ASSIGN_REG(reg) BSDREG_##reg(ptrace_registers) = lpContext->reg;
372 #define ASSIGN_REG(reg)
373 ASSERT("Don't know how to set the context of another process on this platform!");
376 if (lpContext->ContextFlags & CONTEXT_CONTROL & CONTEXT_AREA_MASK)
380 if (lpContext->ContextFlags & CONTEXT_INTEGER & CONTEXT_AREA_MASK)
387 if (ptrace((__ptrace_request)PT_SETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1)
388 #elif HAVE_BSD_REGS_T
389 if (PAL_PTRACE(PT_SETREGS, dwProcessId, &ptrace_registers, 0) == -1)
392 ASSERT("Failed ptrace(PT_SETREGS, processId:%d) errno:%d (%s)\n",
393 dwProcessId, errno, strerror(errno));
394 SetLastError(ERROR_INTERNAL_ERROR);
406 CONTEXTToNativeContext
408 Converts a CONTEXT record to a native context.
411 CONST CONTEXT *lpContext : CONTEXT to convert
412 native_context_t *native : native context to fill in
418 void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native)
420 #define ASSIGN_REG(reg) MCREG_##reg(native->uc_mcontext) = lpContext->reg;
421 if ((lpContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
426 if ((lpContext->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
432 #if HAVE_GREGSET_T || HAVE_GREGSET_T
434 if (native->uc_mcontext.fpregs == nullptr)
435 #elif HAVE___GREGSET_T
436 if (native->uc_mcontext.__fpregs == nullptr)
439 // If the pointer to the floating point state in the native context
440 // is not valid, we can't copy floating point registers regardless of
441 // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags.
446 if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
449 FPREG_ControlWord(native) = lpContext->FltSave.ControlWord;
450 FPREG_StatusWord(native) = lpContext->FltSave.StatusWord;
451 FPREG_TagWord(native) = lpContext->FltSave.TagWord;
452 FPREG_ErrorOffset(native) = lpContext->FltSave.ErrorOffset;
453 FPREG_ErrorSelector(native) = lpContext->FltSave.ErrorSelector;
454 FPREG_DataOffset(native) = lpContext->FltSave.DataOffset;
455 FPREG_DataSelector(native) = lpContext->FltSave.DataSelector;
456 FPREG_MxCsr(native) = lpContext->FltSave.MxCsr;
457 FPREG_MxCsr_Mask(native) = lpContext->FltSave.MxCsr_Mask;
459 for (int i = 0; i < 8; i++)
461 FPREG_St(native, i) = lpContext->FltSave.FloatRegisters[i];
464 for (int i = 0; i < 16; i++)
466 FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i];
471 // TODO: Enable for all Unix systems
472 #if defined(_AMD64_) && defined(XSTATE_SUPPORTED)
473 if ((lpContext->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
475 _ASSERTE(FPREG_HasYmmRegisters(native));
476 memcpy_s(FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16, lpContext->VectorRegister, sizeof(M128A) * 16);
478 #endif //_AMD64_ && XSTATE_SUPPORTED
483 CONTEXTFromNativeContext
485 Converts a native context to a CONTEXT record.
488 const native_context_t *native : native context to convert
489 LPCONTEXT lpContext : CONTEXT to fill in
490 ULONG contextFlags : flags that determine which registers are valid in
491 native and which ones to set in lpContext
497 void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext,
500 lpContext->ContextFlags = contextFlags;
502 #define ASSIGN_REG(reg) lpContext->reg = MCREG_##reg(native->uc_mcontext);
503 if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
507 // WinContext assumes that the least bit of Pc is always 1 (denoting thumb)
508 // although the pc value retrived from native context might not have set the least bit.
509 // This becomes especially problematic if the context is on the JIT_WRITEBARRIER.
510 lpContext->Pc |= 0x1;
514 if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
520 #if HAVE_GREGSET_T || HAVE___GREGSET_T
522 if (native->uc_mcontext.fpregs == nullptr)
523 #elif HAVE___GREGSET_T
524 if (native->uc_mcontext.__fpregs == nullptr)
527 // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's
528 // clear that the floating point and extended state data in the CONTEXT is not
529 // valid. Since these flags are defined as the architecture bit(s) OR'd with one
530 // or more other bits, we first get the bits that are unique to each by resetting
531 // the architecture bits. We determine what those are by inverting the union of
532 // CONTEXT_CONTROL and CONTEXT_INTEGER, both of which should also have the
533 // architecture bit(s) set.
534 const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
535 const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
537 lpContext->ContextFlags &= ~(floatingPointFlags | xstateFlags);
539 // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE
544 if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
547 lpContext->FltSave.ControlWord = FPREG_ControlWord(native);
548 lpContext->FltSave.StatusWord = FPREG_StatusWord(native);
549 lpContext->FltSave.TagWord = FPREG_TagWord(native);
550 lpContext->FltSave.ErrorOffset = FPREG_ErrorOffset(native);
551 lpContext->FltSave.ErrorSelector = FPREG_ErrorSelector(native);
552 lpContext->FltSave.DataOffset = FPREG_DataOffset(native);
553 lpContext->FltSave.DataSelector = FPREG_DataSelector(native);
554 lpContext->FltSave.MxCsr = FPREG_MxCsr(native);
555 lpContext->FltSave.MxCsr_Mask = FPREG_MxCsr_Mask(native);
557 for (int i = 0; i < 8; i++)
559 lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i);
562 for (int i = 0; i < 16; i++)
564 lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i);
570 if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
572 // TODO: Enable for all Unix systems
574 if (FPREG_HasYmmRegisters(native))
576 memcpy_s(lpContext->VectorRegister, sizeof(M128A) * 16, FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16);
579 #endif // XSTATE_SUPPORTED
581 // Reset the CONTEXT_XSTATE bit(s) so it's clear that the extended state data in
582 // the CONTEXT is not valid.
583 const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
584 lpContext->ContextFlags &= ~xstateFlags;
594 Returns the program counter from the native context.
597 const native_context_t *native : native context
600 The program counter from the native context.
603 LPVOID GetNativeContextPC(const native_context_t *context)
606 return (LPVOID)MCREG_Rip(context->uc_mcontext);
608 return (LPVOID) MCREG_Eip(context->uc_mcontext);
610 return (LPVOID) MCREG_Pc(context->uc_mcontext);
611 #elif defined(_ARM64_)
612 return (LPVOID) MCREG_Pc(context->uc_mcontext);
614 # error implement me for this architecture
622 Returns the stack pointer from the native context.
625 const native_context_t *native : native context
628 The stack pointer from the native context.
631 LPVOID GetNativeContextSP(const native_context_t *context)
634 return (LPVOID)MCREG_Rsp(context->uc_mcontext);
636 return (LPVOID) MCREG_Esp(context->uc_mcontext);
638 return (LPVOID) MCREG_Sp(context->uc_mcontext);
639 #elif defined(_ARM64_)
640 return (LPVOID) MCREG_Sp(context->uc_mcontext);
642 # error implement me for this architecture
649 CONTEXTGetExceptionCodeForSignal
651 Translates signal and context information to a Win32 exception code.
654 const siginfo_t *siginfo : signal information from a signal handler
655 const native_context_t *context : context information
658 The Win32 exception code that corresponds to the signal and context
663 // If si_code values are available for all signals, use those.
664 DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo,
665 const native_context_t *context)
667 // IMPORTANT NOTE: This function must not call any signal unsafe functions
668 // since it is called from signal handlers.
669 // That includes ASSERT and TRACE macros.
671 switch (siginfo->si_signo)
674 switch (siginfo->si_code)
676 case ILL_ILLOPC: // Illegal opcode
677 case ILL_ILLOPN: // Illegal operand
678 case ILL_ILLADR: // Illegal addressing mode
679 case ILL_ILLTRP: // Illegal trap
680 case ILL_COPROC: // Co-processor error
681 return EXCEPTION_ILLEGAL_INSTRUCTION;
682 case ILL_PRVOPC: // Privileged opcode
683 case ILL_PRVREG: // Privileged register
684 return EXCEPTION_PRIV_INSTRUCTION;
685 case ILL_BADSTK: // Internal stack error
686 return EXCEPTION_STACK_OVERFLOW;
692 switch (siginfo->si_code)
695 return EXCEPTION_INT_DIVIDE_BY_ZERO;
697 return EXCEPTION_INT_OVERFLOW;
699 return EXCEPTION_FLT_DIVIDE_BY_ZERO;
701 return EXCEPTION_FLT_OVERFLOW;
703 return EXCEPTION_FLT_UNDERFLOW;
705 return EXCEPTION_FLT_INEXACT_RESULT;
707 return EXCEPTION_FLT_INVALID_OPERATION;
709 return EXCEPTION_FLT_INVALID_OPERATION;
715 switch (siginfo->si_code)
717 case SI_USER: // User-generated signal, sometimes sent
718 // for SIGSEGV under normal circumstances
719 case SEGV_MAPERR: // Address not mapped to object
720 case SEGV_ACCERR: // Invalid permissions for mapped object
721 return EXCEPTION_ACCESS_VIOLATION;
726 // Identify privileged instructions that are not identified as such by the system
727 if (g_getGcMarkerExceptionCode != nullptr)
729 DWORD exceptionCode = g_getGcMarkerExceptionCode(GetNativeContextPC(context));
730 if (exceptionCode != 0)
732 return exceptionCode;
735 return EXCEPTION_ACCESS_VIOLATION;
743 switch (siginfo->si_code)
745 case BUS_ADRALN: // Invalid address alignment
746 return EXCEPTION_DATATYPE_MISALIGNMENT;
747 case BUS_ADRERR: // Non-existent physical address
748 return EXCEPTION_ACCESS_VIOLATION;
749 case BUS_OBJERR: // Object-specific hardware error
754 switch (siginfo->si_code)
760 case TRAP_BRKPT: // Process breakpoint
761 return EXCEPTION_BREAKPOINT;
762 case TRAP_TRACE: // Process trace trap
763 return EXCEPTION_SINGLE_STEP;
765 // Got unknown SIGTRAP signal with code siginfo->si_code;
766 return EXCEPTION_ILLEGAL_INSTRUCTION;
772 // Got unknown signal number siginfo->si_signo with code siginfo->si_code;
773 return EXCEPTION_ILLEGAL_INSTRUCTION;
776 DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo,
777 const native_context_t *context)
779 // IMPORTANT NOTE: This function must not call any signal unsafe functions
780 // since it is called from signal handlers.
781 // That includes ASSERT and TRACE macros.
785 if (siginfo->si_signo == SIGFPE)
787 // Floating point exceptions are mapped by their si_code.
788 switch (siginfo->si_code)
791 return EXCEPTION_INT_DIVIDE_BY_ZERO;
793 return EXCEPTION_INT_OVERFLOW;
795 return EXCEPTION_FLT_DIVIDE_BY_ZERO;
797 return EXCEPTION_FLT_OVERFLOW;
799 return EXCEPTION_FLT_UNDERFLOW;
801 return EXCEPTION_FLT_INEXACT_RESULT;
803 return EXCEPTION_FLT_INVALID_OPERATION;
804 case FPE_FLTSUB :/* subscript out of range */
805 return EXCEPTION_FLT_INVALID_OPERATION;
807 // Got unknown signal code siginfo->si_code;
812 trap = context->uc_mcontext.mc_trapno;
815 case T_PRIVINFLT : /* privileged instruction */
816 return EXCEPTION_PRIV_INSTRUCTION;
817 case T_BPTFLT : /* breakpoint instruction */
818 return EXCEPTION_BREAKPOINT;
819 case T_ARITHTRAP : /* arithmetic trap */
820 return 0; /* let the caller pick an exception code */
822 case T_ASTFLT : /* system forced exception : ^C, ^\. SIGINT signal
823 handler shouldn't be calling this function, since
824 it doesn't need an exception code */
825 // Trap code T_ASTFLT received, shouldn't get here;
828 case T_PROTFLT : /* protection fault */
829 return EXCEPTION_ACCESS_VIOLATION;
830 case T_TRCTRAP : /* debug exception (sic) */
831 return EXCEPTION_SINGLE_STEP;
832 case T_PAGEFLT : /* page fault */
833 return EXCEPTION_ACCESS_VIOLATION;
834 case T_ALIGNFLT : /* alignment fault */
835 return EXCEPTION_DATATYPE_MISALIGNMENT;
837 return EXCEPTION_INT_DIVIDE_BY_ZERO;
838 case T_NMI : /* non-maskable trap */
839 return EXCEPTION_ILLEGAL_INSTRUCTION;
841 return EXCEPTION_INT_OVERFLOW;
842 case T_BOUND : /* bound instruction fault */
843 return EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
844 case T_DNA : /* device not available fault */
845 return EXCEPTION_ILLEGAL_INSTRUCTION;
846 case T_DOUBLEFLT : /* double fault */
847 return EXCEPTION_ILLEGAL_INSTRUCTION;
848 case T_FPOPFLT : /* fp coprocessor operand fetch fault */
849 return EXCEPTION_FLT_INVALID_OPERATION;
850 case T_TSSFLT : /* invalid tss fault */
851 return EXCEPTION_ILLEGAL_INSTRUCTION;
852 case T_SEGNPFLT : /* segment not present fault */
853 return EXCEPTION_ACCESS_VIOLATION;
854 case T_STKFLT : /* stack fault */
855 return EXCEPTION_STACK_OVERFLOW;
856 case T_MCHK : /* machine check trap */
857 return EXCEPTION_ILLEGAL_INSTRUCTION;
858 case T_RESERVED : /* reserved (unknown) */
859 return EXCEPTION_ILLEGAL_INSTRUCTION;
861 // Got unknown trap code trap;
864 return EXCEPTION_ILLEGAL_INSTRUCTION;
868 #else // !HAVE_MACH_EXCEPTIONS
870 #include <mach/message.h>
871 #include <mach/thread_act.h>
872 #include "../exception/machexception.h"
876 CONTEXT_GetThreadContextFromPort
878 Helper for GetThreadContext that uses a mach_port
881 CONTEXT_GetThreadContextFromPort(
885 // Extract the CONTEXT from the Mach thread.
887 kern_return_t MachRet = KERN_SUCCESS;
888 mach_msg_type_number_t StateCount;
889 thread_state_flavor_t StateFlavor;
891 if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) & CONTEXT_AREA_MASK)
894 x86_thread_state32_t State;
895 StateFlavor = x86_THREAD_STATE32;
896 #elif defined(_AMD64_)
897 x86_thread_state64_t State;
898 StateFlavor = x86_THREAD_STATE64;
900 #error Unexpected architecture.
902 StateCount = sizeof(State) / sizeof(natural_t);
903 MachRet = thread_get_state(Port, StateFlavor, (thread_state_t)&State, &StateCount);
904 if (MachRet != KERN_SUCCESS)
906 ASSERT("thread_get_state(THREAD_STATE) failed: %d\n", MachRet);
910 CONTEXT_GetThreadContextFromThreadState(StateFlavor, (thread_state_t)&State, lpContext);
913 if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING & CONTEXT_AREA_MASK) {
915 x86_float_state32_t State;
916 StateFlavor = x86_FLOAT_STATE32;
917 #elif defined(_AMD64_)
918 x86_float_state64_t State;
919 StateFlavor = x86_FLOAT_STATE64;
921 #error Unexpected architecture.
923 StateCount = sizeof(State) / sizeof(natural_t);
924 MachRet = thread_get_state(Port, StateFlavor, (thread_state_t)&State, &StateCount);
925 if (MachRet != KERN_SUCCESS)
927 ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet);
931 CONTEXT_GetThreadContextFromThreadState(StateFlavor, (thread_state_t)&State, lpContext);
934 #if defined(_AMD64_) && defined(XSTATE_SUPPORTED)
935 if (lpContext->ContextFlags & CONTEXT_XSTATE & CONTEXT_AREA_MASK) {
936 x86_avx_state64_t State;
937 StateFlavor = x86_AVX_STATE64;
938 StateCount = sizeof(State) / sizeof(natural_t);
939 MachRet = thread_get_state(Port, StateFlavor, (thread_state_t)&State, &StateCount);
940 if (MachRet != KERN_SUCCESS)
942 ASSERT("thread_get_state(XSTATE) failed: %d\n", MachRet);
946 CONTEXT_GetThreadContextFromThreadState(StateFlavor, (thread_state_t)&State, lpContext);
956 CONTEXT_GetThreadContextFromThreadState
960 CONTEXT_GetThreadContextFromThreadState(
961 thread_state_flavor_t threadStateFlavor,
962 thread_state_t threadState,
965 switch (threadStateFlavor)
968 case x86_THREAD_STATE32:
969 if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) & CONTEXT_AREA_MASK)
971 x86_thread_state32_t *pState = (x86_thread_state32_t *)threadState;
973 lpContext->Eax = pState->eax;
974 lpContext->Ebx = pState->ebx;
975 lpContext->Ecx = pState->ecx;
976 lpContext->Edx = pState->edx;
977 lpContext->Edi = pState->edi;
978 lpContext->Esi = pState->esi;
979 lpContext->Ebp = pState->ebp;
980 lpContext->Esp = pState->esp;
981 lpContext->SegSs = pState->ss;
982 lpContext->EFlags = pState->eflags;
983 lpContext->Eip = pState->eip;
984 lpContext->SegCs = pState->cs;
985 lpContext->SegDs_PAL_Undefined = pState->ds;
986 lpContext->SegEs_PAL_Undefined = pState->es;
987 lpContext->SegFs_PAL_Undefined = pState->fs;
988 lpContext->SegGs_PAL_Undefined = pState->gs;
992 case x86_FLOAT_STATE32:
994 x86_float_state32_t *pState = (x86_float_state32_t *)threadState;
996 if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT & CONTEXT_AREA_MASK)
998 lpContext->FloatSave.ControlWord = *(DWORD*)&pState->fpu_fcw;
999 lpContext->FloatSave.StatusWord = *(DWORD*)&pState->fpu_fsw;
1000 lpContext->FloatSave.TagWord = pState->fpu_ftw;
1001 lpContext->FloatSave.ErrorOffset = pState->fpu_ip;
1002 lpContext->FloatSave.ErrorSelector = pState->fpu_cs;
1003 lpContext->FloatSave.DataOffset = pState->fpu_dp;
1004 lpContext->FloatSave.DataSelector = pState->fpu_ds;
1005 lpContext->FloatSave.Cr0NpxState = pState->fpu_mxcsr;
1007 // Windows stores the floating point registers in a packed layout (each 10-byte register end to end
1008 // for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably for
1009 // alignment purposes). So we can't just memcpy the registers over in a single block, we need to copy
1010 // them individually.
1011 for (int i = 0; i < 8; i++)
1012 memcpy(&lpContext->FloatSave.RegisterArea[i * 10], (&pState->fpu_stmm0)[i].mmst_reg, 10);
1015 if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS & CONTEXT_AREA_MASK)
1017 // The only extended register information that Mach will tell us about are the xmm register values.
1018 // Both Windows and Mach store the registers in a packed layout (each of the 8 registers is 16 bytes)
1019 // so we can simply memcpy them across.
1020 memcpy(lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, &pState->fpu_xmm0, 8 * 16);
1025 #elif defined(_AMD64_)
1026 case x86_THREAD_STATE64:
1027 if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) & CONTEXT_AREA_MASK)
1029 x86_thread_state64_t *pState = (x86_thread_state64_t *)threadState;
1031 lpContext->Rax = pState->__rax;
1032 lpContext->Rbx = pState->__rbx;
1033 lpContext->Rcx = pState->__rcx;
1034 lpContext->Rdx = pState->__rdx;
1035 lpContext->Rdi = pState->__rdi;
1036 lpContext->Rsi = pState->__rsi;
1037 lpContext->Rbp = pState->__rbp;
1038 lpContext->Rsp = pState->__rsp;
1039 lpContext->R8 = pState->__r8;
1040 lpContext->R9 = pState->__r9;
1041 lpContext->R10 = pState->__r10;
1042 lpContext->R11 = pState->__r11;
1043 lpContext->R12 = pState->__r12;
1044 lpContext->R13 = pState->__r13;
1045 lpContext->R14 = pState->__r14;
1046 lpContext->R15 = pState->__r15;
1047 lpContext->EFlags = pState->__rflags;
1048 lpContext->Rip = pState->__rip;
1049 lpContext->SegCs = pState->__cs;
1050 // RtlRestoreContext uses the actual ss instead of this one
1051 // to build the iret frame so just set it zero.
1052 lpContext->SegSs = 0;
1053 lpContext->SegDs = 0;
1054 lpContext->SegEs = 0;
1055 lpContext->SegFs = pState->__fs;
1056 lpContext->SegGs = pState->__gs;
1060 case x86_FLOAT_STATE64:
1061 if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT & CONTEXT_AREA_MASK)
1063 x86_float_state64_t *pState = (x86_float_state64_t *)threadState;
1065 lpContext->FltSave.ControlWord = *(DWORD*)&pState->__fpu_fcw;
1066 lpContext->FltSave.StatusWord = *(DWORD*)&pState->__fpu_fsw;
1067 lpContext->FltSave.TagWord = pState->__fpu_ftw;
1068 lpContext->FltSave.ErrorOffset = pState->__fpu_ip;
1069 lpContext->FltSave.ErrorSelector = pState->__fpu_cs;
1070 lpContext->FltSave.DataOffset = pState->__fpu_dp;
1071 lpContext->FltSave.DataSelector = pState->__fpu_ds;
1072 lpContext->FltSave.MxCsr = pState->__fpu_mxcsr;
1073 lpContext->FltSave.MxCsr_Mask = pState->__fpu_mxcsrmask; // note: we don't save the mask for x86
1075 // Windows stores the floating point registers in a packed layout (each 10-byte register end to end
1076 // for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably for
1077 // alignment purposes). So we can't just memcpy the registers over in a single block, we need to copy
1078 // them individually.
1079 for (int i = 0; i < 8; i++)
1080 memcpy(&lpContext->FltSave.FloatRegisters[i], (&pState->__fpu_stmm0)[i].__mmst_reg, 10);
1082 // AMD64's FLOATING_POINT includes the xmm registers.
1083 memcpy(&lpContext->Xmm0, &pState->__fpu_xmm0, 16 * 16);
1087 #ifdef XSTATE_SUPPORTED
1088 case x86_AVX_STATE64:
1089 if (lpContext->ContextFlags & CONTEXT_XSTATE & CONTEXT_AREA_MASK)
1091 x86_avx_state64_t *pState = (x86_avx_state64_t *)threadState;
1092 memcpy(&lpContext->VectorRegister, &pState->__fpu_ymmh0, 16 * 16);
1097 #error Unexpected architecture.
1099 case x86_THREAD_STATE:
1101 x86_thread_state_t *pState = (x86_thread_state_t *)threadState;
1102 CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->tsh.flavor, (thread_state_t)&pState->uts, lpContext);
1106 case x86_FLOAT_STATE:
1108 x86_float_state_t *pState = (x86_float_state_t *)threadState;
1109 CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->fsh.flavor, (thread_state_t)&pState->ufs, lpContext);
1114 ASSERT("Invalid thread state flavor %d\n", threadStateFlavor);
1126 CONTEXT_GetThreadContext(
1129 LPCONTEXT lpContext)
1133 if (lpContext == NULL)
1135 ERROR("Invalid lpContext parameter value\n");
1136 SetLastError(ERROR_NOACCESS);
1140 if (GetCurrentProcessId() == dwProcessId)
1142 if (self != pthread_self())
1144 // the target thread is in the current process, but isn't
1145 // the current one: extract the CONTEXT from the Mach thread.
1146 mach_port_t mptPort;
1147 mptPort = pthread_mach_thread_np(self);
1149 ret = (CONTEXT_GetThreadContextFromPort(mptPort, lpContext) == KERN_SUCCESS);
1153 CONTEXT_CaptureContext(lpContext);
1159 ASSERT("Cross-process GetThreadContext() is not supported on this platform\n");
1160 SetLastError(ERROR_NOACCESS);
1169 SetThreadContextOnPort
1171 Helper for CONTEXT_SetThreadContext
1174 CONTEXT_SetThreadContextOnPort(
1176 IN CONST CONTEXT *lpContext)
1178 kern_return_t MachRet = KERN_SUCCESS;
1179 mach_msg_type_number_t StateCount;
1180 thread_state_flavor_t StateFlavor;
1182 if (lpContext->ContextFlags & (CONTEXT_CONTROL|CONTEXT_INTEGER) & CONTEXT_AREA_MASK)
1185 x86_thread_state32_t State;
1186 StateFlavor = x86_THREAD_STATE32;
1188 State.eax = lpContext->Eax;
1189 State.ebx = lpContext->Ebx;
1190 State.ecx = lpContext->Ecx;
1191 State.edx = lpContext->Edx;
1192 State.edi = lpContext->Edi;
1193 State.esi = lpContext->Esi;
1194 State.ebp = lpContext->Ebp;
1195 State.esp = lpContext->Esp;
1196 State.ss = lpContext->SegSs;
1197 State.eflags = lpContext->EFlags;
1198 State.eip = lpContext->Eip;
1199 State.cs = lpContext->SegCs;
1200 State.ds = lpContext->SegDs_PAL_Undefined;
1201 State.es = lpContext->SegEs_PAL_Undefined;
1202 State.fs = lpContext->SegFs_PAL_Undefined;
1203 State.gs = lpContext->SegGs_PAL_Undefined;
1204 #elif defined(_AMD64_)
1205 x86_thread_state64_t State;
1206 StateFlavor = x86_THREAD_STATE64;
1208 State.__rax = lpContext->Rax;
1209 State.__rbx = lpContext->Rbx;
1210 State.__rcx = lpContext->Rcx;
1211 State.__rdx = lpContext->Rdx;
1212 State.__rdi = lpContext->Rdi;
1213 State.__rsi = lpContext->Rsi;
1214 State.__rbp = lpContext->Rbp;
1215 State.__rsp = lpContext->Rsp;
1216 State.__r8 = lpContext->R8;
1217 State.__r9 = lpContext->R9;
1218 State.__r10 = lpContext->R10;
1219 State.__r11 = lpContext->R11;
1220 State.__r12 = lpContext->R12;
1221 State.__r13 = lpContext->R13;
1222 State.__r14 = lpContext->R14;
1223 State.__r15 = lpContext->R15;
1224 // State.ss = lpContext->SegSs;
1225 State.__rflags = lpContext->EFlags;
1226 State.__rip = lpContext->Rip;
1227 State.__cs = lpContext->SegCs;
1228 // State.ds = lpContext->SegDs_PAL_Undefined;
1229 // State.es = lpContext->SegEs_PAL_Undefined;
1230 State.__fs = lpContext->SegFs;
1231 State.__gs = lpContext->SegGs;
1233 #error Unexpected architecture.
1236 StateCount = sizeof(State) / sizeof(natural_t);
1238 MachRet = thread_set_state(Port,
1240 (thread_state_t)&State,
1242 if (MachRet != KERN_SUCCESS)
1244 ASSERT("thread_set_state(THREAD_STATE) failed: %d\n", MachRet);
1249 if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING & CONTEXT_AREA_MASK)
1253 x86_float_state32_t State;
1254 StateFlavor = x86_FLOAT_STATE32;
1255 StateCount = sizeof(State) / sizeof(natural_t);
1256 #elif defined(_AMD64_)
1257 #ifdef XSTATE_SUPPORTED
1258 // We're relying on the fact that the initial portion of
1259 // x86_avx_state64_t is identical to x86_float_state64_t.
1260 // Check a few fields to make sure the assumption is correct.
1261 static_assert_no_msg(sizeof(x86_avx_state64_t) > sizeof(x86_float_state64_t));
1262 static_assert_no_msg(offsetof(x86_avx_state64_t, __fpu_fcw) == offsetof(x86_float_state64_t, __fpu_fcw));
1263 static_assert_no_msg(offsetof(x86_avx_state64_t, __fpu_xmm0) == offsetof(x86_float_state64_t, __fpu_xmm0));
1265 x86_avx_state64_t State;
1266 if (lpContext->ContextFlags & CONTEXT_XSTATE & CONTEXT_AREA_MASK)
1268 StateFlavor = x86_AVX_STATE64;
1269 StateCount = sizeof(State) / sizeof(natural_t);
1273 StateFlavor = x86_FLOAT_STATE64;
1274 StateCount = sizeof(x86_float_state64_t) / sizeof(natural_t);
1277 x86_float_state64_t State;
1278 StateFlavor = x86_FLOAT_STATE64;
1279 StateCount = sizeof(State) / sizeof(natural_t);
1282 #error Unexpected architecture.
1285 // If we're setting only one of the floating point or extended registers (of which Mach supports only
1286 // the xmm values) then we don't have values for the other set. This is a problem since Mach only
1287 // supports setting both groups as a single unit. So in this case we'll need to fetch the current
1289 if ((lpContext->ContextFlags & CONTEXT_ALL_FLOATING) !=
1290 CONTEXT_ALL_FLOATING)
1292 mach_msg_type_number_t StateCountGet = StateCount;
1293 MachRet = thread_get_state(Port,
1295 (thread_state_t)&State,
1297 if (MachRet != KERN_SUCCESS)
1299 ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet);
1302 _ASSERTE(StateCountGet == StateCount);
1305 if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT & CONTEXT_AREA_MASK)
1308 *(DWORD*)&State.fpu_fcw = lpContext->FloatSave.ControlWord;
1309 *(DWORD*)&State.fpu_fsw = lpContext->FloatSave.StatusWord;
1310 State.fpu_ftw = lpContext->FloatSave.TagWord;
1311 State.fpu_ip = lpContext->FloatSave.ErrorOffset;
1312 State.fpu_cs = lpContext->FloatSave.ErrorSelector;
1313 State.fpu_dp = lpContext->FloatSave.DataOffset;
1314 State.fpu_ds = lpContext->FloatSave.DataSelector;
1315 State.fpu_mxcsr = lpContext->FloatSave.Cr0NpxState;
1317 // Windows stores the floating point registers in a packed layout (each 10-byte register end to
1318 // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably
1319 // for alignment purposes). So we can't just memcpy the registers over in a single block, we need
1320 // to copy them individually.
1321 for (int i = 0; i < 8; i++)
1322 memcpy((&State.fpu_stmm0)[i].mmst_reg, &lpContext->FloatSave.RegisterArea[i * 10], 10);
1323 #elif defined(_AMD64_)
1324 *(DWORD*)&State.__fpu_fcw = lpContext->FltSave.ControlWord;
1325 *(DWORD*)&State.__fpu_fsw = lpContext->FltSave.StatusWord;
1326 State.__fpu_ftw = lpContext->FltSave.TagWord;
1327 State.__fpu_ip = lpContext->FltSave.ErrorOffset;
1328 State.__fpu_cs = lpContext->FltSave.ErrorSelector;
1329 State.__fpu_dp = lpContext->FltSave.DataOffset;
1330 State.__fpu_ds = lpContext->FltSave.DataSelector;
1331 State.__fpu_mxcsr = lpContext->FltSave.MxCsr;
1332 State.__fpu_mxcsrmask = lpContext->FltSave.MxCsr_Mask; // note: we don't save the mask for x86
1334 // Windows stores the floating point registers in a packed layout (each 10-byte register end to
1335 // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably
1336 // for alignment purposes). So we can't just memcpy the registers over in a single block, we need
1337 // to copy them individually.
1338 for (int i = 0; i < 8; i++)
1339 memcpy((&State.__fpu_stmm0)[i].__mmst_reg, &lpContext->FltSave.FloatRegisters[i], 10);
1341 memcpy(&State.__fpu_xmm0, &lpContext->Xmm0, 16 * 16);
1343 #error Unexpected architecture.
1348 if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS & CONTEXT_AREA_MASK)
1350 // The only extended register information that Mach will tell us about are the xmm register
1351 // values. Both Windows and Mach store the registers in a packed layout (each of the 8 registers
1352 // is 16 bytes) so we can simply memcpy them across.
1353 memcpy(&State.fpu_xmm0, lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, 8 * 16);
1357 #if defined(_AMD64_) && defined(XSTATE_SUPPORTED)
1358 if (lpContext->ContextFlags & CONTEXT_XSTATE & CONTEXT_AREA_MASK)
1360 memcpy(&State.__fpu_ymmh0, lpContext->VectorRegister, 16 * 16);
1364 MachRet = thread_set_state(Port,
1366 (thread_state_t)&State,
1368 if (MachRet != KERN_SUCCESS)
1370 ASSERT("thread_set_state(FLOAT_STATE) failed: %d\n", MachRet);
1386 CONTEXT_SetThreadContext(
1389 CONST CONTEXT *lpContext)
1393 if (lpContext == NULL)
1395 ERROR("Invalid lpContext parameter value\n");
1396 SetLastError(ERROR_NOACCESS);
1400 if (dwProcessId != GetCurrentProcessId())
1402 // GetThreadContext() of a thread in another process
1403 ASSERT("Cross-process GetThreadContext() is not supported\n");
1404 SetLastError(ERROR_NOACCESS);
1408 if (self != pthread_self())
1410 // hThread is in the current process, but isn't the current
1411 // thread. Extract the CONTEXT from the Mach thread.
1413 mach_port_t mptPort;
1415 mptPort = pthread_mach_thread_np(self);
1417 ret = (CONTEXT_SetThreadContextOnPort(mptPort, lpContext) == KERN_SUCCESS);
1421 MachSetThreadContext(const_cast<CONTEXT *>(lpContext));
1422 ASSERT("MachSetThreadContext should never return\n");
1429 #endif // !HAVE_MACH_EXCEPTIONS
1433 DBG_FlushInstructionCache: processor-specific portion of
1434 FlushInstructionCache
1439 DBG_FlushInstructionCache(
1440 IN LPCVOID lpBaseAddress,
1444 // Intrinsic should do the right thing across all platforms (except Linux arm)
1445 __builtin___clear_cache((char *)lpBaseAddress, (char *)((INT_PTR)lpBaseAddress + dwSize));
1447 // On Linux/arm (at least on 3.10) we found that there is a problem with __do_cache_op (arch/arm/kernel/traps.c)
1448 // implementing cacheflush syscall. cacheflush flushes only the first page in range [lpBaseAddress, lpBaseAddress + dwSize)
1449 // and leaves other pages in undefined state which causes random tests failures (often due to SIGSEGV) with no particular pattern.
1451 // As a workaround, we call __builtin___clear_cache on each page separately.
1453 const SIZE_T pageSize = GetVirtualPageSize();
1454 INT_PTR begin = (INT_PTR)lpBaseAddress;
1455 const INT_PTR end = begin + dwSize;
1459 INT_PTR endOrNextPageBegin = ALIGN_UP(begin + 1, pageSize);
1460 if (endOrNextPageBegin > end)
1461 endOrNextPageBegin = end;
1463 __builtin___clear_cache((char *)begin, (char *)endOrNextPageBegin);
1464 begin = endOrNextPageBegin;