[x86/Linux] Fix GetCallerSp (dotnet/coreclr#9384)
authorJonghyun Park <parjong@gmail.com>
Fri, 17 Feb 2017 09:19:16 +0000 (18:19 +0900)
committerJan Vorlicek <janvorli@microsoft.com>
Fri, 17 Feb 2017 09:19:16 +0000 (10:19 +0100)
* [x86/Linux] Fix GetCallerSp

* Do NOT pop stack argument for TransitionFrame

* Add ResumeEsp to CONTEXT

Commit migrated from https://github.com/dotnet/coreclr/commit/00fc8f9f212bc00eda9c94707b50e278d9b8d7c4

src/coreclr/src/pal/inc/pal.h
src/coreclr/src/pal/src/arch/i386/asmconstants.h
src/coreclr/src/pal/src/arch/i386/context2.S
src/coreclr/src/pal/src/arch/i386/exceptionhelper.S
src/coreclr/src/pal/src/exception/seh-unwind.cpp
src/coreclr/src/pal/src/thread/context.cpp
src/coreclr/src/unwinder/i386/unwinder_i386.cpp
src/coreclr/src/vm/eetwain.cpp
src/coreclr/src/vm/i386/cgenx86.cpp

index d0b78e9..eedfbe7 100644 (file)
@@ -1782,6 +1782,7 @@ typedef struct _CONTEXT {
 
     UCHAR   ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
 
+    ULONG   ResumeEsp;
 } CONTEXT, *PCONTEXT, *LPCONTEXT;
 
 // To support saving and loading xmm register context we need to know the offset in the ExtendedRegisters
index ff763ef..d947cb8 100644 (file)
@@ -28,3 +28,4 @@
 #define CONTEXT_Xmm5 CONTEXT_Xmm4+16
 #define CONTEXT_Xmm6 CONTEXT_Xmm5+16
 #define CONTEXT_Xmm7 CONTEXT_Xmm6+16
+#define CONTEXT_ResumeEsp CONTEXT_ExtendedRegisters+512
index 11aba5e..16843c8 100644 (file)
@@ -42,6 +42,7 @@ LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
     mov   [eax + CONTEXT_Ebp], ebp
     lea   ebx, [esp + 12]
     mov   [eax + CONTEXT_Esp], ebx
+    mov   [eax + CONTEXT_ResumeEsp], ebx
     mov   ebx, [esp + 8]
     mov   [eax + CONTEXT_Eip], ebx
 
@@ -114,7 +115,7 @@ LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT):
 LOCAL_LABEL(Done_Restore_CONTEXT_EXTENDED_REGISTERS):
 
     // Restore Stack
-    mov   esp, [eax + CONTEXT_Esp]
+    mov   esp, [eax + CONTEXT_ResumeEsp]
 
     // Create a minimal frame
     push  DWORD PTR [eax + CONTEXT_Eip]
index 2061be2..4980b89 100644 (file)
@@ -23,7 +23,7 @@ LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
         mov   ebx, [esp + 8]  // eax: CONTEXT *
 
         mov   ebp, [ebx + CONTEXT_Ebp]
-        mov   esp, [ebx + CONTEXT_Esp]
+        mov   esp, [ebx + CONTEXT_ResumeEsp]
 
         // The ESP is re-initialized as the target frame's value, so the current function's
         // CFA is now right at the ESP.
index e3fa09f..aeb6fa4 100644 (file)
@@ -155,6 +155,7 @@ static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
 #elif defined(_X86_)
     unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Eip);
     unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Esp);
+    unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->ResumeEsp);
     unw_get_reg(cursor, UNW_X86_EBP, (unw_word_t *) &winContext->Ebp);
     unw_get_reg(cursor, UNW_X86_EBX, (unw_word_t *) &winContext->Ebx);
     unw_get_reg(cursor, UNW_X86_ESI, (unw_word_t *) &winContext->Esi);
index 0449df5..bee6ddd 100644 (file)
@@ -499,11 +499,13 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
     if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
     {
         ASSIGN_CONTROL_REGS
-#ifdef _ARM_
+#if defined(_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;
+#elif defined(_X86_)
+        lpContext->ResumeEsp = MCREG_Esp(native->uc_mcontext);
 #endif
     }
 
