};
+#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>
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;}
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);
{
_ASSERTE((pRegDisp != NULL) && (pContext != NULL));
+#ifndef WIN64EXCEPTIONS
+
#if defined(_TARGET_X86_)
pContext->ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL);
pContext->Edi = *pRegDisp->pEdi;
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
}
)
# 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})
--- /dev/null
+// 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
--- /dev/null
+// 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__
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;
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
/*****************************************************************************/
/* 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;
}
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;
-}
}
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);