From 25637ddb68b28563ffc271d8b2868e6ccfc07634 Mon Sep 17 00:00:00 2001 From: Jonghyun Park Date: Wed, 5 Apr 2017 16:22:07 +0900 Subject: [PATCH 1/3] [x86/Linux] Correctly unwind FCALL frames --- src/inc/eetwain.h | 5 +++- src/vm/eetwain.cpp | 44 ++++++++++++++++++++++++++++++++++++ src/vm/exceptionhandling.cpp | 11 +++++++++ src/vm/i386/cgenx86.cpp | 7 +++++- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/inc/eetwain.h b/src/inc/eetwain.h index 54e9a3446422..b0feae7e6700 100644 --- a/src/inc/eetwain.h +++ b/src/inc/eetwain.h @@ -652,7 +652,10 @@ HRESULT FixContextForEnC(PCONTEXT pCtx, #ifdef WIN64EXCEPTIONS static void EnsureCallerContextIsValid( PREGDISPLAY pRD, StackwalkCacheEntry* pCacheEntry, EECodeInfo * pCodeInfo = NULL ); static size_t GetCallerSp( PREGDISPLAY pRD ); -#endif +#ifdef _TARGET_X86_ + static size_t GetResumeSp( PREGDISPLAY pRD ); +#endif // _TARGET_X86_ +#endif // WIN64EXCEPTIONS #ifdef DACCESS_COMPILE virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp index aff250748983..717f0467d83b 100644 --- a/src/vm/eetwain.cpp +++ b/src/vm/eetwain.cpp @@ -4033,6 +4033,50 @@ bool UnwindStackFrame(PREGDISPLAY pContext, #endif // _TARGET_X86_ +#ifdef WIN64EXCEPTIONS +#ifdef _TARGET_X86_ +size_t EECodeManager::GetResumeSp( PREGDISPLAY pRD ) +{ + EECodeInfo codeInfo(pRD->ControlPC); + + PTR_CBYTE methodStart = PTR_CBYTE(codeInfo.GetSavedMethodCode()); + + GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken(); + PTR_VOID methodInfoPtr = gcInfoToken.Info; + DWORD curOffs = codeInfo.GetRelOffset(); + + CodeManStateBuf stateBuf; + + stateBuf.hdrInfoSize = (DWORD)DecodeGCHdrInfo(gcInfoToken, + curOffs, + &stateBuf.hdrInfoBody); + + PTR_CBYTE table = dac_cast(methodInfoPtr) + stateBuf.hdrInfoSize; + + hdrInfo *info = &stateBuf.hdrInfoBody; + + _ASSERTE(info->epilogOffs == hdrInfo::NOT_IN_EPILOG && info->prologOffs == hdrInfo::NOT_IN_PROLOG); + + bool isESPFrame = !info->ebpFrame && !info->doubleAlign; + + if (codeInfo.IsFunclet()) + { + // Treat funclet's frame as ESP frame + isESPFrame = true; + } + + if (isESPFrame) + { + const size_t curESP = pRD->SP; + return curESP + GetPushedArgSize(info, table, curOffs); + } + + const size_t curEBP = *pRD->GetEbpLocation(); + return GetOutermostBaseFP(curEBP, info); +} +#endif // _TARGET_X86_ +#endif // WIN64EXCEPTIONS + #ifndef CROSSGEN_COMPILE #ifndef WIN64EXCEPTIONS diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index 7e82cce604e4..e1088ba2c67f 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -441,6 +441,15 @@ void ExceptionTracker::UpdateNonvolatileRegisters(CONTEXT *pContextRecord, REGDI } \ } while (0) +#define UPDATEREG_VAL(reg) \ + do { \ + STRESS_LOG2(LF_GCROOTS, LL_INFO100, "Updating " #reg " %p to %p\n", \ + pContextRecord->reg, \ + pRegDisplay->pCurrentContext->reg); \ + pContextRecord->reg = pRegDisplay->pCurrentContext->reg; \ + } while (0) + + #if defined(_TARGET_X86_) UPDATEREG(Ebx); @@ -448,6 +457,8 @@ void ExceptionTracker::UpdateNonvolatileRegisters(CONTEXT *pContextRecord, REGDI UPDATEREG(Edi); UPDATEREG(Ebp); + UPDATEREG_VAL(ResumeEsp); + #elif defined(_TARGET_AMD64_) UPDATEREG(Rbx); diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp index 4c83265ff4a8..2703acca8ca6 100644 --- a/src/vm/i386/cgenx86.cpp +++ b/src/vm/i386/cgenx86.cpp @@ -384,7 +384,7 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif // DACCESS_COMPILE pRD->pCurrentContext->Eip = pRD->ControlPC = m_MachState.GetRetAddr(); - pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = pRD->SP = (DWORD) m_MachState.esp(); + pRD->pCurrentContext->Esp = pRD->SP = (DWORD) m_MachState.esp(); #define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *((DWORD*) m_MachState.p##regname()); ENUM_CALLEE_SAVED_REGISTERS(); @@ -402,6 +402,11 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) ClearRegDisplayArgumentAndScratchRegisters(pRD); + // + // Fix up ResumeSp + // + pRD->pCurrentContext->ResumeEsp = EECodeManager::GetResumeSp(pRD); + #else // WIN64EXCEPTIONS // reset pContext; it's only valid for active (top-most) frame From 21db4ced90542d140cde60af5d4acb15a17a0471 Mon Sep 17 00:00:00 2001 From: Jonghyun Park Date: Fri, 7 Apr 2017 13:33:06 +0900 Subject: [PATCH 2/3] Fix Up ResumeEsp inside ProcessCLRException --- src/inc/eetwain.h | 2 +- src/vm/eetwain.cpp | 12 ++++++++---- src/vm/exceptionhandling.cpp | 30 ++++++++++++++++++++---------- src/vm/i386/cgenx86.cpp | 7 +------ 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/inc/eetwain.h b/src/inc/eetwain.h index b0feae7e6700..497e0b0e6b0c 100644 --- a/src/inc/eetwain.h +++ b/src/inc/eetwain.h @@ -653,7 +653,7 @@ HRESULT FixContextForEnC(PCONTEXT pCtx, static void EnsureCallerContextIsValid( PREGDISPLAY pRD, StackwalkCacheEntry* pCacheEntry, EECodeInfo * pCodeInfo = NULL ); static size_t GetCallerSp( PREGDISPLAY pRD ); #ifdef _TARGET_X86_ - static size_t GetResumeSp( PREGDISPLAY pRD ); + static size_t GetResumeSp( PCONTEXT pContext ); #endif // _TARGET_X86_ #endif // WIN64EXCEPTIONS diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp index 717f0467d83b..42a1eae10d83 100644 --- a/src/vm/eetwain.cpp +++ b/src/vm/eetwain.cpp @@ -4035,9 +4035,13 @@ bool UnwindStackFrame(PREGDISPLAY pContext, #ifdef WIN64EXCEPTIONS #ifdef _TARGET_X86_ -size_t EECodeManager::GetResumeSp( PREGDISPLAY pRD ) +size_t EECodeManager::GetResumeSp( PCONTEXT pContext ) { - EECodeInfo codeInfo(pRD->ControlPC); + PCODE currentPc = PCODE(pContext->Eip); + + _ASSERTE(ExecutionManager::IsManagedCode(currentPc)); + + EECodeInfo codeInfo(currentPc); PTR_CBYTE methodStart = PTR_CBYTE(codeInfo.GetSavedMethodCode()); @@ -4067,11 +4071,11 @@ size_t EECodeManager::GetResumeSp( PREGDISPLAY pRD ) if (isESPFrame) { - const size_t curESP = pRD->SP; + const size_t curESP = (size_t)(pContext->Esp); return curESP + GetPushedArgSize(info, table, curOffs); } - const size_t curEBP = *pRD->GetEbpLocation(); + const size_t curEBP = (size_t)(pContext->Ebp); return GetOutermostBaseFP(curEBP, info); } #endif // _TARGET_X86_ diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index e1088ba2c67f..1a966e0a6f61 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -123,6 +123,24 @@ bool FixNonvolatileRegisters(UINT_PTR uOriginalSP, bool fAborting ); +void FixContext(PCONTEXT pContextRecord) +{ +#define FIXUPREG(reg, value) \ + do { \ + STRESS_LOG2(LF_GCROOTS, LL_INFO100, "Updating " #reg " %p to %p\n", \ + pContextRecord->reg, \ + (value)); \ + pContextRecord->reg = (value); \ + } while (0) + +#ifdef _TARGET_X86_ + size_t resumeSp = EECodeManager::GetResumeSp(pContextRecord); + FIXUPREG(ResumeEsp, resumeSp); +#endif // _TARGET_X86_ + +#undef FIXUPREG +} + MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDesc * pILStubMD, Frame ** ppFrameOut); #ifdef FEATURE_PAL @@ -441,14 +459,6 @@ void ExceptionTracker::UpdateNonvolatileRegisters(CONTEXT *pContextRecord, REGDI } \ } while (0) -#define UPDATEREG_VAL(reg) \ - do { \ - STRESS_LOG2(LF_GCROOTS, LL_INFO100, "Updating " #reg " %p to %p\n", \ - pContextRecord->reg, \ - pRegDisplay->pCurrentContext->reg); \ - pContextRecord->reg = pRegDisplay->pCurrentContext->reg; \ - } while (0) - #if defined(_TARGET_X86_) @@ -457,8 +467,6 @@ void ExceptionTracker::UpdateNonvolatileRegisters(CONTEXT *pContextRecord, REGDI UPDATEREG(Edi); UPDATEREG(Ebp); - UPDATEREG_VAL(ResumeEsp); - #elif defined(_TARGET_AMD64_) UPDATEREG(Rbx); @@ -1195,6 +1203,8 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord SetIP(pContextRecord, (PCODE)uResumePC); } + FixContext(pContextRecord); + #ifdef STACK_GUARDS_DEBUG // We are transitioning back to managed code, so ensure that we are in // SO-tolerant mode before we do so. diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp index 2703acca8ca6..4c83265ff4a8 100644 --- a/src/vm/i386/cgenx86.cpp +++ b/src/vm/i386/cgenx86.cpp @@ -384,7 +384,7 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif // DACCESS_COMPILE pRD->pCurrentContext->Eip = pRD->ControlPC = m_MachState.GetRetAddr(); - pRD->pCurrentContext->Esp = pRD->SP = (DWORD) m_MachState.esp(); + pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = pRD->SP = (DWORD) m_MachState.esp(); #define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *((DWORD*) m_MachState.p##regname()); ENUM_CALLEE_SAVED_REGISTERS(); @@ -402,11 +402,6 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) ClearRegDisplayArgumentAndScratchRegisters(pRD); - // - // Fix up ResumeSp - // - pRD->pCurrentContext->ResumeEsp = EECodeManager::GetResumeSp(pRD); - #else // WIN64EXCEPTIONS // reset pContext; it's only valid for active (top-most) frame From 955fbc28d1fc39a5ff5b399ba62c814bb90c7958 Mon Sep 17 00:00:00 2001 From: Jonghyun Park Date: Fri, 7 Apr 2017 16:46:27 +0900 Subject: [PATCH 3/3] Fix Context Before PC Update --- src/vm/exceptionhandling.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index 1a966e0a6f61..31b85bdb0add 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -1200,11 +1200,11 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord pThread->SetFrame(pLimitFrame); + FixContext(pContextRecord); + SetIP(pContextRecord, (PCODE)uResumePC); } - FixContext(pContextRecord); - #ifdef STACK_GUARDS_DEBUG // We are transitioning back to managed code, so ensure that we are in // SO-tolerant mode before we do so.