diff options
Diffstat (limited to 'src/inc/regdisp.h')
-rw-r--r-- | src/inc/regdisp.h | 409 |
1 files changed, 194 insertions, 215 deletions
diff --git a/src/inc/regdisp.h b/src/inc/regdisp.h index 09a6a38f62..d08c44c904 100644 --- a/src/inc/regdisp.h +++ b/src/inc/regdisp.h @@ -8,19 +8,71 @@ #ifdef DEBUG_REGDISPLAY class Thread; +struct REGDISPLAY; +void CheckRegDisplaySP (REGDISPLAY *pRD); +#endif // DEBUG_REGDISPLAY + +struct REGDISPLAY_BASE { + PT_CONTEXT pContext; // This is the context of the active call frame; + // either returned by GetContext or provided at + // exception time. + // + // This will be used to resume execution, so + // do NOT trash it! But DO update any static + // registers here. + +#ifdef WIN64EXCEPTIONS + PT_CONTEXT pCurrentContext; // [trashed] points to current Context of stackwalk + PT_CONTEXT pCallerContext; // [trashed] points to the Context of the caller during stackwalk -- used for GC crawls + + // [trashed] points to current context pointers of stackwalk + T_KNONVOLATILE_CONTEXT_POINTERS *pCurrentContextPointers; + // [trashed] points to the context pointers of the caller during stackwalk -- used for GC crawls + T_KNONVOLATILE_CONTEXT_POINTERS *pCallerContextPointers; + + BOOL IsCallerContextValid; // TRUE if pCallerContext really contains the caller's context + BOOL IsCallerSPValid; // Don't add usage of this field. This is only temporary. + + T_CONTEXT ctxOne; // used by stackwalk + T_CONTEXT ctxTwo; // used by stackwalk + + T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsOne; // used by stackwalk + T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsTwo; // used by stackwalk +#endif // WIN64EXCEPTIONS + +#ifdef DEBUG_REGDISPLAY + Thread *_pThread; #endif // DEBUG_REGDISPLAY + TADDR SP; + TADDR ControlPC; +}; + +inline PCODE GetControlPC(REGDISPLAY_BASE *pRD) { + LIMITED_METHOD_DAC_CONTRACT; + return (PCODE)(pRD->ControlPC); +} + +inline TADDR GetRegdisplaySP(REGDISPLAY_BASE *pRD) { + LIMITED_METHOD_DAC_CONTRACT; + + return pRD->SP; +} + +inline void SetRegdisplaySP(REGDISPLAY_BASE *pRD, LPVOID sp) { + LIMITED_METHOD_DAC_CONTRACT; + + pRD->SP = (TADDR)sp; +} #if defined(_TARGET_X86_) -struct REGDISPLAY { - PCONTEXT pContext; // points to current Context; either - // returned by GetContext or provided - // at exception time. +struct REGDISPLAY : public REGDISPLAY_BASE { +#ifndef WIN64EXCEPTIONS // TODO: Unify with pCurrentContext / pCallerContext used on 64-bit PCONTEXT pContextForUnwind; // scratch context for unwinding - // used to preserve context saved in the frame that + // used to preserve context saved in the frame that // could be otherwise wiped by the unwinding DWORD * pEdi; @@ -31,52 +83,68 @@ struct REGDISPLAY { DWORD * pEax; DWORD * pEbp; - DWORD Esp; // (Esp) Stack Pointer - PCODE ControlPC; - TADDR PCTAddr; +#endif // !WIN64EXCEPTIONS -}; +#ifndef WIN64EXCEPTIONS -inline TADDR GetRegdisplaySP(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; +#define REG_METHODS(reg) \ + inline PDWORD Get##reg##Location(void) { return p##reg; } \ + inline void Set##reg##Location(PDWORD p##reg) { this->p##reg = p##reg; } - return (TADDR)display->Esp; -} +#else // !WIN64EXCEPTIONS -inline void SetRegdisplaySP(REGDISPLAY *display, LPVOID sp ) { - LIMITED_METHOD_DAC_CONTRACT; +#define REG_METHODS(reg) \ + inline PDWORD Get##reg##Location(void) { return pCurrentContextPointers->reg; } \ + inline void Set##reg##Location(PDWORD p##reg) { pCurrentContextPointers->reg = p##reg; } - (display->Esp) = (DWORD)(size_t)sp; -} +#endif // WIN64EXCEPTIONS + + REG_METHODS(Eax) + REG_METHODS(Ecx) + REG_METHODS(Edx) + + REG_METHODS(Ebx) + REG_METHODS(Esi) + REG_METHODS(Edi) + REG_METHODS(Ebp) + +#undef REG_METHODS + + TADDR PCTAddr; +}; inline TADDR GetRegdisplayFP(REGDISPLAY *display) { LIMITED_METHOD_DAC_CONTRACT; - return (TADDR)*(display->pEbp); + return (TADDR)*display->GetEbpLocation(); } inline LPVOID GetRegdisplayFPAddress(REGDISPLAY *display) { LIMITED_METHOD_CONTRACT; - return (LPVOID)display->pEbp; + return (LPVOID)display->GetEbpLocation(); } -inline PCODE GetControlPC(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; - - return display->ControlPC; -} // This function tells us if the given stack pointer is in one of the frames of the functions called by the given frame inline BOOL IsInCalleesFrames(REGDISPLAY *display, LPVOID stackPointer) { LIMITED_METHOD_CONTRACT; +#ifdef WIN64EXCEPTIONS + return stackPointer < ((LPVOID)(display->SP)); +#else return (TADDR)stackPointer < display->PCTAddr; +#endif } inline TADDR GetRegdisplayStackMark(REGDISPLAY *display) { LIMITED_METHOD_DAC_CONTRACT; +#ifdef WIN64EXCEPTIONS + _ASSERTE(GetRegdisplaySP(display) == GetSP(display->pCurrentContext)); + return GetRegdisplaySP(display); +#else return display->PCTAddr; +#endif } #elif defined(_WIN64) @@ -110,42 +178,18 @@ typedef struct _Arm64VolatileContextPointer }; } Arm64VolatileContextPointer; #endif //_TARGET_ARM64_ -struct REGDISPLAY { - PT_CONTEXT pContext; // This is the context of the active call frame. This - // will be used to resume execution, so do not use trash it! - // But DO update any static registers here. - - PT_CONTEXT pCurrentContext; // [trashed] points to current Context of stackwalk - PT_CONTEXT pCallerContext; // [trashed] points to the Context of the caller during stackwalk -- used for GC crawls - - size_t ControlPC; - - size_t SP; - - T_KNONVOLATILE_CONTEXT_POINTERS *pCurrentContextPointers; // [trashed] points to current context pointers of stackwalk - T_KNONVOLATILE_CONTEXT_POINTERS *pCallerContextPointers; // [trashed] points to the context pointers of the caller during stackwalk -- used for GC crawls +struct REGDISPLAY : public REGDISPLAY_BASE { #ifdef _TARGET_ARM64_ Arm64VolatileContextPointer volatileCurrContextPointers; #endif - BOOL IsCallerContextValid; // TRUE if pCallerContext really contains the caller's context - BOOL IsCallerSPValid; // Don't add usage of this field. This is only temporary. - - T_CONTEXT ctxOne; // used by stackwalk - T_CONTEXT ctxTwo; // used by stackwalk - - T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsOne; // used by stackwalk - T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsTwo; // used by stackwalk - -#ifdef DEBUG_REGDISPLAY - Thread *_pThread; -#endif // DEBUG_REGDISPLAY + REGDISPLAY() + { + // Initialize + memset(this, 0, sizeof(REGDISPLAY)); + } }; -inline TADDR GetRegdisplaySP(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; - return (TADDR)display->SP; -} inline TADDR GetRegdisplayFP(REGDISPLAY *display) { LIMITED_METHOD_CONTRACT; @@ -157,28 +201,6 @@ inline TADDR GetRegdisplayFPAddress(REGDISPLAY *display) { return NULL; } -inline PCODE GetControlPC(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; - return (PCODE)(display->ControlPC); -} - -#ifdef DEBUG_REGDISPLAY -void CheckRegDisplaySP (REGDISPLAY *pRD); -#endif // DEBUG_REGDISPLAY - -inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD) -{ - LIMITED_METHOD_CONTRACT; - - pRD->SP = (INT_PTR)GetSP(pRD->pCurrentContext); - -#ifdef DEBUG_REGDISPLAY - CheckRegDisplaySP(pRD); -#endif // DEBUG_REGDISPLAY - - pRD->ControlPC = INT_PTR(GetIP(pRD->pCurrentContext)); -} - // This function tells us if the given stack pointer is in one of the frames of the functions called by the given frame inline BOOL IsInCalleesFrames(REGDISPLAY *display, LPVOID stackPointer) { @@ -204,21 +226,6 @@ inline TADDR GetRegdisplayStackMark(REGDISPLAY *display) #endif // _TARGET_AMD64_ } -// This needs to be implemented for platforms that have funclets. -inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display) -{ - LIMITED_METHOD_CONTRACT; - -#if defined(_TARGET_AMD64_) - return (LPVOID)display->pCurrentContext->Rax; -#elif defined(_TARGET_ARM64_) - return (LPVOID)display->pCurrentContext->X0; -#else - PORTABILITY_ASSERT("GetRegdisplayReturnValue NYI for this platform (Regdisp.h)"); - return NULL; -#endif -} - #elif defined(_TARGET_ARM_) // ResumableFrame is pushed on the stack before @@ -239,31 +246,11 @@ typedef struct _ArmVolatileContextPointer PDWORD R12; } ArmVolatileContextPointer; -struct REGDISPLAY { - PT_CONTEXT pContext; // points to current Context; either - // returned by GetContext or provided - // at exception time. - - PT_CONTEXT pCurrentContext; // [trashed] points to current Context of stackwalk - PT_CONTEXT pCallerContext; // [trashed] points to the Context of the caller during stackwalk -- used for GC crawls - - T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsOne; // used by stackwalk - T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsTwo; // used by stackwalk - - PT_KNONVOLATILE_CONTEXT_POINTERS pCurrentContextPointers; - PT_KNONVOLATILE_CONTEXT_POINTERS pCallerContextPointers; +struct REGDISPLAY : public REGDISPLAY_BASE { ArmVolatileContextPointer volatileCurrContextPointers; - BOOL IsCallerContextValid; // TRUE if pCallerContext really contains the caller's context - BOOL IsCallerSPValid; // Don't add usage of this field. This is only temporary. - - DWORD SP; - DWORD ControlPC; DWORD * pPC; // processor neutral name - T_CONTEXT ctxOne; // used by stackwalk - T_CONTEXT ctxTwo; // used in ExceptionTracker::InitializeCrawlFrame - REGDISPLAY() { // Initialize regdisplay @@ -272,28 +259,8 @@ struct REGDISPLAY { // Setup the pointer to ControlPC field pPC = &ControlPC; } - -#ifdef DEBUG_REGDISPLAY - Thread *_pThread; -#endif // DEBUG_REGDISPLAY - }; -#ifdef DEBUG_REGDISPLAY -void CheckRegDisplaySP (REGDISPLAY *pRD); -#endif // DEBUG_REGDISPLAY - -inline TADDR GetRegdisplaySP(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; - return (TADDR)(size_t)display->SP; -} - -inline PCODE GetControlPC(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; - return (PCODE)(display->ControlPC); -} - - // This function tells us if the given stack pointer is in one of the frames of the functions called by the given frame inline BOOL IsInCalleesFrames(REGDISPLAY *display, LPVOID stackPointer) { LIMITED_METHOD_CONTRACT; @@ -307,42 +274,15 @@ inline TADDR GetRegdisplayStackMark(REGDISPLAY *display) { return GetSP(display->pCallerContext); } -inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD) -{ - LIMITED_METHOD_CONTRACT; - pRD->SP = (DWORD)GetSP(pRD->pCurrentContext); - pRD->ControlPC = (DWORD)GetIP(pRD->pCurrentContext); -} - -// This needs to be implemented for platforms that have funclets. -inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display) -{ - LIMITED_METHOD_CONTRACT; - - return (LPVOID)display->pCurrentContext->R0; -} - #else // none of the above processors PORTABILITY_WARNING("RegDisplay functions are not implemented on this platform.") -struct REGDISPLAY { - PCONTEXT pContext; // points to current Context - size_t SP; +struct REGDISPLAY : public REGDISPLAY_BASE { size_t * FramePtr; SLOT * pPC; }; -inline PCODE GetControlPC(REGDISPLAY *display) { - LIMITED_METHOD_CONTRACT; - return (PCODE) NULL; -} - -inline LPVOID GetRegdisplaySP(REGDISPLAY *display) { - LIMITED_METHOD_DAC_CONTRACT; - return (LPVOID)display->SP; -} - inline TADDR GetRegdisplayFP(REGDISPLAY *display) { LIMITED_METHOD_CONTRACT; return (TADDR)*(display->FramePtr); @@ -359,6 +299,49 @@ inline LPVOID GetRegdisplayStackMark(REGDISPLAY *display) { #endif +#if defined(_WIN64) || defined(_TARGET_ARM_) || (defined(_TARGET_X86_) && defined(WIN64EXCEPTIONS)) +// This needs to be implemented for platforms that have funclets. +inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display) +{ + LIMITED_METHOD_CONTRACT; + +#if defined(_TARGET_AMD64_) + return (LPVOID)display->pCurrentContext->Rax; +#elif defined(_TARGET_ARM64_) + return (LPVOID)display->pCurrentContext->X0; +#elif defined(_TARGET_ARM_) + return (LPVOID)display->pCurrentContext->R0; +#elif defined(_TARGET_X86_) + return (LPVOID)display->pCurrentContext->Eax; +#else + PORTABILITY_ASSERT("GetRegdisplayReturnValue NYI for this platform (Regdisp.h)"); + return NULL; +#endif +} + +inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD) +{ + LIMITED_METHOD_CONTRACT; + +#if defined(_WIN64) + pRD->SP = (INT_PTR)GetSP(pRD->pCurrentContext); + pRD->ControlPC = INT_PTR(GetIP(pRD->pCurrentContext)); +#elif defined(_TARGET_ARM_) // _WIN64 + pRD->SP = (DWORD)GetSP(pRD->pCurrentContext); + pRD->ControlPC = (DWORD)GetIP(pRD->pCurrentContext); +#elif defined(_TARGET_X86_) // _TARGET_ARM_ + pRD->SP = (DWORD)GetSP(pRD->pCurrentContext); + pRD->ControlPC = (DWORD)GetIP(pRD->pCurrentContext); +#else // _TARGET_X86_ + PORTABILITY_ASSERT("SyncRegDisplayToCurrentContext"); +#endif // _TARGET_ARM_ || _TARGET_X86_ + +#ifdef DEBUG_REGDISPLAY + CheckRegDisplaySP(pRD); +#endif // DEBUG_REGDISPLAY +} +#endif // _WIN64 || _TARGET_ARM_ || (_TARGET_X86_ && WIN64EXCEPTIONS) + typedef REGDISPLAY *PREGDISPLAY; @@ -368,6 +351,7 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC SUPPORTS_DAC; +#ifndef WIN64EXCEPTIONS #ifdef _TARGET_X86_ pRD->pContext = pctx; pRD->pContextForUnwind = NULL; @@ -378,23 +362,17 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC pRD->pEax = &(pctx->Eax); pRD->pEcx = &(pctx->Ecx); pRD->pEdx = &(pctx->Edx); - pRD->Esp = pctx->Esp; + pRD->SP = pctx->Esp; pRD->ControlPC = (PCODE)(pctx->Eip); pRD->PCTAddr = (UINT_PTR)&(pctx->Eip); -#elif defined(_WIN64) +#else // _TARGET_X86_ + PORTABILITY_ASSERT("FillRegDisplay"); +#endif // _TARGET_???_ (ELSE) + +#else // !WIN64EXCEPTIONS pRD->pContext = pctx; -#ifdef _TARGET_AMD64_ - for (int i = 0; i < 16; i++) - { - *(&pRD->ctxPtrsOne.Rax + i) = (&pctx->Rax + i); - } -#elif defined(_TARGET_ARM64_) - for (int i = 0; i < 12; i++) - { - *(&pRD->ctxPtrsOne.X19 + i) = (&pctx->X19 + i); - } -#endif // _TARGET_AMD64_ + // Setup the references pRD->pCurrentContextPointers = &pRD->ctxPtrsOne; pRD->pCallerContextPointers = &pRD->ctxPtrsTwo; @@ -417,46 +395,33 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC pRD->IsCallerSPValid = TRUE; // Don't add usage of this field. This is only temporary. } -#ifdef DEBUG_REGDISPLAY - pRD->_pThread = NULL; -#endif // DEBUG_REGDISPLAY - - SyncRegDisplayToCurrentContext(pRD); -#elif defined(_TARGET_ARM_) - pRD->pContext = pctx; - - // Copy over the nonvolatile integer registers (R4-R11) - for (int i = 0; i < 8; i++) +#ifdef _TARGET_AMD64_ + for (int i = 0; i < 16; i++) { - *(&pRD->ctxPtrsOne.R4 + i) = (&pctx->R4 + i); + *(&pRD->ctxPtrsOne.Rax + i) = (&pctx->Rax + i); } - - pRD->ctxPtrsOne.Lr = &pctx->Lr; - - // Setup the references - pRD->pCurrentContextPointers = &pRD->ctxPtrsOne; - pRD->pCallerContextPointers = &pRD->ctxPtrsTwo; - - pRD->pCurrentContext = &(pRD->ctxOne); - pRD->pCallerContext = &(pRD->ctxTwo); - - // copy the active context to initialize our stackwalk - *(pRD->pCurrentContext) = *(pctx); - - // copy the caller context as well if it's specified - if (pCallerCtx == NULL) +#elif defined(_TARGET_ARM64_) // _TARGET_AMD64_ + for (int i = 0; i < 12; i++) { - pRD->IsCallerContextValid = FALSE; - pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. + *(&pRD->ctxPtrsOne.X19 + i) = (&pctx->X19 + i); } - else +#elif defined(_TARGET_ARM_) // _TARGET_ARM64_ + // Copy over the nonvolatile integer registers (R4-R11) + for (int i = 0; i < 8; i++) { - *(pRD->pCallerContext) = *(pCallerCtx); - pRD->IsCallerContextValid = TRUE; - pRD->IsCallerSPValid = TRUE; // Don't add usage of this field. This is only temporary. + *(&pRD->ctxPtrsOne.R4 + i) = (&pctx->R4 + i); } + pRD->ctxPtrsOne.Lr = &pctx->Lr; pRD->pPC = &pRD->pCurrentContext->Pc; +#elif defined(_TARGET_X86_) // _TARGET_ARM_ + for (int i = 0; i < 7; i++) + { + *(&pRD->ctxPtrsOne.Esi + i) = (&pctx->Esi + i); + } +#else // _TARGET_X86_ + PORTABILITY_ASSERT("FillRegDisplay"); +#endif // _TARGET_???_ (ELSE) #ifdef DEBUG_REGDISPLAY pRD->_pThread = NULL; @@ -464,9 +429,7 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC // This will setup the PC and SP SyncRegDisplayToCurrentContext(pRD); -#else - PORTABILITY_ASSERT("@NYI Platform - InitRegDisplay (Threads.cpp)"); -#endif +#endif // !WIN64EXCEPTIONS } // Initialize a new REGDISPLAY/CONTEXT pair from an existing valid REGDISPLAY. @@ -479,7 +442,9 @@ inline void CopyRegDisplay(const PREGDISPLAY pInRD, PREGDISPLAY pOutRD, T_CONTEX T_CONTEXT* pOutCallerCtx = NULL; -#ifdef _TARGET_X86_ +#ifndef WIN64EXCEPTIONS + +#if defined(_TARGET_X86_) if (pInRD->pEdi != NULL) {pOutCtx->Edi = *pInRD->pEdi;} else {pInRD->pEdi = NULL;} if (pInRD->pEsi != NULL) {pOutCtx->Esi = *pInRD->pEsi;} else {pInRD->pEsi = NULL;} if (pInRD->pEbx != NULL) {pOutCtx->Ebx = *pInRD->pEbx;} else {pInRD->pEbx = NULL;} @@ -487,15 +452,21 @@ inline void CopyRegDisplay(const PREGDISPLAY pInRD, PREGDISPLAY pOutRD, T_CONTEX if (pInRD->pEax != NULL) {pOutCtx->Eax = *pInRD->pEax;} else {pInRD->pEax = NULL;} if (pInRD->pEcx != NULL) {pOutCtx->Ecx = *pInRD->pEcx;} else {pInRD->pEcx = NULL;} if (pInRD->pEdx != NULL) {pOutCtx->Edx = *pInRD->pEdx;} else {pInRD->pEdx = NULL;} - pOutCtx->Esp = pInRD->Esp; + pOutCtx->Esp = pInRD->SP; pOutCtx->Eip = pInRD->ControlPC; -#else +#else // _TARGET_X86_ + PORTABILITY_ASSERT("CopyRegDisplay"); +#endif // _TARGET_???_ + +#else // WIN64EXCEPTIONS + *pOutCtx = *(pInRD->pCurrentContext); if (pInRD->IsCallerContextValid) { pOutCallerCtx = pInRD->pCallerContext; } -#endif + +#endif // WIN64EXCEPTIONS if (pOutRD) FillRegDisplay(pOutRD, pOutCtx, pOutCallerCtx); @@ -562,6 +533,8 @@ inline void UpdateContextFromRegDisp(PREGDISPLAY pRegDisp, PT_CONTEXT pContext) { _ASSERTE((pRegDisp != NULL) && (pContext != NULL)); +#ifndef WIN64EXCEPTIONS + #if defined(_TARGET_X86_) pContext->ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL); pContext->Edi = *pRegDisp->pEdi; @@ -571,11 +544,17 @@ inline void UpdateContextFromRegDisp(PREGDISPLAY pRegDisp, PT_CONTEXT pContext) pContext->Eax = *pRegDisp->pEax; pContext->Ecx = *pRegDisp->pEcx; pContext->Edx = *pRegDisp->pEdx; - pContext->Esp = pRegDisp->Esp; + pContext->Esp = pRegDisp->SP; pContext->Eip = pRegDisp->ControlPC; -#else +#else // _TARGET_X86_ + PORTABILITY_ASSERT("UpdateContextFromRegDisp"); +#endif // _TARGET_???_ + +#else // WIN64EXCEPTIONS + *pContext = *pRegDisp->pCurrentContext; -#endif + +#endif // WIN64EXCEPTIONS } |