/*++ 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 HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) { // Reset the CONTEXT_FLOATING_POINT bit(s) so it's clear that the floating point // data in the CONTEXT is not valid. Since CONTEXT_FLOATING_POINT is defined as // the architecture bit(s) OR'd with one or more other bits, we first get the bits // that are unique to CONTEXT_FLOATING_POINT by resetting the architecture bits. // We determine what those are by inverting the union of CONTEXT_CONTROL and // CONTEXT_INTEGER, both of which should also have the architecture bit(s) set. const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); lpContext->ContextFlags &= ~floatingPointFlags; // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT return; } #endif if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef _AMD64_ 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++) { lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i); } for (int i = 0; i < 16; i++) { lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i); } #endif } }
/*++ 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 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 HAVE_GREGSET_T || HAVE_GREGSET_T #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T if (native->uc_mcontext.__fpregs == nullptr) #endif { // If the pointer to the floating point state in the native context // is not valid, we can't copy floating point registers regardless of // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags. return; } #endif if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef _AMD64_ 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) = lpContext->FltSave.FloatRegisters[i]; } for (int i = 0; i < 16; i++) { FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i]; } #endif } }
/*++ 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 #ifdef _ARM_ // WinContext assumes that the least bit of Pc is always 1 (denoting thumb) // although the pc value retrived from native context might not have set the least bit. // This becomes especially problematic if the context is on the JIT_WRITEBARRIER. lpContext->Pc |= 0x1; #endif } if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { ASSIGN_INTEGER_REGS } #undef ASSIGN_REG if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef _AMD64_ 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++) { lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i); } for (int i = 0; i < 16; i++) { lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i); } #endif } }
/*++ 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 #ifdef _ARM_ // WinContext assumes that the least bit of Pc is always 1 (denoting thumb) // although the pc value retrived from native context might not have set the least bit. // This becomes especially problematic if the context is on the JIT_WRITEBARRIER. lpContext->Pc |= 0x1; #endif } if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { ASSIGN_INTEGER_REGS } #undef ASSIGN_REG #if HAVE_GREGSET_T || HAVE___GREGSET_T #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T if (native->uc_mcontext.__fpregs == nullptr) #endif { // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's // clear that the floating point and extended state data in the CONTEXT is not // valid. Since these flags are defined as the architecture bit(s) OR'd with one // or more other bits, we first get the bits that are unique to each by resetting // the architecture bits. We determine what those are by inverting the union of // CONTEXT_CONTROL and CONTEXT_INTEGER, both of which should also have the // architecture bit(s) set. const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); lpContext->ContextFlags &= ~(floatingPointFlags | xstateFlags); // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE return; } #endif if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef _AMD64_ 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++) { lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i); } for (int i = 0; i < 16; i++) { lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i); } #endif } #ifdef _AMD64_ if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) { // TODO: Enable for all Unix systems #if XSTATE_SUPPORTED if (FPREG_HasExtendedState(native)) { memcpy_s(lpContext->VectorRegister, sizeof(M128A) * 16, FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16); } else #endif // XSTATE_SUPPORTED { // Reset the CONTEXT_XSTATE bit(s) so it's clear that the extended state data in // the CONTEXT is not valid. const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); lpContext->ContextFlags &= ~xstateFlags; } } #endif // _AMD64_ }
/*++ 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 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 HAVE_GREGSET_T || HAVE_GREGSET_T #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T if (native->uc_mcontext.__fpregs == nullptr) #endif { // If the pointer to the floating point state in the native context // is not valid, we can't copy floating point registers regardless of // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags. return; } #endif if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef _AMD64_ 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) = lpContext->FltSave.FloatRegisters[i]; } for (int i = 0; i < 16; i++) { FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i]; } #endif } // TODO: Enable for all Unix systems #if defined(_AMD64_) && defined(XSTATE_SUPPORTED) if ((lpContext->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) { _ASSERTE(FPREG_HasExtendedState(native)); memcpy_s(FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16, lpContext->VectorRegister, sizeof(M128A) * 16); } #endif //_AMD64_ && XSTATE_SUPPORTED }
bool ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* dataTarget) { CONTEXT context; context.ContextFlags = CONTEXT_ALL; if (dataTarget->GetThreadContext(m_tid, context.ContextFlags, sizeof(context), reinterpret_cast<PBYTE>(&context)) != S_OK) { return false; } #if defined(__x86_64__) m_gpRegisters.rbp = context.Rbp; m_gpRegisters.rip = context.Rip; m_gpRegisters.cs = context.SegCs; m_gpRegisters.eflags = context.EFlags; m_gpRegisters.ss = context.SegSs; m_gpRegisters.rsp = context.Rsp; m_gpRegisters.rdi = context.Rdi; m_gpRegisters.rsi = context.Rsi; m_gpRegisters.rbx = context.Rbx; m_gpRegisters.rdx = context.Rdx; m_gpRegisters.rcx = context.Rcx; m_gpRegisters.rax = context.Rax; m_gpRegisters.orig_rax = context.Rax; m_gpRegisters.r8 = context.R8; m_gpRegisters.r9 = context.R9; m_gpRegisters.r10 = context.R10; m_gpRegisters.r11 = context.R11; m_gpRegisters.r12 = context.R12; m_gpRegisters.r13 = context.R13; m_gpRegisters.r14 = context.R14; m_gpRegisters.r15 = context.R15; m_gpRegisters.ds = context.SegDs; m_gpRegisters.es = context.SegEs; m_gpRegisters.fs = context.SegFs; m_gpRegisters.gs = context.SegGs; m_gpRegisters.fs_base = 0; m_gpRegisters.gs_base = 0; m_fpRegisters.cwd = context.FltSave.ControlWord; m_fpRegisters.swd = context.FltSave.StatusWord; m_fpRegisters.ftw = context.FltSave.TagWord; m_fpRegisters.fop = context.FltSave.ErrorOpcode; FPREG_ErrorOffset(m_fpRegisters) = context.FltSave.ErrorOffset; FPREG_ErrorSelector(m_fpRegisters) = context.FltSave.ErrorSelector; FPREG_DataOffset(m_fpRegisters) = context.FltSave.DataOffset; FPREG_DataSelector(m_fpRegisters) = context.FltSave.DataSelector; m_fpRegisters.mxcsr = context.FltSave.MxCsr; m_fpRegisters.mxcr_mask = context.FltSave.MxCsr_Mask; assert(sizeof(context.FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space)); memcpy(m_fpRegisters.st_space, context.FltSave.FloatRegisters, sizeof(m_fpRegisters.st_space)); assert(sizeof(context.FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space)); memcpy(m_fpRegisters.xmm_space, context.FltSave.XmmRegisters, sizeof(m_fpRegisters.xmm_space)); #elif defined(__arm__) m_gpRegisters.ARM_sp = context.Sp; m_gpRegisters.ARM_lr = context.Lr; m_gpRegisters.ARM_pc = context.Pc; m_gpRegisters.ARM_cpsr = context.Cpsr; m_gpRegisters.ARM_r0 = context.R0; m_gpRegisters.ARM_ORIG_r0 = context.R0; m_gpRegisters.ARM_r1 = context.R1; m_gpRegisters.ARM_r2 = context.R2; m_gpRegisters.ARM_r3 = context.R3; m_gpRegisters.ARM_r4 = context.R4; m_gpRegisters.ARM_r5 = context.R5; m_gpRegisters.ARM_r6 = context.R6; m_gpRegisters.ARM_r7 = context.R7; m_gpRegisters.ARM_r8 = context.R8; m_gpRegisters.ARM_r9 = context.R9; m_gpRegisters.ARM_r10 = context.R10; m_gpRegisters.ARM_fp = context.R11; m_gpRegisters.ARM_ip = context.R12; #if defined(__VFP_FP__) && !defined(__SOFTFP__) m_vfpRegisters.fpscr = context.Fpscr; assert(sizeof(context.D) == sizeof(m_vfpRegisters.fpregs)); memcpy(m_vfpRegisters.fpregs, context.D, sizeof(context.D)); #endif #else #error Platform not supported #endif return true; }
void ThreadInfo::GetThreadContext(uint32_t flags, CONTEXT* context) const { context->ContextFlags = flags; #if defined(__x86_64__) if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { context->Rbp = m_gpRegisters.rbp; context->Rip = m_gpRegisters.rip; context->SegCs = m_gpRegisters.cs; context->EFlags = m_gpRegisters.eflags; context->SegSs = m_gpRegisters.ss; context->Rsp = m_gpRegisters.rsp; } if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { context->Rdi = m_gpRegisters.rdi; context->Rsi = m_gpRegisters.rsi; context->Rbx = m_gpRegisters.rbx; context->Rdx = m_gpRegisters.rdx; context->Rcx = m_gpRegisters.rcx; context->Rax = m_gpRegisters.rax; context->R8 = m_gpRegisters.r8; context->R9 = m_gpRegisters.r9; context->R10 = m_gpRegisters.r10; context->R11 = m_gpRegisters.r11; context->R12 = m_gpRegisters.r12; context->R13 = m_gpRegisters.r13; context->R14 = m_gpRegisters.r14; context->R15 = m_gpRegisters.r15; } if ((flags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) { context->SegDs = m_gpRegisters.ds; context->SegEs = m_gpRegisters.es; context->SegFs = m_gpRegisters.fs; context->SegGs = m_gpRegisters.gs; } if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { context->FltSave.ControlWord = m_fpRegisters.cwd; context->FltSave.StatusWord = m_fpRegisters.swd; context->FltSave.TagWord = m_fpRegisters.ftw; context->FltSave.ErrorOpcode = m_fpRegisters.fop; context->FltSave.ErrorOffset = FPREG_ErrorOffset(m_fpRegisters); context->FltSave.ErrorSelector = FPREG_ErrorSelector(m_fpRegisters); context->FltSave.DataOffset = FPREG_DataOffset(m_fpRegisters); context->FltSave.DataSelector = FPREG_DataSelector(m_fpRegisters); context->FltSave.MxCsr = m_fpRegisters.mxcsr; context->FltSave.MxCsr_Mask = m_fpRegisters.mxcr_mask; assert(sizeof(context->FltSave.FloatRegisters) == sizeof(m_fpRegisters.st_space)); memcpy(context->FltSave.FloatRegisters, m_fpRegisters.st_space, sizeof(context->FltSave.FloatRegisters)); assert(sizeof(context->FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space)); memcpy(context->FltSave.XmmRegisters, m_fpRegisters.xmm_space, sizeof(context->FltSave.XmmRegisters)); } // TODO: debug registers? #elif defined(__arm__) if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { context->Sp = m_gpRegisters.ARM_sp; context->Lr = m_gpRegisters.ARM_lr; context->Pc = m_gpRegisters.ARM_pc; context->Cpsr = m_gpRegisters.ARM_cpsr; } if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { context->R0 = m_gpRegisters.ARM_r0; context->R1 = m_gpRegisters.ARM_r1; context->R2 = m_gpRegisters.ARM_r2; context->R3 = m_gpRegisters.ARM_r3; context->R4 = m_gpRegisters.ARM_r4; context->R5 = m_gpRegisters.ARM_r5; context->R6 = m_gpRegisters.ARM_r6; context->R7 = m_gpRegisters.ARM_r7; context->R8 = m_gpRegisters.ARM_r8; context->R9 = m_gpRegisters.ARM_r9; context->R10 = m_gpRegisters.ARM_r10; context->R11 = m_gpRegisters.ARM_fp; context->R12 = m_gpRegisters.ARM_ip; } if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #if defined(__VFP_FP__) && !defined(__SOFTFP__) context->Fpscr = m_vfpRegisters.fpscr; assert(sizeof(context->D) == sizeof(m_vfpRegisters.fpregs)); memcpy(context->D, m_vfpRegisters.fpregs, sizeof(context->D)); #endif } #else #error Platform not supported #endif }