summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/inc/eetwain.h7
-rw-r--r--src/inc/regdisp.h26
-rw-r--r--src/unwinder/CMakeLists.txt10
-rw-r--r--src/unwinder/i386/unwinder_i386.cpp205
-rw-r--r--src/unwinder/i386/unwinder_i386.h33
-rw-r--r--src/vm/eetwain.cpp43
-rw-r--r--src/vm/i386/cgenx86.cpp20
-rw-r--r--src/vm/i386/unixstubs.cpp19
-rw-r--r--src/vm/stackwalk.cpp4
9 files changed, 319 insertions, 48 deletions
diff --git a/src/inc/eetwain.h b/src/inc/eetwain.h
index 55cc905576..1d195d77d4 100644
--- a/src/inc/eetwain.h
+++ b/src/inc/eetwain.h
@@ -613,6 +613,13 @@ HRESULT FixContextForEnC(PCONTEXT pCtx,
};
+#ifdef _TARGET_X86_
+bool UnwindStackFrame(PREGDISPLAY pContext,
+ EECodeInfo *pCodeInfo,
+ unsigned flags,
+ CodeManState *pState,
+ StackwalkCacheUnwindInfo *pUnwindInfo);
+#endif
/*****************************************************************************
<TODO>ToDo: Do we want to include JIT/IL/target.h? </TODO>
diff --git a/src/inc/regdisp.h b/src/inc/regdisp.h
index 81143466cd..68060007d1 100644
--- a/src/inc/regdisp.h
+++ b/src/inc/regdisp.h
@@ -489,7 +489,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;}
@@ -499,13 +501,19 @@ inline void CopyRegDisplay(const PREGDISPLAY pInRD, PREGDISPLAY pOutRD, T_CONTEX
if (pInRD->pEdx != NULL) {pOutCtx->Edx = *pInRD->pEdx;} else {pInRD->pEdx = NULL;}
pOutCtx->Esp = pInRD->Esp;
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);
@@ -572,6 +580,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;
@@ -583,9 +593,15 @@ inline void UpdateContextFromRegDisp(PREGDISPLAY pRegDisp, PT_CONTEXT pContext)
pContext->Edx = *pRegDisp->pEdx;
pContext->Esp = pRegDisp->Esp;
pContext->Eip = pRegDisp->ControlPC;
-#else
+#else // _TARGET_X86_
+ PORTABILITY_ASSERT("UpdateContextFromRegDisp");
+#endif // _TARGET_???_
+
+#else // WIN64EXCEPTIONS
+
*pContext = *pRegDisp->pCurrentContext;
-#endif
+
+#endif // WIN64EXCEPTIONS
}
diff --git a/src/unwinder/CMakeLists.txt b/src/unwinder/CMakeLists.txt
index bf1cfa2938..5cd7bae337 100644
--- a/src/unwinder/CMakeLists.txt
+++ b/src/unwinder/CMakeLists.txt
@@ -12,12 +12,10 @@ set(UNWINDER_SOURCES
)
# Include platform specific unwinder for applicable (native and cross-target) builds.
-if(NOT DEFINED CLR_CMAKE_TARGET_ARCH_I386)
- include_directories(${ARCH_SOURCES_DIR})
- list(APPEND UNWINDER_SOURCES
- ${ARCH_SOURCES_DIR}/unwinder_${ARCH_SOURCES_DIR}.cpp
- )
-endif()
+include_directories(${ARCH_SOURCES_DIR})
+list(APPEND UNWINDER_SOURCES
+ ${ARCH_SOURCES_DIR}/unwinder_${ARCH_SOURCES_DIR}.cpp
+)
convert_to_absolute_path(UNWINDER_SOURCES ${UNWINDER_SOURCES})
diff --git a/src/unwinder/i386/unwinder_i386.cpp b/src/unwinder/i386/unwinder_i386.cpp
new file mode 100644
index 0000000000..8d2ea53793
--- /dev/null
+++ b/src/unwinder/i386/unwinder_i386.cpp
@@ -0,0 +1,205 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+#include "stdafx.h"
+#include "unwinder_i386.h"
+
+#ifdef WIN64EXCEPTIONS
+/*++
+
+Routine Description:
+
+ This function virtually unwinds the specified function by executing its
+ prologue code backward or its epilogue code forward.
+
+ If a context pointers record is specified, then the address where each
+ nonvolatile registers is restored from is recorded in the appropriate
+ element of the context pointers record.
+
+Arguments:
+
+ HandlerType - Supplies the handler type expected for the virtual unwind.
+ This may be either an exception or an unwind handler. A flag may
+ optionally be supplied to avoid epilogue detection if it is known
+ the specified control PC is not located inside a function epilogue.
+
+ ImageBase - Supplies the base address of the image that contains the
+ function being unwound.
+
+ ControlPc - Supplies the address where control left the specified
+ function.
+
+ FunctionEntry - Supplies the address of the function table entry for the
+ specified function.
+
+ ContextRecord - Supplies the address of a context record.
+
+
+ HandlerData - Supplies a pointer to a variable that receives a pointer
+ the the language handler data.
+
+ EstablisherFrame - Supplies a pointer to a variable that receives the
+ the establisher frame pointer value.
+
+ ContextPointers - Supplies an optional pointer to a context pointers
+ record.
+
+ HandlerRoutine - Supplies an optional pointer to a variable that receives
+ the handler routine address. If control did not leave the specified
+ function in either the prologue or an epilogue and a handler of the
+ proper type is associated with the function, then the address of the
+ language specific exception handler is returned. Otherwise, NULL is
+ returned.
+--*/
+HRESULT
+OOPStackUnwinderX86::VirtualUnwind(
+ __in DWORD HandlerType,
+ __in DWORD ImageBase,
+ __in DWORD ControlPc,
+ __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
+ __inout PCONTEXT ContextRecord,
+ __out PVOID *HandlerData,
+ __out PDWORD EstablisherFrame,
+ __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
+ __deref_opt_out_opt PEXCEPTION_ROUTINE *HandlerRoutine
+ )
+{
+ *EstablisherFrame = ContextRecord->Esp;
+ if (HandlerRoutine != NULL)
+ {
+ *HandlerRoutine = NULL;
+ }
+
+ REGDISPLAY rd;
+
+ if (ContextPointers != NULL)
+ {
+#define CALLEE_SAVED_REGISTER(reg) rd.p##reg = ContextPointers->reg;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
+ }
+ else
+ {
+#define CALLEE_SAVED_REGISTER(reg) rd.p##reg = NULL;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
+ }
+
+ if (rd.pEbp == NULL)
+ {
+ rd.pEbp = &(ContextRecord->Ebp);
+ }
+ rd.Esp = ContextRecord->Esp;
+ rd.ControlPC = (PCODE)(ContextRecord->Eip);
+ rd.PCTAddr = (UINT_PTR)&(ContextRecord->Eip);
+
+ CodeManState codeManState;
+ codeManState.dwIsSet = 0;
+
+ EECodeInfo codeInfo;
+ codeInfo.Init((PCODE) ControlPc);
+
+ if (!UnwindStackFrame(&rd, &codeInfo, UpdateAllRegs, &codeManState, NULL))
+ {
+ return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
+ }
+
+#define CALLEE_SAVED_REGISTER(reg) if (rd.p##reg != NULL) { ContextRecord->reg = *rd.p##reg; }
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
+
+ if (ContextPointers != NULL)
+ {
+#define CALLEE_SAVED_REGISTER(reg) if (rd.p##reg != &(ContextRecord->reg)) { ContextPointers->reg = rd.p##reg; }
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
+ }
+
+ ContextRecord->Esp = rd.Esp;
+ ContextRecord->Eip = rd.ControlPC;
+ ContextRecord->Ebp = *rd.pEbp;
+
+ return S_OK;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// This function behaves like the RtlVirtualUnwind in Windows.
+// It virtually unwinds the specified function by executing its
+// prologue code backward or its epilogue code forward.
+//
+// If a context pointers record is specified, then the address where each
+// nonvolatile registers is restored from is recorded in the appropriate
+// element of the context pointers record.
+//
+// Arguments:
+//
+// HandlerType - Supplies the handler type expected for the virtual unwind.
+// This may be either an exception or an unwind handler. A flag may
+// optionally be supplied to avoid epilogue detection if it is known
+// the specified control PC is not located inside a function epilogue.
+//
+// ImageBase - Supplies the base address of the image that contains the
+// function being unwound.
+//
+// ControlPc - Supplies the address where control left the specified
+// function.
+//
+// FunctionEntry - Supplies the address of the function table entry for the
+// specified function.
+//
+// ContextRecord - Supplies the address of a context record.
+//
+// HandlerData - Supplies a pointer to a variable that receives a pointer
+// the the language handler data.
+//
+// EstablisherFrame - Supplies a pointer to a variable that receives the
+// the establisher frame pointer value.
+//
+// ContextPointers - Supplies an optional pointer to a context pointers
+// record.
+//
+// Return value:
+//
+// The handler routine address. If control did not leave the specified
+// function in either the prologue or an epilogue and a handler of the
+// proper type is associated with the function, then the address of the
+// language specific exception handler is returned. Otherwise, NULL is
+// returned.
+//
+EXTERN_C
+NTSYSAPI
+PEXCEPTION_ROUTINE
+NTAPI
+RtlVirtualUnwind (
+ __in DWORD HandlerType,
+ __in DWORD ImageBase,
+ __in DWORD ControlPc,
+ __in PRUNTIME_FUNCTION FunctionEntry,
+ __inout PT_CONTEXT ContextRecord,
+ __out PVOID *HandlerData,
+ __out PDWORD EstablisherFrame,
+ __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
+ )
+{
+ PEXCEPTION_ROUTINE handlerRoutine;
+
+ HRESULT res = OOPStackUnwinderX86::VirtualUnwind(
+ HandlerType,
+ ImageBase,
+ ControlPc,
+ (_PIMAGE_RUNTIME_FUNCTION_ENTRY)FunctionEntry,
+ ContextRecord,
+ HandlerData,
+ EstablisherFrame,
+ ContextPointers,
+ &handlerRoutine);
+
+ _ASSERTE(SUCCEEDED(res));
+
+ return handlerRoutine;
+}
+#endif // WIN64EXCEPTIONS
diff --git a/src/unwinder/i386/unwinder_i386.h b/src/unwinder/i386/unwinder_i386.h
new file mode 100644
index 0000000000..bed30bf894
--- /dev/null
+++ b/src/unwinder/i386/unwinder_i386.h
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+#ifndef __unwinder_i386_h__
+#define __unwinder_i386_h__
+
+#include "unwinder.h"
+
+#ifdef WIN64EXCEPTIONS
+//---------------------------------------------------------------------------------------
+//
+// See the comment for the base class code:OOPStackUnwinder.
+//
+
+class OOPStackUnwinderX86 : public OOPStackUnwinder
+{
+public:
+ static HRESULT VirtualUnwind(__in DWORD HandlerType,
+ __in DWORD ImageBase,
+ __in DWORD ControlPc,
+ __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
+ __inout PCONTEXT ContextRecord,
+ __out PVOID *HandlerData,
+ __out PDWORD EstablisherFrame,
+ __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
+ __deref_opt_out_opt PEXCEPTION_ROUTINE *HandlerRoutine);
+};
+#endif // WIN64EXCEPTIONS
+
+#endif // __unwinder_i386_h__
diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp
index 16b9de457f..81a5a0a4b9 100644
--- a/src/vm/eetwain.cpp
+++ b/src/vm/eetwain.cpp
@@ -3884,21 +3884,11 @@ bool UnwindEbpDoubleAlignFrame(
return true;
}
-/*****************************************************************************
- *
- * Unwind the current stack frame, i.e. update the virtual register
- * set in pContext. This will be similar to the state after the function
- * returns back to caller (IP points to after the call, Frame and Stack
- * pointer has been reset, callee-saved registers restored (if UpdateAllRegs),
- * callee-unsaved registers are trashed.
- * Returns success of operation.
- */
-
-bool EECodeManager::UnwindStackFrame(PREGDISPLAY pContext,
- EECodeInfo *pCodeInfo,
- unsigned flags,
- CodeManState *pState,
- StackwalkCacheUnwindInfo *pUnwindInfo /* out-only, perf improvement */)
+bool UnwindStackFrame(PREGDISPLAY pContext,
+ EECodeInfo *pCodeInfo,
+ unsigned flags,
+ CodeManState *pState,
+ StackwalkCacheUnwindInfo *pUnwindInfo /* out-only, perf improvement */)
{
CONTRACTL {
NOTHROW;
@@ -3991,6 +3981,29 @@ bool EECodeManager::UnwindStackFrame(PREGDISPLAY pContext,
return true;
}
+#endif // _TARGET_X86_
+
+#if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
+
+/*****************************************************************************
+ *
+ * Unwind the current stack frame, i.e. update the virtual register
+ * set in pContext. This will be similar to the state after the function
+ * returns back to caller (IP points to after the call, Frame and Stack
+ * pointer has been reset, callee-saved registers restored (if UpdateAllRegs),
+ * callee-unsaved registers are trashed.
+ * Returns success of operation.
+ */
+
+bool EECodeManager::UnwindStackFrame(PREGDISPLAY pContext,
+ EECodeInfo *pCodeInfo,
+ unsigned flags,
+ CodeManState *pState,
+ StackwalkCacheUnwindInfo *pUnwindInfo /* out-only, perf improvement */)
+{
+ return ::UnwindStackFrame(pContext, pCodeInfo, flags, pState, pUnwindInfo);
+}
+
/*****************************************************************************/
#elif !defined(CROSSGEN_COMPILE) // _TARGET_X86_ - UnwindStackFrame
/*****************************************************************************/
diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp
index 55f8459d5c..477ef209a6 100644
--- a/src/vm/i386/cgenx86.cpp
+++ b/src/vm/i386/cgenx86.cpp
@@ -590,6 +590,26 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
/* Now we need to pop off the outgoing arguments */
pRD->Esp = (DWORD) dac_cast<TADDR>(m_pCallSiteSP) + stackArgSize;
+
+#ifdef WIN64EXCEPTIONS
+ pRD->IsCallerContextValid = FALSE;
+ pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
+
+ pRD->pCurrentContext->Eip = pRD->ControlPC;
+ pRD->pCurrentContext->Esp = pRD->Esp;
+ pRD->pCurrentContext->Ebp = *pRD->pEbp;
+
+#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContextPointers->regname = NULL;
+ ENUM_CALLEE_SAVED_REGISTERS();
+#undef CALLEE_SAVED_REGISTER
+
+ pRD->pCurrentContextPointers->Ebp = pRD->pEbp;
+
+ SyncRegDisplayToCurrentContext(pRD);
+#endif
+
+ LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->Esp));
+
RETURN;
}
diff --git a/src/vm/i386/unixstubs.cpp b/src/vm/i386/unixstubs.cpp
index 4025c26216..cb08f276fe 100644
--- a/src/vm/i386/unixstubs.cpp
+++ b/src/vm/i386/unixstubs.cpp
@@ -103,22 +103,3 @@ RtlpGetFunctionEndAddress (
PORTABILITY_ASSERT("RtlpGetFunctionEndAddress");
return 0;
}
-
-EXTERN_C
-NTSYSAPI
-PEXCEPTION_ROUTINE
-NTAPI
-RtlVirtualUnwind (
- __in DWORD HandlerType,
- __in DWORD ImageBase,
- __in DWORD ControlPc,
- __in PRUNTIME_FUNCTION FunctionEntry,
- __inout PT_CONTEXT ContextRecord,
- __out PVOID *HandlerData,
- __out PDWORD EstablisherFrame,
- __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
- )
-{
- PORTABILITY_ASSERT("RtlVirtualUnwind");
- return NULL;
-}
diff --git a/src/vm/stackwalk.cpp b/src/vm/stackwalk.cpp
index 44e5f99640..3e74dfd3eb 100644
--- a/src/vm/stackwalk.cpp
+++ b/src/vm/stackwalk.cpp
@@ -561,9 +561,7 @@ UINT_PTR Thread::VirtualUnwindCallFrame(PREGDISPLAY pRD, EECodeInfo* pCodeInfo /
}
else
{
- PT_KNONVOLATILE_CONTEXT_POINTERS pCurrentContextPointers = NULL;
- NOT_X86(pCurrentContextPointers = pRD->pCurrentContextPointers);
- VirtualUnwindCallFrame(pRD->pCurrentContext, pCurrentContextPointers, pCodeInfo);
+ VirtualUnwindCallFrame(pRD->pCurrentContext, pRD->pCurrentContextPointers, pCodeInfo);
}
SyncRegDisplayToCurrentContext(pRD);