@@ -945,6 +947,7 @@ CONTEXT_GetThreadContextFromThreadState(
                 lpContext->Esi = pState->esi;
                 lpContext->Ebp = pState->ebp;
                 lpContext->Esp = pState->esp;
+                lpContext->ResumeEsp = pState->esp;
                 lpContext->SegSs = pState->ss;
                 lpContext->EFlags = pState->eflags;
                 lpContext->Eip = pState->eip;
index ca9e28e..4de2379 100644 (file)
@@ -76,6 +76,7 @@ OOPStackUnwinderX86::VirtualUnwind(
 
     FillRegDisplay(&rd, ContextRecord);
 
+    rd.SP = ContextRecord->ResumeEsp;
     rd.PCTAddr = (UINT_PTR)&(ContextRecord->Eip);
 
     if (ContextPointers)
@@ -104,7 +105,8 @@ OOPStackUnwinderX86::VirtualUnwind(
     ENUM_CALLEE_SAVED_REGISTERS();
 #undef CALLEE_SAVED_REGISTER
 
-    ContextRecord->Esp = rd.SP;
+    ContextRecord->Esp = rd.SP - codeInfo.GetCodeManager()->GetStackParameterSize(&codeInfo);
+    ContextRecord->ResumeEsp = rd.SP;
     ContextRecord->Eip = rd.ControlPC;
 
     // For x86, the value of Establisher Frame Pointer is Caller SP
index 340ea85..33ef29e 100644 (file)
@@ -3099,7 +3099,8 @@ size_t EECodeManager::GetCallerSp( PREGDISPLAY  pRD )
     {
         EnsureCallerContextIsValid(pRD, NULL);
     }
-    return (size_t) (GetSP(pRD->pCallerContext));
+
+    return GetSP(pRD->pCallerContext);
 }
 
 #endif // WIN64EXCEPTIONS && !CROSSGEN_COMPILE
index 2444fef..83bb255 100644 (file)
@@ -298,6 +298,7 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
 
     MethodDesc * pFunc = GetFunction();
     _ASSERTE(pFunc != NULL);
+
     UpdateRegDisplayHelper(pRD, pFunc->CbStackPop());
 
     LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK    TransitionFrame::UpdateRegDisplay(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP));
@@ -323,11 +324,14 @@ void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStack
 
 #ifdef WIN64EXCEPTIONS
 
+    DWORD CallerSP = (DWORD)(pRD->PCTAddr + sizeof(TADDR));
+
     pRD->IsCallerContextValid = FALSE;
     pRD->IsCallerSPValid      = FALSE;
 
     pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr);;
-    pRD->pCurrentContext->Esp = GetSP();
+    pRD->pCurrentContext->Esp = CallerSP;
+    pRD->pCurrentContext->ResumeEsp = CallerSP + cbStackPop;
 
     UpdateRegDisplayFromCalleeSavedRegisters(pRD, regs);
     ClearRegDisplayArgumentAndScratchRegisters(pRD);
@@ -380,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();
@@ -680,7 +684,8 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
     pRD->IsCallerSPValid      = FALSE;        // Don't add usage of this field.  This is only temporary.
 
     pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr);
-    pRD->pCurrentContext->Esp = (DWORD) dac_cast<TADDR>(m_pCallSiteSP) + stackArgSize;
+    pRD->pCurrentContext->Esp = (DWORD) dac_cast<TADDR>(m_pCallSiteSP);
+    pRD->pCurrentContext->ResumeEsp = (DWORD) dac_cast<TADDR>(m_pCallSiteSP) + stackArgSize;
     pRD->pCurrentContext->Ebp = (DWORD) m_pCalleeSavedFP;
 
     ClearRegDisplayArgumentAndScratchRegisters(pRD);
@@ -818,7 +823,7 @@ void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
     pRD->IsCallerSPValid      = FALSE;        // Don't add usage of this field.  This is only temporary.
 
     pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr);
-    pRD->pCurrentContext->Esp = (DWORD)(pRD->PCTAddr + sizeof(TADDR));
+    pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = (DWORD)(pRD->PCTAddr + sizeof(TADDR));
 
 #define RESTORE_REG(reg) { pRD->pCurrentContext->reg = m_Args->reg; pRD->pCurrentContextPointers->reg = &m_Args->reg; }
 #define CALLEE_SAVED_REGISTER(reg) RESTORE_REG(reg)
@@ -895,7 +900,7 @@ void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
     pRD->IsCallerSPValid      = FALSE;        // Don't add usage of this field.  This is only temporary.
 
     pRD->pCurrentContext->Eip = *PTR_PCODE(pRD->PCTAddr);
-    pRD->pCurrentContext->Esp = (DWORD)(pRD->PCTAddr + sizeof(TADDR));
+    pRD->pCurrentContext->Esp = pRD->pCurrentContext->ResumeEsp = (DWORD)(pRD->PCTAddr + sizeof(TADDR));
 
     UpdateRegDisplayFromCalleeSavedRegisters(pRD, &m_regs);
     ClearRegDisplayArgumentAndScratchRegisters(pRD);