[x86/Linux] Fix ResumeEsp before resume (#10749)
authorJonghyun Park <parjong@gmail.com>
Wed, 12 Apr 2017 22:09:33 +0000 (07:09 +0900)
committerJan Vorlicek <janvorli@microsoft.com>
Wed, 12 Apr 2017 22:09:33 +0000 (00:09 +0200)
* [x86/Linux] Correctly unwind FCALL frames

* Fix Up ResumeEsp inside ProcessCLRException

* Fix Context Before PC Update

src/inc/eetwain.h
src/vm/eetwain.cpp
src/vm/exceptionhandling.cpp

index 54e9a34..497e0b0 100644 (file)
@@ -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( PCONTEXT  pContext );
+#endif // _TARGET_X86_
+#endif // WIN64EXCEPTIONS
 
 #ifdef DACCESS_COMPILE
     virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
index 2c9059b..2886daa 100644 (file)
@@ -4048,6 +4048,54 @@ bool UnwindStackFrame(PREGDISPLAY     pContext,
 
 #endif // _TARGET_X86_
 
+#ifdef WIN64EXCEPTIONS
+#ifdef _TARGET_X86_
+size_t EECodeManager::GetResumeSp( PCONTEXT  pContext )
+{
+    PCODE currentPc = PCODE(pContext->Eip);
+
+    _ASSERTE(ExecutionManager::IsManagedCode(currentPc));
+
+    EECodeInfo codeInfo(currentPc);
+
+    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<PTR_CBYTE>(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 = (size_t)(pContext->Esp);
+        return curESP + GetPushedArgSize(info, table, curOffs);
+    }
+
+    const size_t curEBP = (size_t)(pContext->Ebp);
+    return GetOutermostBaseFP(curEBP, info);
+}
+#endif // _TARGET_X86_
+#endif // WIN64EXCEPTIONS
+
 #ifndef CROSSGEN_COMPILE
 #ifndef WIN64EXCEPTIONS
 
index 7e82cce..31b85bd 100644 (file)
@@ -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,6 +459,7 @@ void ExceptionTracker::UpdateNonvolatileRegisters(CONTEXT *pContextRecord, REGDI
         }                                                                                   \
     } while (0)
 
+
 #if defined(_TARGET_X86_)
 
     UPDATEREG(Ebx);
@@ -1181,6 +1200,8 @@ ProcessCLRException(IN     PEXCEPTION_RECORD   pExceptionRecord
 
                 pThread->SetFrame(pLimitFrame);
 
+                FixContext(pContextRecord);
+
                 SetIP(pContextRecord, (PCODE)uResumePC);
             }