diff --git a/docs/design/datacontracts/data_descriptor.md b/docs/design/datacontracts/data_descriptor.md index 0cc24d14f81086..1f8533517d3d20 100644 --- a/docs/design/datacontracts/data_descriptor.md +++ b/docs/design/datacontracts/data_descriptor.md @@ -335,7 +335,6 @@ The baseline is given in the "regular" format. } ], "globals": [ - { "name": "FEATURE_EH_FUNCLETS", "type": "uint8", "value": "0" }, // baseline defaults value to 0 { "name": "FEATURE_COMINTEROP", "type": "uint8", "value": "1"}, { "name": "s_pThreadStore", "type": "pointer" } // no baseline value ] @@ -383,12 +382,10 @@ And the globals will be: | Name | Type | Value | | ------------------- | ------- | ---------- | | FEATURE_COMINTEROP | uint8 | 0 | -| FEATURE_EH_FUNCLETS | uint8 | 0 | | s_pThreadStore | pointer | 0x0100ffe0 | | RuntimeID | string |"windows-x64"| -The `FEATURE_EH_FUNCLETS` global's value comes from the baseline - not the in-memory data -descriptor. By contrast, `FEATURE_COMINTEROP` comes from the in-memory data descriptor - with the -value embedded directly in the json since it is known at build time and does not vary. Finally the +The `FEATURE_COMINTEROP` comes from the in-memory data descriptor - with the +value embedded directly in the json since it is known at build time and does not vary. The value of the pointer `s_pThreadStore` comes from the auxiliary vector's offset 0 since it is an execution-time value that is only known to the running process. diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props index 6d652a0b66d955..1a07f0aa7c1225 100644 --- a/src/coreclr/clr.featuredefines.props +++ b/src/coreclr/clr.featuredefines.props @@ -2,7 +2,6 @@ true true - true false false true @@ -54,7 +53,6 @@ $(DefineConstants);FEATURE_PERFTRACING $(DefineConstants);FEATURE_EVENTSOURCE_XPLAT $(DefineConstants);FEATURE_TYPEEQUIVALENCE - $(DefineConstants);FEATURE_EH_FUNCLETS $(DefineConstants);FEATURE_INTERPRETER $(DefineConstants);FEATURE_PORTABLE_ENTRYPOINTS $(DefineConstants);FEATURE_PORTABLE_HELPERS diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index c83f4c3762a2ae..3811b7844d2d68 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -202,8 +202,6 @@ if(CLR_CMAKE_TARGET_WIN32) endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386) endif(CLR_CMAKE_TARGET_WIN32) -add_compile_definitions($<$>>:FEATURE_EH_FUNCLETS>) - if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64)) add_definitions(-DFEATURE_SPECIAL_USER_MODE_APC) endif() diff --git a/src/coreclr/cpp.hint b/src/coreclr/cpp.hint index 1eb32d3f9da824..7f73541d18cadf 100644 --- a/src/coreclr/cpp.hint +++ b/src/coreclr/cpp.hint @@ -26,21 +26,6 @@ #define PAL_ENDTRY #define PAL_EXCEPT_FILTER(x) #define PAL_TRY(x, y, z) -#define _EXCEPTION_HANDLER_DECL(funcname) \ - EXCEPTION_DISPOSITION __cdecl funcname(EXCEPTION_RECORD *pExceptionRecord, \ - struct _EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, \ - CONTEXT *pContext, \ - DISPATCHER_CONTEXT *pDispatcherContext) - -#define EXCEPTION_HANDLER_DECL(funcname) \ - extern "C" _EXCEPTION_HANDLER_DECL(funcname) - -#define EXCEPTION_HANDLER_IMPL(funcname) \ - _EXCEPTION_HANDLER_DECL(funcname) - -#define EXCEPTION_HANDLER_FWD(funcname) \ - funcname(pExceptionRecord, pEstablisherFrame, pContext, pDispatcherContext) - // DAC #define GVAL_ADDR(g) (&(g)) diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 2de903dc3b232a..46ebb2dd7e85c7 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: daccess.cpp -// - // // ClrDataAccess implementation. -// //***************************************************************************** #include "stdafx.h" @@ -7816,10 +7814,7 @@ void DacStackReferenceWalker::WalkStack() // Walk the stack, set mEnumerated to true to ensure we don't do it again. unsigned int flagsStackWalk = ALLOW_INVALID_OBJECTS|ALLOW_ASYNC_STACK_WALK|SKIP_GSCOOKIE_CHECK; - -#if defined(FEATURE_EH_FUNCLETS) flagsStackWalk |= GC_FUNCLET_REFERENCE_REPORTING; -#endif // defined(FEATURE_EH_FUNCLETS) // Pre-set mEnumerated in case we hit an unexpected exception. We don't want to // keep walking stack frames if we hit a failure @@ -7984,12 +7979,10 @@ StackWalkAction DacStackReferenceWalker::Callback(CrawlFrame *pCF, VOID *pData) gcctx->cf = pCF; bool fReportGCReferences = true; -#if defined(FEATURE_EH_FUNCLETS) // On Win64 and ARM, we may have unwound this crawlFrame and thus, shouldn't report the invalid // references it may contain. // todo. fReportGCReferences = pCF->ShouldCrawlframeReportGCReferences(); -#endif // defined(FEATURE_EH_FUNCLETS) Frame *pFrame = ((DacScanContext*)gcctx->sc)->pFrame = pCF->GetFrame(); diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index dc13cf59a7f006..d90028dbdfce90 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -23,9 +23,7 @@ #include "interpexec.h" #endif // FEATURE_INTERPRETER -#ifdef FEATURE_EH_FUNCLETS #include "exinfo.h" -#endif // FEATURE_EH_FUNCLETS typedef IDacDbiInterface::StackWalkHandle StackWalkHandle; @@ -269,7 +267,6 @@ BOOL DacDbiInterfaceImpl::UnwindStackWalkFrame(StackWalkHandle pSFIHandle) // Just continue onto the next managed stack frame. continue; } -#ifdef FEATURE_EH_FUNCLETS else if (pIter->GetFrameState() == StackFrameIterator::SFITER_FRAMELESS_METHOD) { // Skip the new exception handling managed code, the debugger clients are not supposed to see them @@ -283,7 +280,6 @@ BOOL DacDbiInterfaceImpl::UnwindStackWalkFrame(StackWalkHandle pSFIHandle) fIsAtEndOfStack = FALSE; } -#endif // FEATURE_EH_FUNCLETS else { fIsAtEndOfStack = FALSE; @@ -383,7 +379,6 @@ IDacDbiInterface::FrameType DacDbiInterfaceImpl::GetStackWalkCurrentFrameInfo(St case StackFrameIterator::SFITER_FRAMELESS_METHOD: { -#ifdef FEATURE_EH_FUNCLETS MethodDesc *pMD = pIter->m_crawl.GetFunction(); // EH.DispatchEx, EH.RhThrowEx, EH.RhThrowHwEx, ExceptionServices.InternalCalls.SfiInit, ExceptionServices.InternalCalls.SfiNext if (pMD->GetMethodTable() == g_pEHClass || pMD->GetMethodTable() == g_pExceptionServicesInternalCallsClass) @@ -391,7 +386,6 @@ IDacDbiInterface::FrameType DacDbiInterfaceImpl::GetStackWalkCurrentFrameInfo(St ftResult = kManagedExceptionHandlingCodeFrame; } else -#endif // FEATURE_EH_FUNCLETS { ftResult = kManagedStackFrame; fInitFrameData = TRUE; @@ -469,7 +463,6 @@ ULONG32 DacDbiInterfaceImpl::GetCountOfInternalFrames(VMPTR_Thread vmThread) ULONG32 uCount = 0; while (pFrame != FRAME_TOP) { -#ifdef FEATURE_EH_FUNCLETS if (InlinedCallFrame::FrameHasActiveCall(pFrame)) { // Skip new exception handling helpers @@ -482,7 +475,6 @@ ULONG32 DacDbiInterfaceImpl::GetCountOfInternalFrames(VMPTR_Thread vmThread) continue; } } -#endif // FEATURE_EH_FUNCLETS CorDebugInternalFrameType ift = GetInternalFrameType(pFrame); if (ift != STUBFRAME_NONE) { @@ -522,7 +514,6 @@ void DacDbiInterfaceImpl::EnumerateInternalFrames(VMPTR_Thread while (pFrame != FRAME_TOP) { -#ifdef FEATURE_EH_FUNCLETS if (InlinedCallFrame::FrameHasActiveCall(pFrame)) { // Skip new exception handling helpers @@ -535,7 +526,6 @@ void DacDbiInterfaceImpl::EnumerateInternalFrames(VMPTR_Thread continue; } } -#endif // FEATURE_EH_FUNCLETS // check if the internal frame is interesting frameData.stubFrame.frameType = GetInternalFrameType(pFrame); if (frameData.stubFrame.frameType != STUBFRAME_NONE) @@ -617,7 +607,6 @@ BOOL DacDbiInterfaceImpl::IsMatchingParentFrame(FramePointer fpToCheck, FramePoi { DD_ENTER_MAY_THROW; -#ifdef FEATURE_EH_FUNCLETS StackFrame sfToCheck = StackFrame((UINT_PTR)fpToCheck.GetSPValue()); StackFrame sfParent = StackFrame((UINT_PTR)fpParent.GetSPValue()); @@ -625,11 +614,6 @@ BOOL DacDbiInterfaceImpl::IsMatchingParentFrame(FramePointer fpToCheck, FramePoi // Ask the ExInfo to figure out the answer. // Don't try to compare the StackFrames/FramePointers ourselves. return ExInfo::IsUnwoundToTargetParentFrame(sfToCheck, sfParent); - -#else // !FEATURE_EH_FUNCLETS - return FALSE; - -#endif // FEATURE_EH_FUNCLETS } // Return the stack parameter size of the given method. @@ -971,7 +955,6 @@ void DacDbiInterfaceImpl::InitNativeCodeAddrAndSize(TADDR t void DacDbiInterfaceImpl::InitParentFrameInfo(CrawlFrame * pCF, DebuggerIPCE_JITFuncData * pJITFuncData) { -#ifdef FEATURE_EH_FUNCLETS pJITFuncData->fIsFilterFrame = pCF->IsFilterFunclet(); if (pCF->IsFunclet()) @@ -1001,7 +984,6 @@ void DacDbiInterfaceImpl::InitParentFrameInfo(CrawlFrame * pCF, pJITFuncData->fpParentOrSelf = FramePointer::MakeFramePointer(sfSelf.SP); pJITFuncData->parentNativeOffset = 0; } -#endif // FEATURE_EH_FUNCLETS } // Return the stack parameter size of the given method. @@ -1213,31 +1195,7 @@ CorDebugInternalFrameType DacDbiInterfaceImpl::GetInternalFrameType(Frame * pFra void DacDbiInterfaceImpl::UpdateContextFromRegDisp(REGDISPLAY * pRegDisp, T_CONTEXT * pContext) { -#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) - // Do a partial copy first. - pContext->ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL); - - pContext->Edi = *pRegDisp->GetEdiLocation(); - pContext->Esi = *pRegDisp->GetEsiLocation(); - pContext->Ebx = *pRegDisp->GetEbxLocation(); - pContext->Ebp = *pRegDisp->GetEbpLocation(); - pContext->Eax = *pRegDisp->GetEaxLocation(); - pContext->Ecx = *pRegDisp->GetEcxLocation(); - pContext->Edx = *pRegDisp->GetEdxLocation(); - pContext->Esp = pRegDisp->SP; - pContext->Eip = pRegDisp->ControlPC; - - // If we still have the pointer to the leaf CONTEXT, and the leaf CONTEXT is the same as the CONTEXT for - // the current frame (i.e. the stackwalker is at the leaf frame), then we do a full copy. - if ((pRegDisp->pContext != NULL) && - (CompareControlRegisters(const_cast(reinterpret_cast(pContext)), - const_cast(reinterpret_cast(pRegDisp->pContext))))) - { - *pContext = *pRegDisp->pContext; - } -#else // TARGET_X86 && !FEATURE_EH_FUNCLETS *pContext = *pRegDisp->pCurrentContext; -#endif // !TARGET_X86 || FEATURE_EH_FUNCLETS } //--------------------------------------------------------------------------------------- diff --git a/src/coreclr/debug/daccess/enummem.cpp b/src/coreclr/debug/daccess/enummem.cpp index 88737aee527c82..338e885f67f3a6 100644 --- a/src/coreclr/debug/daccess/enummem.cpp +++ b/src/coreclr/debug/daccess/enummem.cpp @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: enummem.cpp -// - // // ICLRDataEnumMemoryRegions implementation. -// //***************************************************************************** #include "stdafx.h" @@ -974,7 +972,7 @@ HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags, // back to source lines for functions on stacks is very useful and we don't // want to allow the function to fail for all targets. -#if defined(FEATURE_EH_FUNCLETS) && defined(USE_GC_INFO_DECODER) +#if defined(USE_GC_INFO_DECODER) if (addr != (PCODE)NULL) { @@ -995,7 +993,7 @@ HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags, } } } -#endif // FEATURE_EH_FUNCLETS && USE_GC_INFO_DECODER +#endif // USE_GC_INFO_DECODER } pMethodDefinition.Clear(); } diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index b2052185bc5346..e3650b48cd6a41 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: request.cpp -// - // // CorDataAccess::Request implementation. -// //***************************************************************************** #include "stdafx.h" @@ -889,16 +887,11 @@ HRESULT ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThre TO_CDADDR(thread->m_LastThrownObjectHandle); threadData->nextThread = HOST_CDADDR(ThreadStore::s_pThreadStore->m_ThreadList.GetNext(thread)); -#ifdef FEATURE_EH_FUNCLETS if (thread->m_ExceptionState.m_pCurrentTracker) { threadData->firstNestedException = HOST_CDADDR( thread->m_ExceptionState.m_pCurrentTracker->m_pPrevNestedInfo); } -#else - threadData->firstNestedException = HOST_CDADDR( - thread->m_ExceptionState.m_currentExInfo.m_pPrevNestedInfo); -#endif // FEATURE_EH_FUNCLETS SOSDacLeave(); return hr; diff --git a/src/coreclr/debug/daccess/task.cpp b/src/coreclr/debug/daccess/task.cpp index edbb360a988c36..651285ad5e8f3f 100644 --- a/src/coreclr/debug/daccess/task.cpp +++ b/src/coreclr/debug/daccess/task.cpp @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: task.cpp -// - // // ClrDataTask. -// //***************************************************************************** #include "stdafx.h" @@ -4923,11 +4921,7 @@ ClrDataExceptionState::NewFromThread(ClrDataAccess* dac, ClrDataExStateType* exState; ClrDataExceptionState* exIf; -#ifdef FEATURE_EH_FUNCLETS exState = thread->GetExceptionState()->m_pCurrentTracker; -#else - exState = &(thread->GetExceptionState()->m_currentExInfo); -#endif // FEATURE_EH_FUNCLETS exIf = new (nothrow) ClrDataExceptionState(dac, @@ -4961,11 +4955,7 @@ ClrDataExceptionState::GetCurrentExceptionRecord() { PTR_EXCEPTION_RECORD pExRecord = NULL; -#ifdef FEATURE_EH_FUNCLETS pExRecord = m_exInfo->m_ptrs.ExceptionRecord; -#else // FEATURE_EH_FUNCLETS - pExRecord = m_exInfo->m_pExceptionRecord; -#endif // FEATURE_EH_FUNCLETS return pExRecord; } @@ -4975,11 +4965,7 @@ ClrDataExceptionState::GetCurrentContextRecord() { PTR_CONTEXT pContext = NULL; -#ifdef FEATURE_EH_FUNCLETS pContext = m_exInfo->m_ptrs.ContextRecord; -#else // FEATURE_EH_FUNCLETS - pContext = m_exInfo->m_pContext; -#endif // FEATURE_EH_FUNCLETS return pContext; } diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index d6912642ed7a37..c8deabde8d9c42 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -1,9 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -//***************************************************************************** -// rspriv. -// +//***************************************************************************** +// rspriv.h // // Common include file for right-side of debugger. //***************************************************************************** @@ -6993,11 +6992,9 @@ struct CordbMiscFrame // new-style constructor CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData); -#ifdef FEATURE_EH_FUNCLETS SIZE_T parentIP; FramePointer fpParentOrSelf; bool fIsFilterFunclet; -#endif // FEATURE_EH_FUNCLETS }; @@ -7177,10 +7174,8 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public bool IsFunclet(); bool IsFilterFunclet(); -#ifdef FEATURE_EH_FUNCLETS // return the offset of the parent method frame at which an exception occurs SIZE_T GetParentIP(); -#endif // FEATURE_EH_FUNCLETS TADDR GetAmbientESP() { return m_taAmbientESP; } TADDR GetReturnRegisterValue(); diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index 330004424767cc..8e1a6c7dd739a1 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -1,11 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -//***************************************************************************** // // File: rsthread.cpp // -//***************************************************************************** + #include "stdafx.h" #include "primitives.h" #include @@ -5538,21 +5537,17 @@ const DT_CONTEXT * CordbRuntimeUnwindableFrame::GetContext() const // default constructor to make the compiler happy CordbMiscFrame::CordbMiscFrame() { -#ifdef FEATURE_EH_FUNCLETS this->parentIP = 0; this->fpParentOrSelf = LEAF_MOST_FRAME; this->fIsFilterFunclet = false; -#endif // FEATURE_EH_FUNCLETS } // the real constructor which stores the funclet-related information in the CordbMiscFrame CordbMiscFrame::CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData) { -#ifdef FEATURE_EH_FUNCLETS this->parentIP = pJITFuncData->parentNativeOffset; this->fpParentOrSelf = pJITFuncData->fpParentOrSelf; this->fIsFilterFunclet = (pJITFuncData->fIsFilterFrame == TRUE); -#endif // FEATURE_EH_FUNCLETS } /* ------------------------------------------------------------------------- * @@ -6012,7 +6007,6 @@ HRESULT CordbNativeFrame::IsMatchingParentFrame(ICorDebugNativeFrame2 * pPotenti ThrowHR(CORDBG_E_NOT_CHILD_FRAME); } -#ifdef FEATURE_EH_FUNCLETS CordbNativeFrame * pFrameToCheck = static_cast(pPotentialParentFrame); if (pFrameToCheck->IsFunclet()) { @@ -6026,7 +6020,6 @@ HRESULT CordbNativeFrame::IsMatchingParentFrame(ICorDebugNativeFrame2 * pPotenti IDacDbiInterface * pDAC = GetProcess()->GetDAC(); *pIsParent = pDAC->IsMatchingParentFrame(fpToCheck, fpParent); } -#endif // FEATURE_EH_FUNCLETS } EX_CATCH_HRESULT(hr); @@ -7363,14 +7356,9 @@ bool CordbNativeFrame::IsLeafFrame() const SIZE_T CordbNativeFrame::GetInspectionIP() { -#ifdef FEATURE_EH_FUNCLETS // On 64-bit, if this is a funclet, then return the offset of the parent method frame at which // the exception occurs. Otherwise just return the normal offset. return (IsFunclet() ? GetParentIP() : m_ip); -#else - // Always return the normal offset on all other platforms. - return m_ip; -#endif // FEATURE_EH_FUNCLETS } //--------------------------------------------------------------------------------------- @@ -7383,11 +7371,7 @@ SIZE_T CordbNativeFrame::GetInspectionIP() bool CordbNativeFrame::IsFunclet() { -#ifdef FEATURE_EH_FUNCLETS return (m_misc.parentIP != (SIZE_T)NULL); -#else - return false; -#endif // FEATURE_EH_FUNCLETS } //--------------------------------------------------------------------------------------- @@ -7400,15 +7384,10 @@ bool CordbNativeFrame::IsFunclet() bool CordbNativeFrame::IsFilterFunclet() { -#ifdef FEATURE_EH_FUNCLETS return (IsFunclet() && m_misc.fIsFilterFunclet); -#else - return false; -#endif // FEATURE_EH_FUNCLETS } -#ifdef FEATURE_EH_FUNCLETS //--------------------------------------------------------------------------------------- // // Return the offset of the parent method frame at which the exception occurs. @@ -7421,7 +7400,6 @@ SIZE_T CordbNativeFrame::GetParentIP() { return m_misc.parentIP; } -#endif // FEATURE_EH_FUNCLETS // Accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata. // Refer to that function for comments on the return value, the argument, etc. @@ -8459,7 +8437,6 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, HRESULT hr = S_OK; -#ifdef FEATURE_EH_FUNCLETS if (m_nativeFrame->IsFunclet()) { if ( (pNativeVarInfo->loc.vlType != ICorDebugInfo::VLT_STK) && @@ -8471,7 +8448,6 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, return E_FAIL; } } -#endif // FEATURE_EH_FUNCLETS switch (pNativeVarInfo->loc.vlType) { diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 4080393cf44c06..14b14ff97e7b90 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -3,12 +3,10 @@ // **************************************************************************** // File: controller.cpp -// - // // controller.cpp: Debugger execution control routines -// // **************************************************************************** + // Putting code & #includes, #defines, etc, before the stdafx.h will // cause the code,etc, to be silently ignored // @@ -586,9 +584,7 @@ StackWalkAction ControllerStackInfo::WalkStack(FrameInfo *pInfo, void *data) { i->m_returnFrame = *pInfo; -#if defined(FEATURE_EH_FUNCLETS) CopyREGDISPLAY(&(i->m_returnFrame.registers), &(pInfo->registers)); -#endif // FEATURE_EH_FUNCLETS i->m_returnFound = true; @@ -601,9 +597,7 @@ StackWalkAction ControllerStackInfo::WalkStack(FrameInfo *pInfo, void *data) { i->m_activeFrame = *pInfo; -#if defined(FEATURE_EH_FUNCLETS) CopyREGDISPLAY(&(i->m_activeFrame.registers), &(pInfo->registers)); -#endif // FEATURE_EH_FUNCLETS i->m_activeFound = true; @@ -5181,9 +5175,7 @@ DebuggerStepper::DebuggerStepper(Thread *thread, m_range(NULL), m_rangeCount(0), m_fp(LEAF_MOST_FRAME), -#if defined(FEATURE_EH_FUNCLETS) m_fpParentMethod(LEAF_MOST_FRAME), -#endif // FEATURE_EH_FUNCLETS m_fpException(LEAF_MOST_FRAME), m_fdException(0), m_cFuncEvalNesting(0) @@ -5269,7 +5261,6 @@ bool DebuggerStepper::IsRangeAppropriate(ControllerStackInfo *info) const FrameInfo *realFrame; -#if defined(FEATURE_EH_FUNCLETS) bool fActiveFrameIsFunclet = info->m_activeFrame.IsNonFilterFuncletFrame(); if (fActiveFrameIsFunclet) @@ -5277,7 +5268,6 @@ bool DebuggerStepper::IsRangeAppropriate(ControllerStackInfo *info) realFrame = &(info->GetReturnFrame()); } else -#endif // FEATURE_EH_FUNCLETS { realFrame = &(info->m_activeFrame); } @@ -5293,7 +5283,6 @@ bool DebuggerStepper::IsRangeAppropriate(ControllerStackInfo *info) return true; } -#if defined(FEATURE_EH_FUNCLETS) // There are three scenarios which make this function more complicated with funclets. // 1) We initiate a step in the parent method or a funclet but end up stepping into another funclet closer to the leaf. // a) start in the parent method @@ -5312,7 +5301,6 @@ bool DebuggerStepper::IsRangeAppropriate(ControllerStackInfo *info) LOG((LF_CORDB,LL_INFO10000, "DS::IRA: (parent SP) returning TRUE\n")); return true; } -#endif // FEATURE_EH_FUNCLETS LOG((LF_CORDB,LL_INFO10000, "DS::IRA: returning FALSE\n")); return false; @@ -6071,7 +6059,6 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) if (walker.GetNextIP() != NULL) { -#ifdef FEATURE_EH_FUNCLETS // There are 4 places we could be jumping: // 1) to the beginning of the same method (recursive call) // 2) somewhere in the same funclet, that isn't the method start @@ -6083,7 +6070,6 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) // wanted, option #3 fCallingIntoFunclet = IsAddrWithinMethodIncludingFunclet(ji, info->m_activeFrame.md, walker.GetNextIP()) && ((CORDB_ADDRESS)(SIZE_T)walker.GetNextIP() != ji->m_addrOfCode); -#endif // If we are stepping into a tail call that uses the StoreTailCallArgs // we need to enable the method enter, otherwise it will behave like a resume if (in && IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::StoreTailCallArgs)) @@ -6261,9 +6247,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) } } -#ifdef FEATURE_EH_FUNCLETS fCallingIntoFunclet = IsAddrWithinMethodIncludingFunclet(ji, info->m_activeFrame.md, walker.GetNextIP()); -#endif if (in || fCallingIntoFunclet) { LOG((LF_CORDB, LL_INFO10000, "DS::TS: WALK_CALL step in is true\n")); @@ -6347,7 +6331,6 @@ bool DebuggerStepper::IsAddrWithinFrame(DebuggerJitInfo *dji, } } -#if defined(FEATURE_EH_FUNCLETS) // Also check whether the targetAddr and the currentAddr is in the same funclet. _ASSERTE(currentAddr != NULL); if (result) @@ -6356,7 +6339,6 @@ bool DebuggerStepper::IsAddrWithinFrame(DebuggerJitInfo *dji, int targetFuncletIndex = dji->GetFuncletIndex((CORDB_ADDRESS)targetAddr, DebuggerJitInfo::GFIM_BYADDRESS); result = (currentFuncletIndex == targetFuncletIndex); } -#endif // FEATURE_EH_FUNCLETS return result; } @@ -6386,7 +6368,6 @@ bool DebuggerStepper::IsInterestingFrame(FrameInfo * pFrame) { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS // Ignore managed exception handling frames if (pFrame->md != NULL) { @@ -6396,7 +6377,6 @@ bool DebuggerStepper::IsInterestingFrame(FrameInfo * pFrame) return false; } } -#endif // FEATURE_EH_FUNCLETS return true; } @@ -6411,7 +6391,6 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio bool fReturningFromFinallyFunclet = false; -#if defined(FEATURE_EH_FUNCLETS) // When we step out of a funclet, we should do one of two things, depending // on the original stepping intention: // 1) If we originally want to step out, then we should skip the parent method. @@ -6488,7 +6467,6 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio } } } -#endif // FEATURE_EH_FUNCLETS #ifdef _DEBUG FramePointer dbgLastFP; // for debug, make sure we're making progress through the stack. @@ -6795,14 +6773,12 @@ void DebuggerStepper::StepOut(FramePointer fp, StackTraceTicket ticket) m_stepIn = FALSE; m_fp = info.m_activeFrame.fp; -#if defined(FEATURE_EH_FUNCLETS) // We need to remember the parent method frame pointer here so that we will recognize // the range of the stepper as being valid when we return to the parent method or stackalloc. if (info.HasReturnFrame(true)) { m_fpParentMethod = info.GetReturnFrame(true).fp; } -#endif // FEATURE_EH_FUNCLETS m_eMode = cStepOut; @@ -7129,14 +7105,12 @@ bool DebuggerStepper::Step(FramePointer fp, bool in, else { m_fp = info.m_activeFrame.fp; -#if defined(FEATURE_EH_FUNCLETS) // We need to remember the parent method frame pointer here so that we will recognize // the range of the stepper as being valid when we return to the parent method or stackalloc. if (info.HasReturnFrame(true)) { m_fpParentMethod = info.GetReturnFrame(true).fp; } -#endif // FEATURE_EH_FUNCLETS } m_eMode = m_stepIn ? cStepIn : cStepOver; @@ -7870,11 +7844,7 @@ void DebuggerStepper::PrepareForSendEvent(StackTraceTicket ticket) csi.GetStackInfo(ticket, GetThread(), LEAF_MOST_FRAME, NULL); if (csi.m_targetFrameFound && -#if !defined(FEATURE_EH_FUNCLETS) - IsCloserToRoot(m_fpStepInto, csi.m_activeFrame.fp) -#else IsCloserToRoot(m_fpStepInto, (csi.m_activeFrame.IsNonFilterFuncletFrame() ? csi.GetReturnFrame().fp : csi.m_activeFrame.fp)) -#endif // FEATURE_EH_FUNCLETS ) { @@ -8048,11 +8018,6 @@ bool DebuggerJMCStepper::TrapStepInHelper( bool fCallingIntoFunclet, bool fIsJump) { -#ifndef FEATURE_EH_FUNCLETS - // There are no funclets on x86. - _ASSERTE(!fCallingIntoFunclet); -#endif - // If we are calling into a funclet, then we can't rely on the JMC probe to stop us because there are no // JMC probes in funclets. Instead, we have to perform a traditional step-in here. if (fCallingIntoFunclet) @@ -9230,13 +9195,6 @@ bool DebuggerContinuableExceptionBreakpoint::SendEvent(Thread *thread, bool fIpC g_pDebugger->SendInterceptExceptionComplete(thread); } - // On WIN64, by the time we get here the DebuggerExState is gone already. - // ExInfos are cleaned up before we resume execution for a handled exception. -#if !defined(FEATURE_EH_FUNCLETS) - thread->GetExceptionState()->GetDebuggerState()->SetDebuggerInterceptContext(NULL); -#endif // !FEATURE_EH_FUNCLETS - - // // We delete this now because its no longer needed. We can call // delete here because the queued count is above 0. This object diff --git a/src/coreclr/debug/ee/controller.h b/src/coreclr/debug/ee/controller.h index d4831d8ce189ea..9fc60b4f810dbb 100644 --- a/src/coreclr/debug/ee/controller.h +++ b/src/coreclr/debug/ee/controller.h @@ -1768,11 +1768,9 @@ class DebuggerStepper : public DebuggerController // This is the only frame that the ranges are valid in. FramePointer m_fp; -#if defined(FEATURE_EH_FUNCLETS) // This frame pointer is used for funclet stepping. // See IsRangeAppropriate() for more information. FramePointer m_fpParentMethod; -#endif // FEATURE_EH_FUNCLETS //m_fpException is 0 if we haven't stepped into an exception, // and is ignored. If we get a TriggerUnwind while mid-step, we note diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index ad0d9a3129a6bc..58c287379c2eed 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: debugger.cpp -// - // // Debugger runtime controller routines. -// //***************************************************************************** #include "stdafx.h" @@ -3512,13 +3510,11 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, csi.GetStackInfo(ticket, thread, LEAF_MOST_FRAME, NULL); ULONG offsetNatFrom = csi.m_activeFrame.relOffset; -#if defined(FEATURE_EH_FUNCLETS) if (csi.m_activeFrame.IsFuncletFrame()) { offsetNatFrom = (ULONG)((SIZE_T)GetControlPC(&(csi.m_activeFrame.registers)) - (SIZE_T)(dji->m_addrOfCode)); } -#endif // FEATURE_EH_FUNCLETS _ASSERTE(dji != NULL); @@ -3527,11 +3523,10 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, // the size of the individual funclets or the parent method. pbBase = (BYTE*)CORDB_ADDRESS_TO_PTR(dji->m_addrOfCode); dwSize = (DWORD)dji->m_sizeOfCode; -#if defined(FEATURE_EH_FUNCLETS) + // Currently, method offsets are not bigger than 4 bytes even on WIN64. // Assert that it is so here. _ASSERTE((SIZE_T)dwSize == dji->m_sizeOfCode); -#endif // FEATURE_EH_FUNCLETS // Create our structure for analyzing this. @@ -3539,10 +3534,8 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, // CanSetIP & SetIP. int cFunclet = 0; const DWORD * rgFunclet = NULL; -#if defined(FEATURE_EH_FUNCLETS) cFunclet = dji->GetFuncletCount(); rgFunclet = dji->m_rgFunclet; -#endif // FEATURE_EH_FUNCLETS EHRangeTree* pEHRT = new (nothrow) EHRangeTree(csi.m_activeFrame.pIJM, csi.m_activeFrame.MethodToken, @@ -3580,14 +3573,8 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, // Caveat: we need to go to a sequence point if (fIsIL ) { -#if defined(FEATURE_EH_FUNCLETS) int funcletIndexFrom = dji->GetFuncletIndex((CORDB_ADDRESS)offsetNatFrom, DebuggerJitInfo::GFIM_BYOFFSET); offsetNatTo = dji->MapILOffsetToNativeForSetIP(offsetILTo, funcletIndexFrom, pEHRT, &exact); -#else // FEATURE_EH_FUNCLETS - DebuggerJitInfo::ILToNativeOffsetIterator it; - dji->InitILToNativeOffsetIterator(it, offsetILTo); - offsetNatTo = it.CurrentAssertOnlyOne(&exact); -#endif // FEATURE_EH_FUNCLETS if (!exact) { @@ -11383,7 +11370,6 @@ HRESULT Debugger::GetAndSendInterceptCommand(DebuggerIPCEvent *event) ULONG relOffset = csi.m_activeFrame.relOffset; -#if defined(FEATURE_EH_FUNCLETS) int funcletIndex = PARENT_METHOD_INDEX; // For funclets, we need to make sure that the stack empty sequence point we use is @@ -11395,7 +11381,6 @@ HRESULT Debugger::GetAndSendInterceptCommand(DebuggerIPCEvent *event) // Refer to the loop using pMap below. DebuggerILToNativeMap* pMap = NULL; -#endif // FEATURE_EH_FUNCLETS for (unsigned int i = 0; i < pJitInfo->GetSequenceMapCount(); i++) { @@ -11432,23 +11417,18 @@ HRESULT Debugger::GetAndSendInterceptCommand(DebuggerIPCEvent *event) } if ((foundOffset < startOffset) && (startOffset <= relOffset) -#if defined(FEATURE_EH_FUNCLETS) // Check if we are still in the same funclet. && (funcletIndex == pJitInfo->GetFuncletIndex(startOffset, DebuggerJitInfo::GFIM_BYOFFSET)) -#endif // FEATURE_EH_FUNCLETS ) { LOG((LF_CORDB, LL_INFO10000, "D::HIPCE: updating breakpoint at native offset 0x%zx\n", startOffset)); foundOffset = startOffset; -#if defined(FEATURE_EH_FUNCLETS) // Save the map entry for modification later. pMap = &(pJitInfo->GetSequenceMap()[i]); -#endif // FEATURE_EH_FUNCLETS } } -#if defined(FEATURE_EH_FUNCLETS) // This is nasty. Starting recently we could have multiple sequence points with the same IL offset // in the SAME funclet/parent method (previously different sequence points with the same IL offset // imply that they are in different funclet/parent method). Fortunately, we only run into this @@ -11468,7 +11448,6 @@ HRESULT Debugger::GetAndSendInterceptCommand(DebuggerIPCEvent *event) } } _ASSERTE(foundOffset < relOffset); -#endif // FEATURE_EH_FUNCLETS // // Set up a breakpoint on the intercept IP @@ -12452,12 +12431,7 @@ bool Debugger::IsThreadAtSafePlaceWorker(Thread *thread) CONTEXT ctx; ZeroMemory(&rd, sizeof(rd)); ZeroMemory(&ctx, sizeof(ctx)); -#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) - rd.ControlPC = ctx.Eip; - rd.PCTAddr = (TADDR)&(ctx.Eip); -#else FillRegDisplay(&rd, &ctx); -#endif if (ISREDIRECTEDTHREAD(thread)) { @@ -13209,7 +13183,7 @@ void STDCALL ExceptionHijackWorker( // call SetThreadContext on ourself to fix us. } -#if defined(FEATURE_EH_FUNCLETS) && !defined(TARGET_UNIX) +#ifndef TARGET_UNIX #if defined(TARGET_AMD64) // ---------------------------------------------------------------------------- @@ -13302,7 +13276,7 @@ ExceptionHijackPersonalityRoutine(IN PEXCEPTION_RECORD pExceptionRecord, // exactly the behavior we want. return ExceptionCollidedUnwind; } -#endif // FEATURE_EH_FUNCLETS && !TARGET_UNIX +#endif // !TARGET_UNIX // UEF Prototype from excep.cpp @@ -16364,12 +16338,6 @@ void FuncEvalFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloa return; } -#ifndef FEATURE_EH_FUNCLETS - // Reset pContext; it's only valid for active (top-most) frame. - pRD->pContext = NULL; -#endif // !FEATURE_EH_FUNCLETS - - #ifdef TARGET_X86 // Update all registers in the reg display from the CONTEXT we stored when the thread was hijacked for this func // eval. We have to update all registers, not just the callee saved registers, because we can hijack a thread at any @@ -16383,8 +16351,6 @@ void FuncEvalFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloa pRD->SetEbpLocation(&(pDE->m_context.Ebp)); SetRegdisplayPCTAddr(pRD, GetReturnAddressPtr()); -#ifdef FEATURE_EH_FUNCLETS - pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -16392,12 +16358,6 @@ void FuncEvalFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloa SyncRegDisplayToCurrentContext(pRD); -#else // FEATURE_EH_FUNCLETS - - pRD->SP = (DWORD)GetSP(&pDE->m_context); - -#endif // FEATURE_EH_FUNCLETS - #elif defined(TARGET_AMD64) pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this flag. This is only temporary. diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index 570338f00793b6..8e102e26972d57 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: debugger.h -// - // // Header file for Runtime Controller classes of the CLR Debugging Services. -// //***************************************************************************** #ifndef DEBUGGER_H_ @@ -381,13 +379,9 @@ inline LPVOID PushedRegAddr(REGDISPLAY* pRD, LPVOID pAddr) { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS if ( ((UINT_PTR)(pAddr) >= (UINT_PTR)pRD->pCurrentContextPointers) && ((UINT_PTR)(pAddr) <= ((UINT_PTR)pRD->pCurrentContextPointers + sizeof(T_KNONVOLATILE_CONTEXT_POINTERS))) ) -#else - if ( ((UINT_PTR)(pAddr) >= (UINT_PTR)pRD->pContext) && - ((UINT_PTR)(pAddr) <= ((UINT_PTR)pRD->pContext + sizeof(T_CONTEXT))) ) -#endif + return NULL; // (Microsoft 2/9/07 - putting this in an else clause confuses gcc for some reason, so I've moved @@ -1319,9 +1313,7 @@ class DebuggerHeap class DebuggerJitInfo; -#if defined(FEATURE_EH_FUNCLETS) const int PARENT_METHOD_INDEX = -1; -#endif // FEATURE_EH_FUNCLETS class CodeRegionInfo { @@ -1600,10 +1592,8 @@ class DebuggerJitInfo // The version number of this jitted code SIZE_T m_encVersion; -#if defined(FEATURE_EH_FUNCLETS) DWORD *m_rgFunclet; int m_funcletCount; -#endif // FEATURE_EH_FUNCLETS #ifndef DACCESS_COMPILE @@ -1630,9 +1620,7 @@ class DebuggerJitInfo private: SIZE_T m_ilOffset; -#ifdef FEATURE_EH_FUNCLETS int m_funcletIndex; -#endif }; struct NativeOffset @@ -1679,10 +1667,8 @@ class DebuggerJitInfo SIZE_T MapSpecialToNative(CorDebugMappingResult mapping, SIZE_T which, BOOL *pfAccurate); -#if defined(FEATURE_EH_FUNCLETS) void MapSpecialToNative(int funcletIndex, DWORD* pPrologEndOffset, DWORD* pEpilogStartOffset); SIZE_T MapILOffsetToNativeForSetIP(SIZE_T offsetILTo, int funcletIndexFrom, EHRangeTree* pEHRT, BOOL* pExact); -#endif // FEATURE_EH_FUNCLETS // MapNativeOffsetToIL Takes a given nativeOffset, and maps it back // to the corresponding IL offset, which it returns. If mapping indicates @@ -1696,7 +1682,6 @@ class DebuggerJitInfo void Init(TADDR newAddress); -#if defined(FEATURE_EH_FUNCLETS) enum GetFuncletIndexMode { GFIM_BYOFFSET, @@ -1707,7 +1692,6 @@ class DebuggerJitInfo DWORD GetFuncletOffsetByIndex(int index); int GetFuncletIndex(CORDB_ADDRESS offset, GetFuncletIndexMode mode); int GetFuncletCount() {return m_funcletCount;} -#endif // FEATURE_EH_FUNCLETS void SetVars(ULONG32 cVars, ICorDebugInfo::NativeVarInfo *pVars); void SetBoundaries(ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap); diff --git a/src/coreclr/debug/ee/frameinfo.cpp b/src/coreclr/debug/ee/frameinfo.cpp index 0266dc461f387d..04afb80cbe61b8 100644 --- a/src/coreclr/debug/ee/frameinfo.cpp +++ b/src/coreclr/debug/ee/frameinfo.cpp @@ -16,9 +16,7 @@ #include "COMToClrCall.h" #endif -#ifdef FEATURE_EH_FUNCLETS #include "exinfo.h" -#endif // FEATURE_EH_FUNCLETS // Get a frame pointer from a RegDisplay. // This is mostly used for chains and stub frames (i.e. internal frames), where we don't need an exact @@ -104,12 +102,10 @@ struct DebuggerFrameData this->info.frame = NULL; this->needParentInfo = false; -#ifdef FEATURE_EH_FUNCLETS this->fpParent = LEAF_MOST_FRAME; this->info.fIsLeaf = true; this->info.fIsFunclet = false; this->info.fIsFilter = false; -#endif // FEATURE_EH_FUNCLETS this->info.fIgnoreThisFrameIfSuppressingUMChainFromCLRToCOMMethodFrameGeneric = false; @@ -129,10 +125,9 @@ struct DebuggerFrameData REGDISPLAY regDisplay; -#ifdef FEATURE_EH_FUNCLETS // This is used to skip funclets in a stackwalk. It marks the frame pointer to which we should skip. FramePointer fpParent; -#endif // FEATURE_EH_FUNCLETS + #if defined(_DEBUG) // For debugging, track the previous FramePointer so we can assert that we're // making progress through the stack. @@ -697,7 +692,6 @@ void FrameInfo::InitForUMChain(FramePointer fpRoot, REGDISPLAY * pRDSrc) void FrameInfo::InitForScratchFrameInfo() { -#ifdef FEATURE_EH_FUNCLETS // The following flags cannot be trashed when we are calling this function on the curret FrameInfo // (the one we keep track of across multiple stackwalker callbacks). Thus, make sure you do not call // this function from InitForDynamicMethod(). In all other cases, we can call this method after we @@ -705,7 +699,6 @@ void FrameInfo::InitForScratchFrameInfo() this->fIsLeaf = false; this->fIsFunclet = false; this->fIsFilter = false; -#endif // FEATURE_EH_FUNCLETS } @@ -1306,8 +1299,6 @@ FramePointer GetFramePointerForDebugger(DebuggerFrameData* pData, CrawlFrame* pC return fpResult; } - -#ifdef FEATURE_EH_FUNCLETS //--------------------------------------------------------------------------------------- // // This function is called to determine if we should start skipping funclets. If we should, then we return the @@ -1361,7 +1352,6 @@ inline FramePointer CheckForParentFP(FramePointer fpCurrentParentMarker, CrawlFr return fpCurrentParentMarker; } } -#endif // FEATURE_EH_FUNCLETS //----------------------------------------------------------------------------- @@ -1391,7 +1381,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) if (pCF->IsNativeMarker()) { -#ifdef FEATURE_EH_FUNCLETS // The tricky part here is that we want to skip all frames between a funclet method frame // and the parent method frame UNLESS the funclet is a filter. Moreover, we should never // let a native marker execute the rest of this method, so we just short-circuit it here. @@ -1399,7 +1388,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) { return SWA_CONTINUE; } -#endif // FEATURE_EH_FUNCLETS // This REGDISPLAY is for the native method immediately following the managed method for which // we have received the previous callback, i.e. the native caller of the last managed method @@ -1461,14 +1449,11 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) } } // if (d->needParentInfo) - -#ifdef FEATURE_EH_FUNCLETS // The tricky part here is that we want to skip all frames between a funclet method frame // and the parent method frame UNLESS the funclet is a filter. We only have to check for fpParent // here (instead of checking d->info.fIsFunclet and d->info.fIsFilter as well, as in the beginning of // this method) is because at this point, fpParent is already set by the code above. if (d->fpParent == LEAF_MOST_FRAME) -#endif // FEATURE_EH_FUNCLETS { // Track the UM chain after we flush any managed goo from the last iteration. if (TrackUMChain(pCF, d) == SWA_ABORT) @@ -1489,7 +1474,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) // register display we passed in - assert it to be sure _ASSERTE(pCF->GetRegisterSet() == &d->regDisplay); -#ifdef FEATURE_EH_FUNCLETS Frame* pPrevFrame = d->info.frame; // Here we need to determine if we are in a non-leaf frame, in which case we want to adjust the relative offset. @@ -1538,8 +1522,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) } } -#endif // FEATURE_EH_FUNCLETS - d->info.frame = frame; d->info.ambientSP = (TADDR)NULL; @@ -1550,7 +1532,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) // Grab all the info from CrawlFrame that we need to // check for "Am I in an exception code blob?" now. -#ifdef FEATURE_EH_FUNCLETS // We are still searching for the parent of the last funclet we encounter. if (d->fpParent != LEAF_MOST_FRAME) { @@ -1558,7 +1539,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) LOG((LF_CORDB, LL_INFO100000, "DWSP: Skipping to parent method frame at 0x%p.\n", d->fpParent.GetSPValue())); } else -#endif // FEATURE_EH_FUNCLETS // We ignore most IL stubs with no frames in our stackwalking. As exceptions // we will always report multicast stubs and the tailcall call target stubs // since we treat them specially in the debugger. @@ -1832,9 +1812,7 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) LOG((LF_CORDB, LL_INFO100000, "DWSP: Setting needParentInfo\n")); } -#if defined(FEATURE_EH_FUNCLETS) d->fpParent = CheckForParentFP(d->fpParent, pCF, d->info.IsNonFilterFuncletFrame()); -#endif // FEATURE_EH_FUNCLETS // // The stackwalker doesn't update the register set for the @@ -2077,13 +2055,6 @@ StackWalkAction DebuggerWalkStack(Thread *thread, #endif memset((void *)&data, 0, sizeof(data)); -#if !defined(FEATURE_EH_FUNCLETS) - // @todo - this seems pointless. context->Eip will be 0; and when we copy it over to the DebuggerRD, - // the context will be completely null. - data.regDisplay.ControlPC = context->Eip; - data.regDisplay.PCTAddr = (TADDR)&(context->Eip); - -#else // // @TODO: this should be the code for all platforms now that it uses FillRegDisplay, // which encapsulates the platform variances. This could all be avoided if we used @@ -2094,7 +2065,6 @@ StackWalkAction DebuggerWalkStack(Thread *thread, FillRegDisplay(&data.regDisplay, context); ::SetSP(data.regDisplay.pCallerContext, 0); -#endif } data.Init(thread, targetFP, fIgnoreNonmethodFrames, pCallback, pData); diff --git a/src/coreclr/debug/ee/frameinfo.h b/src/coreclr/debug/ee/frameinfo.h index 0a60c516bb95c2..cabb8d67313f9f 100644 --- a/src/coreclr/debug/ee/frameinfo.h +++ b/src/coreclr/debug/ee/frameinfo.h @@ -88,7 +88,6 @@ struct FrameInfo // only set for stackwalking, not stepping void *exactGenericArgsToken; -#if defined(FEATURE_EH_FUNCLETS) // This field is only used on IA64 to determine which registers are available and // whether we need to adjust the IP. bool fIsLeaf; @@ -100,8 +99,6 @@ struct FrameInfo bool IsFuncletFrame() { return fIsFunclet; } bool IsFilterFrame() { return fIsFilter; } bool IsNonFilterFuncletFrame() { return (fIsFunclet && !fIsFilter); } -#endif // FEATURE_EH_FUNCLETS - // A ridiculous flag that is targeting a very narrow fix at issue 650903 (4.5.1/Blue). // This is set when the currently walked frame is a CLRToCOMMethodFrameGeneric. If the diff --git a/src/coreclr/debug/ee/funceval.cpp b/src/coreclr/debug/ee/funceval.cpp index 652ec434f1f077..f251de3016ce34 100644 --- a/src/coreclr/debug/ee/funceval.cpp +++ b/src/coreclr/debug/ee/funceval.cpp @@ -3989,7 +3989,7 @@ void * STDCALL FuncEvalHijackWorker(DebuggerEval *pDE) } -#if defined(FEATURE_EH_FUNCLETS) && !defined(TARGET_UNIX) && !defined(TARGET_X86) +#if !defined(TARGET_UNIX) && !defined(TARGET_X86) EXTERN_C EXCEPTION_DISPOSITION FuncEvalHijackPersonalityRoutine(IN PEXCEPTION_RECORD pExceptionRecord, @@ -4027,6 +4027,6 @@ FuncEvalHijackPersonalityRoutine(IN PEXCEPTION_RECORD pExceptionRecord, return ExceptionCollidedUnwind; } -#endif // FEATURE_EH_FUNCLETS && !TARGET_UNIX && !TARGET_X86 +#endif // !TARGET_UNIX && !TARGET_X86 #endif // ifndef DACCESS_COMPILE diff --git a/src/coreclr/debug/ee/functioninfo.cpp b/src/coreclr/debug/ee/functioninfo.cpp index d1c7de147d9add..74368ac5ca3337 100644 --- a/src/coreclr/debug/ee/functioninfo.cpp +++ b/src/coreclr/debug/ee/functioninfo.cpp @@ -1,12 +1,10 @@ - // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** -// // File: DebuggerModule.cpp // // Stuff for tracking DebuggerModules. -// //***************************************************************************** #include "stdafx.h" @@ -122,7 +120,6 @@ static void _dumpVarNativeInfo(ICorDebugInfo::NativeVarInfo* vni) } #endif -#if defined(FEATURE_EH_FUNCLETS) void DebuggerJitInfo::InitFuncletAddress() { CONTRACTL @@ -229,21 +226,15 @@ int DebuggerJitInfo::GetFuncletIndex(CORDB_ADDRESS offsetOrAddr, GetFuncletIndex UNREACHABLE(); } -#endif // FEATURE_EH_FUNCLETS - // It is entirely possible that we have multiple sequence points for the // same IL offset (because of funclets, optimization, etc.). Just to be // uniform in all cases, let's return the sequence point with the smallest // native offset if fWantFirst is TRUE. -#if defined(FEATURE_EH_FUNCLETS) #define ADJUST_MAP_ENTRY(_map, _wantFirst) \ if ((_wantFirst)) \ for ( ; (_map) > m_sequenceMap && (((_map)-1)->ilOffset == (_map)->ilOffset); (_map)--); \ else \ for ( ; (_map) < m_sequenceMap + (m_sequenceMapCount-1) && (((_map)+1)->ilOffset == (_map)->ilOffset); (_map)++); -#else -#define ADJUST_MAP_ENTRY(_map, _wantFirst) -#endif // FEATURE_EH_FUNCLETS DebuggerJitInfo::DebuggerJitInfo(DebuggerMethodInfo *minfo, NativeCodeVersion nativeCodeVersion) : m_nativeCodeVersion(nativeCodeVersion), @@ -263,10 +254,8 @@ DebuggerJitInfo::DebuggerJitInfo(DebuggerMethodInfo *minfo, NativeCodeVersion na m_sequenceMapSorted(false), m_varNativeInfo(NULL), m_varNativeInfoCount(0), m_fAttemptInit(false) -#if defined(FEATURE_EH_FUNCLETS) ,m_rgFunclet(NULL) , m_funcletCount(0) -#endif // defined(FEATURE_EH_FUNCLETS) { WRAPPER_NO_CONTRACT; @@ -377,18 +366,14 @@ DebuggerJitInfo::NativeOffset DebuggerJitInfo::MapILOffsetToNative(DebuggerJitIn DebuggerILToNativeMap *map = MapILOffsetToMapEntry(ilOffset.m_ilOffset, &(resultOffset.m_fExact)); -#if defined(FEATURE_EH_FUNCLETS) // See if we want the map entry for the parent. if (ilOffset.m_funcletIndex <= PARENT_METHOD_INDEX) { -#endif // FEATURE_EH_FUNCLETS _ASSERTE( map != NULL ); LOG((LF_CORDB, LL_INFO10000, "DJI::MILOTN: ilOffset 0x%zx to nat 0x%x exact:%s (Entry IL Off:0x%x)\n", ilOffset.m_ilOffset, map->nativeStartOffset, (resultOffset.m_fExact ? "true" : "false"), map->ilOffset)); resultOffset.m_nativeOffset = map->nativeStartOffset; - -#if defined(FEATURE_EH_FUNCLETS) } else { @@ -436,7 +421,6 @@ DebuggerJitInfo::NativeOffset DebuggerJitInfo::MapILOffsetToNative(DebuggerJitIn } } } -#endif // FEATURE_EH_FUNCLETS return resultOffset; } @@ -448,9 +432,7 @@ DebuggerJitInfo::ILToNativeOffsetIterator::ILToNativeOffsetIterator() m_dji = NULL; m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET; -#ifdef FEATURE_EH_FUNCLETS m_currentILOffset.m_funcletIndex = PARENT_METHOD_INDEX; -#endif } void DebuggerJitInfo::ILToNativeOffsetIterator::Init(DebuggerJitInfo* dji, SIZE_T ilOffset) @@ -459,9 +441,7 @@ void DebuggerJitInfo::ILToNativeOffsetIterator::Init(DebuggerJitInfo* dji, SIZE_ m_dji = dji; m_currentILOffset.m_ilOffset = ilOffset; -#ifdef FEATURE_EH_FUNCLETS m_currentILOffset.m_funcletIndex = PARENT_METHOD_INDEX; -#endif m_currentNativeOffset = m_dji->MapILOffsetToNative(m_currentILOffset); } @@ -498,7 +478,6 @@ SIZE_T DebuggerJitInfo::ILToNativeOffsetIterator::CurrentAssertOnlyOne(BOOL* pfE void DebuggerJitInfo::ILToNativeOffsetIterator::Next() { -#if defined(FEATURE_EH_FUNCLETS) NativeOffset tmpNativeOffset; for (m_currentILOffset.m_funcletIndex += 1; @@ -518,13 +497,8 @@ void DebuggerJitInfo::ILToNativeOffsetIterator::Next() { m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET; } -#else // !FEATURE_EH_FUNCLETS - m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET; -#endif // !FEATURE_EH_FUNCLETS } - - // SIZE_T DebuggerJitInfo::MapSpecialToNative(): Maps something like // a prolog to a native offset. // CordDebugMappingResult mapping: Mapping type to be looking for. @@ -588,7 +562,6 @@ SIZE_T DebuggerJitInfo::MapSpecialToNative(CorDebugMappingResult mapping, return 0; } -#if defined(FEATURE_EH_FUNCLETS) // // DebuggerJitInfo::MapILOffsetToNativeForSetIP() // @@ -648,7 +621,6 @@ SIZE_T DebuggerJitInfo::MapILOffsetToNativeForSetIP(SIZE_T offsetILTo, int funcl return offsetNatTo; } -#endif // FEATURE_EH_FUNCLETS // void DebuggerJitInfo::MapILRangeToMapEntryRange(): MIRTMER // calls MapILOffsetToNative for the startOffset (putting the @@ -859,14 +831,11 @@ DebuggerJitInfo::~DebuggerJitInfo() DeleteInteropSafe(m_varNativeInfo); } -#if defined(FEATURE_EH_FUNCLETS) if (m_rgFunclet) { DeleteInteropSafe(m_rgFunclet); m_rgFunclet = NULL; } -#endif // FEATURE_EH_FUNCLETS - #ifdef _DEBUG // Trash pointers to garbage. @@ -1258,9 +1227,7 @@ void DebuggerJitInfo::Init(TADDR newAddress) this->m_encVersion = this->m_methodInfo->GetCurrentEnCVersion(); -#if defined(FEATURE_EH_FUNCLETS) this->InitFuncletAddress(); -#endif // FEATURE_EH_FUNCLETS LOG((LF_CORDB,LL_INFO10000,"De::JITCo:Got DJI %p (encVersion: %zx)," "Hot section from %p to %p " diff --git a/src/coreclr/debug/ee/i386/debuggerregdisplayhelper.cpp b/src/coreclr/debug/ee/i386/debuggerregdisplayhelper.cpp index bda129a9b95476..17923a7a8281cd 100644 --- a/src/coreclr/debug/ee/i386/debuggerregdisplayhelper.cpp +++ b/src/coreclr/debug/ee/i386/debuggerregdisplayhelper.cpp @@ -15,7 +15,6 @@ void CopyREGDISPLAY(REGDISPLAY* pDst, REGDISPLAY* pSrc) { *pDst = *pSrc; -#ifdef FEATURE_EH_FUNCLETS if (pSrc->pCurrentContextPointers == &(pSrc->ctxPtrsOne)) { pDst->pCurrentContextPointers = &(pDst->ctxPtrsOne); @@ -37,5 +36,4 @@ void CopyREGDISPLAY(REGDISPLAY* pDst, REGDISPLAY* pSrc) pDst->pCurrentContext = &(pDst->ctxTwo); pDst->pCallerContext = &(pDst->ctxOne); } -#endif } diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h index 8382e505a128bc..05be8d03666586 100644 --- a/src/coreclr/debug/inc/dbgipcevents.h +++ b/src/coreclr/debug/inc/dbgipcevents.h @@ -1,9 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + /* ------------------------------------------------------------------------- * * DbgIPCEvents.h -- header file for private Debugger data shared by various -// - * debugger components. * ------------------------------------------------------------------------- */ @@ -1356,11 +1355,9 @@ struct MSLAYOUT DebuggerIPCE_JITFuncData LSPTR_DJI nativeCodeJITInfoToken; VMPTR_MethodDesc vmNativeCodeMethodDescToken; -#ifdef FEATURE_EH_FUNCLETS BOOL fIsFilterFrame; SIZE_T parentNativeOffset; FramePointer fpParentOrSelf; -#endif // FEATURE_EH_FUNCLETS // indicates if the MethodDesc is a generic function or a method inside a generic class (or // both!). diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 17c5aa40c61dc6..311b72820ed4b1 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -222,9 +222,7 @@ CONFIG_DWORD_INFO(INTERNAL_ContinueOnAssert, W("ContinueOnAssert"), 0, "If set, CONFIG_DWORD_INFO(INTERNAL_InjectFatalError, W("InjectFatalError"), 0, "") CONFIG_DWORD_INFO(INTERNAL_InjectFault, W("InjectFault"), 0, "") CONFIG_DWORD_INFO(INTERNAL_SuppressChecks, W("SuppressChecks"),0, "") -#ifdef FEATURE_EH_FUNCLETS CONFIG_DWORD_INFO(INTERNAL_SuppressLockViolationsOnReentryFromOS, W("SuppressLockViolationsOnReentryFromOS"), 0, "64 bit OOM tests re-enter the CLR via RtlVirtualUnwind. This indicates whether to suppress resulting locking violations.") -#endif // FEATURE_EH_FUNCLETS /// /// Exception Handling diff --git a/src/coreclr/inc/daccess.h b/src/coreclr/inc/daccess.h index a26146c05a88d3..9870093d1bca57 100644 --- a/src/coreclr/inc/daccess.h +++ b/src/coreclr/inc/daccess.h @@ -1,9 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // File: daccess.h -// - // // Support for external access of runtime data structures. These // macros and templates hide the details of pointer and data handling @@ -554,7 +553,6 @@ // //***************************************************************************** - #ifndef __daccess_h__ #define __daccess_h__ @@ -822,12 +820,10 @@ interface IMDInternalImport* DacGetMDImport(const ReflectionModule* reflectionMo int DacGetIlMethodSize(TADDR methAddr); struct COR_ILMETHOD* DacGetIlMethod(TADDR methAddr); -#ifdef FEATURE_EH_FUNCLETS struct _UNWIND_INFO * DacGetUnwindInfo(TADDR taUnwindInfo); // virtually unwind a CONTEXT out-of-process BOOL DacUnwindStackFrame(T_CONTEXT * pContext, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers); -#endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS class SString; @@ -2441,7 +2437,7 @@ typedef DPTR(IMAGE_TLS_DIRECTORY) PTR_IMAGE_TLS_DIRECTORY; #endif #ifndef NATIVEAOT -#if defined(TARGET_X86) && defined(FEATURE_EH_FUNCLETS) +#if defined(TARGET_X86) typedef DPTR(struct _UNWIND_INFO) PTR_UNWIND_INFO; #endif diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index eec6d073243915..5803ae1f33b3b5 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // This file contains the globals and statics that are visible to DAC. // It is used for the following: // 1. in daccess.h to build the table of DAC globals @@ -121,11 +122,9 @@ DEFINE_DACVAR(DWORD, dac__g_debuggerWordTLSIndex, g_debuggerWordTLSIndex) DEFINE_DACVAR(DWORD, dac__g_TlsIndex, g_TlsIndex) DEFINE_DACVAR(DWORD, dac__g_offsetOfCurrentThreadInfo, g_offsetOfCurrentThreadInfo) -#ifdef FEATURE_EH_FUNCLETS DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pEHClass, ::g_pEHClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pExceptionServicesInternalCallsClass, ::g_pExceptionServicesInternalCallsClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pStackFrameIteratorClass, ::g_pStackFrameIteratorClass) -#endif DEFINE_DACVAR(PTR_SString, SString__s_Empty, SString::s_Empty) diff --git a/src/coreclr/inc/eetwain.h b/src/coreclr/inc/eetwain.h index 1062ebf5692409..040551270ea6c5 100644 --- a/src/coreclr/inc/eetwain.h +++ b/src/coreclr/inc/eetwain.h @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + //***************************************************************************** // // EETwain.h @@ -149,19 +150,6 @@ enum SHADOW_SP_BITS = 0x3 }; -#ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS -virtual void FixContext(ContextType ctxType, - EHContext *ctx, - EECodeInfo *pCodeInfo, - DWORD dwRelOffset, - DWORD nestingLevel, - OBJECTREF thrownObject, - size_t ** ppShadowSP, // OUT - size_t ** ppEndRegion) = 0; // OUT -#endif // !FEATURE_EH_FUNCLETS -#endif // #ifndef DACCESS_COMPILE - #ifdef TARGET_X86 /* Gets the ambient stack pointer value at the given nesting level within @@ -193,9 +181,7 @@ virtual bool UnwindStackFrame(PREGDISPLAY pRD, virtual void UnwindStackFrame(T_CONTEXT *pContext) = 0; -#ifdef FEATURE_EH_FUNCLETS virtual void EnsureCallerContextIsValid(PREGDISPLAY pRD, EECodeInfo * pCodeInfo = NULL, unsigned flags = 0) = 0; -#endif // FEATURE_EH_FUNCLETS /* Is the function currently at a "GC safe point" ? @@ -261,15 +247,6 @@ virtual void * GetGSCookieAddr(PREGDISPLAY pContext, virtual bool IsInPrologOrEpilog(DWORD relPCOffset, GCInfoToken gcInfoToken, size_t* prologSize) = 0; -#ifndef FEATURE_EH_FUNCLETS -/* - Returns true if the given IP is in the synchronized region of the method (valid for synchronized methods only) -*/ -virtual bool IsInSynchronizedRegion( - DWORD relOffset, - GCInfoToken gcInfoToken, - unsigned flags) = 0; -#endif // FEATURE_EH_FUNCLETS #endif // !USE_GC_INFO_DECODER /* @@ -298,23 +275,11 @@ virtual unsigned int GetFrameSize(GCInfoToken gcInfoToken) = 0; /* Debugger API */ -#ifndef FEATURE_EH_FUNCLETS -virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg)=0; - -virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx) = 0; - -virtual void LeaveCatch(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx)=0; -#else // FEATURE_EH_FUNCLETS virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter) = 0; virtual void ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted) = 0; #if defined(HOST_AMD64) && defined(HOST_WINDOWS) virtual void UpdateSSP(PREGDISPLAY pRD) = 0; #endif // HOST_AMD64 && HOST_WINDOWS -#endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION @@ -355,25 +320,6 @@ class EECodeManager : public ICodeManager { public: - -#ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS -/* - Last chance for the runtime support to do fixups in the context - before execution continues inside a filter, catch handler, or finally -*/ -virtual -void FixContext(ContextType ctxType, - EHContext *ctx, - EECodeInfo *pCodeInfo, - DWORD dwRelOffset, - DWORD nestingLevel, - OBJECTREF thrownObject, - size_t ** ppShadowSP, // OUT - size_t ** ppEndRegion); // OUT -#endif // !FEATURE_EH_FUNCLETS -#endif // #ifndef DACCESS_COMPILE - #ifdef TARGET_X86 /* Gets the ambient stack pointer value at the given nesting level within @@ -484,7 +430,7 @@ PTR_VOID GetParamTypeArg(PREGDISPLAY pContext, virtual GenericParamContextType GetParamContextType(PREGDISPLAY pContext, EECodeInfo * pCodeInfo); -#if defined(FEATURE_EH_FUNCLETS) && defined(USE_GC_INFO_DECODER) +#ifdef USE_GC_INFO_DECODER /* Returns the generics token. This is used by GetInstance() and GetParamTypeArg() on WIN64. */ @@ -497,7 +443,7 @@ PTR_VOID GetExactGenericsToken(TADDR sp, TADDR fp, EECodeInfo * pCodeInfo); -#endif // FEATURE_EH_FUNCLETS && USE_GC_INFO_DECODER +#endif // USE_GC_INFO_DECODER /* Returns the offset of the GuardStack cookie if it exists. @@ -518,17 +464,6 @@ bool IsInPrologOrEpilog( DWORD relOffset, GCInfoToken gcInfoToken, size_t* prologSize); - -#ifndef FEATURE_EH_FUNCLETS -/* - Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only) -*/ -virtual -bool IsInSynchronizedRegion( - DWORD relOffset, - GCInfoToken gcInfoToken, - unsigned flags); -#endif // FEATURE_EH_FUNCLETS #endif // !USE_GC_INFO_DECODER /* @@ -555,22 +490,12 @@ unsigned int GetFrameSize(GCInfoToken gcInfoToken); #ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS -virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg); -virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx); -virtual void LeaveCatch(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx); -#else // FEATURE_EH_FUNCLETS virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter); virtual void ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted); #if defined(HOST_AMD64) && defined(HOST_WINDOWS) virtual void UpdateSSP(PREGDISPLAY pRD); #endif // HOST_AMD64 && HOST_WINDOWS -#endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION /* @@ -589,13 +514,11 @@ HRESULT FixContextForEnC(PCONTEXT pCtx, #endif // #ifndef DACCESS_COMPILE -#ifdef FEATURE_EH_FUNCLETS virtual void EnsureCallerContextIsValid( PREGDISPLAY pRD, EECodeInfo * pCodeInfo = NULL, unsigned flags = 0); static size_t GetCallerSp( PREGDISPLAY pRD ); #ifdef TARGET_X86 static size_t GetResumeSp( PCONTEXT pContext ); #endif // TARGET_X86 -#endif // FEATURE_EH_FUNCLETS #ifdef DACCESS_COMPILE virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); @@ -611,25 +534,6 @@ class InterpreterCodeManager : public ICodeManager { public: - -#ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS -virtual -void FixContext(ContextType ctxType, - EHContext *ctx, - EECodeInfo *pCodeInfo, - DWORD dwRelOffset, - DWORD nestingLevel, - OBJECTREF thrownObject, - size_t ** ppShadowSP, // OUT - size_t ** ppEndRegion) // OUT -{ - // Interpreter-TODO: Implement this if needed - _ASSERTE(FALSE); -} -#endif // !FEATURE_EH_FUNCLETS -#endif // !DACCESS_COMPILE - #ifdef TARGET_X86 /* Gets the ambient stack pointer value at the given nesting level within @@ -662,10 +566,8 @@ bool UnwindStackFrame( virtual void UnwindStackFrame(T_CONTEXT *pContext); -#ifdef FEATURE_EH_FUNCLETS virtual void EnsureCallerContextIsValid(PREGDISPLAY pRD, EECodeInfo * pCodeInfo = NULL, unsigned flags = 0); -#endif // FEATURE_EH_FUNCLETS virtual bool IsGcSafe( EECodeInfo *pCodeInfo, @@ -720,19 +622,6 @@ bool IsInPrologOrEpilog( _ASSERTE(FALSE); return false; } - -#ifndef FEATURE_EH_FUNCLETS -virtual -bool IsInSynchronizedRegion( - DWORD relOffset, - GCInfoToken gcInfoToken, - unsigned flags) -{ - // Interpreter-TODO: Implement this if needed - _ASSERTE(FALSE); - return false; -} -#endif // FEATURE_EH_FUNCLETS #endif // !USE_GC_INFO_DECODER virtual @@ -758,37 +647,11 @@ unsigned int GetFrameSize(GCInfoToken gcInfoToken) #ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS -virtual const BYTE* GetFinallyReturnAddr(PREGDISPLAY pReg) -{ - // Interpreter-TODO: Implement this if needed - _ASSERTE(FALSE); - return NULL; -} - -virtual BOOL LeaveFinally(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx) -{ - // Interpreter-TODO: Implement this if needed - _ASSERTE(FALSE); - return FALSE; -} - -virtual void LeaveCatch(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx) -{ - // Interpreter-TODO: Implement this if needed - _ASSERTE(FALSE); -} -#else // FEATURE_EH_FUNCLETS virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter); virtual void ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted); #if defined(HOST_AMD64) && defined(HOST_WINDOWS) virtual void UpdateSSP(PREGDISPLAY pRD); #endif // HOST_AMD64 && HOST_WINDOWS -#endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION diff --git a/src/coreclr/inc/gc_unwind_x86.h b/src/coreclr/inc/gc_unwind_x86.h index 74fe4e753972a0..2c6a3e6ec4d1e1 100644 --- a/src/coreclr/inc/gc_unwind_x86.h +++ b/src/coreclr/inc/gc_unwind_x86.h @@ -5,18 +5,12 @@ #define _UNWIND_X86_H // This file is shared between CoreCLR and NativeAOT. Some of the differences are handled -// with the FEATURE_NATIVEAOT and FEATURE_EH_FUNCLETS defines. There are three main methods -// that are used by both runtimes - DecodeGCHdrInfo, UnwindStackFrameX86, and EnumGcRefsX86. +// with the FEATURE_NATIVEAOT define. There are three main methods that are used by both +// runtimes - DecodeGCHdrInfo, UnwindStackFrameX86, and EnumGcRefsX86. // -// The IN_EH_FUNCLETS and IN_EH_FUNCLETS_COMMA macros are used to specify some parameters -// for the above methods that are specific for a certain runtime or configuration. -#ifdef FEATURE_EH_FUNCLETS -#define IN_EH_FUNCLETS(a) a +// The IN_EH_FUNCLETS_COMMA macro is used to specify some parameters for the above methods +// that are specific for a certain runtime or configuration. #define IN_EH_FUNCLETS_COMMA(a) a, -#else -#define IN_EH_FUNCLETS(a) -#define IN_EH_FUNCLETS_COMMA(a) -#endif enum regNum { diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 6aeece530ad847..a755946c2685f2 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // Allow multiple inclusion. @@ -17,7 +18,6 @@ // ////////////////////////////////////////////////////////////////////////////////////////////////////////// - #ifndef DYNAMICJITHELPER //I should never try to generate an alignment stub for a dynamic helper #define DYNAMICJITHELPER(code,fn,binderId) JITHELPER(code,fn,binderId) @@ -154,22 +154,10 @@ DYNAMICJITHELPER(CORINFO_HELP_FIELD_ACCESS_EXCEPTION, NULL, METHOD__THROWHELPERS__THROWFIELDACCESSEXCEPTION) DYNAMICJITHELPER(CORINFO_HELP_CLASS_ACCESS_EXCEPTION, NULL, METHOD__THROWHELPERS__THROWCLASSACCESSEXCEPTION) -#ifdef FEATURE_EH_FUNCLETS JITHELPER(CORINFO_HELP_ENDCATCH, NULL, METHOD__NIL) -#else - JITHELPER(CORINFO_HELP_ENDCATCH, JIT_EndCatch, METHOD__NIL) -#endif -// -// The legacy x86 monitor helpers do not need a state argument -// -#if defined(FEATURE_EH_FUNCLETS) DYNAMICJITHELPER(CORINFO_HELP_MON_ENTER, NULL, METHOD__MONITOR__SYNCHRONIZED_METHOD_ENTER) DYNAMICJITHELPER(CORINFO_HELP_MON_EXIT, NULL, METHOD__MONITOR__SYNCHRONIZED_METHOD_EXIT) -#else - DYNAMICJITHELPER(CORINFO_HELP_MON_ENTER, NULL, METHOD__MONITOR__ENTER) - DYNAMICJITHELPER(CORINFO_HELP_MON_EXIT, NULL, METHOD__MONITOR__EXIT) -#endif JITHELPER(CORINFO_HELP_GETCLASSFROMMETHODPARAM, JIT_GetClassFromMethodParam, METHOD__NIL) DYNAMICJITHELPER(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, NULL, METHOD__RT_TYPE_HANDLE__GETRUNTIMETYPEFROMHANDLE) @@ -274,13 +262,8 @@ JITHELPER(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, NULL, METHOD__NIL) JITHELPER(CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE, NULL, METHOD__NIL) -#ifdef FEATURE_EH_FUNCLETS DYNAMICJITHELPER(CORINFO_HELP_EE_PERSONALITY_ROUTINE, ProcessCLRException, METHOD__NIL) DYNAMICJITHELPER(CORINFO_HELP_EE_PERSONALITY_ROUTINE_FILTER_FUNCLET, ProcessCLRException,METHOD__NIL) -#else // FEATURE_EH_FUNCLETS - JITHELPER(CORINFO_HELP_EE_PERSONALITY_ROUTINE, NULL, METHOD__NIL) - JITHELPER(CORINFO_HELP_EE_PERSONALITY_ROUTINE_FILTER_FUNCLET, NULL, METHOD__NIL) -#endif // !FEATURE_EH_FUNCLETS #ifdef TARGET_X86 DYNAMICJITHELPER(CORINFO_HELP_ASSIGN_REF_EAX, RhpAssignRefEAX, METHOD__NIL) diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index db88393b101576..50197dbba339a2 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -431,11 +431,9 @@ enum ReadyToRunHelper READYTORUN_HELPER_DblRound = 0xE2, READYTORUN_HELPER_FltRound = 0xE3, -#ifdef FEATURE_EH_FUNCLETS // Personality routines READYTORUN_HELPER_PersonalityRoutine = 0xF0, READYTORUN_HELPER_PersonalityRoutineFilterFunclet = 0xF1, -#endif // Synchronized methods READYTORUN_HELPER_MonitorEnter = 0xF8, diff --git a/src/coreclr/inc/regdisp.h b/src/coreclr/inc/regdisp.h index e0f22343065741..afd24a1d566df7 100644 --- a/src/coreclr/inc/regdisp.h +++ b/src/coreclr/inc/regdisp.h @@ -20,7 +20,6 @@ struct REGDISPLAY_BASE { // do NOT trash it! But DO update any static // registers here. -#ifdef FEATURE_EH_FUNCLETS PT_CONTEXT pCurrentContext; // [trashed] points to current Context of stackwalk PT_CONTEXT pCallerContext; // [trashed] points to the Context of the caller during stackwalk -- used for GC crawls @@ -37,7 +36,6 @@ struct REGDISPLAY_BASE { T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsOne; // used by stackwalk T_KNONVOLATILE_CONTEXT_POINTERS ctxPtrsTwo; // used by stackwalk -#endif // FEATURE_EH_FUNCLETS #ifdef DEBUG_REGDISPLAY Thread *_pThread; @@ -72,30 +70,6 @@ inline void SetRegdisplaySP(REGDISPLAY_BASE *pRD, LPVOID sp) { struct REGDISPLAY : public REGDISPLAY_BASE { -#ifndef FEATURE_EH_FUNCLETS - // TODO: Unify with pCurrentContext / pCallerContext used on 64-bit - PCONTEXT pContextForUnwind; // scratch context for unwinding - // used to preserve context saved in the frame that - // could be otherwise wiped by the unwinding - - DWORD * pEdi; - DWORD * pEsi; - DWORD * pEbx; - DWORD * pEdx; - DWORD * pEcx; - DWORD * pEax; - - DWORD * pEbp; -#endif // !FEATURE_EH_FUNCLETS - -#ifndef FEATURE_EH_FUNCLETS - -#define REG_METHODS(reg) \ - inline PDWORD Get##reg##Location(void) { return p##reg; } \ - inline void Set##reg##Location(PDWORD p##reg) { this->p##reg = p##reg; } - -#else // !FEATURE_EH_FUNCLETS - #define REG_METHODS(reg) \ inline PDWORD Get##reg##Location(void) { return pCurrentContextPointers->reg; } \ inline void Set##reg##Location(PDWORD p##reg) \ @@ -104,8 +78,6 @@ struct REGDISPLAY : public REGDISPLAY_BASE { pCurrentContext->reg = *p##reg; \ } -#endif // FEATURE_EH_FUNCLETS - REG_METHODS(Eax) REG_METHODS(Ecx) REG_METHODS(Edx) @@ -122,21 +94,13 @@ struct REGDISPLAY : public REGDISPLAY_BASE { inline TADDR GetRegdisplayFP(REGDISPLAY *display) { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS return (TADDR)display->pCurrentContext->Ebp; -#else - return (TADDR)*display->GetEbpLocation(); -#endif } inline LPVOID GetRegdisplayFPAddress(REGDISPLAY *display) { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS return &display->pCurrentContext->Ebp; -#else - return (LPVOID)display->GetEbpLocation(); -#endif } inline TADDR GetRegdisplayPCTAddr(REGDISPLAY *display) @@ -147,9 +111,7 @@ inline TADDR GetRegdisplayPCTAddr(REGDISPLAY *display) inline void SetRegdisplayPCTAddr(REGDISPLAY *display, TADDR addr) { display->PCTAddr = addr; -#ifdef FEATURE_EH_FUNCLETS display->pCurrentContext->Eip = *PTR_PCODE(addr); -#endif display->ControlPC = *PTR_PCODE(addr); } @@ -366,8 +328,6 @@ inline BOOL IsInCalleesFrames(REGDISPLAY *display, LPVOID stackPointer) { #error "RegDisplay functions are not implemented on this platform." #endif -#ifdef FEATURE_EH_FUNCLETS -// This needs to be implemented for platforms that have funclets. inline LPVOID GetRegdisplayReturnValue(REGDISPLAY *display) { LIMITED_METHOD_CONTRACT; @@ -401,11 +361,9 @@ inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD) CheckRegDisplaySP(pRD); #endif // DEBUG_REGDISPLAY } -#endif // FEATURE_EH_FUNCLETS typedef REGDISPLAY *PREGDISPLAY; -#ifdef FEATURE_EH_FUNCLETS inline void FillContextPointers(PT_KNONVOLATILE_CONTEXT_POINTERS pCtxPtrs, PT_CONTEXT pCtx) { #ifdef TARGET_AMD64 @@ -463,7 +421,6 @@ inline void FillContextPointers(PT_KNONVOLATILE_CONTEXT_POINTERS pCtxPtrs, PT_CO PORTABILITY_ASSERT("FillContextPointers"); #endif // _TARGET_???_ (ELSE) } -#endif // FEATURE_EH_FUNCLETS inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pCallerCtx = NULL, bool fLightUnwind = false) { @@ -471,25 +428,6 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC SUPPORTS_DAC; -#ifndef FEATURE_EH_FUNCLETS -#ifdef TARGET_X86 - pRD->pContext = pctx; - pRD->pContextForUnwind = NULL; - pRD->pEdi = &(pctx->Edi); - pRD->pEsi = &(pctx->Esi); - pRD->pEbx = &(pctx->Ebx); - pRD->pEbp = &(pctx->Ebp); - pRD->pEax = &(pctx->Eax); - pRD->pEcx = &(pctx->Ecx); - pRD->pEdx = &(pctx->Edx); - pRD->SP = pctx->Esp; - pRD->ControlPC = (PCODE)(pctx->Eip); - pRD->PCTAddr = (UINT_PTR)&(pctx->Eip); -#else // TARGET_X86 - PORTABILITY_ASSERT("FillRegDisplay"); -#endif // _TARGET_???_ (ELSE) - -#else // !FEATURE_EH_FUNCLETS pRD->pContext = pctx; // Setup the references @@ -587,8 +525,6 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC pRD->volatileCurrContextPointers.T5 = &pctx->T5; pRD->volatileCurrContextPointers.T6 = &pctx->T6; #endif // TARGET_RISCV64 - -#endif // !FEATURE_EH_FUNCLETS } // Initialize a new REGDISPLAY/CONTEXT pair from an existing valid REGDISPLAY. @@ -601,32 +537,12 @@ inline void CopyRegDisplay(const PREGDISPLAY pInRD, PREGDISPLAY pOutRD, T_CONTEX T_CONTEXT* pOutCallerCtx = NULL; -#ifndef FEATURE_EH_FUNCLETS - -#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->pEbp != NULL) {pOutCtx->Ebp = *pInRD->pEbp;} else {pInRD->pEbp = NULL;} - if (pInRD->pEax != NULL) {pOutCtx->Eax = *pInRD->pEax;} else {pInRD->pEax = NULL;} - if (pInRD->pEcx != NULL) {pOutCtx->Ecx = *pInRD->pEcx;} else {pInRD->pEcx = NULL;} - if (pInRD->pEdx != NULL) {pOutCtx->Edx = *pInRD->pEdx;} else {pInRD->pEdx = NULL;} - pOutCtx->Esp = pInRD->SP; - pOutCtx->Eip = pInRD->ControlPC; -#else // TARGET_X86 - PORTABILITY_ASSERT("CopyRegDisplay"); -#endif // _TARGET_???_ - -#else // FEATURE_EH_FUNCLETS - *pOutCtx = *(pInRD->pCurrentContext); if (pInRD->IsCallerContextValid) { pOutCallerCtx = pInRD->pCallerContext; } -#endif // FEATURE_EH_FUNCLETS - if (pOutRD) FillRegDisplay(pOutRD, pOutCtx, pOutCallerCtx); } @@ -684,28 +600,7 @@ inline void UpdateContextFromRegDisp(PREGDISPLAY pRegDisp, PT_CONTEXT pContext) { _ASSERTE((pRegDisp != NULL) && (pContext != NULL)); -#ifndef FEATURE_EH_FUNCLETS - -#if defined(TARGET_X86) - pContext->ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL); - pContext->Edi = *pRegDisp->pEdi; - pContext->Esi = *pRegDisp->pEsi; - pContext->Ebx = *pRegDisp->pEbx; - pContext->Ebp = *pRegDisp->pEbp; - pContext->Eax = *pRegDisp->pEax; - pContext->Ecx = *pRegDisp->pEcx; - pContext->Edx = *pRegDisp->pEdx; - pContext->Esp = pRegDisp->SP; - pContext->Eip = pRegDisp->ControlPC; -#else // TARGET_X86 - PORTABILITY_ASSERT("UpdateContextFromRegDisp"); -#endif // _TARGET_???_ - -#else // FEATURE_EH_FUNCLETS - *pContext = *pRegDisp->pCurrentContext; - -#endif // FEATURE_EH_FUNCLETS } diff --git a/src/coreclr/inc/stackframe.h b/src/coreclr/inc/stackframe.h index 3c33d0e1e9fb35..f720c74db96162 100644 --- a/src/coreclr/inc/stackframe.h +++ b/src/coreclr/inc/stackframe.h @@ -114,13 +114,11 @@ struct CallerStackFrame : StackFrame { } -#ifdef FEATURE_EH_FUNCLETS static inline CallerStackFrame FromRegDisplay(REGDISPLAY* pRD) { _ASSERTE(pRD->IsCallerSPValid || pRD->IsCallerContextValid); return CallerStackFrame(GetSP(pRD->pCallerContext)); } -#endif // FEATURE_EH_FUNCLETS }; #endif // __STACKFRAME_H diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index c5179723a6700d..78f3431dc912e1 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -3687,9 +3687,7 @@ PhaseStatus Compiler::lvaMarkLocalVars() // saved EBP <-- EBP points here // other callee-saved registers // InfoHdrSmall.savedRegsCountExclFP specifies this size // optional GS cookie // InfoHdrSmall.security is 1 if this exists - // if FEATURE_EH_FUNCLETS // issynchronized bool if it is a synchronized method - // endif // FEATURE_EH_FUNCLETS // LocAllocSP slot // -- lower addresses -- // diff --git a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp index ec315adbd9e39c..b2a85e88d588e5 100644 --- a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp @@ -23,7 +23,6 @@ #include "eventtracebase.h" #ifdef TARGET_X86 -#define FEATURE_EH_FUNCLETS // Disable contracts #define LIMITED_METHOD_CONTRACT diff --git a/src/coreclr/tools/cdac-build-tool/README.md b/src/coreclr/tools/cdac-build-tool/README.md index 512026a29860b9..80087ff390e141 100644 --- a/src/coreclr/tools/cdac-build-tool/README.md +++ b/src/coreclr/tools/cdac-build-tool/README.md @@ -81,10 +81,10 @@ CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() CDAC_GLOBAL_POINTER(ManagedThreadStore, &g_managedThreadStore) -#if FEATURE_EH_FUNCLETS -CDAC_GLOBAL(FeatureEHFunclets, uint8, 1) +#if FEATURE_COMINTEROP +CDAC_GLOBAL(FeatureCOMInterop, uint8, 1) #else -CDAC_GLOBAL(FeatureEHFunclets, uint8, 0) +CDAC_GLOBAL(FeatureCOMInterop, uint8, 0) #endif CDAC_GLOBAL(SomeMagicNumber, uint32, 42) CDAC_GLOBALS_END() diff --git a/src/coreclr/tools/cdac-build-tool/sample/sample.data.h b/src/coreclr/tools/cdac-build-tool/sample/sample.data.h index 58ed59d02de4a1..022fbbf1a8353e 100644 --- a/src/coreclr/tools/cdac-build-tool/sample/sample.data.h +++ b/src/coreclr/tools/cdac-build-tool/sample/sample.data.h @@ -57,10 +57,10 @@ CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() CDAC_GLOBAL_POINTER(ManagedThreadStore, &g_managedThreadStore) -#if FEATURE_EH_FUNCLETS -CDAC_GLOBAL(FeatureEHFunclets, uint8, 1) +#if FEATURE_COMINTEROP +CDAC_GLOBAL(FeatureCOMInterop, uint8, 1) #else -CDAC_GLOBAL(FeatureEHFunclets, uint8, 0) +CDAC_GLOBAL(FeatureCOMInterop, uint8, 0) #endif CDAC_GLOBAL(SomeMagicNumber, uint32, 42) CDAC_GLOBAL_STRING(RuntimeIdentifier, "windows-x64") diff --git a/src/coreclr/unwinder/i386/unwinder.cpp b/src/coreclr/unwinder/i386/unwinder.cpp index 4ad7cfeccc0ff6..5c9eab50e387f1 100644 --- a/src/coreclr/unwinder/i386/unwinder.cpp +++ b/src/coreclr/unwinder/i386/unwinder.cpp @@ -6,7 +6,6 @@ #include "stdafx.h" #include "unwinder.h" -#ifdef FEATURE_EH_FUNCLETS BOOL OOPStackUnwinderX86::Unwind(T_CONTEXT* pContextRecord, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers) { REGDISPLAY rd; @@ -218,4 +217,3 @@ RtlVirtualUnwind ( return handlerRoutine; } -#endif // FEATURE_EH_FUNCLETS diff --git a/src/coreclr/unwinder/i386/unwinder.h b/src/coreclr/unwinder/i386/unwinder.h index 9e60af26d36147..b409cc58d2a47a 100644 --- a/src/coreclr/unwinder/i386/unwinder.h +++ b/src/coreclr/unwinder/i386/unwinder.h @@ -8,7 +8,6 @@ #include "baseunwinder.h" -#ifdef FEATURE_EH_FUNCLETS //--------------------------------------------------------------------------------------- // // See the comment for the base class code:OOPStackUnwinder. @@ -29,6 +28,5 @@ class OOPStackUnwinderX86 : public OOPStackUnwinder __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _Outptr_opt_result_maybenull_ PEXCEPTION_ROUTINE *HandlerRoutine); }; -#endif // FEATURE_EH_FUNCLETS #endif // __unwinder_i386_h__ diff --git a/src/coreclr/vm/amd64/excepcpu.h b/src/coreclr/vm/amd64/excepcpu.h index 3403f99a5e8d91..7c9a12f30da0e9 100644 --- a/src/coreclr/vm/amd64/excepcpu.h +++ b/src/coreclr/vm/amd64/excepcpu.h @@ -25,17 +25,6 @@ EXTERN_C void RedirectForThrowControl(); #define STATUS_CLR_GCCOVER_CODE STATUS_PRIVILEGED_INSTRUCTION -// -// No FS:0, nothing to do. -// -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) - -// -// On Win64, the COMPlusFrameHandler's work is done by our personality routine. -// -#define DECLARE_CPFH_EH_RECORD(pCurThread) - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index e75348394e15c0..efdc75e8d099d6 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1106,11 +1106,9 @@ void SystemDomain::LoadBaseSystemClasses() } #endif -#ifdef FEATURE_EH_FUNCLETS g_pEHClass = CoreLibBinder::GetClass(CLASS__EH); g_pExceptionServicesInternalCallsClass = CoreLibBinder::GetClass(CLASS__EXCEPTIONSERVICES_INTERNALCALLS); g_pStackFrameIteratorClass = CoreLibBinder::GetClass(CLASS__STACKFRAMEITERATOR); -#endif g_pGetGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_GC_STATIC)->GetMultiCallableAddrOfCode(); g_pGetNonGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_NONGC_STATIC)->GetMultiCallableAddrOfCode(); diff --git a/src/coreclr/vm/arm/excepcpu.h b/src/coreclr/vm/arm/excepcpu.h index 7637cec21e76fd..26783a330faab4 100644 --- a/src/coreclr/vm/arm/excepcpu.h +++ b/src/coreclr/vm/arm/excepcpu.h @@ -1,8 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// - #ifndef __excepcpu_h__ #define __excepcpu_h__ @@ -15,13 +12,6 @@ EXTERN_C void RedirectForThreadAbort(); class Thread; class FaultingExceptionFrame; -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) -// -// On ARM, the COMPlusFrameHandler's work is done by our personality routine. -// -#define DECLARE_CPFH_EH_RECORD(pCurThread) - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/coreclr/vm/arm64/excepcpu.h b/src/coreclr/vm/arm64/excepcpu.h index acbd29b102e7b5..8c5ab14f33a2f0 100644 --- a/src/coreclr/vm/arm64/excepcpu.h +++ b/src/coreclr/vm/arm64/excepcpu.h @@ -17,13 +17,6 @@ EXTERN_C void RedirectForThreadAbort(); class Thread; class FaultingExceptionFrame; -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) -// -// On ARM, the COMPlusFrameHandler's work is done by our personality routine. -// -#define DECLARE_CPFH_EH_RECORD(pCurThread) - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index 96df6009215b2f..783c1a239cc4ad 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -1,9 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + /* * CallHelpers.CPP: helpers to call managed code - * - */ #include "common.h" @@ -29,15 +28,12 @@ void AssertMulticoreJitAllowedModule(PCODE pTarget) #endif -// For X86, INSTALL_COMPLUS_EXCEPTION_HANDLER grants us sufficient protection to call into -// managed code. -// -// But on 64-bit, the personality routine will not pop frames or trackers as exceptions unwind +// The personality routine will not pop frames or trackers as exceptions unwind // out of managed code. Instead, we rely on explicit cleanup like CLRException::HandlerState::CleanupTry // or UMThunkUnwindFrameChainHandler. // -// So all callers should call through CallDescrWorkerWithHandler (or a wrapper like MethodDesc::Call) -// and get the platform-appropriate exception handling. +// All callers should call through CallDescrWorkerWithHandler (or a wrapper like MethodDesc::Call) +// to get proper exception handling. //******************************************************************************* void CallDescrWorkerWithHandler( diff --git a/src/coreclr/vm/callhelpers.h b/src/coreclr/vm/callhelpers.h index 256744467d5837..9526da60dbbe39 100644 --- a/src/coreclr/vm/callhelpers.h +++ b/src/coreclr/vm/callhelpers.h @@ -1,20 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + /*============================================================ -** ** File: callhelpers.h ** Purpose: Provides helpers for making managed calls -** - ===========================================================*/ + #ifndef __CALLHELPERS_H__ #define __CALLHELPERS_H__ struct CallDescrData { - // // Input arguments - // LPVOID pSrc; UINT32 numStackSlots; #ifdef CALLDESCR_ARGREGS @@ -480,7 +477,6 @@ enum EEToManagedCallFlags #define BEGIN_CALL_TO_MANAGEDEX(flags) \ { \ MAKE_CURRENT_THREAD_AVAILABLE(); \ - DECLARE_CPFH_EH_RECORD(CURRENT_THREAD); \ _ASSERTE(CURRENT_THREAD); \ _ASSERTE((CURRENT_THREAD->m_StateNC & Thread::TSNC_OwnsSpinLock) == 0); \ /* This bit should never be set when we call into managed code. The */ \ @@ -494,11 +490,9 @@ enum EEToManagedCallFlags if (CURRENT_THREAD->IsAbortRequested()) { \ CURRENT_THREAD->HandleThreadAbort(); \ } \ - } \ - INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE(); + } #define END_CALL_TO_MANAGED() \ - UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); \ } /***********************************************************************/ diff --git a/src/coreclr/vm/clrex.cpp b/src/coreclr/vm/clrex.cpp index ca64a95aebd36f..4bf876ce778ac8 100644 --- a/src/coreclr/vm/clrex.cpp +++ b/src/coreclr/vm/clrex.cpp @@ -16,9 +16,7 @@ #include "sigformat.h" #include "eeconfig.h" -#ifdef FEATURE_EH_FUNCLETS #include "exceptionhandling.h" -#endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_COMINTEROP #include "interoputil.inl" diff --git a/src/coreclr/vm/clrtocomcall.cpp b/src/coreclr/vm/clrtocomcall.cpp index eff0398678e30c..f5151ca19b0716 100644 --- a/src/coreclr/vm/clrtocomcall.cpp +++ b/src/coreclr/vm/clrtocomcall.cpp @@ -1,14 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // File: CLRtoCOMCall.cpp -// - // // CLR to COM call support. // - #include "common.h" #include "stublink.h" @@ -38,7 +36,6 @@ void CreateCLRToDispatchCOMStub( DWORD dwStubFlags // PInvokeStubFlags ); - PCODE TheGenericCLRToCOMCallStub() { LIMITED_METHOD_CONTRACT; @@ -46,8 +43,6 @@ PCODE TheGenericCLRToCOMCallStub() return GetEEFuncEntryPoint(GenericCLRToCOMCallStub); } - - CLRToCOMCallInfo *CLRToCOMCall::PopulateCLRToCOMCallMethodDesc(MethodDesc* pMD, DWORD* pdwStubFlags) { CONTRACTL @@ -162,8 +157,6 @@ MethodDesc* CLRToCOMCall::GetILStubMethodDesc(MethodDesc* pMD, DWORD dwStubFlags dwStubFlags); } - - PCODE CLRToCOMCall::GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD) { STANDARD_VM_CONTRACT; @@ -202,7 +195,6 @@ PCODE CLRToCOMCall::GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD) return pStub; } - I4ARRAYREF SetUpWrapperInfo(MethodDesc *pMD) { CONTRACTL diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 893a7a87ae9305..2338ab43a56071 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -909,8 +909,6 @@ void IJitManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) #endif // #ifdef DACCESS_COMPILE -#if defined(FEATURE_EH_FUNCLETS) - PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFunction, /* out */ SIZE_T * pSize) { LIMITED_METHOD_CONTRACT; @@ -1112,17 +1110,6 @@ BOOL IJitManager::IsFilterFunclet(EECodeInfo * pCodeInfo) return false; } -#else // FEATURE_EH_FUNCLETS - -PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFunction, /* out */ SIZE_T * pSize) -{ - *pSize = 0; - return dac_cast(pRuntimeFunction->UnwindData + moduleBase); -} - -#endif // FEATURE_EH_FUNCLETS - - #ifndef DACCESS_COMPILE @@ -2517,8 +2504,6 @@ CodeHeapRequestInfo::CodeHeapRequestInfo(MethodDesc* pMD, LoaderAllocator* pAllo m_isCollectible = m_pAllocator->IsCollectible(); } -#ifdef FEATURE_EH_FUNCLETS - #ifdef HOST_64BIT extern "C" PT_RUNTIME_FUNCTION GetRuntimeFunctionCallback(IN ULONG64 ControlPc, IN PVOID Context) @@ -2557,7 +2542,6 @@ extern "C" PT_RUNTIME_FUNCTION GetRuntimeFunctionCallback(IN ULONG ControlPc return prf; } -#endif // FEATURE_EH_FUNCLETS HeapList* EECodeGenManager::NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList) { @@ -2831,9 +2815,7 @@ template void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader -#ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos -#endif ) { CONTRACTL { @@ -2879,9 +2861,7 @@ void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reser #ifdef FEATURE_INTERPRETER if (std::is_same::value) { -#ifdef FEATURE_EH_FUNCLETS _ASSERTE(nUnwindInfos == 0); -#endif _ASSERTE(reserveForJumpStubs == 0); requestInfo.SetInterpreted(); realHeaderSize = sizeof(InterpreterRealCodeHeader); @@ -2891,11 +2871,7 @@ void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reser { requestInfo.SetReserveForJumpStubs(reserveForJumpStubs); -#ifdef FEATURE_EH_FUNCLETS realHeaderSize = offsetof(RealCodeHeader, unwindInfos[0]) + (sizeof(T_RUNTIME_FUNCTION) * nUnwindInfos); -#else - realHeaderSize = sizeof(RealCodeHeader); -#endif } // if this is a LCG method then we will be allocating the RealCodeHeader @@ -2975,12 +2951,10 @@ void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reser } pCodeHdrRW->SetMethodDesc(pMDTarget); -#ifdef FEATURE_EH_FUNCLETS if (std::is_same::value) { ((CodeHeader*)pCodeHdrRW)->SetNumberOfUnwindInfos(nUnwindInfos); } -#endif if (requestInfo.IsDynamicDomain()) { @@ -2999,18 +2973,14 @@ void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reser template void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader -#ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos -#endif ); #ifdef FEATURE_INTERPRETER template void EECodeGenManager::AllocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader -#ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos -#endif ); #endif // FEATURE_INTERPRETER @@ -4299,13 +4269,11 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ this->pRealCodeHeader.EnumMem(); -#ifdef FEATURE_EH_FUNCLETS // UnwindInfos are stored in an array immediately following the RealCodeHeader structure in memory. if (this->pRealCodeHeader->nUnwindInfos) { DacEnumMemoryRegion(PTR_TO_MEMBER_TADDR(RealCodeHeader, pRealCodeHeader, unwindInfos), this->pRealCodeHeader->nUnwindInfos * sizeof(T_RUNTIME_FUNCTION)); } -#endif // FEATURE_EH_FUNCLETS if (this->GetDebugInfo() != NULL) { @@ -4440,7 +4408,6 @@ BOOL EECodeGenManager::JitCodeToMethodInfoWorker( // take into account cold code. pCodeInfo->m_relOffset = (DWORD)(PCODEToPINSTR(currentPC) - start); -#ifdef FEATURE_EH_FUNCLETS // Computed lazily by code:EEJitManager::LazyGetFunctionEntry if (pCHdr->MayHaveFunclets()) { @@ -4453,7 +4420,6 @@ BOOL EECodeGenManager::JitCodeToMethodInfoWorker( pCodeInfo->m_pFunctionEntry = pCHdr->GetUnwindInfo(0); pCodeInfo->m_isFuncletCache = EECodeInfo::IsFuncletCache::IsNotFunclet; } -#endif } if (ppMethodDesc) @@ -4836,7 +4802,6 @@ void EECodeGenManager::NibbleMapDeleteUnlocked(HeapList* pHp, TADDR pCode) #endif // !DACCESS_COMPILE -#if defined(FEATURE_EH_FUNCLETS) PTR_RUNTIME_FUNCTION EEJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo) { CONTRACTL { @@ -5050,7 +5015,6 @@ extern "C" void GetRuntimeStackWalkInfo(IN ULONG64 ControlPc, *pFuncEntry = (UINT_PTR)(PT_RUNTIME_FUNCTION)codeInfo.GetFunctionEntry(); } } -#endif // FEATURE_EH_FUNCLETS #ifdef DACCESS_COMPILE @@ -6040,7 +6004,7 @@ static void GetFuncletStartOffsetsHelper(PCODE pCodeStart, SIZE_T size, SIZE_T o } } -#if defined(FEATURE_EH_FUNCLETS) && defined(DACCESS_COMPILE) +#if defined(DACCESS_COMPILE) // // To locate an entry in the function entry table (the program exceptions data directory), the debugger @@ -6094,7 +6058,7 @@ static void EnumRuntimeFunctionEntriesToFindEntry(PTR_RUNTIME_FUNCTION pRtf, PTR _ASSERTE(low <= mid && mid <= high); } } -#endif // FEATURE_EH_FUNCLETS +#endif // DACCESS_COMPILE #if defined(FEATURE_READYTORUN) @@ -6714,7 +6678,6 @@ BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, return TRUE; } -#ifdef FEATURE_EH_FUNCLETS // Save the raw entry PTR_RUNTIME_FUNCTION RawFunctionEntry = pRuntimeFunctions + MethodIndex; @@ -6728,17 +6691,12 @@ BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, MethodDesc *pMethodDesc; while ((pMethodDesc = pInfo->GetMethodDescForEntryPoint(ImageBase + RUNTIME_FUNCTION__BeginAddress(pRuntimeFunctions + MethodIndex))) == NULL) MethodIndex--; -#endif PTR_RUNTIME_FUNCTION FunctionEntry = pRuntimeFunctions + MethodIndex; if (ppMethodDesc) { -#ifdef FEATURE_EH_FUNCLETS *ppMethodDesc = pMethodDesc; -#else - *ppMethodDesc = pInfo->GetMethodDescForEntryPoint(ImageBase + RUNTIME_FUNCTION__BeginAddress(FunctionEntry)); -#endif _ASSERTE(*ppMethodDesc != NULL); } @@ -6747,10 +6705,8 @@ BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, // We are using RUNTIME_FUNCTION as METHODTOKEN pCodeInfo->m_methodToken = METHODTOKEN(pRangeSection, dac_cast(FunctionEntry)); -#ifdef FEATURE_EH_FUNCLETS AMD64_ONLY(_ASSERTE((RawFunctionEntry->UnwindData & RUNTIME_FUNCTION_INDIRECT) == 0)); pCodeInfo->m_pFunctionEntry = RawFunctionEntry; -#endif MethodRegionInfo methodRegionInfo; JitTokenToMethodRegionInfo(pCodeInfo->m_methodToken, &methodRegionInfo); if ((methodRegionInfo.coldSize > 0) && (currentInstr >= methodRegionInfo.coldStartAddress)) @@ -6767,7 +6723,6 @@ BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, return TRUE; } -#if defined(FEATURE_EH_FUNCLETS) PTR_RUNTIME_FUNCTION ReadyToRunJitManager::LazyGetFunctionEntry(EECodeInfo * pCodeInfo) { CONTRACTL { @@ -6922,8 +6877,6 @@ BOOL ReadyToRunJitManager::IsFilterFunclet(EECodeInfo * pCodeInfo) #endif } -#endif // FEATURE_EH_FUNCLETS - void ReadyToRunJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodToken, MethodRegionInfo * methodRegionInfo) { @@ -6987,8 +6940,6 @@ void ReadyToRunJitManager::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) IJitManager::EnumMemoryRegions(flags); } -#if defined(FEATURE_EH_FUNCLETS) - // // EnumMemoryRegionsForMethodUnwindInfo - enumerate the memory necessary to read the unwind info for the // specified method. @@ -7023,8 +6974,6 @@ void ReadyToRunJitManager::EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemor if (pUnwindData != NULL) DacEnumMemoryRegion(PTR_TO_TADDR(pUnwindData), size); } - -#endif //FEATURE_EH_FUNCLETS #endif // #ifdef DACCESS_COMPILE #endif diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index d94ee1f39dbc7e..3737097e90ccf8 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -180,10 +180,8 @@ struct RealCodeHeader PTR_MethodDesc phdrMDesc; -#ifdef FEATURE_EH_FUNCLETS DWORD nUnwindInfos; T_RUNTIME_FUNCTION unwindInfos[0]; -#endif // FEATURE_EH_FUNCLETS }; struct InterpreterRealCodeHeader @@ -279,7 +277,6 @@ struct CodeHeader pRealCodeHeader = (PTR_RealCodeHeader)kind; } -#if defined(FEATURE_EH_FUNCLETS) UINT GetNumberOfUnwindInfos() { SUPPORTS_DAC; @@ -302,7 +299,6 @@ struct CodeHeader return dac_cast( PTR_TO_MEMBER_TADDR(RealCodeHeader, pRealCodeHeader, unwindInfos) + iUnwindInfo * sizeof(T_RUNTIME_FUNCTION)); } -#endif // FEATURE_EH_FUNCLETS #ifdef DACCESS_COMPILE @@ -374,7 +370,6 @@ struct InterpreterCodeHeader return FALSE; } -#if defined(FEATURE_EH_FUNCLETS) bool MayHaveFunclets() { LIMITED_METHOD_CONTRACT; @@ -387,7 +382,6 @@ struct InterpreterCodeHeader _ASSERTE(!"Unexpected call to GetUnwindInfoZero"); return NULL; } -#endif #ifdef DACCESS_COMPILE void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan); @@ -1751,7 +1745,6 @@ class IJitManager TADDR JitTokenToModuleBase(const METHODTOKEN& MethodToken); -#if defined(FEATURE_EH_FUNCLETS) virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) = 0; // GetFuncletStartAddress returns the starting address of the function or funclet indicated by the EECodeInfo address. @@ -1761,7 +1754,6 @@ class IJitManager virtual BOOL LazyIsFunclet(EECodeInfo * pCodeInfo); virtual BOOL IsFilterFunclet(EECodeInfo * pCodeInfo); -#endif // FEATURE_EH_FUNCLETS virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) = 0; @@ -1771,10 +1763,8 @@ class IJitManager #if defined(DACCESS_COMPILE) virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) = 0; -#if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) = 0; -#endif // FEATURE_EH_FUNCLETS #endif // DACCESS_COMPILE #ifndef DACCESS_COMPILE @@ -1943,9 +1933,7 @@ class EECodeGenManager : public IJitManager template void AllocCode(MethodDesc* pMD, size_t blockSize, size_t reserveForJumpStubs, CorJitAllocMemFlag flag, void** ppCodeHeader, void** ppCodeHeaderRW, size_t* pAllocatedSize, HeapList** ppCodeHeap , BYTE** ppRealHeader -#ifdef FEATURE_EH_FUNCLETS , UINT nUnwindInfos -#endif ); BYTE *AllocFromJitMetaHeap(MethodDesc *pMD, size_t blockSize); @@ -2178,16 +2166,13 @@ class EEJitManager final : public EECodeGenManager static CodeHeader * GetCodeHeader(const METHODTOKEN& MethodToken); static CodeHeader * GetCodeHeaderFromStartAddress(TADDR methodStartAddress); -#if defined(FEATURE_EH_FUNCLETS) // Compute function entry lazily. Do not call directly. Use EECodeInfo::GetFunctionEntry instead. virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo); virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength); -#endif // FEATURE_EH_FUNCLETS virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); -#if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { @@ -2197,7 +2182,6 @@ class EEJitManager final : public EECodeGenManager // unwind information at dump generation time (since it's dynamic, it will not be otherwise // available at debug time). } -#endif // FEATURE_EH_FUNCLETS #if !defined DACCESS_COMPILE protected: @@ -2737,24 +2721,20 @@ class ReadyToRunJitManager final : public IJitManager virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); -#if defined(FEATURE_EH_FUNCLETS) virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo); virtual TADDR GetFuncletStartAddress(EECodeInfo * pCodeInfo); virtual DWORD GetFuncletStartOffsets(const METHODTOKEN& MethodToken, DWORD* pStartFuncletOffsets, DWORD dwLength); virtual BOOL LazyIsFunclet(EECodeInfo * pCodeInfo); virtual BOOL IsFilterFunclet(EECodeInfo * pCodeInfo); -#endif // FEATURE_EH_FUNCLETS virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC); #if defined(DACCESS_COMPILE) virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); -#if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); -#endif //FEATURE_EH_FUNCLETS #endif //DACCESS_COMPILE }; @@ -2850,7 +2830,6 @@ class InterpreterJitManager final : public EECodeGenManager CrawlFrame *pCf); #endif // #ifndef DACCESS_COMPILE -#if defined(FEATURE_EH_FUNCLETS) virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo) { // Not used for the interpreter @@ -2871,8 +2850,6 @@ class InterpreterJitManager final : public EECodeGenManager public: #endif // !DACCESS_COMPILE -#endif // FEATURE_EH_FUNCLETS - virtual StubCodeBlockKind GetStubCodeBlockKind(RangeSection * pRangeSection, PCODE currentPC) { return STUB_CODE_BLOCK_UNKNOWN; @@ -2887,14 +2864,12 @@ class InterpreterJitManager final : public EECodeGenManager virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); -#if defined(FEATURE_EH_FUNCLETS) virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { // Not used for the interpreter _ASSERTE(FALSE); } -#endif // FEATURE_EH_FUNCLETS #endif // DACCESS_COMPILE private : Crst m_interpreterLoadLock; @@ -2921,14 +2896,12 @@ class EECodeInfo friend BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection, PCODE currentPC, MethodDesc** ppMethodDesc, EECodeInfo * pCodeInfo); #endif -#if defined(FEATURE_EH_FUNCLETS) enum class IsFuncletCache : uint32_t { NotSet = 2, IsFunclet = 1, IsNotFunclet = 0 }; -#endif // FEATURE_EH_FUNCLETS public: EECodeInfo(); @@ -3021,11 +2994,9 @@ class EECodeInfo return GetJitManager()->JitTokenToModuleBase(GetMethodToken()); } -#ifdef FEATURE_EH_FUNCLETS PTR_RUNTIME_FUNCTION GetFunctionEntry(); BOOL IsFunclet(); EECodeInfo GetMainFunctionInfo(); -#endif // FEATURE_EH_FUNCLETS #if defined(TARGET_X86) ULONG GetFixedStackSize() @@ -3068,10 +3039,8 @@ ULONG GetFixedStackSize(); MethodDesc *m_pMD; IJitManager *m_pJM; DWORD m_relOffset; -#ifdef FEATURE_EH_FUNCLETS IsFuncletCache m_isFuncletCache; PTR_RUNTIME_FUNCTION m_pFunctionEntry; -#endif // FEATURE_EH_FUNCLETS #ifdef TARGET_X86 PTR_CBYTE m_hdrInfoTable; diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 9e2e71bb3a4bc3..79fb0c563ac6c2 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1358,14 +1358,12 @@ DEFINE_FIELD_U(signature, GenericHandleArgs, signature) DEFINE_FIELD_U(module, GenericHandleArgs, module) DEFINE_FIELD_U(dictionaryIndexAndSlot, GenericHandleArgs, dictionaryIndexAndSlot) -#ifdef FEATURE_EH_FUNCLETS DEFINE_CLASS(EH, Runtime, EH) DEFINE_METHOD(EH, RH_THROW_EX, RhThrowEx, SM_Obj_RefExInfo_RetVoid) DEFINE_METHOD(EH, RH_THROWHW_EX, RhThrowHwEx, SM_UInt_RefExInfo_RetVoid) DEFINE_METHOD(EH, RH_RETHROW, RhRethrow, SM_RefExInfo_RefExInfo_RetVoid) DEFINE_CLASS(EXCEPTIONSERVICES_INTERNALCALLS, ExceptionServices, InternalCalls) DEFINE_CLASS(STACKFRAMEITERATOR, Runtime, StackFrameIterator) -#endif // FEATURE_EH_FUNCLETS DEFINE_CLASS(EXINFO, Runtime, EH+ExInfo) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 32fed129136099..660f79cf77edcb 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -664,10 +664,8 @@ CDAC_TYPE_INDETERMINATE(RealCodeHeader) CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, MethodDesc, offsetof(RealCodeHeader, phdrMDesc)) CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, DebugInfo, offsetof(RealCodeHeader, phdrDebugInfo)) CDAC_TYPE_FIELD(RealCodeHeader, /*pointer*/, GCInfo, offsetof(RealCodeHeader, phdrJitGCInfo)) -#ifdef FEATURE_EH_FUNCLETS CDAC_TYPE_FIELD(RealCodeHeader, /*uint32*/, NumUnwindInfos, offsetof(RealCodeHeader, nUnwindInfos)) CDAC_TYPE_FIELD(RealCodeHeader, /* T_RUNTIME_FUNCTION */, UnwindInfos, offsetof(RealCodeHeader, unwindInfos)) -#endif // FEATURE_EH_FUNCLETS CDAC_TYPE_END(RealCodeHeader) CDAC_TYPE_BEGIN(CodeHeapListNode) @@ -882,9 +880,7 @@ CDAC_TYPE_END(HijackArgs) CDAC_TYPE_BEGIN(FaultingExceptionFrame) CDAC_TYPE_SIZE(sizeof(FaultingExceptionFrame)) -#ifdef FEATURE_EH_FUNCLETS CDAC_TYPE_FIELD(FaultingExceptionFrame, /*T_CONTEXT*/, TargetContext, cdac_data::TargetContext) -#endif // FEATURE_EH_FUNCLETS CDAC_TYPE_END(FaultingExceptionFrame) #if defined(TARGET_X86) && !defined(UNIX_X86_ABI) diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index a1217e30a16631..e544d89b39eb23 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -416,10 +416,6 @@ class UMEntryThunkCache AppDomain *m_pDomain; }; -#ifndef FEATURE_EH_FUNCLETS -EXCEPTION_HANDLER_DECL(FastNExportExceptHandler); -#endif // FEATURE_EH_FUNCLETS - extern "C" void TheUMEntryPrestub(void); extern "C" PCODE TheUMEntryPrestubWorker(UMEntryThunkData * pUMEntryThunk); diff --git a/src/coreclr/vm/dwreport.cpp b/src/coreclr/vm/dwreport.cpp index 4ed6f50d3a7623..a650f352b49118 100644 --- a/src/coreclr/vm/dwreport.cpp +++ b/src/coreclr/vm/dwreport.cpp @@ -1,13 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// FILE: dwreport.cpp -// // - +// FILE: dwreport.cpp // -// ============================================================================ #include "common.h" @@ -23,9 +19,7 @@ #include "utilcode.h" #include "../dlls/mscorrc/resource.h" // for resource ids -#ifdef FEATURE_EH_FUNCLETS #include "exinfo.h" -#endif EFaultRepRetVal DoReportFault(EXCEPTION_POINTERS * pExceptionInfo); diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 7eaf2b6567f6c3..3ac8563207491a 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -1,13 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// EEConfig.CPP -// +// EEConfig.CPP // // Fetched configuration data from the registry (should we Jit, run GC checks ...) // -// - #include "common.h" #include "eeconfig.h" @@ -185,7 +182,7 @@ HRESULT EEConfig::Init() m_fInteropValidatePinnedObjects = false; m_fInteropLogArguments = false; -#if defined(_DEBUG) && defined(FEATURE_EH_FUNCLETS) +#if defined(_DEBUG) fSuppressLockViolationsOnReentryFromOS = false; #endif @@ -653,7 +650,7 @@ HRESULT EEConfig::sync() m_fInteropValidatePinnedObjects = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_InteropValidatePinnedObjects) != 0); m_fInteropLogArguments = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InteropLogArguments) != 0); -#if defined(_DEBUG) && defined(FEATURE_EH_FUNCLETS) +#if defined(_DEBUG) fSuppressLockViolationsOnReentryFromOS = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressLockViolationsOnReentryFromOS) != 0); #endif diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 1bc9986443e9cf..fadd2515f2cf6a 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -269,9 +269,7 @@ class EEConfig bool IsJitVerificationDisabled(void) const {LIMITED_METHOD_CONTRACT; return fJitVerificationDisable; } -#ifdef FEATURE_EH_FUNCLETS bool SuppressLockViolationsOnReentryFromOS() const {LIMITED_METHOD_CONTRACT; return fSuppressLockViolationsOnReentryFromOS; } -#endif #endif // _DEBUG @@ -520,9 +518,7 @@ class EEConfig // at load time. bool fJitVerificationDisable; // Turn off jit verification (for testing purposes only) -#ifdef FEATURE_EH_FUNCLETS bool fSuppressLockViolationsOnReentryFromOS; -#endif #endif // _DEBUG #ifdef ENABLE_STARTUP_DELAY diff --git a/src/coreclr/vm/eedbginterface.h b/src/coreclr/vm/eedbginterface.h index e6cae0fc3ff698..a6fd0182fd5a19 100644 --- a/src/coreclr/vm/eedbginterface.h +++ b/src/coreclr/vm/eedbginterface.h @@ -1,11 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // EE to Debugger Interface Header // - - #ifndef _eedbginterface_h_ #define _eedbginterface_h_ @@ -154,10 +153,8 @@ class EEDebugInterface size_t * hotSize, size_t * coldSize) = 0; -#if defined(FEATURE_EH_FUNCLETS) virtual DWORD GetFuncletStartOffsets(const BYTE *pStart, DWORD* pStartOffsets, DWORD dwLength) = 0; virtual StackFrame FindParentStackFrame(CrawlFrame* pCF) = 0; -#endif // FEATURE_EH_FUNCLETS virtual size_t GetFunctionSize(MethodDesc *pFD) = 0; diff --git a/src/coreclr/vm/eedbginterfaceimpl.cpp b/src/coreclr/vm/eedbginterfaceimpl.cpp index f810dbdab7960e..6b35ea2e9a6f40 100644 --- a/src/coreclr/vm/eedbginterfaceimpl.cpp +++ b/src/coreclr/vm/eedbginterfaceimpl.cpp @@ -1,11 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - /* - * * EE to Debugger Interface Implementation - * */ #include "common.h" @@ -556,7 +553,6 @@ void EEDbgInterfaceImpl::GetMethodRegionInfo(const PCODE pStart, *coldSize = methodRegionInfo.coldSize; } -#if defined(FEATURE_EH_FUNCLETS) DWORD EEDbgInterfaceImpl::GetFuncletStartOffsets(const BYTE *pStart, DWORD* pStartOffsets, DWORD dwLength) { CONTRACTL @@ -592,7 +588,6 @@ StackFrame EEDbgInterfaceImpl::FindParentStackFrame(CrawlFrame* pCF) #endif // !DACCESS_COMPILE } -#endif // FEATURE_EH_FUNCLETS #ifndef DACCESS_COMPILE size_t EEDbgInterfaceImpl::GetFunctionSize(MethodDesc *pFD) diff --git a/src/coreclr/vm/eedbginterfaceimpl.h b/src/coreclr/vm/eedbginterfaceimpl.h index c2d62dad7674b8..3e59d15da56ab3 100644 --- a/src/coreclr/vm/eedbginterfaceimpl.h +++ b/src/coreclr/vm/eedbginterfaceimpl.h @@ -135,10 +135,8 @@ class EEDbgInterfaceImpl : public EEDebugInterface size_t *hotSize, size_t *coldSize); -#if defined(FEATURE_EH_FUNCLETS) DWORD GetFuncletStartOffsets(const BYTE *pStart, DWORD* pStartOffsets, DWORD dwLength); StackFrame FindParentStackFrame(CrawlFrame* pCF); -#endif // FEATURE_EH_FUNCLETS size_t GetFunctionSize(MethodDesc *pFD) DAC_UNEXPECTED(); diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index 888cf716d7e32c..004232f320b5a9 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - #include "common.h" #include "ecall.h" @@ -43,85 +42,6 @@ void promoteVarArgs(PTR_BYTE argsStart, PTR_VASigCookie varArgSig, GCCONTEXT* ct #include "exceptionhandling.h" #ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS - -/***************************************************************************** - * - * Setup context to enter an exception handler (a 'catch' block). - * This is the last chance for the runtime support to do fixups in - * the context before execution continues inside a filter, catch handler, - * or finally. - */ -void EECodeManager::FixContext( ContextType ctxType, - EHContext *ctx, - EECodeInfo *pCodeInfo, - DWORD dwRelOffset, - DWORD nestingLevel, - OBJECTREF thrownObject, - size_t ** ppShadowSP, - size_t ** ppEndRegion) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - _ASSERTE((ctxType == FINALLY_CONTEXT) == (thrownObject == NULL)); - - /* Extract the necessary information from the info block header */ - hdrInfo hdrInfoBody = { 0 }; - pCodeInfo->DecodeGCHdrInfo(&hdrInfoBody, dwRelOffset); - -#ifdef _DEBUG - if (trFixContext) { - minipal_log_print_info("FixContext [%s][%s] for %s.%s: ", - hdrInfoBody.ebpFrame?"ebp":" ", - hdrInfoBody.interruptible?"int":" ", - "UnknownClass","UnknownMethod"); - minipal_log_flush_info(); - } -#endif - - /* make sure that we have an ebp stack frame */ - - _ASSERTE(hdrInfoBody.ebpFrame); - _ASSERTE(hdrInfoBody.handlers); // @TODO : This will always be set. Remove it - - TADDR baseSP; - GetHandlerFrameInfo(&hdrInfoBody, ctx->Ebp, - ctxType == FILTER_CONTEXT ? ctx->Esp : IGNORE_VAL, - ctxType == FILTER_CONTEXT ? (DWORD) IGNORE_VAL : nestingLevel, - &baseSP, - &nestingLevel); - - _ASSERTE((size_t)ctx->Ebp >= baseSP); - _ASSERTE(baseSP >= (size_t)ctx->Esp); - - ctx->Esp = (DWORD)baseSP; - - // EE will write Esp to **pShadowSP before jumping to handler - - PTR_TADDR pBaseSPslots = - GetFirstBaseSPslotPtr(ctx->Ebp, &hdrInfoBody); - *ppShadowSP = (size_t *)&pBaseSPslots[-(int) nestingLevel ]; - pBaseSPslots[-(int)(nestingLevel+1)] = 0; // Zero out the next slot - - // EE will write the end offset of the filter - if (ctxType == FILTER_CONTEXT) - *ppEndRegion = (size_t *)pBaseSPslots + 1; - - /* This is just a simple assignment of throwObject to ctx->Eax, - just pretend the cast goo isn't there. - */ - - *((OBJECTREF*)&(ctx->Eax)) = thrownObject; -} - -#endif // !FEATURE_EH_FUNCLETS - - - - /*****************************************************************************/ @@ -206,45 +126,13 @@ bool VarIsInReg(ICorDebugInfo::VarLoc varLoc) return E_FAIL; // stack should be empty - @TODO : Barring localloc } -#ifdef FEATURE_EH_FUNCLETS // EnC remap inside handlers is not supported if (pOldCodeInfo->IsFunclet() || pNewCodeInfo->IsFunclet()) return CORDBG_E_ENC_IN_FUNCLET; -#else - if (oldInfo->handlers) - { - bool hasInnerFilter; - TADDR baseSP; - FrameType frameType = GetHandlerFrameInfo(oldInfo, pCtx->Ebp, - pCtx->Esp, IGNORE_VAL, - &baseSP, NULL, &hasInnerFilter); - _ASSERTE(frameType != FR_INVALID); - _ASSERTE(!hasInnerFilter); // FixContextForEnC() is called for bottommost funclet - - // If the method is in a fuclet, and if the framesize grows, we are in trouble. - - if (frameType != FR_NORMAL) - { - /* @TODO : What if the new method offset is in a fuclet, - and the old is not, or the nesting level changed, etc */ - - if (oldInfo->stackSize != newInfo->stackSize) { - LOG((LF_ENC, LL_INFO100, "**Error** EECM::FixContextForEnC stack size mismatch\n")); - return CORDBG_E_ENC_IN_FUNCLET; - } - } - } -#endif // FEATURE_EH_FUNCLETS /* @TODO: Check if we have grown out of space for locals, in the face of localloc */ _ASSERTE(!oldInfo->localloc && !newInfo->localloc); -#ifndef FEATURE_EH_FUNCLETS - // @TODO: If nesting level grows above the MAX_EnC_HANDLER_NESTING_LEVEL, - // we should return EnC_NESTED_HANLDERS - _ASSERTE(oldInfo->handlers && newInfo->handlers); -#endif - LOG((LF_ENC, LL_INFO100, "EECM::FixContextForEnC: Checks out\n")); #elif defined(TARGET_AMD64) || defined(TARGET_ARM64) @@ -878,9 +766,6 @@ bool EECodeManager::IsGcSafe( EECodeInfo *pCodeInfo, #endif // !USE_GC_INFO_DECODER - -#if defined(FEATURE_EH_FUNCLETS) - void EECodeManager::EnsureCallerContextIsValid( PREGDISPLAY pRD, EECodeInfo * pCodeInfo /*= NULL*/, unsigned flags /*= 0*/) { CONTRACTL @@ -936,8 +821,6 @@ size_t EECodeManager::GetCallerSp( PREGDISPLAY pRD ) return GetSP(pRD->pCallerContext); } -#endif // FEATURE_EH_FUNCLETS - #ifdef HAS_LIGHTUNWIND /* * Light unwind the current stack frame, using provided cache entry. @@ -1006,7 +889,6 @@ void EECodeManager::LightUnwindStackFrame(PREGDISPLAY pRD, EECodeInfo* pCodeInfo } #endif // HAS_LIGHTUNWIND -#ifdef FEATURE_EH_FUNCLETS #ifdef TARGET_X86 size_t EECodeManager::GetResumeSp( PCONTEXT pContext ) { @@ -1043,59 +925,6 @@ size_t EECodeManager::GetResumeSp( PCONTEXT pContext ) return GetOutermostBaseFP(curEBP, hdrInfoBody); } #endif // TARGET_X86 -#endif // FEATURE_EH_FUNCLETS - -#ifndef FEATURE_EH_FUNCLETS - -/***************************************************************************** - * - * Unwind the current stack frame, i.e. update the virtual register - * set in pRD. 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 pRD, - EECodeInfo *pCodeInfo, - unsigned flags) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - SUPPORTS_DAC; - } CONTRACTL_END; - -#ifdef TARGET_X86 - bool updateAllRegs = flags & UpdateAllRegs; - - // Address where the method has been interrupted - PCODE breakPC = pRD->ControlPC; - _ASSERTE(PCODEToPINSTR(breakPC) == pCodeInfo->GetCodeAddress()); - - hdrInfo *hdrInfoBody; - PTR_CBYTE table = pCodeInfo->DecodeGCHdrInfo(&hdrInfoBody); - - hdrInfoBody->isSpeculativeStackWalk = ((flags & SpeculativeStackwalk) != 0); - - return UnwindStackFrameX86(pRD, - PTR_CBYTE(pCodeInfo->GetSavedMethodCode()), - pCodeInfo->GetRelOffset(), - hdrInfoBody, - table, - IN_EH_FUNCLETS_COMMA(PTR_CBYTE(pCodeInfo->GetJitManager()->GetFuncletStartAddress(pCodeInfo))) - IN_EH_FUNCLETS_COMMA(pCodeInfo->IsFunclet()) - updateAllRegs); -#else // TARGET_X86 - PORTABILITY_ASSERT("EECodeManager::UnwindStackFrame"); - return false; -#endif // _TARGET_???_ -} - -/*****************************************************************************/ -#else // !FEATURE_EH_FUNCLETS -/*****************************************************************************/ bool EECodeManager::UnwindStackFrame(PREGDISPLAY pRD, EECodeInfo *pCodeInfo, @@ -1131,11 +960,6 @@ void EECodeManager::UnwindStackFrame(T_CONTEXT *pContext) Thread::VirtualUnwindCallFrame(pContext, NULL, &codeInfo); } -/*****************************************************************************/ -#endif // FEATURE_EH_FUNCLETS - -/*****************************************************************************/ - /* report args in 'msig' to the GC. 'argsStart' is start of the stack-based arguments 'varArgSig' describes the arguments @@ -1328,8 +1152,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, methodName, curOffs)); } - -#if defined(FEATURE_EH_FUNCLETS) // funclets if (pCodeInfo->GetJitManager()->IsFilterFunclet(pCodeInfo)) { // Filters are the only funclet that run during the 1st pass, and must have @@ -1337,7 +1159,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, // reporting of the untracked variables, do not report them for the filter. flags |= NoReportUntracked; } -#endif // FEATURE_EH_FUNCLETS bool reportScratchSlots; @@ -1366,7 +1187,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, return false; } -#ifdef FEATURE_EH_FUNCLETS // funclets // // If we're in a funclet, we do not want to report the incoming varargs. This is // taken care of by the parent method and the funclet should access those arguments @@ -1376,7 +1196,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, { return true; } -#endif // FEATURE_EH_FUNCLETS if (gcInfoDecoder.GetIsVarArg()) { @@ -1528,54 +1347,6 @@ OBJECTREF EECodeManager::GetInstance( PREGDISPLAY pContext, fastSkipUnsigned(table); fastSkipUnsigned(table); } -#ifndef FEATURE_EH_FUNCLETS - /* Parse the untracked frame variable table */ - - /* The 'this' pointer can never be located in the untracked table */ - /* as we only allow pinned and byrefs in the untracked table */ - - count = hdrInfoBody->untrackedCnt; - while (count-- > 0) - { - fastSkipSigned(table); - } - - /* Look for the 'this' pointer in the frame variable lifetime table */ - - count = hdrInfoBody->varPtrTableSize; - unsigned tmpOffs = 0; - while (count-- > 0) - { - unsigned varOfs = fastDecodeUnsigned(table); - unsigned begOfs = tmpOffs + fastDecodeUnsigned(table); - unsigned endOfs = begOfs + fastDecodeUnsigned(table); - _ASSERTE(!hdrInfoBody->ebpFrame || (varOfs!=0)); - /* Is this variable live right now? */ - if (((unsigned)relOffset >= begOfs) && ((unsigned)relOffset < endOfs)) - { - /* Does it contain the 'this' pointer */ - if (varOfs & this_OFFSET_FLAG) - { - unsigned ofs = varOfs & ~OFFSET_MASK; - - /* Tracked locals for EBP frames are always at negative offsets */ - - if (hdrInfoBody->ebpFrame) - taArgBase -= ofs; - else - taArgBase += ofs; - - return (OBJECTREF)(size_t)(*PTR_DWORD(taArgBase)); - } - } - tmpOffs = begOfs; - } - -#if VERIFY_GC_TABLES - _ASSERTE(*castto(table, unsigned short *) == 0xBABE); -#endif - -#else // FEATURE_EH_FUNCLETS if (pCodeInfo->GetMethodDesc()->AcquiresInstMethodTableFromThis() && (hdrInfoBody->genericsContext)) // Generic Context is "this" { // Untracked table must have at least one entry - this pointer @@ -1586,7 +1357,6 @@ OBJECTREF EECodeManager::GetInstance( PREGDISPLAY pContext, taArgBase -= stkOffs & ~OFFSET_MASK; return (OBJECTREF)(size_t)(*PTR_DWORD(taArgBase)); } -#endif // FEATURE_EH_FUNCLETS return NULL; #else // !USE_GC_INFO_DECODER @@ -1685,7 +1455,7 @@ PTR_VOID EECodeManager::GetParamTypeArg(PREGDISPLAY pContext, #endif // USE_GC_INFO_DECODER } -#if defined(FEATURE_EH_FUNCLETS) && defined(USE_GC_INFO_DECODER) +#if defined(USE_GC_INFO_DECODER) /* Returns the generics token. This is used by GetInstance() and GetParamTypeArg() on WIN64. */ @@ -1726,7 +1496,7 @@ PTR_VOID EECodeManager::GetExactGenericsToken(TADDR sp, } -#endif // FEATURE_EH_FUNCLETS && USE_GC_INFO_DECODER +#endif // USE_GC_INFO_DECODER /*****************************************************************************/ @@ -1741,12 +1511,10 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext, unsigned relOffset = pCodeInfo->GetRelOffset(); -#ifdef FEATURE_EH_FUNCLETS if (pCodeInfo->IsFunclet()) { return NULL; } -#endif #ifdef HAS_LIGHTUNWIND // LightUnwind does not track sufficient context to compute GS cookie address @@ -1830,39 +1598,6 @@ bool EECodeManager::IsInPrologOrEpilog(DWORD relPCoffset, return ((info.prologOffs != hdrInfo::NOT_IN_PROLOG) || (info.epilogOffs != hdrInfo::NOT_IN_EPILOG)); } - -#ifndef FEATURE_EH_FUNCLETS -/***************************************************************************** - * - * Returns true if the given IP is in the synchronized region of the method (valid for synchronized functions only) -*/ -bool EECodeManager::IsInSynchronizedRegion(DWORD relOffset, - GCInfoToken gcInfoToken, - unsigned flags) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - hdrInfo info; - - DecodeGCHdrInfo(gcInfoToken, relOffset, &info); - - // We should be called only for synchronized methods - _ASSERTE(info.syncStartOffset != INVALID_SYNC_OFFSET && info.syncEndOffset != INVALID_SYNC_OFFSET); - - _ASSERTE(info.syncStartOffset < info.syncEndOffset); - _ASSERTE(info.epilogCnt <= 1); - _ASSERTE(info.epilogCnt == 0 || info.syncEndOffset <= info.syncEpilogStart); - - return (info.syncStartOffset < relOffset && relOffset < info.syncEndOffset) || - (info.syncStartOffset == relOffset && (flags & (ActiveStackFrame|ExecutionAborted))) || - // Synchronized methods have at most one epilog. The epilog does not have to be at the end of the method though. - // Everything after the epilog is also in synchronized region. - (info.epilogCnt != 0 && info.syncEpilogStart + info.epilogSize <= relOffset); -} -#endif // FEATURE_EH_FUNCLETS #endif // !USE_GC_INFO_DECODER /***************************************************************************** @@ -1964,74 +1699,6 @@ unsigned int EECodeManager::GetFrameSize(GCInfoToken gcInfoToken) /*****************************************************************************/ -#ifndef FEATURE_EH_FUNCLETS -const BYTE* EECodeManager::GetFinallyReturnAddr(PREGDISPLAY pReg) -{ - LIMITED_METHOD_CONTRACT; - - return *(const BYTE**)(size_t)(GetRegdisplaySP(pReg)); -} - -BOOL EECodeManager::LeaveFinally(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - - hdrInfo info; - - DecodeGCHdrInfo(gcInfoToken, - offset, - &info); - - DWORD nestingLevel; - GetHandlerFrameInfo(&info, pCtx->Ebp, pCtx->Esp, (DWORD) IGNORE_VAL, NULL, &nestingLevel); - - // Compute an index into the stack-based table of esp values from - // each level of catch block. - PTR_TADDR pBaseSPslots = GetFirstBaseSPslotPtr(pCtx->Ebp, &info); - PTR_TADDR pPrevSlot = pBaseSPslots - (nestingLevel - 1); - - /* Currently, LeaveFinally() is not used if the finally is invoked in the - second pass for unwinding. So we expect the finally to be called locally */ - _ASSERTE(*pPrevSlot == LCL_FINALLY_MARK); - - *pPrevSlot = 0; // Zero out the previous shadow ESP - - pCtx->Esp += sizeof(TADDR); // Pop the return value off the stack - return TRUE; -} - -void EECodeManager::LeaveCatch(GCInfoToken gcInfoToken, - unsigned offset, - PCONTEXT pCtx) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - -#ifdef _DEBUG - TADDR baseSP; - DWORD nestingLevel; - bool hasInnerFilter; - hdrInfo info; - - DecodeGCHdrInfo(gcInfoToken, offset, &info); - GetHandlerFrameInfo(&info, pCtx->Ebp, pCtx->Esp, (DWORD) IGNORE_VAL, - &baseSP, &nestingLevel, &hasInnerFilter); -// _ASSERTE(frameType == FR_HANDLER); -// _ASSERTE(pCtx->Esp == baseSP); -#endif - - return; -} -#else // !FEATURE_EH_FUNCLETS - #ifndef TARGET_WASM // This is an assembly helper that enables us to call into EH funclets. @@ -2265,8 +1932,6 @@ void InterpreterCodeManager::UpdateSSP(PREGDISPLAY pRD) #endif // HOST_AMD64 && HOST_WINDOWS #endif // FEATURE_INTERPRETER -#endif // !FEATURE_EH_FUNCLETS - #endif // #ifndef DACCESS_COMPILE #ifdef DACCESS_COMPILE @@ -2391,13 +2056,11 @@ ULONG32 EECodeManager::GetStackParameterSize(EECodeInfo * pCodeInfo) } CONTRACTL_END; #if defined(TARGET_X86) -#if defined(FEATURE_EH_FUNCLETS) if (pCodeInfo->IsFunclet()) { // Funclet has no stack argument return 0; } -#endif // FEATURE_EH_FUNCLETS hdrInfo * hdrInfoBody; pCodeInfo->DecodeGCHdrInfo(&hdrInfoBody); @@ -2557,8 +2220,6 @@ bool InterpreterCodeManager::EnumGcRefs(PREGDISPLAY pContext, methodName, curOffs)); } - -#if defined(FEATURE_EH_FUNCLETS) // funclets if (pCodeInfo->GetJitManager()->IsFilterFunclet(pCodeInfo)) { // Filters are the only funclet that run during the 1st pass, and must have @@ -2566,7 +2227,6 @@ bool InterpreterCodeManager::EnumGcRefs(PREGDISPLAY pContext, // reporting of the untracked variables, do not report them for the filter. flags |= NoReportUntracked; } -#endif // FEATURE_EH_FUNCLETS bool reportScratchSlots; @@ -2595,7 +2255,6 @@ bool InterpreterCodeManager::EnumGcRefs(PREGDISPLAY pContext, return false; } -#ifdef FEATURE_EH_FUNCLETS // funclets // // If we're in a funclet, we do not want to report the incoming varargs. This is // taken care of by the parent method and the funclet should access those arguments @@ -2605,7 +2264,6 @@ bool InterpreterCodeManager::EnumGcRefs(PREGDISPLAY pContext, { return true; } -#endif // FEATURE_EH_FUNCLETS if (gcInfoDecoder.GetIsVarArg()) { diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index fd71c70704a3fb..3f88bc29cd8c12 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -1,10 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -/* EXCEP.CPP: - * - */ - #include "common.h" #include "frames.h" @@ -33,9 +29,7 @@ #ifdef FEATURE_COMINTEROP #include #endif -#ifdef FEATURE_EH_FUNCLETS #include "exceptionhandling.h" -#endif #include #ifndef TARGET_UNIX @@ -920,7 +914,6 @@ bool EHRangeTreeNode::TryContains(EHRangeTreeNode* pNode) } } -#ifdef FEATURE_EH_FUNCLETS // If we are boot-strapping the tree, don't recurse down because the result could be unreliable. Note that // even if we don't recurse, given a particular node, we can still always find its most specific container with // the logic above, i.e. it's always safe to do one depth level of checking. @@ -965,7 +958,6 @@ bool EHRangeTreeNode::TryContains(EHRangeTreeNode* pNode) } } } -#endif // FEATURE_EH_FUNCLETS return false; } @@ -1017,7 +1009,6 @@ bool EHRangeTreeNode::HandlerContains(EHRangeTreeNode* pNode) } } -#ifdef FEATURE_EH_FUNCLETS // Refer to the comment in TryContains(). if (!m_pTree->m_fInitializing) { @@ -1041,7 +1032,6 @@ bool EHRangeTreeNode::HandlerContains(EHRangeTreeNode* pNode) } } } -#endif // FEATURE_EH_FUNCLETS return false; } @@ -1093,7 +1083,6 @@ bool EHRangeTreeNode::FilterContains(EHRangeTreeNode* pNode) } } -#ifdef FEATURE_EH_FUNCLETS // Refer to the comment in TryContains(). if (!m_pTree->m_fInitializing) { @@ -1117,7 +1106,6 @@ bool EHRangeTreeNode::FilterContains(EHRangeTreeNode* pNode) } } } -#endif // FEATURE_EH_FUNCLETS return false; } @@ -1230,7 +1218,6 @@ EHRangeTree::EHRangeTree(IJitManager* pIJM, if (pEHClause->Flags == COR_ILEXCEPTION_CLAUSE_FILTER) { -#ifdef FEATURE_EH_FUNCLETS // Because of funclets, there is no way to guarantee the placement of a filter. // Thus, we need to loop through the funclets to find the end offset. for (int f = 0; f < cFunclet; f++) @@ -1251,19 +1238,6 @@ EHRangeTree::EHRangeTree(IJitManager* pIJM, break; } } -#else // FEATURE_EH_FUNCLETS - // On x86, since the filter doesn't have an end FilterPC, the only way we can know the size - // of the filter is if it's located immediately prior to it's handler and immediately after - // its try region. We assume that this is, and if it isn't, we're so amazingly hosed that - // we can't continue. - if ((pEHClause->FilterOffset >= pEHClause->HandlerStartPC) || - (pEHClause->FilterOffset < pEHClause->TryEndPC)) - { - m_hrInit = CORDBG_E_SET_IP_IMPOSSIBLE; - goto LError; - } - pNodeCur->m_FilterEndPC = pEHClause->HandlerStartPC; -#endif // FEATURE_EH_FUNCLETS } pNodeCur->MarkAsRange(); @@ -1490,72 +1464,6 @@ const char *TCFStringFromConst(TRY_CATCH_FINALLY tcf) } #endif //LOGGING -#ifndef FEATURE_EH_FUNCLETS -// We're unwinding if we'll return to the EE's code. Otherwise -// we'll return to someplace in the current code. Anywhere outside -// this function is "EE code". -bool FinallyIsUnwinding(EHRangeTreeNode *pNode, - ICodeManager* pEECM, - PREGDISPLAY pReg, - SLOT addrStart) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - FORBID_FAULT; - } - CONTRACTL_END; - - const BYTE *pbRetAddr = pEECM->GetFinallyReturnAddr(pReg); - - if (pbRetAddr < (const BYTE *)addrStart) - return true; - - DWORD offset = (DWORD)(size_t)(pbRetAddr - addrStart); - EHRangeTreeNode *pRoot = pNode->m_pTree->m_root; - - if (!pRoot->Contains(offset)) - return true; - else - return false; -} - -BOOL LeaveCatch(ICodeManager* pEECM, - Thread *pThread, - CONTEXT *pCtx, - GCInfoToken gcInfoToken, - unsigned offset) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // We can assert these things here, and skip a call - // to COMPlusCheckForAbort later. - - // If no abort has been requested, - _ASSERTE((pThread->GetThrowable() != NULL) || - // or if there is a pending exception. - (!pThread->IsAbortRequested()) ); - - LPVOID esp = COMPlusEndCatchWorker(pThread); - - PopNestedExceptionRecords(esp, pCtx, pThread->GetExceptionListPtr()); - - // Do JIT-specific work - pEECM->LeaveCatch(gcInfoToken, offset, pCtx); - - SetSP(pCtx, (UINT_PTR)esp); - return TRUE; -} -#endif // FEATURE_EH_FUNCLETS - TRY_CATCH_FINALLY GetTcf(EHRangeTreeNode *pNode, unsigned offset) { @@ -1711,30 +1619,7 @@ HRESULT IsLegalTransition(Thread *pThread, case TCF_NONE: case TCF_TRY: { -#if !defined(FEATURE_EH_FUNCLETS) - CONTEXT *pFilterCtx = pThread->GetFilterContext(); - if (pFilterCtx == NULL) - return CORDBG_E_SET_IP_IMPOSSIBLE; - - if (!fCanSetIPOnly) - { - if (!LeaveCatch(pEECM, - pThread, - pFilterCtx, - gcInfoToken, - offFrom)) - return E_FAIL; - } - return S_OK; -#else // FEATURE_EH_FUNCLETS - // - // Setting IP out of a catch clause is not supported for FEATURE_EH_FUNCLETS because of funclets. - // This scenario is disabled with approval from VS because it's not considered to - // be a common user scenario. - // return CORDBG_E_CANT_SET_IP_OUT_OF_CATCH_ON_WIN64; -#endif // !FEATURE_EH_FUNCLETS - break; } case TCF_FILTER: @@ -1767,36 +1652,7 @@ HRESULT IsLegalTransition(Thread *pThread, case TCF_NONE: case TCF_TRY: { -#ifndef FEATURE_EH_FUNCLETS - if (!FinallyIsUnwinding(pNode, pEECM, pReg, addrStart)) - { - CONTEXT *pFilterCtx = pThread->GetFilterContext(); - if (pFilterCtx == NULL) - return CORDBG_E_SET_IP_IMPOSSIBLE; - - if (!fCanSetIPOnly) - { - if (!pEECM->LeaveFinally(gcInfoToken, - offFrom, - pFilterCtx)) - return E_FAIL; - } - return S_OK; - } - else - { - return CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY; - } -#else // !FEATURE_EH_FUNCLETS - // - // Setting IP out of a non-unwinding finally clause is not supported on FEATURE_EH_FUNCLETS because of funclets. - // This scenario is disabled with approval from VS because it's not considered to be a common user - // scenario. - // return CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY_ON_WIN64; -#endif // FEATURE_EH_FUNCLETS - - break; } case TCF_FILTER: @@ -2048,78 +1904,6 @@ BOOL IsInFirstFrameOfHandler(Thread *pThread, IJitManager *pJitManager, const ME return FALSE; } // BOOL IsInFirstFrameOfHandler() - -#if !defined(FEATURE_EH_FUNCLETS) - -//****************************************************************************** -// LookForHandler -- search for a function that will handle the exception. -//****************************************************************************** -LFH LookForHandler( // LFH return types - const EXCEPTION_POINTERS *pExceptionPointers, // The ExceptionRecord and ExceptionContext - Thread *pThread, // Thread on which to look (always current?) - ThrowCallbackType *tct) // Structure to pass back to callback functions. -{ - // We don't want to use a runtime contract here since this codepath is used during - // the processing of a hard SO. Contracts use a significant amount of stack - // which we can't afford for those cases. - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - // go through to find if anyone handles the exception - StackWalkAction action = pThread->StackWalkFrames((PSTACKWALKFRAMESCALLBACK)COMPlusThrowCallback, - tct, - 0, //can't use FUNCTIONSONLY because the callback uses non-function frames to stop the walk - tct->pBottomFrame); - - // If someone handles it, the action will be SWA_ABORT with pFunc and dHandler indicating the - // function and handler that is handling the exception. Debugger can put a hook in here. - if (action == SWA_ABORT && tct->pFunc != NULL) - return LFH_FOUND; - - // nobody is handling it - return LFH_NOT_FOUND; -} // LFH LookForHandler() - -StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData); - -//****************************************************************************** -// UnwindFrames -//****************************************************************************** -void UnwindFrames( // No return value. - Thread *pThread, // Thread to unwind. - ThrowCallbackType *tct) // Structure to pass back to callback function. -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE; - - if (pThread->IsExceptionInProgress()) - { - pThread->GetExceptionState()->GetFlags()->SetUnwindHasStarted(); - } - - #ifdef DEBUGGING_SUPPORTED - // - // If a debugger is attached, notify it that unwinding is going on. - // - if (CORDebuggerAttached()) - { - g_pDebugInterface->ManagedExceptionUnwindBegin(pThread); - } - #endif // DEBUGGING_SUPPORTED - - LOG((LF_EH, LL_INFO1000, "UnwindFrames: going to: pFunc:%#X, pStack:%#X\n", - tct->pFunc, tct->pStack)); - - pThread->StackWalkFrames((PSTACKWALKFRAMESCALLBACK)COMPlusUnwindCallback, - tct, - POPFRAMES, - tct->pBottomFrame); -} // void UnwindFrames() - -#endif // !defined(FEATURE_EH_FUNCLETS) - // Copy a context record, being careful about whether or not the target // is large enough to support CONTEXT_EXTENDED_REGISTERS. // @@ -2202,17 +1986,6 @@ VOID FixupOnRethrow(Thread* pCurThread, EXCEPTION_POINTERS* pExceptionPointers) memcpy((void*)pExceptionPointers->ExceptionRecord, (void*)pExState->GetExceptionRecord(), offsetof(EXCEPTION_RECORD, ExceptionInformation)); - -// Replacing the exception context breaks unwinding on AMD64. It also breaks exception dispatch on IA64. -// The info saved by pExState will be given to exception filters. -#ifndef FEATURE_EH_FUNCLETS - // Restore original context if available. - if (pExState->GetContextRecord()) - { - ReplaceExceptionContextRecord(pExceptionPointers->ContextRecord, - pExState->GetContextRecord()); - } -#endif // !FEATURE_EH_FUNCLETS } pExState->GetFlags()->SetIsRethrown(); @@ -2235,10 +2008,9 @@ LONG RaiseExceptionFilter(EXCEPTION_POINTERS* ep, LPVOID pv) { // need to reset the EH info back to the original thrown exception FixupOnRethrow(GetThread(), ep); -#ifdef FEATURE_EH_FUNCLETS + // only do this once pParam->isRethrown++; -#endif // FEATURE_EH_FUNCLETS } else { @@ -2418,8 +2190,6 @@ VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL r UNREACHABLE(); } - -// INSTALL_COMPLUS_EXCEPTION_HANDLER has a filter, so must put the call in a separate fcn static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL rethrow) { STATIC_CONTRACT_THROWS; @@ -2432,15 +2202,13 @@ static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL r _ASSERTE(throwable != CLRException::GetPreallocatedStackOverflowException()); - // TODO: Do we need to install COMPlusFrameHandler here? - INSTALL_COMPLUS_EXCEPTION_HANDLER(); if (throwable == NULL) { _ASSERTE(!"RealCOMPlusThrow(OBJECTREF) called with NULL argument. Somebody forgot to post an exception!"); EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); } + RaiseTheExceptionInternalOnly(throwable, rethrow); - UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); } VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow) @@ -2759,27 +2527,6 @@ DWORD MapWin32FaultToCOMPlusException(EXCEPTION_RECORD *pExceptionRecord) } } -#ifdef _DEBUG -#ifndef FEATURE_EH_FUNCLETS -// check if anyone has written to the stack above the handler which would wipe out the EH registration -void CheckStackBarrier(EXCEPTION_REGISTRATION_RECORD *exRecord) -{ - LIMITED_METHOD_CONTRACT; - - if (exRecord->Handler != (PEXCEPTION_ROUTINE)COMPlusFrameHandler) - return; - - DWORD *stackOverwriteBarrier = (DWORD *)((BYTE*)exRecord - offsetof(FrameHandlerExRecordWithBarrier, m_ExRecord)); - for (int i =0; i < STACK_OVERWRITE_BARRIER_SIZE; i++) { - if (*(stackOverwriteBarrier+i) != STACK_OVERWRITE_BARRIER_VALUE) { - // to debug this error, you must determine who erroneously overwrote the stack - _ASSERTE(!"Fatal error: the stack has been overwritten"); - } - } -} -#endif // FEATURE_EH_FUNCLETS -#endif // _DEBUG - //------------------------------------------------------------------------- // A marker for JIT -> EE transition when we know we're in preemptive // gc mode. As we leave the EE, we fix a few things: @@ -2812,28 +2559,6 @@ void COMPlusCooperativeTransitionHandler(Frame* pFrame) // Pop the frame chain. UnwindFrameChain(pThread, pFrame); CONSISTENCY_CHECK(pFrame == pThread->GetFrame()); - -#ifndef FEATURE_EH_FUNCLETS - // An exception is being thrown through here. The CLR exception - // info keeps a pointer to a frame that is used by the next - // CLR Exception Handler as the starting point of its crawl. - // We may have popped this marker -- in which case, we need to - // update it to the current frame. - // - ThreadExceptionState* pExState = pThread->GetExceptionState(); - Frame* pSearchBoundary = NULL; - - if (pThread->IsExceptionInProgress()) - { - pSearchBoundary = pExState->m_currentExInfo.m_pSearchBoundary; - } - - if (pSearchBoundary && pSearchBoundary < pFrame) - { - LOG((LF_EH, LL_INFO1000, "\tpExInfo->m_pSearchBoundary = %08x\n", (void*)pFrame)); - pExState->m_currentExInfo.m_pSearchBoundary = pFrame; - } -#endif // FEATURE_EH_FUNCLETS } // Restore us to preemptive gc mode. @@ -3289,10 +3014,6 @@ LONG NotifyDebuggerLastChance(Thread *pThread, LONG retval = EXCEPTION_CONTINUE_SEARCH; - // Debugger does func-evals inside this call, which may take nested exceptions. We need a nested exception - // handler to allow this. - INSTALL_NESTED_EXCEPTION_HANDLER(pThread->GetFrame()); - EXCEPTION_POINTERS dummy; dummy.ExceptionRecord = NULL; dummy.ContextRecord = NULL; @@ -3316,8 +3037,6 @@ LONG NotifyDebuggerLastChance(Thread *pThread, retval = EXCEPTION_CONTINUE_EXECUTION; } - UNINSTALL_NESTED_EXCEPTION_HANDLER(); - #ifdef DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED EX_TRY { @@ -4219,22 +3938,6 @@ BOOL UpdateCurrentThrowable(PEXCEPTION_RECORD pExceptionRecord) // NotifyAppDomainsOfUnhandledException, which needs to get a throwable // from somewhere, with which to notify the AppDomains. useLastThrownObject = TRUE; - - if (IsComPlusException(pExceptionRecord)) - { -#ifndef FEATURE_EH_FUNCLETS - OBJECTREF oThrowable = pThread->LastThrownObject(); - - // @TODO: we have a problem on Win64 where we won't have any place to - // store the throwable on an unhandled exception. Currently this - // only effects the managed debugging services as they will try - // to inspect the thread to see what the throwable is on an unhandled - // exception.. (but clearly it needs to be fixed asap) - // We have the same problem in EEPolicy::LogFatalError(). - LOG((LF_EH, LL_INFO100, "UpdateCurrentThrowable: setting throwable to %s\n", (oThrowable == NULL) ? "NULL" : oThrowable->GetMethodTable()->GetDebugClassName())); - pThread->SafeSetThrowables(oThrowable); -#endif // FEATURE_EH_FUNCLETS - } } return useLastThrownObject; @@ -4742,9 +4445,7 @@ static SString GetExceptionMessageWrapper(Thread* pThread, OBJECTREF throwable) StackSString result; - INSTALL_NESTED_EXCEPTION_HANDLER(pThread->GetFrame()); GetExceptionMessage(throwable, result); - UNINSTALL_NESTED_EXCEPTION_HANDLER(); return SString{ result }; } @@ -5076,39 +4777,9 @@ void NotifyAppDomainsOfUnhandledException( // Send up the unhandled exception appdomain event. if (pThread->DetermineIfGuardPagePresent()) { - // x86 only -#if !defined(FEATURE_EH_FUNCLETS) - // If the Thread object's exception state's exception pointers - // is null, use the passed-in pointer. - BOOL bSetPointers = FALSE; - - ThreadExceptionState* pExceptionState = pThread->GetExceptionState(); - - if (pExceptionState->GetExceptionPointers() == NULL) - { - bSetPointers = TRUE; - pExceptionState->SetExceptionPointers(pExceptionPointers); - } - -#endif // !defined(FEATURE_EH_FUNCLETS) - - INSTALL_NESTED_EXCEPTION_HANDLER(pThread->GetFrame()); - // This guy will never throw, but it will need a spot to store // any nested exceptions it might find. AppDomain::OnUnhandledException(&throwable); - - UNINSTALL_NESTED_EXCEPTION_HANDLER(); - -#if !defined(FEATURE_EH_FUNCLETS) - - if (bSetPointers) - { - pExceptionState->SetExceptionPointers(NULL); - } - -#endif // !defined(FEATURE_EH_FUNCLETS) - } GCPROTECT_END(); @@ -5470,37 +5141,12 @@ void AdjustContextForThreadStop(Thread* pThread, _ASSERTE(pThread->m_OSContext); -#ifndef FEATURE_EH_FUNCLETS - SetIP(pContext, GetIP(pThread->m_OSContext)); - SetSP(pContext, (GetSP(pThread->m_OSContext))); - - if (GetFP(pThread->m_OSContext) != 0) // ebp = 0 implies that we got here with the right values for ebp - { - SetFP(pContext, GetFP(pThread->m_OSContext)); - } - - // We might have been interrupted execution at a point where the jit has roots in - // registers. We just need to store a "safe" value in here so that the collector - // doesn't trap. We're not going to use these objects after the exception. - // - // Only callee saved registers are going to be reported by the faulting excepiton frame. -#if defined(TARGET_X86) - // Ebx,esi,edi are important. Eax,ecx,edx are not. - pContext->Ebx = 0; - pContext->Edi = 0; - pContext->Esi = 0; -#else - PORTABILITY_ASSERT("AdjustContextForThreadStop"); -#endif - -#else // !FEATURE_EH_FUNCLETS CopyOSContext(pContext, pThread->m_OSContext); #if defined(TARGET_ARM) && defined(_DEBUG) // Make sure that the thumb bit is set on the IP of the original abort context we just restored. PCODE controlPC = GetIP(pContext); _ASSERTE(controlPC & THUMB_CODE); #endif // TARGET_ARM -#endif // !FEATURE_EH_FUNCLETS pThread->ResetThrowControlForThread(); @@ -5809,8 +5455,6 @@ IsDebuggerFault(EXCEPTION_RECORD *pExceptionRecord, EXTERN_C void JIT_StackProbe_End(); #endif // !TARGET_ARM64 && !TARGET_LOONGARCH64 && !TARGET_RISCV64 -#ifdef FEATURE_EH_FUNCLETS - #ifndef TARGET_X86 EXTERN_C void JIT_WriteBarrier_End(); EXTERN_C void JIT_CheckedWriteBarrier_End(); @@ -5860,7 +5504,6 @@ BOOL IsIPinVirtualStub(PCODE f_IP) return FALSE; #endif // FEATURE_VIRTUAL_STUB_DISPATCH } -#endif // FEATURE_EH_FUNCLETS typedef uint8_t CODE_LOCATION; EXTERN_C CODE_LOCATION RhpAssignRefAVLocation; @@ -6044,7 +5687,7 @@ AdjustContextForJITHelpers( } return FALSE; -#elif defined(FEATURE_EH_FUNCLETS) // TARGET_X86 && !TARGET_UNIX +#else // TARGET_X86 && !TARGET_UNIX PCODE f_IP = GetIP(pContext); CONTEXT tempContext; @@ -6110,13 +5753,10 @@ AdjustContextForJITHelpers( } return FALSE; -#else // FEATURE_EH_FUNCLETS - PORTABILITY_ASSERT("AdjustContextForJITHelpers"); - return FALSE; -#endif // ELSE +#endif // TARGET_X86 && !TARGET_UNIX } -#if defined(USE_FEF) && !defined(TARGET_UNIX) +#ifndef TARGET_UNIX struct HandleManagedFaultFilterParam { @@ -6181,7 +5821,7 @@ void HandleManagedFault(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext) UNREACHABLE(); } -#endif // USE_FEF && !TARGET_UNIX +#endif // !TARGET_UNIX // // Init a new frame @@ -6189,21 +5829,9 @@ void HandleManagedFault(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext) void FaultingExceptionFrame::Init(CONTEXT *pContext) { WRAPPER_NO_CONTRACT; -#ifndef FEATURE_EH_FUNCLETS -#ifdef TARGET_X86 - CalleeSavedRegisters *pRegs = GetCalleeSavedRegisters(); -#define CALLEE_SAVED_REGISTER(regname) pRegs->regname = pContext->regname; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - m_ReturnAddress = ::GetIP(pContext); - m_Esp = (DWORD)GetSP(pContext); -#else // TARGET_X86 - PORTABILITY_ASSERT("FaultingExceptionFrame::Init"); -#endif // _TARGET_???_ (ELSE) -#else // !FEATURE_EH_FUNCLETS + m_ReturnAddress = ::GetIP(pContext); CopyOSContext(&m_ctx, pContext); -#endif // !FEATURE_EH_FUNCLETS #if defined(TARGET_AMD64) && defined(TARGET_WINDOWS) m_SSP = 0; @@ -6271,19 +5899,6 @@ bool ShouldHandleManagedFault( return false; #endif // _DEBUG -#ifndef FEATURE_EH_FUNCLETS - // If there's any frame below the ESP of the exception, then we can forget it. - if (pThread->m_pFrame < dac_cast(GetSP(pContext))) - return false; - - // If we're a subsequent handler forget it. - EXCEPTION_REGISTRATION_RECORD* pBottomMostHandler = pThread->GetExceptionState()->m_currentExInfo.m_pBottomMostHandler; - if (pBottomMostHandler != NULL && pEstablisherFrame > pBottomMostHandler) - { - return false; - } -#endif // FEATURE_EH_FUNCLETS - { // If it's not a fault in jitted code, forget it. @@ -6402,21 +6017,21 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo // 1. pThread refers to *this* thread. // 2. If another thread tries to hijack this thread, it will see we are not in managed // code (and thus won't try to hijack us). -#if defined(FEATURE_EH_FUNCLETS) && defined(FEATURE_HIJACK) +#if defined(FEATURE_HIJACK) if (pThread != NULL) { pThread->UnhijackThreadNoAlloc(); } -#endif // defined(FEATURE_EH_FUNCLETS) && defined(FEATURE_HIJACK) +#endif // FEATURE_HIJACK if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) { // // Not an Out-of-memory situation, so no need for a forbid fault region here // -#ifdef FEATURE_EH_FUNCLETS + EEPolicy::HandleStackOverflow(); -#endif // FEATURE_EH_FUNCLETS + return VEH_CONTINUE_SEARCH; } @@ -6472,16 +6087,11 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase2(PEXCEPTION_POINTERS pExcepti return action; } -#if defined(FEATURE_EH_FUNCLETS) - if (action == VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION) { return action; } -#endif // defined(FEATURE_EH_FUNCLETS) - - // // In OOM situations, this call better not fault. // @@ -6535,7 +6145,6 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase2(PEXCEPTION_POINTERS pExcepti return (VEH_ACTION)UserBreakpointFilter(pExceptionInfo); } -#if defined(FEATURE_EH_FUNCLETS) BOOL fShouldHandleManagedFault; { @@ -6552,7 +6161,6 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase2(PEXCEPTION_POINTERS pExcepti { return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION; } -#endif // defined(FEATURE_EH_FUNCLETS) return VEH_EXECUTE_HANDLER; } @@ -6652,16 +6260,14 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase3(PEXCEPTION_POINTERS pExcepti // // On 64-bit, some additional work is required.. pContext->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE; -#ifdef FEATURE_EH_FUNCLETS + return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION; -#endif // defined(FEATURE_EH_FUNCLETS) } else if (AdjustContextForVirtualStub(pExceptionRecord, pContext)) { pContext->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE; -#ifdef FEATURE_EH_FUNCLETS + return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION; -#endif } // Remember the EIP for stress debugging purposes. @@ -7034,15 +6640,6 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) return EXCEPTION_CONTINUE_SEARCH; } -#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) - if (dwCode == EXCEPTION_BREAKPOINT || dwCode == EXCEPTION_SINGLE_STEP) - { - // For interop debugging, debugger bashes our managed exception handler. - // Interop debugging does not work with real vectored exception handler :( - return EXCEPTION_CONTINUE_SEARCH; - } -#endif - if (NtCurrentTeb()->ThreadLocalStoragePointer == NULL) { // Ignore exceptions early during thread startup before the thread is fully initialized by the OS @@ -7104,7 +6701,6 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) { VEH_ACTION action = CLRVectoredExceptionHandler(pExceptionInfo); -#ifdef FEATURE_EH_FUNCLETS if (VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION == action) { // @@ -7113,7 +6709,6 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) HandleManagedFault(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_EXECUTION; } -#endif // FEATURE_EH_FUNCLETS if (VEH_EXECUTE_HANDLER == action) { @@ -7132,20 +6727,6 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) } #ifdef _DEBUG -#ifndef FEATURE_EH_FUNCLETS - { - CantAllocHolder caHolder; - - PEXCEPTION_REGISTRATION_RECORD pRecord = GetCurrentSEHRecord(); - while (pRecord != EXCEPTION_CHAIN_END) - { - STRESS_LOG2(LF_EH, LL_INFO10000, "CLRVectoredExceptionHandlerShim: FS:0 %p:%p\n", - pRecord, pRecord->Handler); - pRecord = pRecord->Next; - } - } -#endif // FEATURE_EH_FUNCLETS - { // The call to "CLRVectoredExceptionHandler" above can return EXCEPTION_CONTINUE_SEARCH // for different scenarios like StackOverFlow/SOFT_SO, or if it is forbidden to enter the EE. @@ -7184,14 +6765,6 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) } } #endif // _DEBUG - -#ifndef FEATURE_EH_FUNCLETS - { - CantAllocHolder caHolder; - STRESS_LOG1(LF_EH, LL_INFO1000, "CLRVectoredExceptionHandlerShim: returning %d\n", result); - } -#endif // FEATURE_EH_FUNCLETS - } else if (bIsGCMarker) { @@ -7283,7 +6856,6 @@ VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFra Exception::Delete(pException); -#ifdef FEATURE_EH_FUNCLETS if (!nativeRethrow) { Thread *pThread = GetThread(); @@ -7306,7 +6878,6 @@ VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFra } } else -#endif // FEATURE_EH_FUNCLETS { RaiseTheExceptionInternalOnly(orThrowable, FALSE); } @@ -7860,78 +7431,6 @@ void StripFileInfoFromStackTrace(SString &ssStackTrace) ssStackTrace.Truncate(end); } -#ifdef _DEBUG -//============================================================================== -// This function will set a thread state indicating if an exception is escaping -// the last CLR personality routine on the stack in a reverse pinvoke scenario. -// -// If the exception continues to go unhandled, it will eventually reach the OS -// that will start invoking the UEFs. Since CLR registers its UEF only to handle -// unhandled exceptions on such reverse pinvoke threads, we will assert this -// state in our UEF to ensure it does not get called for any other reason. -// -// This function should be called only if the personality routine returned -// EXCEPTION_CONTINUE_SEARCH. -//============================================================================== -void SetReversePInvokeEscapingUnhandledExceptionStatus(BOOL fIsUnwinding, -#if defined(TARGET_X86) - EXCEPTION_REGISTRATION_RECORD * pEstablisherFrame -#elif defined(FEATURE_EH_FUNCLETS) - PVOID pEstablisherFrame -#else -#error Unsupported platform -#endif - ) -{ -#ifndef DACCESS_COMPILE - - LIMITED_METHOD_CONTRACT; - - Thread *pCurThread = GetThread(); - if (pCurThread->GetExceptionState()->IsExceptionInProgress()) - { - if (!fIsUnwinding) - { - // Get the top-most Frame of this thread. - Frame* pCurFrame = pCurThread->GetFrame(); - Frame* pTopMostFrame = pCurFrame; - while (pCurFrame && (pCurFrame != FRAME_TOP)) - { - pTopMostFrame = pCurFrame; - pCurFrame = pCurFrame->PtrNextFrame(); - } - - // Is the exception escaping the last CLR personality routine on the stack of a - // reverse pinvoke thread? - if (((pTopMostFrame == NULL) || (pTopMostFrame == FRAME_TOP)) || - ((void *)(pEstablisherFrame) > (void *)(pTopMostFrame))) - { - LOG((LF_EH, LL_INFO100, "SetReversePInvokeEscapingUnhandledExceptionStatus: setting Ex_RPInvokeEscapingException\n")); - // Set the flag on the thread indicating the exception is escaping the - // top most reverse pinvoke exception handler. - pCurThread->GetExceptionState()->GetFlags()->SetReversePInvokeEscapingException(); - } - } - else - { - // Since we are unwinding, simply unset the flag indicating escaping unhandled exception - // if it was set. - if (pCurThread->GetExceptionState()->GetFlags()->ReversePInvokeEscapingException()) - { - LOG((LF_EH, LL_INFO100, "SetReversePInvokeEscapingUnhandledExceptionStatus: unsetting Ex_RPInvokeEscapingException\n")); - pCurThread->GetExceptionState()->GetFlags()->ResetReversePInvokeEscapingException(); - } - } - } - else - { - LOG((LF_EH, LL_INFO100, "SetReversePInvokeEscapingUnhandledExceptionStatus: not setting Ex_RPInvokeEscapingException since no exception is in progress.\n")); - } -#endif // !DACCESS_COMPILE -} - -#endif // _DEBUG - #ifndef TARGET_UNIX // This function will capture the watson buckets for the current exception object that is: @@ -10410,8 +9909,6 @@ void ExceptionNotifications::DeliverFirstChanceNotification() } } - -#ifdef FEATURE_EH_FUNCLETS struct TAResetStateCallbackData { // Do we have more managed code up the stack? @@ -10462,34 +9959,6 @@ StackWalkAction TAResetStateCallback(CrawlFrame* pCf, void* data) return retStatus; } -#endif // FEATURE_EH_FUNCLETS - -// This function will reset the thread abort state against the specified thread if it is determined that -// there is no more managed code on the stack. -// -// Note: This function should be invoked ONLY during unwind. -#ifndef FEATURE_EH_FUNCLETS -void ResetThreadAbortState(PTR_Thread pThread, void *pEstablisherFrame) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(pThread != NULL); - PRECONDITION(pEstablisherFrame != NULL); - } - CONTRACTL_END; - - if (pThread->IsAbortRequested()) - { - if (GetNextCOMPlusSEHRecord(static_cast(pEstablisherFrame)) == EXCEPTION_CHAIN_END) - { - _ASSERTE(!"Topmost handler and abort requested."); - } - } -} -#endif // !FEATURE_EH_FUNCLETS #endif // !DACCESS_COMPILE @@ -11315,7 +10784,6 @@ void SoftwareExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS #define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *dac_cast((TADDR)m_ContextPointers.regname); ENUM_CALLEE_SAVED_REGISTERS(); #undef CALLEE_SAVED_REGISTER @@ -11342,16 +10810,6 @@ void SoftwareExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. -#elif defined(TARGET_X86) -#define CALLEE_SAVED_REGISTER(regname) pRD->Set##regname##Location(&m_Context.regname); - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - pRD->ControlPC = ::GetIP(&m_Context); - pRD->SP = ::GetSP(&m_Context); -#else // FEATURE_EH_FUNCLETS - PORTABILITY_ASSERT("SoftwareExceptionFrame::UpdateRegDisplay_Impl"); -#endif // FEATURE_EH_FUNCLETS } #ifndef DACCESS_COMPILE @@ -11368,7 +10826,6 @@ void SoftwareExceptionFrame::UpdateContextFromTransitionBlock(TransitionBlock *p m_Context.Eax = 0; m_Context.Ecx = pTransitionBlock->m_argumentRegisters.ECX; m_Context.Edx = pTransitionBlock->m_argumentRegisters.EDX; -#ifdef FEATURE_EH_FUNCLETS m_ContextPointers.Ecx = &m_Context.Ecx; m_ContextPointers.Edx = &m_Context.Edx; @@ -11377,12 +10834,6 @@ void SoftwareExceptionFrame::UpdateContextFromTransitionBlock(TransitionBlock *p m_ContextPointers.reg = &m_Context.reg; ENUM_CALLEE_SAVED_REGISTERS(); #undef CALLEE_SAVED_REGISTER -#else // FEATURE_EH_FUNCLETS -#define CALLEE_SAVED_REGISTER(reg) \ - m_Context.reg = pTransitionBlock->m_calleeSavedRegisters.reg; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER -#endif // FEATURE_EH_FUNCLETS m_Context.Esp = (UINT_PTR)(pTransitionBlock + 1); m_Context.Eip = pTransitionBlock->m_ReturnAddress; diff --git a/src/coreclr/vm/excep.h b/src/coreclr/vm/excep.h index 06a87e8dfbb101..b09c6124a204b9 100644 --- a/src/coreclr/vm/excep.h +++ b/src/coreclr/vm/excep.h @@ -1,10 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// EXCEP.H -// - -// - #ifndef __excep_h__ #define __excep_h__ @@ -109,15 +104,6 @@ void TerminateExceptionHandling(); // Prototypes EXTERN_C VOID STDCALL ResetCurrentContext(); -#if !defined(FEATURE_EH_FUNCLETS) -#ifdef _DEBUG -void CheckStackBarrier(EXCEPTION_REGISTRATION_RECORD *exRecord); -#endif -EXCEPTION_REGISTRATION_RECORD *FindNestedEstablisherFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame); -LFH LookForHandler(const EXCEPTION_POINTERS *pExceptionPointers, Thread *pThread, ThrowCallbackType *tct); -StackWalkAction COMPlusThrowCallback (CrawlFrame *pCf, ThrowCallbackType *pData); -void UnwindFrames(Thread *pThread, ThrowCallbackType *tct); -#endif // !defined(FEATURE_EH_FUNCLETS) void UnwindFrameChain(Thread *pThread, LPVOID pvLimitSP); DWORD MapWin32FaultToCOMPlusException(EXCEPTION_RECORD *pExceptionRecord); @@ -366,47 +352,6 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowInvalidCastException(TypeHandle thCastFro VOID DECLSPEC_NORETURN RealCOMPlusThrowInvalidCastException(OBJECTREF *pObj, TypeHandle thCastTo); -#ifndef FEATURE_EH_FUNCLETS - -#include "eexcp.h" -#include "exinfo.h" - -struct FrameHandlerExRecord -{ - EXCEPTION_REGISTRATION_RECORD m_ExReg; - - Frame *m_pEntryFrame; - - Frame *GetCurrFrame() - { - LIMITED_METHOD_CONTRACT; - return m_pEntryFrame; - } -}; - -struct NestedHandlerExRecord : public FrameHandlerExRecord -{ - ExInfo m_handlerInfo; - BOOL m_ActiveForUnwind; - ExInfo *m_pCurrentExInfo; - EXCEPTION_REGISTRATION_RECORD *m_pCurrentHandler; - NestedHandlerExRecord() : m_handlerInfo() {LIMITED_METHOD_CONTRACT;} - void Init(PEXCEPTION_ROUTINE pFrameHandler, Frame *pEntryFrame) - { - WRAPPER_NO_CONTRACT; - - m_ExReg.Next=NULL; - m_ExReg.Handler=pFrameHandler; - m_pEntryFrame=pEntryFrame; - m_pCurrentExInfo = NULL; - m_pCurrentHandler = NULL; - m_handlerInfo.Init(); - m_ActiveForUnwind = FALSE; - } -}; - -#endif // !FEATURE_EH_FUNCLETS - #if defined(ENABLE_CONTRACTS_IMPL) // Never call this class directly: Call it through CANNOTTHROWCOMPLUSEXCEPTION. @@ -485,35 +430,6 @@ PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord(); VOID SetCurrentSEHRecord(EXCEPTION_REGISTRATION_RECORD *pSEH); #endif -#if !defined(FEATURE_EH_FUNCLETS) -EXCEPTION_HANDLER_DECL(COMPlusFrameHandler); -EXCEPTION_HANDLER_DECL(COMPlusNestedExceptionHandler); -#ifdef FEATURE_COMINTEROP -EXCEPTION_HANDLER_DECL(COMPlusFrameHandlerRevCom); -#endif // FEATURE_COMINTEROP - -#ifdef DEBUGGING_SUPPORTED -VOID UnwindExceptionTrackerAndResumeInInterceptionFrame(ExInfo* pExInfo, EHContext* context); -#endif // DEBUGGING_SUPPORTED - -BOOL PopNestedExceptionRecords(LPVOID pTargetSP, BOOL bCheckForUnknownHandlers = FALSE); -VOID PopNestedExceptionRecords(LPVOID pTargetSP, T_CONTEXT *pCtx, void *pSEH); - -#define STACK_OVERWRITE_BARRIER_SIZE 20 -#define STACK_OVERWRITE_BARRIER_VALUE 0xabcdefab - -#ifdef _DEBUG -#if defined(TARGET_X86) -struct FrameHandlerExRecordWithBarrier { - DWORD m_StackOverwriteBarrier[STACK_OVERWRITE_BARRIER_SIZE]; - FrameHandlerExRecord m_ExRecord; -}; - -void VerifyValidTransitionFromManagedCode(Thread *pThread, CrawlFrame *pCF); -#endif // defined(TARGET_X86) -#endif // _DEBUG -#endif // !defined(FEATURE_EH_FUNCLETS) - //========================================================================== // This is a workaround designed to allow the use of the StubLinker object at bootup // time where the EE isn't sufficient awake to create CLR exception objects. @@ -731,18 +647,6 @@ inline void CopyOSContext(T_CONTEXT* pDest, T_CONTEXT* pSrc) void SaveCurrentExceptionInfo(PEXCEPTION_RECORD pRecord, PT_CONTEXT pContext); -#ifdef _DEBUG -void SetReversePInvokeEscapingUnhandledExceptionStatus(BOOL fIsUnwinding, -#ifdef TARGET_X86 - EXCEPTION_REGISTRATION_RECORD * pEstablisherFrame -#elif defined(FEATURE_EH_FUNCLETS) - PVOID pEstablisherFrame -#else -#error Unsupported platform -#endif - ); -#endif // _DEBUG - // See implementation for detailed comments in excep.cpp LONG AppDomainTransitionExceptionFilter( EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function. @@ -791,15 +695,9 @@ class ExceptionNotifications #ifndef DACCESS_COMPILE -#ifndef FEATURE_EH_FUNCLETS -void ResetThreadAbortState(PTR_Thread pThread, void *pEstablisherFrame); -#endif - X86_ONLY(EXCEPTION_REGISTRATION_RECORD* GetNextCOMPlusSEHRecord(EXCEPTION_REGISTRATION_RECORD* pRec);) -#ifdef FEATURE_EH_FUNCLETS VOID DECLSPEC_NORETURN ContinueExceptionInterceptionUnwind(); -#endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_INTERPRETER void ThrowResumeAfterCatchException(TADDR resumeSP, TADDR resumeIP); diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index cea6ccc4a375ef..0d7fb29410cdb0 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -3,7 +3,6 @@ #include "common.h" -#ifdef FEATURE_EH_FUNCLETS #include "exceptionhandling.h" #include "dbginterface.h" #include "asmconstants.h" @@ -463,7 +462,7 @@ void CleanUpForSecondPass(Thread* pThread, bool fIsSO, LPVOID MemoryStackFpForFr static void PopExplicitFrames(Thread *pThread, void *targetSp, void *targetCallerSp, bool popGCFrames = true) { -#if defined(TARGET_X86) && defined(TARGET_WINDOWS) && defined(FEATURE_EH_FUNCLETS) +#if defined(TARGET_X86) && defined(TARGET_WINDOWS) PopSEHRecords((void*)targetSp); #endif @@ -2967,9 +2966,9 @@ static TADDR GetSpForDiagnosticReporting(REGDISPLAY *pRD) { #ifdef ESTABLISHER_FRAME_ADDRESS_IS_CALLER_SP TADDR sp = CallerStackFrame::FromRegDisplay(pRD).SP; -#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86) - sp -= sizeof(TADDR); // For X86 with funclets we want the address 1 pointer into the callee. -#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_X86) +#if defined(TARGET_X86) + sp -= sizeof(TADDR); // For X86 we want the address 1 pointer into the callee. +#endif // defined(TARGET_X86) return sp; #else return GetSP(pRD->pCurrentContext); @@ -4517,5 +4516,3 @@ namespace AsmOffsetsAsserts }; #endif - -#endif // FEATURE_EH_FUNCLETS diff --git a/src/coreclr/vm/exceptionhandling.h b/src/coreclr/vm/exceptionhandling.h index 472074fa3e5325..9cf69fae0342a3 100644 --- a/src/coreclr/vm/exceptionhandling.h +++ b/src/coreclr/vm/exceptionhandling.h @@ -7,8 +7,6 @@ #ifndef __EXCEPTION_HANDLING_h__ #define __EXCEPTION_HANDLING_h__ -#ifdef FEATURE_EH_FUNCLETS - #include "eexcp.h" #include "exstatecommon.h" @@ -91,8 +89,6 @@ class ResumeAfterCatchException void DECLSPEC_NORETURN ExecuteFunctionBelowContext(PCODE functionPtr, CONTEXT *pContext, size_t targetSSP, size_t arg1 = 0, size_t arg2 = 0); -#endif // FEATURE_EH_FUNCLETS - #if defined(TARGET_X86) #define USE_CURRENT_CONTEXT_IN_FILTER #endif // TARGET_X86 diff --git a/src/coreclr/vm/exceptionhandlingqcalls.h b/src/coreclr/vm/exceptionhandlingqcalls.h index c9dd9ba353250b..7cc00295fbf3f3 100644 --- a/src/coreclr/vm/exceptionhandlingqcalls.h +++ b/src/coreclr/vm/exceptionhandlingqcalls.h @@ -1,12 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// #ifndef EXCEPTION_HANDLING_QCALLS_H #define EXCEPTION_HANDLING_QCALLS_H -#ifdef FEATURE_EH_FUNCLETS - struct RhEHClause; struct ExInfo; @@ -20,6 +17,4 @@ extern "C" CLR_BOOL QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStack extern "C" CLR_BOOL QCALLTYPE SfiNext(StackFrameIterator* pThis, unsigned int* uExCollideClauseIdx, CLR_BOOL* fUnwoundReversePInvoke, CLR_BOOL* pIsExceptionIntercepted); #endif // DACCESS_COMPILE -#endif // FEATURE_EH_FUNCLETS - #endif // EXCEPTION_HANDLING_QCALLS_H \ No newline at end of file diff --git a/src/coreclr/vm/exceptmacros.h b/src/coreclr/vm/exceptmacros.h index bae313a30cf892..913d0013e89f58 100644 --- a/src/coreclr/vm/exceptmacros.h +++ b/src/coreclr/vm/exceptmacros.h @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// // // EXCEPTMACROS.H - @@ -106,8 +105,6 @@ // around the call to simulate a CLR "try-finally" but EX_TRY // is relatively expensive compared to the real thing.) // -// - #ifndef __exceptmacros_h__ #define __exceptmacros_h__ @@ -180,68 +177,6 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowOM(); PAL_ENDTRY \ } - - - -//========================================================================== -// Helpful macros to declare exception handlers, their implementation, -// and to call them. -//========================================================================== - -#define _EXCEPTION_HANDLER_DECL(funcname) \ - EXCEPTION_DISPOSITION __cdecl funcname(EXCEPTION_RECORD *pExceptionRecord, \ - struct _EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, \ - CONTEXT *pContext, \ - DISPATCHER_CONTEXT *pDispatcherContext) - -#define EXCEPTION_HANDLER_DECL(funcname) \ - extern "C" _EXCEPTION_HANDLER_DECL(funcname) - -#define EXCEPTION_HANDLER_IMPL(funcname) \ - _EXCEPTION_HANDLER_DECL(funcname) - -#define EXCEPTION_HANDLER_FWD(funcname) \ - funcname(pExceptionRecord, pEstablisherFrame, pContext, pDispatcherContext) - -//========================================================================== -// Declares a CLR frame handler that can be used to make sure that -// exceptions that should be handled from within managed code -// are handled within and don't leak out to give other handlers a -// chance at them. -//========================================================================== -#define INSTALL_COMPLUS_EXCEPTION_HANDLER() \ - DECLARE_CPFH_EH_RECORD(GET_THREAD()); \ - INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE() - -#define INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE() \ -{ \ - INSTALL_EXCEPTION_HANDLING_RECORD(&(___pExRecord->m_ExReg)); \ - /* work around unreachable code warning */ \ - if (true) { - -#define UNINSTALL_COMPLUS_EXCEPTION_HANDLER() \ - } \ - UNINSTALL_EXCEPTION_HANDLING_RECORD(&(___pExRecord->m_ExReg)); \ -} - -#if !defined(FEATURE_EH_FUNCLETS) - -#define INSTALL_NESTED_EXCEPTION_HANDLER(frame) \ - NestedHandlerExRecord *__pNestedHandlerExRecord = (NestedHandlerExRecord*) _alloca(sizeof(NestedHandlerExRecord)); \ - __pNestedHandlerExRecord->m_handlerInfo.m_hThrowable = NULL; \ - __pNestedHandlerExRecord->Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, frame); \ - INSTALL_EXCEPTION_HANDLING_RECORD(&(__pNestedHandlerExRecord->m_ExReg)); - -#define UNINSTALL_NESTED_EXCEPTION_HANDLER() \ - UNINSTALL_EXCEPTION_HANDLING_RECORD(&(__pNestedHandlerExRecord->m_ExReg)); - -#else // defined(FEATURE_EH_FUNCLETS) - -#define INSTALL_NESTED_EXCEPTION_HANDLER(frame) -#define UNINSTALL_NESTED_EXCEPTION_HANDLER() - -#endif // !defined(FEATURE_EH_FUNCLETS) - enum VEH_ACTION { VEH_NO_ACTION = -3, @@ -322,7 +257,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar UNREACHABLE(); \ } -#elif defined(TARGET_X86) && defined(TARGET_WINDOWS) && defined(FEATURE_EH_FUNCLETS) +#elif defined(TARGET_X86) && defined(TARGET_WINDOWS) #define INSTALL_MANAGED_EXCEPTION_DISPATCHER #define UNINSTALL_MANAGED_EXCEPTION_DISPATCHER diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index 6751c4b85525b8..88a14de1aee29b 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -1,306 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// - -// #include "common.h" #include "exinfo.h" #include "dbginterface.h" -#ifdef FEATURE_EH_FUNCLETS #include "eetoprofinterfacewrapper.inl" #include "eedbginterfaceimpl.inl" -#endif - -#ifndef FEATURE_EH_FUNCLETS -#ifndef DACCESS_COMPILE -// -// Destroy the handle within an ExInfo. This respects the fact that we can have preallocated global handles living -// in ExInfo's. -// -void ExInfo::DestroyExceptionHandle(void) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - // Never, ever destroy a preallocated exception handle. - if ((m_hThrowable != NULL) && !CLRException::IsPreallocatedExceptionHandle(m_hThrowable)) - { - DestroyHandle(m_hThrowable); - } - - m_hThrowable = NULL; -} - -// -// CopyAndClearSource copies the contents of the given ExInfo into the current ExInfo, then re-initializes the -// given ExInfo. -// -void ExInfo::CopyAndClearSource(ExInfo *from) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - if (GetThreadNULLOk() != NULL) MODE_COOPERATIVE; else MODE_ANY; - FORBID_FAULT; - } - CONTRACTL_END; - -#ifdef TARGET_X86 - LOG((LF_EH, LL_INFO100, "In ExInfo::CopyAndClearSource: m_dEsp=%08x, %08x <- [%08x], stackAddress = 0x%p <- 0x%p\n", - from->m_dEsp, &(this->m_dEsp), &from->m_dEsp, this->m_StackAddress, from->m_StackAddress)); -#endif // TARGET_X86 - - // If we have a handle to an exception object in this ExInfo already, then go ahead and destroy it before we - // loose it. - DestroyExceptionHandle(); - - // The stack address is handled differently. Save the original value. - void* stackAddress = this->m_StackAddress; - - // Blast the entire record. Note: we're copying the handle from the source ExInfo to this object. That's okay, - // since we're going to clear out the source ExInfo right below this. - memcpy(this, from, sizeof(ExInfo)); - - // Preserve the stack address. It should never change. - m_StackAddress = stackAddress; - - // This ExInfo just took ownership of the handle to the exception object, so clear out that handle in the - // source ExInfo. - from->m_hThrowable = NULL; - - // Finally, initialize the source ExInfo. - from->Init(); - -#ifndef TARGET_UNIX - // Clear the Watson Bucketing information as well since they - // have been transferred over by the "memcpy" above. - from->GetWatsonBucketTracker()->Init(); -#endif // TARGET_UNIX -} - -void ExInfo::Init() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - FORBID_FAULT; - } - CONTRACTL_END; - - m_ExceptionFlags.Init(); - m_DebuggerExState.Init(); - - m_pSearchBoundary = NULL; - STRESS_LOG3(LF_EH, LL_INFO10000, "ExInfo::Init: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", - this, m_pBottomMostHandler, NULL); - m_pBottomMostHandler = NULL; - m_pPrevNestedInfo = NULL; - m_ExceptionCode = 0xcccccccc; - m_pExceptionRecord = NULL; - m_pContext = NULL; - m_pShadowSP = NULL; - m_StackAddress = this; - DestroyExceptionHandle(); - m_hThrowable = NULL; - m_ExceptionCode = 0; - - // By default, mark the tracker as not having delivered the first - // chance exception notification - m_fDeliveredFirstChanceNotification = FALSE; - - m_pTopMostHandlerDuringSO = NULL; - -#ifdef DEBUGGING_SUPPORTED - m_InterceptionContext.Init(); - m_ValidInterceptionContext = FALSE; -#endif // DEBUGGING_SUPPORTED -} - -ExInfo::ExInfo() -{ - WRAPPER_NO_CONTRACT; - - m_hThrowable = NULL; - Init(); - -#ifndef TARGET_UNIX - // Init the WatsonBucketTracker - m_WatsonBucketTracker.Init(); -#endif // TARGET_UNIX -} - -//******************************************************************************* -// When we hit an endcatch or an unwind and have nested handler info, either -// 1) we have contained a nested exception and will continue handling the original -// exception -// - or - -// 2) the nested exception was not contained, and was thrown beyond the original -// bounds where the first exception occurred. -// -// The way we can tell this is from the stack pointer. The topmost nested handler is -// installed at the point where the exception occurred. For a nested exception to be -// contained, it must be caught within the scope of any code that is called after -// the nested handler is installed. (remember: after is a lower stack address.) -// -// If it is caught by anything earlier on the stack, it was not contained, and we -// unwind the nested handlers until we get to one that is higher on the stack -// than the esp we will unwind to. -// -// If we still have a nested handler, then we have successfully handled a nested -// exception and should restore the exception settings that we saved so that -// processing of the original exception can continue. -// Otherwise the nested exception has gone beyond where the original exception was -// thrown and therefore replaces the original exception. -// -// We will always remove the current exception info from the chain. -// -void ExInfo::UnwindExInfo(VOID* limit) -{ - CONTRACTL - { - NOTHROW; // This function does not throw. - GC_NOTRIGGER; - if (GetThreadNULLOk() != NULL) MODE_COOPERATIVE; else MODE_ANY; - } - CONTRACTL_END; - - // We must be in cooperative mode to do the chaining below -#ifdef DEBUGGING_SUPPORTED - // The debugger thread will be using this, even though it has no - // Thread object associated with it. - _ASSERTE((GetThreadNULLOk() != NULL && GetThread()->PreemptiveGCDisabled()) || - ((g_pDebugInterface != NULL) && (g_pDebugInterface->GetRCThreadId() == GetCurrentThreadId()))); -#endif // DEBUGGING_SUPPORTED - - LOG((LF_EH, LL_INFO100, "UnwindExInfo: unwind limit is 0x%p, prevNested is 0x%p\n", limit, m_pPrevNestedInfo)); - - ExInfo *pPrevNestedInfo = m_pPrevNestedInfo; - - // At first glance, you would think that each nested exception has - // been unwound by it's corresponding NestedExceptionHandler. But that's - // not necessarily the case. The following assertion cannot be made here, - // and the loop is necessary. - // - //_ASSERTE(pPrevNestedInfo == 0 || (DWORD)pPrevNestedInfo >= limit); - // - // Make sure we've unwound any nested exceptions that we're going to skip over. - // - while (pPrevNestedInfo && pPrevNestedInfo->m_StackAddress < limit) - { - STRESS_LOG1(LF_EH, LL_INFO100, "UnwindExInfo: PopExInfo(): popping nested ExInfo at 0x%p\n", pPrevNestedInfo->m_StackAddress); - - if (pPrevNestedInfo->m_hThrowable != NULL) - { - pPrevNestedInfo->DestroyExceptionHandle(); - } - - #ifndef TARGET_UNIX - // Free the Watson bucket details when ExInfo - // is being released - pPrevNestedInfo->GetWatsonBucketTracker()->ClearWatsonBucketDetails(); - #endif // TARGET_UNIX - - #ifdef DEBUGGING_SUPPORTED - if (g_pDebugInterface != NULL) - { - g_pDebugInterface->DeleteInterceptContext(pPrevNestedInfo->m_DebuggerExState.GetDebuggerInterceptContext()); - } - #endif - - // Get the next nested handler detail... - ExInfo* pPrev = pPrevNestedInfo->m_pPrevNestedInfo; - - if (pPrevNestedInfo->IsHeapAllocated()) - { - delete pPrevNestedInfo; - } - - pPrevNestedInfo = pPrev; - } - - if (pPrevNestedInfo) - { - // found nested handler info that is above the esp restore point so successfully caught nested - STRESS_LOG2(LF_EH, LL_INFO100, "UnwindExInfo: resetting nested ExInfo to 0x%p stackaddress:0x%p\n", pPrevNestedInfo, pPrevNestedInfo->m_StackAddress); - - // Remember if this ExInfo is heap allocated or not. - BOOL isHeapAllocated = pPrevNestedInfo->IsHeapAllocated(); - - // Copy pPrevNestedInfo to 'this', clearing pPrevNestedInfo in the process. - CopyAndClearSource(pPrevNestedInfo); - - if (isHeapAllocated) - { - delete pPrevNestedInfo; // Now delete the old record if we needed to. - } - } - else - { - STRESS_LOG0(LF_EH, LL_INFO100, "UnwindExInfo: clearing topmost ExInfo\n"); - - // We just do a basic Init of the current top ExInfo here. - Init(); - - #ifndef TARGET_UNIX - // Init the Watson buckets as well - GetWatsonBucketTracker()->ClearWatsonBucketDetails(); - #endif // TARGET_UNIX - } -} -#endif // DACCESS_COMPILE - - -#ifdef DACCESS_COMPILE - -void -ExInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) -{ - SUPPORTS_DAC; - // ExInfo is embedded so don't enum 'this'. - OBJECTHANDLE_EnumMemoryRegions(m_hThrowable); - - m_pExceptionRecord.EnumMem(); - m_pContext.EnumMem(); -} - -#endif // #ifdef DACCESS_COMPILE - - -void ExInfo::SetExceptionCode(const EXCEPTION_RECORD *pCER) -{ -#ifndef DACCESS_COMPILE - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_FORBID_FAULT; - - _ASSERTE(pCER != NULL); - m_ExceptionCode = pCER->ExceptionCode; - - if (IsInstanceTaggedSEHCode(pCER->ExceptionCode) && ::WasThrownByUs(pCER, pCER->ExceptionCode)) - { - m_ExceptionFlags.SetWasThrownByUs(); - } - else - { - m_ExceptionFlags.ResetWasThrownByUs(); - } -#else // DACCESS_COMPILE - // This method is invoked by the X86 version of CLR's exception handler for - // managed code. There is no reason why DAC would be invoking this. - DacError(E_UNEXPECTED); -#endif // !DACCESS_COMPILE -} -#else // !FEATURE_EH_FUNCLETS #ifndef DACCESS_COMPILE @@ -530,5 +236,3 @@ void ExInfo::MakeCallbacksRelatedToHandler( } #endif // DACCESS_COMPILE - -#endif // !FEATURE_EH_FUNCLETS diff --git a/src/coreclr/vm/exinfo.h b/src/coreclr/vm/exinfo.h index 26ee34c393e942..f6773f023dffff 100644 --- a/src/coreclr/vm/exinfo.h +++ b/src/coreclr/vm/exinfo.h @@ -1,161 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// - -// - #ifndef __ExInfo_h__ #define __ExInfo_h__ -#if !defined(FEATURE_EH_FUNCLETS) - -#include "exstatecommon.h" - -typedef DPTR(class ExInfo) PTR_ExInfo; -class ExInfo -{ - friend class ThreadExceptionState; - friend class ClrDataExceptionState; - -public: - - BOOL IsHeapAllocated() - { - LIMITED_METHOD_CONTRACT; - return m_StackAddress != (void *) this; - } - - void CopyAndClearSource(ExInfo *from); - - void UnwindExInfo(VOID* limit); - - // Q: Why does this thing take an EXCEPTION_RECORD rather than an ExceptionCode? - // A: Because m_ExceptionCode and Ex_WasThrownByUs have to be kept - // in sync and this function needs the exception parms inside the record to figure - // out the "IsTagged" part. - void SetExceptionCode(const EXCEPTION_RECORD *pCER); - - DWORD GetExceptionCode() - { - LIMITED_METHOD_CONTRACT; - return m_ExceptionCode; - } - -public: // @TODO: make more of these private! - // Note: the debugger assumes that m_pThrowable is a strong - // reference so it can check it for NULL with preemptive GC - // enabled. - OBJECTHANDLE m_hThrowable; // thrown exception - PTR_Frame m_pSearchBoundary; // topmost frame for current managed frame group -private: - DWORD m_ExceptionCode; // After a catch of a CLR exception, pointers/context are trashed. -public: - PTR_EXCEPTION_REGISTRATION_RECORD m_pBottomMostHandler; // most recent EH record registered - - // Reference to the topmost handler we saw during an SO that goes past us - PTR_EXCEPTION_REGISTRATION_RECORD m_pTopMostHandlerDuringSO; - - LPVOID m_dEsp; // Esp when fault occurred, OR esp to restore on endcatch - - PTR_ExInfo m_pPrevNestedInfo; // pointer to nested info if are handling nested exception - - size_t* m_pShadowSP; // Zero this after endcatch - - PTR_EXCEPTION_RECORD m_pExceptionRecord; - PTR_EXCEPTION_POINTERS m_pExceptionPointers; - PTR_CONTEXT m_pContext; - - // We have a rare case where (re-entry to the EE from an unmanaged filter) where we - // need to create a new ExInfo ... but don't have a nested handler for it. The handlers - // use stack addresses to figure out their correct lifetimes. This stack location is - // used for that. For most records, it will be the stack address of the ExInfo ... but - // for some records, it will be a pseudo stack location -- the place where we think - // the record should have been (except for the re-entry case). - // - // - // - void* m_StackAddress; // A pseudo or real stack location for this record. - -#ifndef TARGET_UNIX -private: - EHWatsonBucketTracker m_WatsonBucketTracker; -public: - inline PTR_EHWatsonBucketTracker GetWatsonBucketTracker() - { - LIMITED_METHOD_CONTRACT; - return PTR_EHWatsonBucketTracker(PTR_HOST_MEMBER_TADDR(ExInfo, this, m_WatsonBucketTracker)); - } -#endif - -private: - BOOL m_fDeliveredFirstChanceNotification; -public: - inline BOOL DeliveredFirstChanceNotification() - { - LIMITED_METHOD_CONTRACT; - - return m_fDeliveredFirstChanceNotification; - } - - inline void SetFirstChanceNotificationStatus(BOOL fDelivered) - { - LIMITED_METHOD_CONTRACT; - - m_fDeliveredFirstChanceNotification = fDelivered; - } - - // Returns the exception tracker previous to the current - inline PTR_ExInfo GetPreviousExceptionTracker() - { - LIMITED_METHOD_CONTRACT; - - return m_pPrevNestedInfo; - } - - // Returns the throwable associated with the tracker - inline OBJECTREF GetThrowable() - { - LIMITED_METHOD_CONTRACT; - - return (m_hThrowable != NULL)?ObjectFromHandle(m_hThrowable):NULL; - } - - // Returns the throwble associated with the tracker as handle - inline OBJECTHANDLE GetThrowableAsHandle() - { - LIMITED_METHOD_CONTRACT; - - return m_hThrowable; - } - -public: - - DebuggerExState m_DebuggerExState; - EHClauseInfo m_EHClauseInfo; - ExceptionFlags m_ExceptionFlags; - -#ifdef DEBUGGING_SUPPORTED - EHContext m_InterceptionContext; - BOOL m_ValidInterceptionContext; -#endif - -#ifdef DACCESS_COMPILE - void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); -#endif - - void Init(); - ExInfo() DAC_EMPTY(); - - void DestroyExceptionHandle(); - -private: - // Don't allow this - ExInfo& operator=(const ExInfo &from); -}; - -PTR_ExInfo GetEHTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, PTR_ExInfo pStartingEHTracker); - -#else // !FEATURE_EH_FUNCLETS #include "exceptionhandling.h" @@ -533,5 +380,4 @@ struct cdac_data }; #endif // TARGET_UNIX -#endif // !FEATURE_EH_FUNCLETS #endif // __ExInfo_h__ diff --git a/src/coreclr/vm/exstate.cpp b/src/coreclr/vm/exstate.cpp index d85cf506b214a5..50ce0024b3a41f 100644 --- a/src/coreclr/vm/exstate.cpp +++ b/src/coreclr/vm/exstate.cpp @@ -17,24 +17,18 @@ OBJECTHANDLE ThreadExceptionState::GetThrowableAsHandle() { WRAPPER_NO_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { return m_pCurrentTracker->m_hThrowable; } return (OBJECTHANDLE)NULL; -#else // FEATURE_EH_FUNCLETS - return m_currentExInfo.m_hThrowable; -#endif // FEATURE_EH_FUNCLETS } ThreadExceptionState::ThreadExceptionState() { -#ifdef FEATURE_EH_FUNCLETS m_pCurrentTracker = NULL; -#endif // FEATURE_EH_FUNCLETS m_flag = TEF_None; @@ -70,17 +64,10 @@ OBJECTREF ThreadExceptionState::GetThrowable() } CONTRACTL_END; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker && m_pCurrentTracker->m_hThrowable) { return ObjectFromHandle(m_pCurrentTracker->m_hThrowable); } -#else // FEATURE_EH_FUNCLETS - if (m_currentExInfo.m_hThrowable) - { - return ObjectFromHandle(m_currentExInfo.m_hThrowable); - } -#endif // FEATURE_EH_FUNCLETS return NULL; } @@ -95,14 +82,10 @@ void ThreadExceptionState::SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowab } CONTRACTL_END; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { m_pCurrentTracker->DestroyExceptionHandle(); } -#else // FEATURE_EH_FUNCLETS - m_currentExInfo.DestroyExceptionHandle(); -#endif // FEATURE_EH_FUNCLETS if (throwable != NULL) { @@ -126,7 +109,6 @@ void ThreadExceptionState::SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowab hNewThrowable = pDomain->CreateHandle(throwable); } -#ifdef FEATURE_EH_FUNCLETS #ifdef _DEBUG // // Fatal stack overflow policy ends up short-circuiting the normal exception handling @@ -145,9 +127,6 @@ void ThreadExceptionState::SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowab { m_pCurrentTracker->m_hThrowable = hNewThrowable; } -#else // FEATURE_EH_FUNCLETS - m_currentExInfo.m_hThrowable = hNewThrowable; -#endif // FEATURE_EH_FUNCLETS } } @@ -155,12 +134,8 @@ DWORD ThreadExceptionState::GetExceptionCode() { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS _ASSERTE(m_pCurrentTracker); return m_pCurrentTracker->m_ExceptionCode; -#else // FEATURE_EH_FUNCLETS - return m_currentExInfo.m_ExceptionCode; -#endif // FEATURE_EH_FUNCLETS } BOOL ThreadExceptionState::IsComPlusException() @@ -188,11 +163,7 @@ BOOL ThreadExceptionState::IsExceptionInProgress() { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS return (m_pCurrentTracker != NULL); -#else // FEATURE_EH_FUNCLETS - return (m_currentExInfo.m_pBottomMostHandler != NULL); -#endif // FEATURE_EH_FUNCLETS } #if !defined(DACCESS_COMPILE) @@ -201,7 +172,6 @@ EXCEPTION_POINTERS* ThreadExceptionState::GetExceptionPointers() { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { return (EXCEPTION_POINTERS*)&(m_pCurrentTracker->m_ptrs); @@ -210,32 +180,14 @@ EXCEPTION_POINTERS* ThreadExceptionState::GetExceptionPointers() { return NULL; } -#else // FEATURE_EH_FUNCLETS - return m_currentExInfo.m_pExceptionPointers; -#endif // FEATURE_EH_FUNCLETS } -//----------------------------------------------------------------------------- -// SetExceptionPointers -- accessor to set pointer to EXCEPTION_POINTERS -// member. -// -// only x86 -// -#if !defined(FEATURE_EH_FUNCLETS) -void ThreadExceptionState::SetExceptionPointers( - EXCEPTION_POINTERS *pExceptionPointers) // Value to set -{ - m_currentExInfo.m_pExceptionPointers = pExceptionPointers; -} // void ThreadExceptionState::SetExceptionPointers() -#endif - #endif // !DACCESS_COMPILE PTR_EXCEPTION_RECORD ThreadExceptionState::GetExceptionRecord() { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { return m_pCurrentTracker->m_ptrs.ExceptionRecord; @@ -244,16 +196,12 @@ PTR_EXCEPTION_RECORD ThreadExceptionState::GetExceptionRecord() { return NULL; } -#else // FEATURE_EH_FUNCLETS - return m_currentExInfo.m_pExceptionRecord; -#endif // FEATURE_EH_FUNCLETS } PTR_CONTEXT ThreadExceptionState::GetContextRecord() { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { return m_pCurrentTracker->m_ptrs.ContextRecord; @@ -262,14 +210,10 @@ PTR_CONTEXT ThreadExceptionState::GetContextRecord() { return NULL; } -#else // FEATURE_EH_FUNCLETS - return m_currentExInfo.m_pContext; -#endif // FEATURE_EH_FUNCLETS } ExceptionFlags* ThreadExceptionState::GetFlags() { -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { @@ -281,11 +225,6 @@ ExceptionFlags* ThreadExceptionState::GetFlags() return NULL; } -#else // FEATURE_EH_FUNCLETS - - return &(m_currentExInfo.m_ExceptionFlags); - -#endif // FEATURE_EH_FUNCLETS } #if !defined(DACCESS_COMPILE) @@ -295,7 +234,6 @@ static DebuggerExState s_emptyDebuggerExState; DebuggerExState* ThreadExceptionState::GetDebuggerState() { -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { return &(m_pCurrentTracker->m_DebuggerExState); @@ -305,15 +243,11 @@ DebuggerExState* ThreadExceptionState::GetDebuggerState() _ASSERTE(!"unexpected use of GetDebuggerState() when no exception in flight"); return &s_emptyDebuggerExState; } -#else // FEATURE_EH_FUNCLETS - return &(m_currentExInfo.m_DebuggerExState); -#endif // FEATURE_EH_FUNCLETS } void ThreadExceptionState::SetDebuggerIndicatedFramePointer(LPVOID indicatedFramePointer) { WRAPPER_NO_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { m_pCurrentTracker->m_DebuggerExState.SetDebuggerIndicatedFramePointer(indicatedFramePointer); @@ -322,9 +256,6 @@ void ThreadExceptionState::SetDebuggerIndicatedFramePointer(LPVOID indicatedFram { _ASSERTE(!"unexpected use of SetDebuggerIndicatedFramePointer() when no exception in flight"); } -#else // FEATURE_EH_FUNCLETS - m_currentExInfo.m_DebuggerExState.SetDebuggerIndicatedFramePointer(indicatedFramePointer); -#endif // FEATURE_EH_FUNCLETS } BOOL ThreadExceptionState::IsDebuggerInterceptable() @@ -404,27 +335,6 @@ BOOL DebuggerExState::SetDebuggerInterceptInfo(IJitManager *pJitManager, int nestingLevel = 0; -#ifndef FEATURE_EH_FUNCLETS - // - // Get the SEH frame that covers this location on the stack. Note: we pass a skip count of 1. We know that when - // this is called, there is a nested exception handler on pThread's stack that is only there during exception - // processing, and it won't be there when we go to do the interception. Therefore, we skip that nested record, - // and pick the next valid record above it. - // - m_pDebuggerInterceptFrame = GetClrSEHRecordServicingStackPointer(pThread, (LPVOID)sfDebuggerInterceptFramePointer.SP); - if (m_pDebuggerInterceptFrame == EXCEPTION_CHAIN_END) - { - return FALSE; - } - - // - // Now we need to search and find the function information for this entry on the stack. - // - nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager, - methodToken, - natOffset); -#endif // !FEATURE_EH_FUNCLETS - // // These values will override the normal information used by the EH subsystem to handle the exception. // They are retrieved by GetDebuggerInterceptInfo(). @@ -444,7 +354,6 @@ BOOL DebuggerExState::SetDebuggerInterceptInfo(IJitManager *pJitManager, EHClauseInfo* ThreadExceptionState::GetCurrentEHClauseInfo() { -#ifdef FEATURE_EH_FUNCLETS if (m_pCurrentTracker) { return &(m_pCurrentTracker->m_EHClauseInfo); @@ -464,9 +373,6 @@ EHClauseInfo* ThreadExceptionState::GetCurrentEHClauseInfo() return &m_emptyEHClauseInfo; } -#else // FEATURE_EH_FUNCLETS - return &(m_currentExInfo.m_EHClauseInfo); -#endif // FEATURE_EH_FUNCLETS } void ThreadExceptionState::SetThreadExceptionFlag(ThreadExceptionFlag flag) @@ -514,7 +420,6 @@ ThreadExceptionFlagHolder::~ThreadExceptionFlagHolder() void ThreadExceptionState::EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags) { -#ifdef FEATURE_EH_FUNCLETS ExInfo* head = m_pCurrentTracker; if (head == NULL) @@ -522,10 +427,6 @@ ThreadExceptionState::EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags) return; } -#else // FEATURE_EH_FUNCLETS - ExInfo* head = &m_currentExInfo; -#endif // FEATURE_EH_FUNCLETS - for (;;) { head->EnumMemoryRegions(flags); diff --git a/src/coreclr/vm/exstate.h b/src/coreclr/vm/exstate.h index d36c67f468bba1..86a838d70309be 100644 --- a/src/coreclr/vm/exstate.h +++ b/src/coreclr/vm/exstate.h @@ -14,12 +14,8 @@ class EHClauseInfo; #include "exceptionhandling.h" #include "cdacdata.h" -#ifndef FEATURE_EH_FUNCLETS -#include "exinfo.h" -#else struct ExInfo; typedef DPTR(ExInfo) PTR_ExInfo; -#endif #if !defined(DACCESS_COMPILE) #define PRESERVE_WATSON_ACROSS_CONTEXTS 1 @@ -50,11 +46,7 @@ class ThreadExceptionState friend struct ::cdac_data; -#ifdef FEATURE_EH_FUNCLETS friend struct ExInfo; -#else - friend class ExInfo; -#endif public: @@ -81,11 +73,6 @@ class ThreadExceptionState ThreadExceptionState(); ~ThreadExceptionState(); -#if !defined(FEATURE_EH_FUNCLETS) - void SetExceptionPointers(EXCEPTION_POINTERS *pExceptionPointers); -#endif - - #ifdef DEBUGGING_SUPPORTED // DebuggerExState stores information necessary for intercepting an exception DebuggerExState* GetDebuggerState(); @@ -138,7 +125,6 @@ class ThreadExceptionState private: Thread* GetMyThread(); -#ifdef FEATURE_EH_FUNCLETS PTR_ExInfo m_pCurrentTracker; public: PTR_ExInfo GetCurrentExceptionTracker() @@ -155,16 +141,6 @@ class ThreadExceptionState } #endif // DACCESS_COMPILE -#else - ExInfo m_currentExInfo; -public: - PTR_ExInfo GetCurrentExceptionTracker() - { - LIMITED_METHOD_CONTRACT; - return PTR_ExInfo(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_currentExInfo)); - } -#endif - private: ThreadExceptionFlag m_flag; @@ -178,77 +154,6 @@ class ThreadExceptionState return PTR_EHWatsonBucketTracker(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_UEWatsonBucketTracker)); } #endif // !TARGET_UNIX - -private: - -#ifndef FEATURE_EH_FUNCLETS - - // - // @NICE: Ideally, these friends shouldn't all be enumerated like this. If they were all part of the same - // class, that would be nice. I'm trying to avoid adding x86-specific accessors to this class as well as - // trying to limit the visibility of the ExInfo struct since Win64 doesn't use ExInfo. - // - friend EXCEPTION_DISPOSITION COMPlusAfterUnwind( - EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - ThrowCallbackType& tct); - friend EXCEPTION_DISPOSITION COMPlusAfterUnwind( - EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - ThrowCallbackType& tct, - Frame *pStartFrame); - - friend EXCEPTION_HANDLER_IMPL(COMPlusFrameHandler); - - friend EXCEPTION_DISPOSITION __cdecl - CPFH_RealFirstPassHandler(EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - CONTEXT *pContext, - void *pDispatcherContext, - BOOL bAsynchronousThreadStop, - BOOL fPGCDisabledOnEntry); - - friend EXCEPTION_DISPOSITION __cdecl - CPFH_UnwindHandler(EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - CONTEXT *pContext, - void *pDispatcherContext); - - friend void CPFH_UnwindFrames1(Thread* pThread, - EXCEPTION_REGISTRATION_RECORD* pEstablisherFrame, - DWORD exceptionCode); - -#ifdef TARGET_X86 - friend LPVOID COMPlusEndCatchWorker(Thread * pThread); -#endif - - friend StackWalkAction COMPlusThrowCallback(CrawlFrame *pCf, ThrowCallbackType *pData); - - friend StackWalkAction COMPlusUnwindCallback(CrawlFrame *pCf, ThrowCallbackType *pData); - -#if defined(TARGET_X86) - friend void ResumeAtJitEH(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHClausePtr, - DWORD nestingLevel, Thread *pThread, BOOL unwindStack); -#endif // TARGET_X86 - - friend _EXCEPTION_HANDLER_DECL(COMPlusNestedExceptionHandler); - - friend void COMPlusCooperativeTransitionHandler(Frame* pFrame); - - friend bool ShouldHandleManagedFault( - EXCEPTION_RECORD* pExceptionRecord, - CONTEXT* pContext, - EXCEPTION_REGISTRATION_RECORD* pEstablisherFrame, - Thread* pThread); - - friend class Thread; - // It it the following method that needs to be a friend. But the prototype pulls in a lot more stuff, - // so just make the Thread class a friend. - // friend StackWalkAction Thread::StackWalkFramesEx(PREGDISPLAY pRD, PSTACKWALKFRAMESCALLBACK pCallback, - // VOID *pData, unsigned flags, Frame *pStartFrame); - -#endif // FEATURE_EH_FUNCLETS - }; diff --git a/src/coreclr/vm/exstatecommon.h b/src/coreclr/vm/exstatecommon.h index 93e99e03272da8..7cc933fdc29457 100644 --- a/src/coreclr/vm/exstatecommon.h +++ b/src/coreclr/vm/exstatecommon.h @@ -51,10 +51,6 @@ class DebuggerExState m_pDebuggerContext = NULL; m_pDebuggerInterceptNativeOffset = 0; - #ifndef FEATURE_EH_FUNCLETS - // x86-specific fields - m_pDebuggerInterceptFrame = EXCEPTION_CHAIN_END; - #endif // !FEATURE_EH_FUNCLETS m_dDebuggerInterceptHandlerDepth = 0; } @@ -133,9 +129,6 @@ class DebuggerExState // void GetDebuggerInterceptInfo( - #ifndef FEATURE_EH_FUNCLETS - PEXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - #endif // !FEATURE_EH_FUNCLETS MethodDesc **ppFunc, int *pdHandler, BYTE **ppStack, @@ -144,13 +137,6 @@ class DebuggerExState { LIMITED_METHOD_CONTRACT; -#ifndef FEATURE_EH_FUNCLETS - if (pEstablisherFrame != NULL) - { - *pEstablisherFrame = m_pDebuggerInterceptFrame; - } -#endif // !FEATURE_EH_FUNCLETS - if (ppFunc != NULL) { *ppFunc = m_pDebuggerInterceptFunc; @@ -194,12 +180,6 @@ class DebuggerExState // the native offset at which to resume execution ULONG_PTR m_pDebuggerInterceptNativeOffset; - // The remaining fields are only used on x86. -#ifndef FEATURE_EH_FUNCLETS - // the exception registration record covering the stack range containing the interception point - PEXCEPTION_REGISTRATION_RECORD m_pDebuggerInterceptFrame; -#endif // !FEATURE_EH_FUNCLETS - // the nesting level at which we want to resume execution int m_dDebuggerInterceptHandlerDepth; }; @@ -281,7 +261,6 @@ class ExceptionFlags Init(); } -#if defined(FEATURE_EH_FUNCLETS) ExceptionFlags(bool fReadOnly) { Init(); @@ -292,18 +271,17 @@ class ExceptionFlags } #endif // _DEBUG } -#endif // defined(FEATURE_EH_FUNCLETS) void AssertIfReadOnly() { SUPPORTS_DAC; -#if defined(FEATURE_EH_FUNCLETS) && defined(_DEBUG) +#ifdef _DEBUG if (m_flags & Ex_FlagsAreReadOnly) { _ASSERTE(!"Tried to update read-only flags!"); } -#endif // defined(FEATURE_EH_FUNCLETS) && defined(_DEBUG) +#endif // _DEBUG } void Init() @@ -393,11 +371,8 @@ class ExceptionFlags #ifdef _DEBUG Ex_RPInvokeEscapingException = 0x40000000, -#endif // _DEBUG - -#if defined(FEATURE_EH_FUNCLETS) && defined(_DEBUG) Ex_FlagsAreReadOnly = 0x80000000 -#endif // defined(FEATURE_EH_FUNCLETS) && defined(_DEBUG) +#endif // _DEBUG }; diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 5491e238918411..47e1175a7d157a 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// FRAMES.H +// FRAMES.H // // These C++ classes expose activation frames to the rest of the EE. @@ -565,9 +565,7 @@ class Frame #ifdef HOST_64BIT friend Thread * JIT_InitPInvokeFrame(InlinedCallFrame *pFrame); #endif -#ifdef FEATURE_EH_FUNCLETS friend struct ExInfo; -#endif #if defined(DACCESS_COMPILE) friend class DacDbiInterfaceImpl; #endif // DACCESS_COMPILE @@ -898,27 +896,15 @@ class TransitionFrame : public Frame // TransitionFrames for exceptions //----------------------------------------------------------------------- -// The define USE_FEF controls how this class is used. Look for occurrences -// of USE_FEF. typedef DPTR(class FaultingExceptionFrame) PTR_FaultingExceptionFrame; class FaultingExceptionFrame : public Frame { friend class CheckAsmOffsets; -#ifndef FEATURE_EH_FUNCLETS -#ifdef TARGET_X86 - DWORD m_Esp; - CalleeSavedRegisters m_regs; - TADDR m_ReturnAddress; -#else // TARGET_X86 - #error "Unsupported architecture" -#endif // TARGET_X86 -#else // FEATURE_EH_FUNCLETS BOOL m_fFilterExecuted; // Flag for FirstCallToHandler TADDR m_ReturnAddress; T_CONTEXT m_ctx; -#endif // !FEATURE_EH_FUNCLETS #ifdef TARGET_AMD64 TADDR m_SSP; @@ -949,26 +935,9 @@ class FaultingExceptionFrame : public Frame unsigned GetFrameAttribs_Impl() { LIMITED_METHOD_DAC_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS return FRAME_ATTR_EXCEPTION | (!!(m_ctx.ContextFlags & CONTEXT_EXCEPTION_ACTIVE) ? FRAME_ATTR_FAULTED : 0); -#else - return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED; -#endif } -#ifndef FEATURE_EH_FUNCLETS - CalleeSavedRegisters *GetCalleeSavedRegisters() - { -#ifdef TARGET_X86 - LIMITED_METHOD_DAC_CONTRACT; - return &m_regs; -#else - PORTABILITY_ASSERT("GetCalleeSavedRegisters"); -#endif // TARGET_X86 - } -#endif // FEATURE_EH_FUNCLETS - -#ifdef FEATURE_EH_FUNCLETS T_CONTEXT *GetExceptionContext () { LIMITED_METHOD_CONTRACT; @@ -980,7 +949,6 @@ class FaultingExceptionFrame : public Frame LIMITED_METHOD_CONTRACT; return &m_fFilterExecuted; } -#endif // FEATURE_EH_FUNCLETS #ifdef TARGET_AMD64 void SetSSP(TADDR value) @@ -1002,9 +970,7 @@ class FaultingExceptionFrame : public Frame template<> struct cdac_data { -#ifdef FEATURE_EH_FUNCLETS static constexpr size_t TargetContext = offsetof(FaultingExceptionFrame, m_ctx); -#endif // FEATURE_EH_FUNCLETS }; typedef DPTR(class SoftwareExceptionFrame) PTR_SoftwareExceptionFrame; @@ -1012,9 +978,7 @@ typedef DPTR(class SoftwareExceptionFrame) PTR_SoftwareExceptionFrame; class SoftwareExceptionFrame : public Frame { TADDR m_ReturnAddress; -#if !defined(TARGET_X86) || defined(FEATURE_EH_FUNCLETS) T_KNONVOLATILE_CONTEXT_POINTERS m_ContextPointers; -#endif // This T_CONTEXT field needs to be the last field in the class because it is a // different size between Linux (pal.h) and the Windows cross-DAC (winnt.h). T_CONTEXT m_Context; @@ -2145,12 +2109,8 @@ struct ReversePInvokeFrame Thread* currentThread; MethodDesc* pMD; #if defined(TARGET_X86) && defined(TARGET_WINDOWS) -#ifndef FEATURE_EH_FUNCLETS - FrameHandlerExRecord record; -#else EXCEPTION_REGISTRATION_RECORD m_ExReg; #endif -#endif }; //------------------------------------------------------------------------ diff --git a/src/coreclr/vm/gc_unwind_x86.inl b/src/coreclr/vm/gc_unwind_x86.inl index 0e240a1869409a..a726950b8a715a 100644 --- a/src/coreclr/vm/gc_unwind_x86.inl +++ b/src/coreclr/vm/gc_unwind_x86.inl @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // This file is shared between CoreCLR and NativeAOT. Some of the differences are handled -// with the FEATURE_NATIVEAOT and FEATURE_EH_FUNCLETS defines. There are three main methods +// with the FEATURE_NATIVEAOT define. There are three main methods // that are used by both runtimes - DecodeGCHdrInfo, UnwindStackFrameX86, and EnumGcRefsX86. #define RETURN_ADDR_OFFS 1 // in DWORDS @@ -178,12 +178,8 @@ size_t DecodeGCHdrInfo(GCInfoToken gcInfoToken, header.syncEndOffset = decodeUnsigned(table); _ASSERTE(header.syncStartOffset != INVALID_SYNC_OFFSET && header.syncEndOffset != INVALID_SYNC_OFFSET); -#ifdef FEATURE_EH_FUNCLETS _ASSERTE(header.syncStartOffset == 1); _ASSERTE(header.syncEndOffset == 1); -#else - _ASSERTE(header.syncStartOffset < header.syncEndOffset); -#endif } if (header.revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET) @@ -372,9 +368,7 @@ size_t GetLocallocSPOffset(hdrInfo * info) _ASSERTE(info->localloc && info->ebpFrame); unsigned position = info->savedRegsCountExclFP + -#ifdef FEATURE_EH_FUNCLETS ((info->syncStartOffset != INVALID_SYNC_OFFSET) ? 1 : 0) + // Is this method synchronized -#endif 1; return position * sizeof(TADDR); } @@ -386,63 +380,13 @@ size_t GetParamTypeArgOffset(hdrInfo * info) _ASSERTE((info->genericsContext || info->handlers) && info->ebpFrame); -#ifdef FEATURE_EH_FUNCLETS unsigned position = info->savedRegsCountExclFP + ((info->syncStartOffset != INVALID_SYNC_OFFSET) ? 1 : 0) + // Is this method synchronized info->localloc + 1; // For CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG -#else - unsigned position = info->savedRegsCountExclFP + - info->localloc + - 1; // For CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG -#endif - return position * sizeof(TADDR); -} - -#ifndef FEATURE_EH_FUNCLETS -inline size_t GetStartShadowSPSlotsOffset(hdrInfo * info) -{ - LIMITED_METHOD_DAC_CONTRACT; - - _ASSERTE(info->handlers && info->ebpFrame); - - return GetParamTypeArgOffset(info) + - sizeof(TADDR); // Slot for end-of-last-executed-filter -} - -/***************************************************************************** - * Returns the start of the hidden slots for the shadowSP for functions - * with exception handlers. There is one slot per nesting level starting - * near Ebp and is zero-terminated after the active slots. - */ - -inline -PTR_TADDR GetFirstBaseSPslotPtr(TADDR ebp, hdrInfo * info) -{ - LIMITED_METHOD_DAC_CONTRACT; - - _ASSERTE(info->handlers && info->ebpFrame); - - size_t offsetFromEBP = GetStartShadowSPSlotsOffset(info) - + sizeof(TADDR); // to get to the *start* of the next slot - - return PTR_TADDR(ebp - offsetFromEBP); -} - -inline size_t GetEndShadowSPSlotsOffset(hdrInfo * info, unsigned maxHandlerNestingLevel) -{ - LIMITED_METHOD_DAC_CONTRACT; - _ASSERTE(info->handlers && info->ebpFrame); - - unsigned numberOfShadowSPSlots = maxHandlerNestingLevel + - 1 + // For zero-termination - 1; // For a filter (which can be active at the same time as a catch/finally handler - - return GetStartShadowSPSlotsOffset(info) + - (numberOfShadowSPSlots * sizeof(TADDR)); + return position * sizeof(TADDR); } -#endif // FEATURE_EH_FUNCLETS /***************************************************************************** * returns the base frame pointer corresponding to the target nesting level. @@ -555,71 +499,6 @@ FrameType GetHandlerFrameInfo(hdrInfo * info, // Since each subsequent slot contains the SP of a more nested EH clause, the contents of the slots are // expected to be in decreasing order. size_t lvl = 0; -#ifndef FEATURE_EH_FUNCLETS - PTR_TADDR pFirstBaseSPslot = GetFirstBaseSPslotPtr(frameEBP, info); - PTR_TADDR pSlot; - for(lvl = 0, pSlot = pFirstBaseSPslot; - *pSlot && lvl < unwindLevel; - pSlot--, lvl++) - { - // Filters cant have inner funclets - FAIL_IF_SPECULATIVE_WALK(!(baseSP & ICodeManager::SHADOW_SP_IN_FILTER)); - - TADDR curSlotVal = *pSlot; - - // The shadowSPs have to be less unless the stack has been unwound. - FAIL_IF_SPECULATIVE_WALK(baseSP > curSlotVal || - (baseSP == curSlotVal && pSlot == pFirstBaseSPslot)); - - if (curSlotVal == LCL_FINALLY_MARK) - { - // Locally called finally - baseSP -= sizeof(TADDR); - } - else - { - // Is this a funclet we unwound before (can only happen with filters) ? - // If unwindESP is specified, normally we expect it to be the last entry in the shadow slot array. - // Or, if there is a filter, we expect unwindESP to be the second last entry. However, this may - // not be the case in DAC builds. For example, the user can use .cxr in an EH clause to set a - // CONTEXT captured in the try clause. In this case, unwindESP will be the ESP of the parent - // function, but the shadow slot array will contain the SP of the EH clause, which is closer to - // the leaf than the parent method. - - if (unwindESP != (TADDR) IGNORE_VAL && - unwindESP > END_FIN_POP_STACK + - (curSlotVal & ~ICodeManager::SHADOW_SP_BITS)) - { - // In non-DAC builds, the only time unwindESP is closer to the root than entries in the shadow - // slot array is when the last entry in the array is for a filter. Also, filters can't have - // nested handlers. - if ((pSlot[0] & ICodeManager::SHADOW_SP_IN_FILTER) && - (pSlot[-1] == 0) && - !(baseSP & ICodeManager::SHADOW_SP_IN_FILTER)) - { - if (pSlot[0] & ICodeManager::SHADOW_SP_FILTER_DONE) - hadInnerFilter = true; - else - hasInnerFilter = true; - break; - } - else - { -#if defined(DACCESS_COMPILE) - // In DAC builds, this could happen. We just need to bail out of this loop early. - break; -#else // !DACCESS_COMPILE - // In non-DAC builds, this is an error. - FAIL_IF_SPECULATIVE_WALK(FALSE); -#endif // DACCESS_COMPILE - } - } - - nonLocalHandlers = true; - baseSP = curSlotVal; - } - } -#endif // FEATURE_EH_FUNCLETS if (unwindESP != (TADDR) IGNORE_VAL) { @@ -671,7 +550,6 @@ inline size_t GetSizeOfFrameHeaderForEnC(hdrInfo * info) { WRAPPER_NO_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS _ASSERTE(info->ebpFrame); unsigned position = info->savedRegsCountExclFP + info->localloc + @@ -679,19 +557,6 @@ inline size_t GetSizeOfFrameHeaderForEnC(hdrInfo * info) ((info->syncStartOffset != INVALID_SYNC_OFFSET) ? 1 : 0) // Is this method synchronized + 1; // for ebpFrame return position * sizeof(TADDR); -#else - // See comment above Compiler::lvaAssignFrameOffsets() in src\jit\il\lclVars.cpp - // for frame layout - - // EnC supports increasing the maximum handler nesting level by always - // assuming that the max is MAX_EnC_HANDLER_NESTING_LEVEL. Methods with - // a higher max cannot be updated by EnC - - // Take the offset (from EBP) of the last slot of the header, plus one for the EBP slot itself - // to get the total size of the header. - return sizeof(TADDR) + - GetEndShadowSPSlotsOffset(info, MAX_EnC_HANDLER_NESTING_LEVEL); -#endif // FEATURE_EH_FUNCLETS } #endif // FEATURE_NATIVEAOT @@ -1626,15 +1491,11 @@ unsigned scanArgRegTableI(PTR_CBYTE table, bool hasPartialArgInfo; -#ifndef FEATURE_EH_FUNCLETS - hasPartialArgInfo = info->ebpFrame; -#else // For funclets, interruptible code always has full arg info // // This should be aligned with emitFullArgInfo setting at // emitter::emitEndCodeGen (in JIT) hasPartialArgInfo = false; -#endif /* Encoding table for methods that are fully interruptible @@ -2450,7 +2311,7 @@ static void SetLocation(PREGDISPLAY pRD, int ind, PDWORD loc) SIZE_T offsetOfRegPtr = OFFSET_OF_CALLEE_SAVED_REGISTERS[ind]; *(LPVOID*)(PBYTE(pRD) + offsetOfRegPtr) = loc; -#elif defined(FEATURE_EH_FUNCLETS) +#else static const SIZE_T OFFSET_OF_CALLEE_SAVED_REGISTERS[] = { offsetof(T_KNONVOLATILE_CONTEXT_POINTERS, Edi), // first register to be pushed @@ -2461,17 +2322,6 @@ static void SetLocation(PREGDISPLAY pRD, int ind, PDWORD loc) SIZE_T offsetOfRegPtr = OFFSET_OF_CALLEE_SAVED_REGISTERS[ind]; *(LPVOID*)(PBYTE(pRD->pCurrentContextPointers) + offsetOfRegPtr) = loc; -#else - static const SIZE_T OFFSET_OF_CALLEE_SAVED_REGISTERS[] = - { - offsetof(REGDISPLAY, pEdi), // first register to be pushed - offsetof(REGDISPLAY, pEsi), - offsetof(REGDISPLAY, pEbx), - offsetof(REGDISPLAY, pEbp), // last register to be pushed - }; - - SIZE_T offsetOfRegPtr = OFFSET_OF_CALLEE_SAVED_REGISTERS[ind]; - *(LPVOID*)(PBYTE(pRD) + offsetOfRegPtr) = loc; #endif } @@ -3042,7 +2892,6 @@ bool UnwindEbpDoubleAlignFrame( { TADDR baseSP; -#ifdef FEATURE_EH_FUNCLETS // Funclets' frame pointers(EBP) are always restored so they can access to main function's local variables. // Therefore the value of EBP is invalid for unwinder so we should use ESP instead. if (isFunclet) @@ -3069,55 +2918,6 @@ bool UnwindEbpDoubleAlignFrame( return true; } -#else // FEATURE_EH_FUNCLETS - - FrameType frameType = GetHandlerFrameInfo(info, curEBP, - curESP, (DWORD) IGNORE_VAL, - &baseSP); - - /* If we are in a filter, we only need to unwind the funclet stack. - For catches/finallies, the normal handling will - cause the frame to be unwound all the way up to ebp skipping - other frames above it. This is OK, as those frames will be - dead. Also, the EE will detect that this has happened and it - will handle any EE frames correctly. - */ - - if (frameType == FR_INVALID) - { - return false; - } - - if (frameType == FR_FILTER) - { - SetRegdisplayPCTAddr(pContext, (TADDR)baseSP); - - pContext->SP = (DWORD)(baseSP + sizeof(TADDR)); - - // pContext->pEbp = same as before; - -#ifdef _DEBUG - /* The filter has to be called by the VM. So we dont need to - update callee-saved registers. - */ - - if (updateAllRegs) - { - static DWORD s_badData = 0xDEADBEEF; - - pContext->SetEaxLocation(&s_badData); - pContext->SetEcxLocation(&s_badData); - pContext->SetEdxLocation(&s_badData); - - pContext->SetEbxLocation(&s_badData); - pContext->SetEsiLocation(&s_badData); - pContext->SetEdiLocation(&s_badData); - } -#endif - - return true; - } -#endif // !FEATURE_EH_FUNCLETS } // @@ -3234,13 +3034,11 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, GCEnumCallback pCallBack, LPVOID hCallBack) { -#ifdef FEATURE_EH_FUNCLETS if (flags & ParentOfFuncletStackFrame) { LOG((LF_GCROOTS, LL_INFO100000, "Not reporting this frame because it was already reported via another funclet.\n")); return true; } -#endif // FEATURE_EH_FUNCLETS unsigned EBP = GetRegdisplayFP(pContext); unsigned ESP = pContext->SP; @@ -3325,53 +3123,6 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, #endif // _DEBUG - /* What kind of a frame is this ? */ - -#ifndef FEATURE_EH_FUNCLETS - FrameType frameType = FR_NORMAL; - TADDR baseSP = 0; - - if (info.handlers) - { - _ASSERTE(info.ebpFrame); - - bool hasInnerFilter, hadInnerFilter; - frameType = GetHandlerFrameInfo(&info, EBP, - ESP, (DWORD) IGNORE_VAL, - &baseSP, NULL, - &hasInnerFilter, &hadInnerFilter); - _ASSERTE(frameType != FR_INVALID); - - /* If this is the parent frame of a filter which is currently - executing, then the filter would have enumerated the frame using - the filter PC. - */ - - if (hasInnerFilter) - return true; - - /* If are in a try and we had a filter execute, we may have reported - GC refs from the filter (and not using the try's offset). So - we had better use the filter's end offset, as the try is - effectively dead and its GC ref's would be stale */ - - if (hadInnerFilter) - { - PTR_TADDR pFirstBaseSPslot = GetFirstBaseSPslotPtr(EBP, &info); - curOffs = (unsigned)pFirstBaseSPslot[1] - 1; - _ASSERTE(curOffs < info.methodSize); - - /* Extract the necessary information from the info block header */ - - table = PTR_CBYTE(gcInfoToken.Info); - - table += DecodeGCHdrInfo(gcInfoToken, - curOffs, - &info); - } - } -#endif - bool willContinueExecution = !(flags & ExecutionAborted); unsigned pushedSize = 0; @@ -3454,7 +3205,6 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, { _ASSERTE(willContinueExecution); -#ifdef FEATURE_EH_FUNCLETS // Funclets' frame pointers(EBP) are always restored so they can access to main function's local variables. // Therefore the value of EBP is invalid for unwinder so we should use ESP instead. // See UnwindStackFrame for details. @@ -3479,13 +3229,6 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, // -sizeof(void*) because we want to point *AT* first parameter pPendingArgFirst = (DWORD *)(size_t)(baseSP - sizeof(void*)); } -#else // FEATURE_EH_FUNCLETS - if (info.handlers) - { - // -sizeof(void*) because we want to point *AT* first parameter - pPendingArgFirst = (DWORD *)(size_t)(baseSP - sizeof(void*)); - } -#endif else if (info.localloc) { TADDR locallocBaseSP = *(DWORD *)(size_t)(EBP - GetLocallocSPOffset(&info)); @@ -3702,7 +3445,6 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, /* Process the untracked frame variable table */ -#if defined(FEATURE_EH_FUNCLETS) // funclets // Filters are the only funclet that run during the 1st pass, and must have // both the leaf and the parent frame reported. In order to avoid double // reporting of the untracked variables, do not report them for the filter. @@ -3715,7 +3457,6 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, } } else -#endif // FEATURE_EH_FUNCLETS { count = info.untrackedCnt; int lastStkOffs = 0; @@ -3837,12 +3578,7 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, if (dspPtr) { printf(" Frame %s%s local at [E", (lowBits & byref_OFFSET_FLAG) ? "byref " : "", -#ifndef FEATURE_EH_FUNCLETS - (lowBits & this_OFFSET_FLAG) ? "this-ptr" : ""); -#else (lowBits & pinned_OFFSET_FLAG) ? "pinned" : ""); -#endif - int dspOffs = ptrAddr; char frameType; @@ -3864,17 +3600,11 @@ bool EnumGcRefsX86(PREGDISPLAY pContext, #endif unsigned flags = CHECK_APP_DOMAIN; -#ifndef FEATURE_EH_FUNCLETS - // First Bit : byref - // Second Bit : this - // The second bit means `this` not `pinned`. So we ignore it. - flags |= lowBits & byref_OFFSET_FLAG; -#else + // First Bit : byref // Second Bit : pinned // Both bits are valid flags |= lowBits; -#endif _ASSERTE(byref_OFFSET_FLAG == GC_CALL_INTERIOR); pCallBack(hCallBack, (OBJECTREF*)(size_t)ptrAddr, flags diff --git a/src/coreclr/vm/gcenv.ee.common.cpp b/src/coreclr/vm/gcenv.ee.common.cpp index 38f80969ce77fd..6175c61a3b776b 100644 --- a/src/coreclr/vm/gcenv.ee.common.cpp +++ b/src/coreclr/vm/gcenv.ee.common.cpp @@ -5,7 +5,6 @@ #include "gcenv.h" #include -#if defined(FEATURE_EH_FUNCLETS) #if defined(USE_GC_INFO_DECODER) struct FindFirstInterruptiblePointState @@ -86,7 +85,6 @@ unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned en } #endif -#endif // FEATURE_EH_FUNCLETS //----------------------------------------------------------------------------- // Determine whether we should report the generic parameter context @@ -266,11 +264,10 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) gcctx->cf = pCF; bool fReportGCReferences = true; -#if defined(FEATURE_EH_FUNCLETS) + // We may have unwound this crawlFrame and thus, shouldn't report the invalid // references it may contain. fReportGCReferences = pCF->ShouldCrawlframeReportGCReferences(); -#endif // defined(FEATURE_EH_FUNCLETS) if (fReportGCReferences) { @@ -297,7 +294,7 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) #endif // _DEBUG DWORD relOffsetOverride = NO_OVERRIDE_OFFSET; -#if defined(FEATURE_EH_FUNCLETS) + if (pCF->ShouldParentToFuncletUseUnwindTargetLocationForGCReporting()) { // We're in a special case of unwinding from a funclet, and resuming execution in @@ -317,7 +314,6 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) STRESS_LOG3(LF_GCROOTS, LL_INFO1000, "Setting override offset = %u for method %pM ControlPC = %p\n", relOffsetOverride, pMD, GetControlPC(pCF->GetRegisterSet())); } -#endif // FEATURE_EH_FUNCLETS pCM->EnumGcRefs(pCF->GetRegisterSet(), pCF->GetCodeInfo(), diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp index 3ac2d160ea691a..51c4904537f1b1 100644 --- a/src/coreclr/vm/gcenv.ee.cpp +++ b/src/coreclr/vm/gcenv.ee.cpp @@ -5,8 +5,6 @@ * GCENV.EE.CPP * * GCToEEInterface implementation - * - * */ @@ -141,7 +139,6 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) IsGCSpecialThread() || (GetThread() == ThreadSuspend::GetSuspensionThread() && ThreadStore::HoldingThreadStore())); -#if defined(FEATURE_CONSERVATIVE_GC) || defined(USE_FEF) Frame* pTopFrame = pThread->GetFrame(); Object ** topStack = (Object **)pTopFrame; if (InlinedCallFrame::FrameHasActiveCall(pTopFrame)) @@ -150,19 +147,10 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) InlinedCallFrame* pInlinedFrame = dac_cast(pTopFrame); topStack = (Object **)pInlinedFrame->GetCallSiteSP(); } -#endif // FEATURE_CONSERVATIVE_GC || USE_FEF -#ifdef USE_FEF - // We only set the stack_limit when FEF (FaultingExceptionFrame) is enabled, because without the - // FEF, the code above would have to check if hardware exception is being handled and get the limit - // from the exception frame. Since the stack_limit is strictly necessary only on Unix and FEF is - // not enabled on Window x86 only, it is sufficient to keep the stack_limit set to 0 in this case. + // We set the stack_limit when FEF (FaultingExceptionFrame) is enabled. // See the comment on the stack_limit usage in the PromoteCarefully function for more details. sc->stack_limit = (uintptr_t)topStack; -#else // USE_FEF - // It should be set to 0 in the ScanContext constructor - _ASSERTE(sc->stack_limit == 0); -#endif // USE_FEF #ifdef FEATURE_CONSERVATIVE_GC if (g_pConfig->GetGCConservative()) @@ -202,9 +190,9 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) #endif { unsigned flagsStackWalk = ALLOW_ASYNC_STACK_WALK | ALLOW_INVALID_OBJECTS; -#if defined(FEATURE_EH_FUNCLETS) + flagsStackWalk |= GC_FUNCLET_REFERENCE_REPORTING; -#endif // defined(FEATURE_EH_FUNCLETS) + gcctx.pScannedSlots = NULL; pThread->StackWalkFrames( GcStackCrawlCallBack, &gcctx, flagsStackWalk); delete gcctx.pScannedSlots; diff --git a/src/coreclr/vm/i386/asmconstants.h b/src/coreclr/vm/i386/asmconstants.h index 209a1e731050b6..bec176ddca3fed 100644 --- a/src/coreclr/vm/i386/asmconstants.h +++ b/src/coreclr/vm/i386/asmconstants.h @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // asmconstants.h - // // This header defines field offsets and constants used by assembly code @@ -74,36 +75,6 @@ ASMCONSTANTS_C_ASSERT(CONTEXT_Eip == offsetof(CONTEXT,Eip)) #define CONTEXT_Esp 0xc4 ASMCONSTANTS_C_ASSERT(CONTEXT_Esp == offsetof(CONTEXT,Esp)) -#ifndef FEATURE_EH_FUNCLETS -// EHContext from clr/src/vm/i386/cgencpu.h -#define EHContext_Eax 0x00 -ASMCONSTANTS_C_ASSERT(EHContext_Eax == offsetof(EHContext,Eax)) - -#define EHContext_Ebx 0x04 -ASMCONSTANTS_C_ASSERT(EHContext_Ebx == offsetof(EHContext,Ebx)) - -#define EHContext_Ecx 0x08 -ASMCONSTANTS_C_ASSERT(EHContext_Ecx == offsetof(EHContext,Ecx)) - -#define EHContext_Edx 0x0c -ASMCONSTANTS_C_ASSERT(EHContext_Edx == offsetof(EHContext,Edx)) - -#define EHContext_Esi 0x10 -ASMCONSTANTS_C_ASSERT(EHContext_Esi == offsetof(EHContext,Esi)) - -#define EHContext_Edi 0x14 -ASMCONSTANTS_C_ASSERT(EHContext_Edi == offsetof(EHContext,Edi)) - -#define EHContext_Ebp 0x18 -ASMCONSTANTS_C_ASSERT(EHContext_Ebp == offsetof(EHContext,Ebp)) - -#define EHContext_Esp 0x1c -ASMCONSTANTS_C_ASSERT(EHContext_Esp == offsetof(EHContext,Esp)) - -#define EHContext_Eip 0x20 -ASMCONSTANTS_C_ASSERT(EHContext_Eip == offsetof(EHContext,Eip)) -#endif // FEATURE_EH_FUNCLETS - #define VASigCookie__StubOffset 4 ASMCONSTANTS_C_ASSERT(VASigCookie__StubOffset == offsetof(VASigCookie, pPInvokeILStub)) @@ -198,17 +169,6 @@ ASMCONSTANTS_C_ASSERT(SZARRAY_BASE_SIZE == OBJECT_BASESIZE + sizeof(DWORD)); #ifdef FEATURE_COMINTEROP -#ifndef FEATURE_EH_FUNCLETS -#define SIZEOF_FrameHandlerExRecord 0x0c -#define OFFSETOF__FrameHandlerExRecord__m_ExReg__Next 0 -#define OFFSETOF__FrameHandlerExRecord__m_ExReg__Handler 4 -#define OFFSETOF__FrameHandlerExRecord__m_pEntryFrame 8 -ASMCONSTANTS_C_ASSERT(SIZEOF_FrameHandlerExRecord == sizeof(FrameHandlerExRecord)) -ASMCONSTANTS_C_ASSERT(OFFSETOF__FrameHandlerExRecord__m_ExReg__Next == offsetof(FrameHandlerExRecord, m_ExReg) + offsetof(EXCEPTION_REGISTRATION_RECORD, Next)) -ASMCONSTANTS_C_ASSERT(OFFSETOF__FrameHandlerExRecord__m_ExReg__Handler == offsetof(FrameHandlerExRecord, m_ExReg) + offsetof(EXCEPTION_REGISTRATION_RECORD, Handler)) -ASMCONSTANTS_C_ASSERT(OFFSETOF__FrameHandlerExRecord__m_pEntryFrame == offsetof(FrameHandlerExRecord, m_pEntryFrame)) -#endif - #ifdef _DEBUG #ifndef STACK_OVERWRITE_BARRIER_SIZE #define STACK_OVERWRITE_BARRIER_SIZE 20 diff --git a/src/coreclr/vm/i386/asmhelpers.asm b/src/coreclr/vm/i386/asmhelpers.asm index 77341186120aaa..2b74e0ac6d9b51 100644 --- a/src/coreclr/vm/i386/asmhelpers.asm +++ b/src/coreclr/vm/i386/asmhelpers.asm @@ -30,19 +30,13 @@ EXTERN __imp__RtlUnwind@16:DWORD ifdef FEATURE_HIJACK EXTERN _OnHijackWorker@4:PROC endif ;FEATURE_HIJACK -ifdef FEATURE_EH_FUNCLETS EXTERN _ProcessCLRException:PROC EXTERN _UMEntryPrestubUnwindFrameChainHandler:PROC EXTERN _CallDescrWorkerUnwindFrameChainHandler:PROC ifdef FEATURE_COMINTEROP EXTERN _ReverseComUnwindFrameChainHandler:PROC endif ; FEATURE_COMINTEROP -else -EXTERN _COMPlusFrameHandler:PROC -ifdef FEATURE_COMINTEROP -EXTERN _COMPlusFrameHandlerRevCom:PROC -endif ; FEATURE_COMINTEROP -endif ; FEATURE_EH_FUNCLETS +EXTERN _ProcessCLRException:PROC EXTERN __alloca_probe:PROC EXTERN _PInvokeImportWorker@4:PROC @@ -97,58 +91,6 @@ UNREFERENCED macro arg unref equ size arg endm -ifndef FEATURE_EH_FUNCLETS -ifdef FEATURE_COMINTEROP -ifdef _DEBUG - CPFH_STACK_SIZE equ SIZEOF_FrameHandlerExRecord + STACK_OVERWRITE_BARRIER_SIZE*4 -else ; _DEBUG - CPFH_STACK_SIZE equ SIZEOF_FrameHandlerExRecord -endif ; _DEBUG - -PUSH_CPFH_FOR_COM macro trashReg, pFrameBaseReg, pFrameOffset - - ; - ; Setup the FrameHandlerExRecord - ; - push dword ptr [pFrameBaseReg + pFrameOffset] - push _COMPlusFrameHandlerRevCom - mov trashReg, fs:[0] - push trashReg - mov fs:[0], esp - -ifdef _DEBUG - mov trashReg, STACK_OVERWRITE_BARRIER_SIZE -@@: - push STACK_OVERWRITE_BARRIER_VALUE - dec trashReg - jnz @B -endif ; _DEBUG - -endm ; PUSH_CPFH_FOR_COM - - -POP_CPFH_FOR_COM macro trashReg - - ; - ; Unlink FrameHandlerExRecord from FS:0 chain - ; -ifdef _DEBUG - add esp, STACK_OVERWRITE_BARRIER_SIZE*4 -endif - mov trashReg, [esp + OFFSETOF__FrameHandlerExRecord__m_ExReg__Next] - mov fs:[0], trashReg - add esp, SIZEOF_FrameHandlerExRecord - -endm ; POP_CPFH_FOR_COM -endif ; FEATURE_COMINTEROP - -PUSH_CLR_EXCEPTION_HANDLER macro handlerName -endm -POP_CLR_EXCEPTION_HANDLER macro -endm - -else ; FEATURE_EH_FUNCLETS - CPFH_STACK_SIZE equ 8 PUSH_CLR_EXCEPTION_HANDLER macro handlerName @@ -172,8 +114,6 @@ POP_CPFH_FOR_COM macro trashReg POP_CLR_EXCEPTION_HANDLER endm -endif ; FEATURE_EH_FUNCLETS - ; ; FramedMethodFrame prolog ; @@ -288,18 +228,6 @@ _RestoreFPUContext@4 ENDP ; Note that these directives must be in a file that defines symbols that will be used during linking, ; otherwise it's possible that the resulting .obj will completely be ignored by the linker and these ; directives will have no effect. -ifndef FEATURE_EH_FUNCLETS -COMPlusFrameHandler proto c -.safeseh COMPlusFrameHandler -COMPlusNestedExceptionHandler proto c -.safeseh COMPlusNestedExceptionHandler -FastNExportExceptHandler proto c -.safeseh FastNExportExceptHandler -ifdef FEATURE_COMINTEROP -COMPlusFrameHandlerRevCom proto c -.safeseh COMPlusFrameHandlerRevCom -endif -else ; FEATURE_EH_FUNCLETS ProcessCLRException proto c .safeseh ProcessCLRException UMEntryPrestubUnwindFrameChainHandler proto c @@ -310,7 +238,6 @@ ifdef FEATURE_COMINTEROP ReverseComUnwindFrameChainHandler proto c .safeseh ReverseComUnwindFrameChainHandler endif ; FEATURE_COMINTEROP -endif ; FEATURE_EH_FUNCLETS ifdef HAS_ADDRESS_SANITIZER EXTERN ___asan_handle_no_return:PROC @@ -332,130 +259,6 @@ CallRtlUnwind PROC stdcall public USES ebx esi edi, pEstablisherFrame :DWORD, ca RET CallRtlUnwind ENDP -ifndef FEATURE_EH_FUNCLETS -_ResumeAtJitEHHelper@4 PROC public - ; Call ___asan_handle_no_return here as we are not going to return. -ifdef HAS_ADDRESS_SANITIZER - call ___asan_handle_no_return -endif - mov edx, [esp+4] ; edx = pContext (EHContext*) - - mov ebx, [edx+EHContext_Ebx] - mov esi, [edx+EHContext_Esi] - mov edi, [edx+EHContext_Edi] - mov ebp, [edx+EHContext_Ebp] - mov ecx, [edx+EHContext_Esp] - mov eax, [edx+EHContext_Eip] - mov [ecx-4], eax - mov eax, [edx+EHContext_Eax] - mov [ecx-8], eax - mov eax, [edx+EHContext_Ecx] - mov [ecx-0Ch], eax - mov eax, [edx+EHContext_Edx] - mov [ecx-10h], eax - lea esp, [ecx-10h] - pop edx - pop ecx - pop eax - ret -_ResumeAtJitEHHelper@4 ENDP - -; int __stdcall CallJitEHFilterHelper(size_t *pShadowSP, EHContext *pContext); -; on entry, only the pContext->Esp, Ebx, Esi, Edi, Ebp, and Eip are initialized -_CallJitEHFilterHelper@8 PROC public - ; Call ___asan_handle_no_return here as we touch registers that ASAN uses. -ifdef HAS_ADDRESS_SANITIZER - call ___asan_handle_no_return -endif - push ebp - mov ebp, esp - push ebx - push esi - push edi - - pShadowSP equ [ebp+8] - pContext equ [ebp+12] - - mov eax, pShadowSP ; Write esp-4 to the shadowSP slot - test eax, eax - jz DONE_SHADOWSP_FILTER - mov ebx, esp - sub ebx, 4 - or ebx, SHADOW_SP_IN_FILTER_ASM - mov [eax], ebx - DONE_SHADOWSP_FILTER: - - mov edx, [pContext] - mov eax, [edx+EHContext_Eax] - mov ebx, [edx+EHContext_Ebx] - mov esi, [edx+EHContext_Esi] - mov edi, [edx+EHContext_Edi] - mov ebp, [edx+EHContext_Ebp] - - call dword ptr [edx+EHContext_Eip] -ifdef _DEBUG - nop ; Indicate that it is OK to call managed code directly from here -endif - - pop edi - pop esi - pop ebx - pop ebp ; don't use 'leave' here, as ebp as been trashed - retn 8 -_CallJitEHFilterHelper@8 ENDP - - -; void __stdcall CallJITEHFinallyHelper(size_t *pShadowSP, EHContext *pContext); -; on entry, only the pContext->Esp, Ebx, Esi, Edi, Ebp, and Eip are initialized -_CallJitEHFinallyHelper@8 PROC public - ; Call ___asan_handle_no_return here as we touch registers that ASAN uses. -ifdef HAS_ADDRESS_SANITIZER - call ___asan_handle_no_return -endif - push ebp - mov ebp, esp - push ebx - push esi - push edi - - pShadowSP equ [ebp+8] - pContext equ [ebp+12] - - mov eax, pShadowSP ; Write esp-4 to the shadowSP slot - test eax, eax - jz DONE_SHADOWSP_FINALLY - mov ebx, esp - sub ebx, 4 - mov [eax], ebx - DONE_SHADOWSP_FINALLY: - - mov edx, [pContext] - mov eax, [edx+EHContext_Eax] - mov ebx, [edx+EHContext_Ebx] - mov esi, [edx+EHContext_Esi] - mov edi, [edx+EHContext_Edi] - mov ebp, [edx+EHContext_Ebp] - call dword ptr [edx+EHContext_Eip] -ifdef _DEBUG - nop ; Indicate that it is OK to call managed code directly from here -endif - - ; Reflect the changes to the context and only update non-volatile registers. - ; This will be used later to update REGDISPLAY - mov edx, [esp+12+12] - mov [edx+EHContext_Ebx], ebx - mov [edx+EHContext_Esi], esi - mov [edx+EHContext_Edi], edi - mov [edx+EHContext_Ebp], ebp - - pop edi - pop esi - pop ebx - pop ebp ; don't use 'leave' here, as ebp as been trashed - retn 8 -_CallJitEHFinallyHelper@8 ENDP -endif - ;------------------------------------------------------------------------------ ; This helper routine enregisters the appropriate arguments and makes the ; actual call. diff --git a/src/coreclr/vm/i386/cgencpu.h b/src/coreclr/vm/i386/cgencpu.h index 021d74c9d6908b..2bdf28ae25203f 100644 --- a/src/coreclr/vm/i386/cgencpu.h +++ b/src/coreclr/vm/i386/cgencpu.h @@ -1,12 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // CGENX86.H - // // Various helper routines for generating x86 assembly code. // // DO NOT INCLUDE THIS FILE DIRECTLY - ALWAYS USE CGENSYS.H INSTEAD -// - #ifndef TARGET_X86 @@ -135,57 +134,6 @@ struct ArgumentRegisters { struct REGDISPLAY; typedef REGDISPLAY *PREGDISPLAY; -#ifndef FEATURE_EH_FUNCLETS -// Sufficient context for Try/Catch restoration. -struct EHContext { - INT32 Eax; - INT32 Ebx; - INT32 Ecx; - INT32 Edx; - INT32 Esi; - INT32 Edi; - INT32 Ebp; - INT32 Esp; - INT32 Eip; - - void Setup(PCODE resumePC, PREGDISPLAY regs); - void UpdateFrame(PREGDISPLAY regs); - - inline TADDR GetSP() { - LIMITED_METHOD_CONTRACT; - return (TADDR)Esp; - } - inline void SetSP(LPVOID esp) { - LIMITED_METHOD_CONTRACT; - Esp = (INT32)(size_t)esp; - } - - inline LPVOID GetFP() { - LIMITED_METHOD_CONTRACT; - return (LPVOID)(UINT_PTR)Ebp; - } - - inline void SetArg(LPVOID arg) { - LIMITED_METHOD_CONTRACT; - Eax = (INT32)(size_t)arg; - } - - inline void Init() - { - LIMITED_METHOD_CONTRACT; - Eax = 0; - Ebx = 0; - Ecx = 0; - Edx = 0; - Esi = 0; - Edi = 0; - Ebp = 0; - Esp = 0; - Eip = 0; - } -}; -#endif // !FEATURE_EH_FUNCLETS - #define ARGUMENTREGISTERS_SIZE sizeof(ArgumentRegisters) //********************************************************************** diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp index 2942e3767bf54b..54ff2e2cbdb85e 100644 --- a/src/coreclr/vm/i386/cgenx86.cpp +++ b/src/coreclr/vm/i386/cgenx86.cpp @@ -41,7 +41,6 @@ #include "perfmap.h" #endif -#ifdef FEATURE_EH_FUNCLETS void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegisters * regs) { LIMITED_METHOD_CONTRACT; @@ -65,73 +64,6 @@ void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD) ENUM_ARGUMENT_AND_SCRATCH_REGISTERS(); #undef ARGUMENT_AND_SCRATCH_REGISTER } -#endif // FEATURE_EH_FUNCLETS - -#ifndef FEATURE_EH_FUNCLETS -//--------------------------------------------------------------------------------------- -// -// Initialize the EHContext using the resume PC and the REGDISPLAY. The EHContext is currently used in two -// scenarios: to store the register state before calling an EH clause, and to retrieve the ambient SP of a -// particular stack frame. resumePC means different things in the two scenarios. In the former case, it -// is the IP at which we are going to resume execution when we call an EH clause. In the latter case, it -// is just the current IP. -// -// Arguments: -// resumePC - refer to the comment above -// regs - This is the REGDISPLAY obtained from the CrawlFrame used in the stackwalk. It represents the -// stack frame of the method containing the EH clause we are about to call. For getting the -// ambient SP, this is the stack frame we are interested in. -// - -void EHContext::Setup(PCODE resumePC, PREGDISPLAY regs) -{ - LIMITED_METHOD_DAC_CONTRACT; - - // EAX ECX EDX are scratch - this->Esp = regs->SP; - this->Ebx = *regs->pEbx; - this->Esi = *regs->pEsi; - this->Edi = *regs->pEdi; - this->Ebp = *regs->pEbp; - - this->Eip = (ULONG)(size_t)resumePC; -} - -// -// Update the registers using new context -// -// This is necessary to reflect GC pointer changes during the middle of a unwind inside a -// finally clause, because: -// 1. GC won't see the part of stack inside try (which has thrown an exception) that is already -// unwinded and thus GC won't update GC pointers for this portion of the stack, but rather the -// call stack in finally. -// 2. upon return of finally, the unwind process continues and unwinds stack based on the part -// of stack inside try and won't see the updated values in finally. -// As a result, we need to manually update the context using register values upon return of finally -// -// Note that we only update the registers for finally clause because -// 1. For filter handlers, stack walker is able to see the whole stack (including the try part) -// with the help of ExceptionFilterFrame as filter handlers are called in first pass -// 2. For catch handlers, the current unwinding is already finished -// -void EHContext::UpdateFrame(PREGDISPLAY regs) -{ - LIMITED_METHOD_CONTRACT; - - // EAX ECX EDX are scratch. - // No need to update ESP as unwinder takes care of that for us - - LOG((LF_EH, LL_INFO1000, "Updating saved EBX: *%p= %p\n", regs->pEbx, this->Ebx)); - LOG((LF_EH, LL_INFO1000, "Updating saved ESI: *%p= %p\n", regs->pEsi, this->Esi)); - LOG((LF_EH, LL_INFO1000, "Updating saved EDI: *%p= %p\n", regs->pEdi, this->Edi)); - LOG((LF_EH, LL_INFO1000, "Updating saved EBP: *%p= %p\n", regs->pEbp, this->Ebp)); - - *regs->pEbx = this->Ebx; - *regs->pEsi = this->Esi; - *regs->pEdi = this->Edi; - *regs->pEbp = this->Ebp; -} -#endif // FEATURE_EH_FUNCLETS void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) { @@ -173,8 +105,6 @@ void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStack DWORD CallerSP = (DWORD)(GetReturnAddressPtr() + sizeof(TADDR) + cbStackPop); -#ifdef FEATURE_EH_FUNCLETS - pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; @@ -185,19 +115,6 @@ void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStack SyncRegDisplayToCurrentContext(pRD); -#else // FEATURE_EH_FUNCLETS - - // reset pContext; it's only valid for active (top-most) frame - pRD->pContext = NULL; - -#define CALLEE_SAVED_REGISTER(regname) pRD->p##regname = (DWORD*) ®s->regname; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - pRD->SP = CallerSP; - -#endif // FEATURE_EH_FUNCLETS - RETURN; } @@ -251,12 +168,11 @@ void StubDispatchFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool update // This path is hit when we are throwing null reference exception from // code:VSD_ResolveWorker or code:StubDispatchFixupWorker pRD->ControlPC = GetAdjustedCallAddress(pRD->ControlPC); -#ifdef FEATURE_EH_FUNCLETS + // We need to set EIP to match ControlPC to ensure Thread::VirtualUnwindCallFrame // doesn't fail assertion on GetControlPC(pRD) == GetIP(pRD->pCurrentContext) // precondition. pRD->pCurrentContext->Eip = pRD->ControlPC; -#endif } LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK StubDispatchFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); @@ -295,8 +211,6 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u SetRegdisplayPCTAddr(pRD, GetReturnAddressPtr()); -#ifdef FEATURE_EH_FUNCLETS - memcpy(pRD->pCurrentContext, &m_ctx, sizeof(CONTEXT)); // Clear the CONTEXT_XSTATE, since the REGDISPLAY contains just plain CONTEXT structure @@ -317,21 +231,6 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. -#else // FEATURE_EH_FUNCLETS - - // reset pContext; it's only valid for active (top-most) frame - pRD->pContext = NULL; - - CalleeSavedRegisters* regs = GetCalleeSavedRegisters(); - -#define CALLEE_SAVED_REGISTER(regname) pRD->p##regname = (DWORD*) ®s->regname; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - pRD->SP = m_Esp; - -#endif // FEATURE_EH_FUNCLETS - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); RETURN; @@ -367,9 +266,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF #if !defined(UNIX_X86_ABI) TADDR datum = dac_cast(m_Datum); -#ifdef FEATURE_EH_FUNCLETS datum &= ~(TADDR)InlinedCallFrameMarker::Mask; -#endif stackArgSize = (DWORD)datum; @@ -388,8 +285,6 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF /* The return address is just above the "ESP" */ SetRegdisplayPCTAddr(pRD, PTR_HOST_MEMBER_TADDR(InlinedCallFrame, this, m_pCallerReturnAddress)); -#ifdef FEATURE_EH_FUNCLETS - pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -406,18 +301,6 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF SyncRegDisplayToCurrentContext(pRD); -#else // FEATURE_EH_FUNCLETS - - // reset pContext; it's only valid for active (top-most) frame - pRD->pContext = NULL; - - pRD->pEbp = (DWORD*) &m_pCalleeSavedFP; - - /* Now we need to pop off the outgoing arguments */ - pRD->SP = (DWORD) dac_cast(m_pCallSiteSP) + stackArgSize; - -#endif // FEATURE_EH_FUNCLETS - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); RETURN; @@ -446,8 +329,6 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo SetRegdisplayPCTAddr(pRD, dac_cast(m_Regs) + offsetof(CONTEXT, Eip)); -#ifdef FEATURE_EH_FUNCLETS - CopyMemory(pRD->pCurrentContext, m_Regs, sizeof(T_CONTEXT)); pRD->SP = m_Regs->Esp; @@ -463,48 +344,6 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. -#else // FEATURE_EH_FUNCLETS - - // reset pContext; it's only valid for active (top-most) frame - pRD->pContext = NULL; - - CONTEXT* pUnwoundContext = m_Regs; - -#if !defined(DACCESS_COMPILE) - // "pContextForUnwind" field is only used on X86 since not only is it initialized just for it, - // but its used only under the confines of STACKWALKER_MAY_POP_FRAMES preprocessor define, - // which is defined for x86 only (refer to its definition in stackwalk.cpp). - if (pRD->pContextForUnwind != NULL) - { - pUnwoundContext = pRD->pContextForUnwind; - - pUnwoundContext->Eax = m_Regs->Eax; - pUnwoundContext->Ecx = m_Regs->Ecx; - pUnwoundContext->Edx = m_Regs->Edx; - - pUnwoundContext->Edi = m_Regs->Edi; - pUnwoundContext->Esi = m_Regs->Esi; - pUnwoundContext->Ebx = m_Regs->Ebx; - pUnwoundContext->Ebp = m_Regs->Ebp; - pUnwoundContext->Eip = m_Regs->Eip; - } -#endif // !defined(DACCESS_COMPILE) - - pRD->pEax = &pUnwoundContext->Eax; - pRD->pEcx = &pUnwoundContext->Ecx; - pRD->pEdx = &pUnwoundContext->Edx; - - pRD->pEdi = &pUnwoundContext->Edi; - pRD->pEsi = &pUnwoundContext->Esi; - pRD->pEbx = &pUnwoundContext->Ebx; - pRD->pEbp = &pUnwoundContext->Ebp; - - pRD->ControlPC = pUnwoundContext->Eip; - - pRD->SP = m_Regs->Esp; - -#endif // !FEATURE_EH_FUNCLETS - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); RETURN; @@ -523,8 +362,6 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats SetRegdisplayPCTAddr(pRD, dac_cast(m_Args) + offsetof(HijackArgs, Eip)); -#ifdef FEATURE_EH_FUNCLETS - pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -542,25 +379,6 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats SyncRegDisplayToCurrentContext(pRD); -#else // FEATURE_EH_FUNCLETS - - // This only describes the top-most frame - pRD->pContext = NULL; - -#define RESTORE_REG(reg) { pRD->p##reg = &m_Args->reg; } -#define CALLEE_SAVED_REGISTER(reg) RESTORE_REG(reg) - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - -#define ARGUMENT_AND_SCRATCH_REGISTER(reg) RESTORE_REG(reg) - ENUM_ARGUMENT_AND_SCRATCH_REGISTERS(); -#undef ARGUMENT_AND_SCRATCH_REGISTER -#undef RESTORE_REG - - pRD->SP = (DWORD)(GetRegdisplayPCTAddr(pRD) + sizeof(TADDR)); - -#endif // FEATURE_EH_FUNCLETS - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); } @@ -599,8 +417,6 @@ void TailCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloa SetRegdisplayPCTAddr(pRD, GetReturnAddressPtr()); -#ifdef FEATURE_EH_FUNCLETS - pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -611,19 +427,6 @@ void TailCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloa SyncRegDisplayToCurrentContext(pRD); -#else - - // reset pContext; it's only valid for active (top-most) frame - pRD->pContext = NULL; - -#define CALLEE_SAVED_REGISTER(regname) pRD->p##regname = (DWORD*) &m_regs.regname; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - pRD->SP = (DWORD)(GetRegdisplayPCTAddr(pRD) + sizeof(TADDR)); - -#endif - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TailCallFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); RETURN; diff --git a/src/coreclr/vm/i386/ehhelpers.asm b/src/coreclr/vm/i386/ehhelpers.asm index e2259b178d9d68..b65d3a0637cb01 100644 --- a/src/coreclr/vm/i386/ehhelpers.asm +++ b/src/coreclr/vm/i386/ehhelpers.asm @@ -10,8 +10,6 @@ include asmconstants.inc option casemap:none .code -ifdef FEATURE_EH_FUNCLETS - ; DWORD_PTR STDCALL CallEHFunclet(Object *pThrowable, UINT_PTR pFuncletToInvoke, CONTEXT *pContext, UINT_PTR *pFuncletCallerSP); ; ESP based frame _CallEHFunclet@16 proc public @@ -96,6 +94,4 @@ _CallEHFilterFunclet@16 proc public _CallEHFilterFunclet@16 endp -endif ; FEATURE_EH_FUNCLETS - end diff --git a/src/coreclr/vm/i386/excepcpu.h b/src/coreclr/vm/i386/excepcpu.h index 6eca4a596ca79a..057bdac4465f87 100644 --- a/src/coreclr/vm/i386/excepcpu.h +++ b/src/coreclr/vm/i386/excepcpu.h @@ -33,59 +33,6 @@ } #endif // TARGET_WINDOWS -#ifndef FEATURE_EH_FUNCLETS -class Thread; - -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) \ - { \ - PEXCEPTION_REGISTRATION_RECORD __record = (record); \ - _ASSERTE(__record < GetCurrentSEHRecord()); \ - INSTALL_SEH_RECORD(record); \ - } - -// -// Note: this only pops a handler from the top of the stack. It will not remove a record from the middle of the -// chain, and I can assure you that you don't want to do that anyway. -// -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) \ - { \ - PEXCEPTION_REGISTRATION_RECORD __record = (record); \ - _ASSERTE(__record == GetCurrentSEHRecord()); \ - UNINSTALL_SEH_RECORD(record); \ - } - -// stackOverwriteBarrier is used to detect overwriting of stack which will mess up handler registration -#if defined(_DEBUG) -#define DECLARE_CPFH_EH_RECORD(pCurThread) \ - FrameHandlerExRecordWithBarrier *___pExRecordWithBarrier = (FrameHandlerExRecordWithBarrier *)_alloca(sizeof(FrameHandlerExRecordWithBarrier)); \ - for (int ___i =0; ___i < STACK_OVERWRITE_BARRIER_SIZE; ___i++) \ - ___pExRecordWithBarrier->m_StackOverwriteBarrier[___i] = STACK_OVERWRITE_BARRIER_VALUE; \ - FrameHandlerExRecord *___pExRecord = &(___pExRecordWithBarrier->m_ExRecord); \ - ___pExRecord->m_ExReg.Handler = (PEXCEPTION_ROUTINE)COMPlusFrameHandler; \ - ___pExRecord->m_pEntryFrame = (pCurThread)->GetFrame(); - -#else -#define DECLARE_CPFH_EH_RECORD(pCurThread) \ - FrameHandlerExRecord *___pExRecord = (FrameHandlerExRecord *)_alloca(sizeof(FrameHandlerExRecord)); \ - ___pExRecord->m_ExReg.Handler = (PEXCEPTION_ROUTINE)COMPlusFrameHandler; \ - ___pExRecord->m_pEntryFrame = (pCurThread)->GetFrame(); - -#endif - - -PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord(); -PEXCEPTION_REGISTRATION_RECORD GetFirstCOMPlusSEHRecord(Thread*); - -LPVOID COMPlusEndCatchWorker(Thread *pCurThread); -EXTERN_C LPVOID STDCALL COMPlusEndCatch(LPVOID ebp, DWORD ebx, DWORD edi, DWORD esi, LPVOID* pRetAddress); - -#else // FEATURE_EH_FUNCLETS -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) -#define DECLARE_CPFH_EH_RECORD(pCurThread) - -#endif // FEATURE_EH_FUNCLETS - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/coreclr/vm/i386/excepx86.cpp b/src/coreclr/vm/i386/excepx86.cpp index a1eed20405e172..603af5e2f4fd58 100644 --- a/src/coreclr/vm/i386/excepx86.cpp +++ b/src/coreclr/vm/i386/excepx86.cpp @@ -33,3194 +33,6 @@ #include "asmconstants.h" #include "virtualcallstub.h" -#ifndef FEATURE_EH_FUNCLETS -MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDesc * pILStubMD, Frame ** ppFrameOut); - -#if !defined(DACCESS_COMPILE) - -#define FORMAT_MESSAGE_BUFFER_LENGTH 1024 - -BOOL ComPlusFrameSEH(EXCEPTION_REGISTRATION_RECORD*); -PEXCEPTION_REGISTRATION_RECORD GetPrevSEHRecord(EXCEPTION_REGISTRATION_RECORD*); - -extern "C" { -// in asmhelpers.asm: -VOID STDCALL ResumeAtJitEHHelper(EHContext *pContext); -int STDCALL CallJitEHFilterHelper(size_t *pShadowSP, EHContext *pContext); -VOID STDCALL CallJitEHFinallyHelper(size_t *pShadowSP, EHContext *pContext); - -typedef void (*RtlUnwindCallbackType)(void); - -BOOL CallRtlUnwind(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - RtlUnwindCallbackType callback, - EXCEPTION_RECORD *pExceptionRecord, - void *retval); - -BOOL CallRtlUnwindSafe(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - RtlUnwindCallbackType callback, - EXCEPTION_RECORD *pExceptionRecord, - void *retval); -} - -static inline BOOL -CPFH_ShouldUnwindStack(const EXCEPTION_RECORD * pCER) { - - LIMITED_METHOD_CONTRACT; - - _ASSERTE(pCER != NULL); - - // We can only unwind those exceptions whose context/record we don't need for a - // rethrow. This is complus, and stack overflow. For all the others, we - // need to keep the context around for a rethrow, which means they can't - // be unwound. - if (IsComPlusException(pCER) || pCER->ExceptionCode == STATUS_STACK_OVERFLOW) - return TRUE; - else - return FALSE; -} - -static inline BOOL IsComPlusNestedExceptionRecord(EXCEPTION_REGISTRATION_RECORD* pEHR) -{ - LIMITED_METHOD_CONTRACT; - if (pEHR->Handler == (PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler) - return TRUE; - return FALSE; -} - -EXCEPTION_REGISTRATION_RECORD *TryFindNestedEstablisherFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) -{ - LIMITED_METHOD_CONTRACT; - while (pEstablisherFrame->Handler != (PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler) { - pEstablisherFrame = pEstablisherFrame->Next; - if (pEstablisherFrame == EXCEPTION_CHAIN_END) return 0; - } - return pEstablisherFrame; -} - -#ifdef _DEBUG -// stores last handler we went to in case we didn't get an endcatch and stack is -// corrupted we can figure out who did it. -static MethodDesc *gLastResumedExceptionFunc = NULL; -static DWORD gLastResumedExceptionHandler = 0; -#endif - -//--------------------------------------------------------------------- -// void RtlUnwindCallback() -// call back function after global unwind, rtlunwind calls this function -//--------------------------------------------------------------------- -static void RtlUnwindCallback() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"Should never get here"); -} - -BOOL FastNExportSEH(EXCEPTION_REGISTRATION_RECORD* pEHR) -{ - LIMITED_METHOD_CONTRACT; - - if ((LPVOID)pEHR->Handler == (LPVOID)FastNExportExceptHandler) - return TRUE; - return FALSE; -} - -BOOL ReverseCOMSEH(EXCEPTION_REGISTRATION_RECORD* pEHR) -{ - LIMITED_METHOD_CONTRACT; - -#ifdef FEATURE_COMINTEROP - if ((LPVOID)pEHR->Handler == (LPVOID)COMPlusFrameHandlerRevCom) - return TRUE; -#endif // FEATURE_COMINTEROP - return FALSE; -} - - -// -// Returns true if the given SEH handler is one of our SEH handlers that is responsible for managing exceptions in -// regions of managed code. -// -BOOL IsUnmanagedToManagedSEHHandler(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) -{ - WRAPPER_NO_CONTRACT; - - // - // ComPlusFrameSEH() is for COMPlusFrameHandler & COMPlusNestedExceptionHandler. - // FastNExportSEH() is for FastNExportExceptHandler. - // - return (ComPlusFrameSEH(pEstablisherFrame) || FastNExportSEH(pEstablisherFrame) || ReverseCOMSEH(pEstablisherFrame)); -} - -Frame *GetCurrFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) -{ - Frame *pFrame; - WRAPPER_NO_CONTRACT; - _ASSERTE(IsUnmanagedToManagedSEHHandler(pEstablisherFrame)); - pFrame = ((FrameHandlerExRecord *)pEstablisherFrame)->GetCurrFrame(); - - // Assert that the exception frame is on the thread or that the exception frame is the top frame. - _ASSERTE(GetThreadNULLOk() == NULL || GetThread()->GetFrame() == (Frame*)-1 || GetThread()->GetFrame() <= pFrame); - - return pFrame; -} - -EXCEPTION_REGISTRATION_RECORD* GetNextCOMPlusSEHRecord(EXCEPTION_REGISTRATION_RECORD* pRec) { - WRAPPER_NO_CONTRACT; - if (pRec == EXCEPTION_CHAIN_END) - return EXCEPTION_CHAIN_END; - - do { - _ASSERTE(pRec != 0); - pRec = pRec->Next; - } while (pRec != EXCEPTION_CHAIN_END && !IsUnmanagedToManagedSEHHandler(pRec)); - - _ASSERTE(pRec == EXCEPTION_CHAIN_END || IsUnmanagedToManagedSEHHandler(pRec)); - return pRec; -} - - -/* - * GetClrSEHRecordServicingStackPointer - * - * This function searchs all the Frame SEH records, and finds the one that is - * currently signed up to do all exception handling for the given stack pointer - * on the given thread. - * - * Parameters: - * pThread - The thread to search on. - * pStackPointer - The stack location that we are finding the Frame SEH Record for. - * - * Returns - * A pointer to the SEH record, or EXCEPTION_CHAIN_END if none was found. - * - */ - -PEXCEPTION_REGISTRATION_RECORD -GetClrSEHRecordServicingStackPointer(Thread *pThread, - void *pStackPointer) -{ - ThreadExceptionState* pExState = pThread->GetExceptionState(); - - // - // We can only do this if there is a context in the pExInfo. There are cases (most notably the - // EEPolicy::HandleFatalError case) where we don't have that. In these cases we will return - // no enclosing handler since we cannot accurately determine the FS:0 entry which services - // this stack address. - // - // The side effect of this is that for these cases, the debugger cannot intercept - // the exception - // - CONTEXT* pContextRecord = pExState->GetContextRecord(); - if (pContextRecord == NULL) - { - return EXCEPTION_CHAIN_END; - } - - void *exceptionSP = dac_cast(GetSP(pContextRecord)); - - - // - // Now set the establishing frame. What this means in English is that we need to find - // the fs:0 entry that handles exceptions for the place on the stack given in stackPointer. - // - PEXCEPTION_REGISTRATION_RECORD pSEHRecord = GetFirstCOMPlusSEHRecord(pThread); - - while (pSEHRecord != EXCEPTION_CHAIN_END) - { - - // - // Skip any SEHRecord which is not a CLR record or was pushed after the exception - // on this thread occurred. - // - if (IsUnmanagedToManagedSEHHandler(pSEHRecord) && (exceptionSP <= (void *)pSEHRecord)) - { - Frame *pFrame = GetCurrFrame(pSEHRecord); - // - // Arcane knowledge here. All Frame records are stored on the stack by the runtime - // in ever decreasing address space. So, we merely have to search back until - // we find the first frame record with a higher stack value to find the - // establishing frame for the given stack address. - // - if (((void *)pFrame) >= pStackPointer) - { - break; - } - - } - - pSEHRecord = GetNextCOMPlusSEHRecord(pSEHRecord); - } - - return pSEHRecord; -} - -#ifdef _DEBUG -// We've deteremined during a stack walk that managed code is transitioning to unamanaged (EE) code. Check that the -// state of the EH chain is correct. -// -// For x86, check that we do INSTALL_COMPLUS_EXCEPTION_HANDLER before calling managed code. This check should be -// done for all managed code sites, not just transitions. But this will catch most problem cases. -void VerifyValidTransitionFromManagedCode(Thread *pThread, CrawlFrame *pCF) -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(ExecutionManager::IsManagedCode(GetControlPC(pCF->GetRegisterSet()))); - - // Cannot get to the TEB of other threads. So ignore them. - if (pThread != GetThreadNULLOk()) - { - return; - } - - // Find the EH record guarding the current region of managed code, based on the CrawlFrame passed in. - PEXCEPTION_REGISTRATION_RECORD pEHR = GetCurrentSEHRecord(); - - while ((pEHR != EXCEPTION_CHAIN_END) && ((ULONG_PTR)pEHR < GetRegdisplaySP(pCF->GetRegisterSet()))) - { - pEHR = pEHR->Next; - } - - // VerifyValidTransitionFromManagedCode can be called before the CrawlFrame's MethodDesc is initialized. - // Fix that if necessary for the consistency check. - MethodDesc * pFunction = pCF->GetFunction(); - if ((!IsUnmanagedToManagedSEHHandler(pEHR)) && // Will the assert fire? If not, don't waste our time. - (pFunction == NULL)) - { - _ASSERTE(pCF->GetRegisterSet()); - PCODE ip = GetControlPC(pCF->GetRegisterSet()); - pFunction = ExecutionManager::GetCodeMethodDesc(ip); - _ASSERTE(pFunction); - } - - // Great, we've got the EH record that's next up the stack from the current SP (which is in managed code). That - // had better be a record for one of our handlers responsible for handling exceptions in managed code. If its - // not, then someone made it into managed code without setting up one of our EH handlers, and that's really - // bad. - CONSISTENCY_CHECK_MSGF(IsUnmanagedToManagedSEHHandler(pEHR), - ("Invalid transition into managed code!\n\n" - "We're walking this thread's stack and we've reached a managed frame at Esp=0x%p. " - "(The method is %s::%s) " - "The very next FS:0 record (0x%p) up from this point on the stack should be one of " - "our 'unmanaged to managed SEH handlers', but its not... its something else, and " - "that's very bad. It indicates that someone managed to call into managed code without " - "setting up the proper exception handling.\n\n" - "Get a good unmanaged stack trace for this thread. All FS:0 records are on the stack, " - "so you can see who installed the last handler. Somewhere between that function and " - "where the thread is now is where the bad transition occurred.\n\n" - "A little extra info: FS:0 = 0x%p, pEHR->Handler = 0x%p\n", - GetRegdisplaySP(pCF->GetRegisterSet()), - pFunction ->m_pszDebugClassName, - pFunction ->m_pszDebugMethodName, - pEHR, - GetCurrentSEHRecord(), - pEHR->Handler)); -} - -#endif - -//================================================================================ - -// There are some things that should never be true when handling an -// exception. This function checks for them. Will assert or trap -// if it finds an error. -static inline void -CPFH_VerifyThreadIsInValidState(Thread* pThread, DWORD exceptionCode, EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) { - WRAPPER_NO_CONTRACT; - - if ( exceptionCode == STATUS_BREAKPOINT - || exceptionCode == STATUS_SINGLE_STEP) { - return; - } - -#ifdef _DEBUG - // check for overwriting of stack - CheckStackBarrier(pEstablisherFrame); - // trigger check for bad fs:0 chain - GetCurrentSEHRecord(); -#endif - - if (!g_fEEShutDown) { - // An exception on the GC thread, or while holding the thread store lock, will likely lock out the entire process. - if (::IsGCThread() || ThreadStore::HoldingThreadStore()) - { - _ASSERTE(!"Exception during garbage collection or while holding thread store"); - EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); - } - } -} - - -uint32_t g_exceptionCount; - -//****************************************************************************** -EXCEPTION_DISPOSITION COMPlusAfterUnwind( - EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - ThrowCallbackType& tct) -{ - WRAPPER_NO_CONTRACT; - - // Note: we've completed the unwind pass up to the establisher frame, and we're headed off to finish our - // cleanup and end up back in jitted code. Any more FS0 handlers pushed from this point on out will _not_ be - // unwound. We go ahead and assert right here that indeed there are no handlers below the establisher frame - // before we go any further. - _ASSERTE(pEstablisherFrame == GetCurrentSEHRecord()); - - Thread* pThread = GetThread(); - - _ASSERTE(tct.pCurrentExceptionRecord == pEstablisherFrame); - - NestedHandlerExRecord nestedHandlerExRecord; - nestedHandlerExRecord.Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, GetCurrFrame(pEstablisherFrame)); - - // ... and now, put the nested record back on. - INSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg)); - - // We entered COMPlusAfterUnwind in PREEMP, but we need to be in COOP from here on out - GCX_COOP_NO_DTOR(); - - tct.bIsUnwind = TRUE; - tct.pProfilerNotify = NULL; - - LOG((LF_EH, LL_INFO100, "COMPlusFrameHandler: unwinding\n")); - - tct.bUnwindStack = CPFH_ShouldUnwindStack(pExceptionRecord); - - LOG((LF_EH, LL_INFO1000, "COMPlusAfterUnwind: going to: pFunc:%#X, pStack:%#X\n", - tct.pFunc, tct.pStack)); - - UnwindFrames(pThread, &tct); - -#ifdef DEBUGGING_SUPPORTED - ExInfo* pExInfo = pThread->GetExceptionState()->GetCurrentExceptionTracker(); - if (pExInfo->m_ValidInterceptionContext) - { - // By now we should have all unknown FS:[0] handlers unwinded along with the managed Frames until - // the interception point. We can now pop nested exception handlers and resume at interception context. - EHContext context = pExInfo->m_InterceptionContext; - pExInfo->m_InterceptionContext.Init(); - pExInfo->m_ValidInterceptionContext = FALSE; - - UnwindExceptionTrackerAndResumeInInterceptionFrame(pExInfo, &context); - } -#endif // DEBUGGING_SUPPORTED - - _ASSERTE(!"Should not get here"); - return ExceptionContinueSearch; -} // EXCEPTION_DISPOSITION COMPlusAfterUnwind() - -#ifdef DEBUGGING_SUPPORTED - -//--------------------------------------------------------------------------------------- -// -// This function is called to intercept an exception and start an unwind. -// -// Arguments: -// pCurrentEstablisherFrame - the exception registration record covering the stack range -// containing the interception point -// pExceptionRecord - EXCEPTION_RECORD of the exception being intercepted -// -// Return Value: -// ExceptionContinueSearch if the exception cannot be intercepted -// -// Notes: -// If the exception is intercepted, this function never returns. -// - -EXCEPTION_DISPOSITION ClrDebuggerDoUnwindAndIntercept(EXCEPTION_REGISTRATION_RECORD *pCurrentEstablisherFrame, - EXCEPTION_RECORD *pExceptionRecord) -{ - WRAPPER_NO_CONTRACT; - - if (!CheckThreadExceptionStateForInterception()) - { - return ExceptionContinueSearch; - } - - Thread* pThread = GetThread(); - ThreadExceptionState* pExState = pThread->GetExceptionState(); - - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame; - ThrowCallbackType tct; - tct.Init(); - - pExState->GetDebuggerState()->GetDebuggerInterceptInfo(&pEstablisherFrame, - &(tct.pFunc), - &(tct.dHandler), - &(tct.pStack), - NULL, - &(tct.pBottomFrame) - ); - - // - // If the handler that we've selected as the handler for the target frame of the unwind is in fact above the - // handler that we're currently executing in, then use the current handler instead. Why? Our handlers for - // nested exceptions actually process managed frames that live above them, up to the COMPlusFrameHanlder that - // pushed the nested handler. If the user selectes a frame above the nested handler, then we will have selected - // the COMPlusFrameHandler above the current nested handler. But we don't want to ask RtlUnwind to unwind past - // the nested handler that we're currently executing in. - // - if (pEstablisherFrame > pCurrentEstablisherFrame) - { - // This should only happen if we're in a COMPlusNestedExceptionHandler. - _ASSERTE(IsComPlusNestedExceptionRecord(pCurrentEstablisherFrame)); - - pEstablisherFrame = pCurrentEstablisherFrame; - } - -#ifdef _DEBUG - tct.pCurrentExceptionRecord = pEstablisherFrame; -#endif - - LOG((LF_EH|LF_CORDB, LL_INFO100, "ClrDebuggerDoUnwindAndIntercept: Intercepting at %s\n", tct.pFunc->m_pszDebugMethodName)); - LOG((LF_EH|LF_CORDB, LL_INFO100, "\t\t: pFunc is 0x%X\n", tct.pFunc)); - LOG((LF_EH|LF_CORDB, LL_INFO100, "\t\t: pStack is 0x%X\n", tct.pStack)); - - CallRtlUnwindSafe(pEstablisherFrame, RtlUnwindCallback, pExceptionRecord, 0); - - ExInfo* pExInfo = pThread->GetExceptionState()->GetCurrentExceptionTracker(); - if (pExInfo->m_ValidInterceptionContext) - { - // By now we should have all unknown FS:[0] handlers unwinded along with the managed Frames until - // the interception point. We can now pop nested exception handlers and resume at interception context. - GCX_COOP(); - EHContext context = pExInfo->m_InterceptionContext; - pExInfo->m_InterceptionContext.Init(); - pExInfo->m_ValidInterceptionContext = FALSE; - - UnwindExceptionTrackerAndResumeInInterceptionFrame(pExInfo, &context); - } - - // on x86 at least, RtlUnwind always returns - - // Note: we've completed the unwind pass up to the establisher frame, and we're headed off to finish our - // cleanup and end up back in jitted code. Any more FS0 handlers pushed from this point on out will _not_ be - // unwound. - return COMPlusAfterUnwind(pExState->GetExceptionRecord(), pEstablisherFrame, tct); -} // EXCEPTION_DISPOSITION ClrDebuggerDoUnwindAndIntercept() - -#endif // DEBUGGING_SUPPORTED - -// This is a wrapper around the assembly routine that invokes RtlUnwind in the OS. -// When we invoke RtlUnwind, the OS will modify the ExceptionFlags field in the -// exception record to reflect unwind. Since we call RtlUnwind in the first pass -// with a valid exception record when we find an exception handler AND because RtlUnwind -// returns on x86, the OS would have flagged the exception record for unwind. -// -// Incase the exception is rethrown from the catch/filter-handler AND it's a non-COMPLUS -// exception, the runtime will use the reference to the saved exception record to reraise -// the exception, as part of rethrow fixup. Since the OS would have modified the exception record -// to reflect unwind, this wrapper will "reset" the ExceptionFlags field when RtlUnwind returns. -// Otherwise, the rethrow will result in second pass, as opposed to first, since the ExceptionFlags -// would indicate an unwind. -// -// This rethrow issue does not affect COMPLUS exceptions since we always create a brand new exception -// record for them in RaiseTheExceptionInternalOnly. -BOOL CallRtlUnwindSafe(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - RtlUnwindCallbackType callback, - EXCEPTION_RECORD *pExceptionRecord, - void *retval) -{ - LIMITED_METHOD_CONTRACT; - - // Save the ExceptionFlags value before invoking RtlUnwind. - DWORD dwExceptionFlags = pExceptionRecord->ExceptionFlags; - - BOOL fRetVal = CallRtlUnwind(pEstablisherFrame, callback, pExceptionRecord, retval); - - // Reset ExceptionFlags field, if applicable - if (pExceptionRecord->ExceptionFlags != dwExceptionFlags) - { - // We would expect the 32bit OS to have set the unwind flag at this point. - _ASSERTE(pExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING); - LOG((LF_EH, LL_INFO100, "CallRtlUnwindSafe: Resetting ExceptionFlags from %lu to %lu\n", pExceptionRecord->ExceptionFlags, dwExceptionFlags)); - pExceptionRecord->ExceptionFlags = dwExceptionFlags; - } - - return fRetVal; -} - -//****************************************************************************** -// The essence of the first pass handler (after we've decided to actually do -// the first pass handling). -//****************************************************************************** -inline EXCEPTION_DISPOSITION __cdecl -CPFH_RealFirstPassHandler( // ExceptionContinueSearch, etc. - EXCEPTION_RECORD *pExceptionRecord, // The exception record, with exception type. - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, // Exception frame on whose behalf this is called. - CONTEXT *pContext, // Context from the exception. - void *pDispatcherContext, // @todo - BOOL bAsynchronousThreadStop, // @todo - BOOL fPGCDisabledOnEntry) // @todo -{ - // We don't want to use a runtime contract here since this codepath is used during - // the processing of a hard SO. Contracts use a significant amount of stack - // which we can't afford for those cases. - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - -#ifdef _DEBUG - static int breakOnFirstPass = -1; - - if (breakOnFirstPass == -1) - breakOnFirstPass = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnFirstPass); - - if (breakOnFirstPass != 0) - { - _ASSERTE(!"First pass exception handler"); - } -#endif - - EXCEPTION_DISPOSITION retval; - DWORD exceptionCode = pExceptionRecord->ExceptionCode; - Thread *pThread = GetThread(); - - // We always want to be in co-operative mode when we run this function and whenever we return - // from it, want to go to pre-emptive mode because are returning to OS. - _ASSERTE(pThread->PreemptiveGCDisabled()); - - BOOL bPopNestedHandlerExRecord = FALSE; - LFH found = LFH_NOT_FOUND; // Result of calling LookForHandler. - BOOL bRethrownException = FALSE; - BOOL bNestedException = FALSE; - -#if defined(USE_FEF) - BOOL bPopFaultingExceptionFrame = FALSE; - FaultingExceptionFrame faultingExceptionFrame; -#endif // USE_FEF - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - - ThrowCallbackType tct; - tct.Init(); - - tct.pTopFrame = GetCurrFrame(pEstablisherFrame); // highest frame to search to - -#ifdef _DEBUG - tct.pCurrentExceptionRecord = pEstablisherFrame; - tct.pPrevExceptionRecord = GetPrevSEHRecord(pEstablisherFrame); -#endif // _DEBUG - - BOOL fIsManagedCode = pContext ? ExecutionManager::IsManagedCode(GetIP(pContext)) : FALSE; - - - // this establishes a marker so can determine if are processing a nested exception - // don't want to use the current frame to limit search as it could have been unwound by - // the time get to nested handler (ie if find an exception, unwind to the call point and - // then resume in the catch and then get another exception) so make the nested handler - // have the same boundary as this one. If nested handler can't find a handler, we won't - // end up searching this frame list twice because the nested handler will set the search - // boundary in the thread and so if get back to this handler it will have a range that starts - // and ends at the same place. - - NestedHandlerExRecord nestedHandlerExRecord; - nestedHandlerExRecord.Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, GetCurrFrame(pEstablisherFrame)); - - INSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg)); - bPopNestedHandlerExRecord = TRUE; - -#if defined(USE_FEF) - // Note: don't attempt to push a FEF for an exception in managed code if we weren't in cooperative mode when - // the exception was received. If preemptive GC was enabled when we received the exception, then it means the - // exception was rethrown from unmangaed code (including EE impl), and we shouldn't push a FEF. - if (fIsManagedCode && - fPGCDisabledOnEntry && - (pThread->m_pFrame == FRAME_TOP || - pThread->m_pFrame->GetFrameIdentifier() != FrameIdentifier::FaultingExceptionFrame || - (size_t)pThread->m_pFrame > (size_t)pEstablisherFrame)) - { - // setup interrupted frame so that GC during calls to init won't collect the frames - // only need it for non CLR exceptions in managed code when haven't already - // got one on the stack (will have one already if we have called rtlunwind because - // the instantiation that called unwind would have installed one) - faultingExceptionFrame.InitAndLink(pContext); - bPopFaultingExceptionFrame = TRUE; - } -#endif // USE_FEF - - OBJECTREF e; - e = pThread->LastThrownObject(); - - STRESS_LOG7(LF_EH, LL_INFO10, "CPFH_RealFirstPassHandler: code:%X, LastThrownObject:%p, MT:%pT" - ", IP:%p, SP:%p, pContext:%p, pEstablisherFrame:%p\n", - exceptionCode, OBJECTREFToObject(e), (e!=0)?e->GetMethodTable():0, - pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0, - pContext, pEstablisherFrame); - -#ifdef LOGGING - // If it is a complus exception, and there is a thrown object, get its name, for better logging. - if (IsComPlusException(pExceptionRecord)) - { - const char * eClsName = "!EXCEPTION_COMPLUS"; - if (e != 0) - { - eClsName = e->GetMethodTable()->GetDebugClassName(); - } - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: exception: 0x%08X, class: '%s', IP: 0x%p\n", - exceptionCode, eClsName, pContext ? GetIP(pContext) : NULL)); - } -#endif - - EXCEPTION_POINTERS exceptionPointers = {pExceptionRecord, pContext}; - - STRESS_LOG4(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: setting boundaries: Exinfo: 0x%p, BottomMostHandler:0x%p, SearchBoundary:0x%p, TopFrame:0x%p\n", - pExInfo, pExInfo->m_pBottomMostHandler, pExInfo->m_pSearchBoundary, tct.pTopFrame); - - // Here we are trying to decide if we are coming in as: - // 1) first handler in a brand new exception - // 2) a subsequent handler in an exception - // 3) a nested exception - // m_pBottomMostHandler is the registration structure (establisher frame) for the most recent (ie lowest in - // memory) non-nested handler that was installed and pEstablisher frame is what the current handler - // was registered with. - // The OS calls each registered handler in the chain, passing its establisher frame to it. - if (pExInfo->m_pBottomMostHandler != NULL && pEstablisherFrame > pExInfo->m_pBottomMostHandler) - { - STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: detected subsequent handler. ExInfo:0x%p, BottomMost:0x%p SearchBoundary:0x%p\n", - pExInfo, pExInfo->m_pBottomMostHandler, pExInfo->m_pSearchBoundary); - - // If the establisher frame of this handler is greater than the bottommost then it must have been - // installed earlier and therefore we are case 2 - if (pThread->GetThrowable() == NULL) - { - // Bottommost didn't setup a throwable, so not exception not for us - retval = ExceptionContinueSearch; - goto exit; - } - - // setup search start point - tct.pBottomFrame = pExInfo->m_pSearchBoundary; - - if (tct.pTopFrame == tct.pBottomFrame) - { - // this will happen if our nested handler already searched for us so we don't want - // to search again - retval = ExceptionContinueSearch; - goto exit; - } - } - else - { // we are either case 1 or case 3 -#if defined(_DEBUG_IMPL) - //@todo: merge frames, context, handlers - if (pThread->GetFrame() != FRAME_TOP) - pThread->GetFrame()->LogFrameChain(LF_EH, LL_INFO1000); -#endif // _DEBUG_IMPL - - // If the exception was rethrown, we'll create a new ExInfo, which will represent the rethrown exception. - // The original exception is not the rethrown one. - if (pExInfo->m_ExceptionFlags.IsRethrown() && pThread->LastThrownObject() != NULL) - { - pExInfo->m_ExceptionFlags.ResetIsRethrown(); - bRethrownException = TRUE; - -#if defined(USE_FEF) - if (bPopFaultingExceptionFrame) - { - // if we added a FEF, it will refer to the frame at the point of the original exception which is - // already unwound so don't want it. - // If we rethrew the exception we have already added a helper frame for the rethrow, so don't - // need this one. If we didn't rethrow it, (ie rethrow from native) then there the topmost frame will - // be a transition to native frame in which case we don't need it either - faultingExceptionFrame.Pop(); - bPopFaultingExceptionFrame = FALSE; - } -#endif - } - - // If the establisher frame is less than the bottommost handler, then this is nested because the - // establisher frame was installed after the bottommost. - if (pEstablisherFrame < pExInfo->m_pBottomMostHandler - /* || IsComPlusNestedExceptionRecord(pEstablisherFrame) */ ) - { - bNestedException = TRUE; - - // case 3: this is a nested exception. Need to save and restore the thread info - STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: ExInfo:0x%p detected nested exception 0x%p < 0x%p\n", - pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler); - - EXCEPTION_REGISTRATION_RECORD* pNestedER = TryFindNestedEstablisherFrame(pEstablisherFrame); - ExInfo *pNestedExInfo; - - if (!pNestedER || pNestedER >= pExInfo->m_pBottomMostHandler ) - { - // RARE CASE. We've re-entered the EE from an unmanaged filter. - // - // OR - // - // We can be here if we dont find a nested exception handler. This is exemplified using - // call chain of scenario 2 explained further below. - // - // Assuming __try of NativeB throws an exception E1 and it gets caught in ManagedA2, then - // bottom-most handler (BMH) is going to be CPFH_A. The catch will trigger an unwind - // and invoke __finally in NativeB. Let the __finally throw a new exception E2. - // - // Assuming ManagedB2 has a catch block to catch E2, when we enter CPFH_B looking for a - // handler for E2, our establisher frame will be that of CPFH_B, which will be lower - // in stack than current BMH (which is CPFH_A). Thus, we will come here, determining - // E2 to be nested exception correctly but not find a nested exception handler. - void *limit = (void *) GetPrevSEHRecord(pExInfo->m_pBottomMostHandler); - - pNestedExInfo = new (nothrow) ExInfo(); // Very rare failure here; need robust allocator. - if (pNestedExInfo == NULL) - { // if we can't allocate memory, we can't correctly continue. - EEPOLICY_HANDLE_FATAL_ERROR(COR_E_OUTOFMEMORY); - } - - - pNestedExInfo->m_StackAddress = limit; // Note: this is also the flag that tells us this - // ExInfo was stack allocated. - } - else - { - pNestedExInfo = &((NestedHandlerExRecord*)pNestedER)->m_handlerInfo; - } - - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: PushExInfo() current: 0x%p previous: 0x%p\n", - pExInfo->m_StackAddress, pNestedExInfo->m_StackAddress)); - - _ASSERTE(pNestedExInfo); - pNestedExInfo->m_hThrowable = NULL; // pNestedExInfo may be stack allocated, and as such full of - // garbage. m_hThrowable must be sane, so set it to NULL. (We could - // zero the entire record, but this is cheaper.) - - pNestedExInfo->CopyAndClearSource(pExInfo); - - pExInfo->m_pPrevNestedInfo = pNestedExInfo; // Save at head of nested info chain - -#if 0 -/* the following code was introduced in Whidbey as part of the Faulting Exception Frame removal (12/03). - However it isn't correct. If any nested exceptions occur while processing a rethrow, we would - incorrectly consider the nested exception to be a rethrow. See VSWhidbey 349379 for an example. - - Therefore I am disabling this code until we see a failure that explains why it was added in the first - place. cwb 9/04. -*/ - // If we're here as a result of a rethrown exception, set the rethrown flag on the new ExInfo. - if (bRethrownException) - { - pExInfo->m_ExceptionFlags.SetIsRethrown(); - } -#endif - } - else - { - // At this point, either: - // - // 1) the bottom-most handler is NULL, implying this is a new exception for which we are getting ready, OR - // 2) the bottom-most handler is not-NULL, implying that a there is already an existing exception in progress. - // - // Scenario 1 is that of a new throw and is easy to understand. Scenario 2 is the interesting one. - // - // ManagedA1 -> ManagedA2 -> ManagedA3 -> NativeCodeA -> ManagedB1 -> ManagedB2 -> ManagedB3 -> NativeCodeB - // - // On x86, each block of managed code is protected by one COMPlusFrameHandler [CPFH] (CLR's exception handler - // for managed code), unlike 64bit where each frame has a personality routine attached to it. Thus, - // for the example above, assume CPFH_A protects ManagedA* blocks and is setup just before the call to - // ManagedA1. Likewise, CPFH_B protects ManagedB* blocks and is setup just before the call to ManagedB1. - // - // When ManagedB3 throws an exception, CPFH_B is invoked to look for a handler in all of the ManagedB* blocks. - // At this point, it is setup as the "bottom-most-handler" (BMH). If no handler is found and exception reaches - // ManagedA* blocks, CPFH_A is invoked to look for a handler and thus, becomes BMH. - // - // Thus, in the first pass on x86 for a given exception, a particular CPFH will be invoked only once when looking - // for a handler and thus, registered as BMH only once. Either the exception goes unhandled and the process will - // terminate or a handler will be found and second pass will commence. - // - // However, assume NativeCodeB had a __try/__finally and raised an exception [E1] within the __try. Let's assume - // it gets caught in ManagedB1 and thus, unwind is triggered. At this point, the active exception tracker - // has context about the exception thrown out of __try and CPFH_B is registered as BMH. - // - // If the __finally throws a new exception [E2], CPFH_B will be invoked again for first pass while looking for - // a handler for the thrown exception. Since BMH is already non-NULL, we will come here since EstablisherFrame will be - // the same as BMH (because EstablisherFrame will be that of CPFH_B). We will proceed to overwrite the "required" parts - // of the existing exception tracker with the details of E2 (see setting of exception record and context below), erasing - // any artifact of E1. - // - // This is unlike Scenario 1 when exception tracker is completely initialized to default values. This is also - // unlike 64bit which will detect that E1 and E2 are different exceptions and hence, will setup a new tracker - // to track E2, effectively behaving like Scenario 1 above. X86 cannot do this since there is no nested exception - // tracker setup that gets to see the new exception. - // - // Thus, if E1 was a CSE and E2 isn't, we will come here and treat E2 as a CSE as well since corruption severity - // is initialized as part of exception tracker initialization. Thus, E2 will start to be treated as CSE, which is - // incorrect. Similar argument applies to delivery of First chance exception notification delivery. - // - // Another example why we should unify EH systems :) - // - // To address this issue, we will need to reset exception tracker here, just like the overwriting of "required" - // parts of exception tracker. - - // If the current establisher frame is the same as the bottom-most-handler and we are here - // in the first pass, assert that current exception and the one tracked by active exception tracker - // are indeed different exceptions. In such a case, we must reset the exception tracker so that it can be - // setup correctly further down when CEHelper::SetupCorruptionSeverityForActiveException is invoked. - - if ((pExInfo->m_pBottomMostHandler != NULL) && - (pEstablisherFrame == pExInfo->m_pBottomMostHandler)) - { - // Current exception should be different from the one exception tracker is already tracking. - _ASSERTE(pExceptionRecord != pExInfo->m_pExceptionRecord); - - // This cannot be nested exceptions - they are handled earlier (see above). - _ASSERTE(!bNestedException); - - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: Bottom-most handler (0x%p) is the same as EstablisherFrame.\n", - pExInfo->m_pBottomMostHandler)); - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: Exception record in exception tracker is 0x%p, while that of new exception is 0x%p.\n", - pExInfo->m_pExceptionRecord, pExceptionRecord)); - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: Resetting exception tracker (0x%p).\n", pExInfo)); - - // This will reset the exception tracker state, including the corruption severity. - pExInfo->Init(); - } - } - - // If we are handling a fault from managed code, we need to set the Thread->ExInfo->pContext to - // the current fault context, which is used in the stack walk to get back into the managed - // stack with the correct registers. (Previously, this was done by linking in a FaultingExceptionFrame - // record.) - // We are about to create the managed exception object, which may trigger a GC, so set this up now. - - pExInfo->m_pExceptionRecord = pExceptionRecord; - pExInfo->m_pContext = pContext; - if (pContext && ShouldHandleManagedFault(pExceptionRecord, pContext, pEstablisherFrame, pThread)) - { // If this was a fault in managed code, rather than create a Frame for stackwalking, - // we can use this exinfo (after all, it has all the register info.) - pExInfo->m_ExceptionFlags.SetUseExInfoForStackwalk(); - } - - // It should now be safe for a GC to happen. - - // case 1 & 3: this is the first time through of a new, nested, or rethrown exception, so see if we can - // find a handler. Only setup throwable if are bottommost handler - if (IsComPlusException(pExceptionRecord) && (!bAsynchronousThreadStop)) - { - - // Update the throwable from the last thrown object. Note: this may cause OOM, in which case we replace - // both throwables with the preallocated OOM exception. - pThread->SafeSetThrowables(pThread->LastThrownObject()); - - // now we've got a CLR exception, fall through to so see if we handle it - - STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: fall through ExInfo:0x%p setting m_pBottomMostHandler to 0x%p from 0x%p\n", - pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler); - pExInfo->m_pBottomMostHandler = pEstablisherFrame; - } - else if (bRethrownException) - { - // If it was rethrown and not CLR, will still be the last one thrown. Either we threw it last and - // stashed it here or someone else caught it and rethrew it, in which case it will still have been - // originally stashed here. - - // Update the throwable from the last thrown object. Note: this may cause OOM, in which case we replace - // both throwables with the preallocated OOM exception. - pThread->SafeSetThrowables(pThread->LastThrownObject()); - STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: rethrow non-CLR ExInfo:0x%p setting m_pBottomMostHandler to 0x%p from 0x%p\n", - pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler); - pExInfo->m_pBottomMostHandler = pEstablisherFrame; - } - else - { - if (!fIsManagedCode) - { - tct.bDontCatch = false; - } - - if (exceptionCode == STATUS_BREAKPOINT) - { - // don't catch int 3 - retval = ExceptionContinueSearch; - goto exit; - } - - // We need to set m_pBottomMostHandler here, Thread::IsExceptionInProgress returns 1. - // This is a necessary part of suppressing thread abort exceptions in the constructor - // of any exception object we might create. - STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: setting ExInfo:0x%p m_pBottomMostHandler for IsExceptionInProgress to 0x%p from 0x%p\n", - pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler); - pExInfo->m_pBottomMostHandler = pEstablisherFrame; - - // Create the managed exception object. - OBJECTREF throwable = CreateCOMPlusExceptionObject(pThread, pExceptionRecord, bAsynchronousThreadStop); - - // Set the throwables on the thread to the newly created object. If this fails, it will return a - // preallocated exception object instead. This also updates the last thrown exception, for rethrows. - throwable = pThread->SafeSetThrowables(throwable); - - // Set the exception code and pointers. We set these after setting the throwables on the thread, - // because if the proper exception is replaced by an OOM exception, we still want the exception code - // and pointers set in the OOM exception. - EXCEPTIONREF exceptionRef = (EXCEPTIONREF)throwable; - exceptionRef->SetXCode(pExceptionRecord->ExceptionCode); - exceptionRef->SetXPtrs(&exceptionPointers); - } - - tct.pBottomFrame = NULL; - - EEToProfilerExceptionInterfaceWrapper::ExceptionThrown(pThread); - - InterlockedIncrement((LONG*)&g_exceptionCount); - - } // End of case-1-or-3 - - { - // Allocate storage for the stack trace. - OBJECTREF throwable = NULL; - GCPROTECT_BEGIN(throwable); - throwable = pThread->GetThrowable(); - - if (IsProcessCorruptedStateException(exceptionCode, throwable)) - { - // Failfast if exception indicates corrupted process state - EEPOLICY_HANDLE_FATAL_ERROR(exceptionCode); - } - - GCPROTECT_END(); - } - - // Set up information for GetExceptionPointers()/GetExceptionCode() callback. - pExInfo->SetExceptionCode(pExceptionRecord); - - pExInfo->m_pExceptionPointers = &exceptionPointers; - - if (bRethrownException || bNestedException) - { - _ASSERTE(pExInfo->m_pPrevNestedInfo != NULL); - SetStateForWatsonBucketing(bRethrownException, pExInfo->GetPreviousExceptionTracker()->GetThrowableAsHandle()); - } - -#ifdef DEBUGGING_SUPPORTED - // - // At this point the exception is still fresh to us, so assert that - // there should be nothing from the debugger on it. - // - _ASSERTE(!pExInfo->m_ExceptionFlags.DebuggerInterceptInfo()); -#endif - - if (pThread->IsRudeAbort()) - { - OBJECTREF throwable = pThread->GetThrowable(); - if (throwable == NULL || !IsExceptionOfType(kThreadAbortException, &throwable)) - { - // Neither of these sets will throw because the throwable that we're setting is a preallocated - // exception. This also updates the last thrown exception, for rethrows. - pThread->SafeSetThrowables(CLRException::GetBestThreadAbortException()); - } - - if (!pThread->IsRudeAbortInitiated()) - { - pThread->PreWorkForThreadAbort(); - } - } - - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: looking for handler bottom %x, top %x\n", - tct.pBottomFrame, tct.pTopFrame)); - tct.bIsNewException = pExInfo->m_pBottomMostHandler == pEstablisherFrame && !bRethrownException; - tct.bSkipLastElement = bRethrownException && bNestedException; - found = LookForHandler(&exceptionPointers, - pThread, - &tct); - - // We have searched this far. - pExInfo->m_pSearchBoundary = tct.pTopFrame; - LOG((LF_EH, LL_INFO1000, "CPFH_RealFirstPassHandler: set pSearchBoundary to 0x%p\n", pExInfo->m_pSearchBoundary)); - - if ((found == LFH_NOT_FOUND) -#ifdef DEBUGGING_SUPPORTED - && !pExInfo->m_ExceptionFlags.DebuggerInterceptInfo() -#endif - ) - { - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: NOT_FOUND\n")); - - if (tct.pTopFrame == FRAME_TOP) - { - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: NOT_FOUND at FRAME_TOP\n")); - } - - retval = ExceptionContinueSearch; - goto exit; - } - else - { - // so we are going to handle the exception - - // Remove the nested exception record -- before calling RtlUnwind. - // The second-pass callback for a NestedExceptionRecord assumes that if it's - // being unwound, it should pop one exception from the pExInfo chain. This is - // true for any older NestedRecords that might be unwound -- but not for the - // new one we're about to add. To avoid this, we remove the new record - // before calling Unwind. - // - // @NICE: This can probably be a little cleaner -- the nested record currently - // is also used to guard the running of the filter code. When we clean up the - // behaviour of exceptions within filters, we should be able to get rid of this - // PUSH/POP/PUSH behaviour. - _ASSERTE(bPopNestedHandlerExRecord); - - UNINSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg)); - - // Since we are going to handle the exception we switch into preemptive mode - GCX_PREEMP_NO_DTOR(); - -#ifdef DEBUGGING_SUPPORTED - // - // Check if the debugger wants to intercept this frame at a different point than where we are. - // - if (pExInfo->m_ExceptionFlags.DebuggerInterceptInfo()) - { - ClrDebuggerDoUnwindAndIntercept(pEstablisherFrame, pExceptionRecord); - - // - // If this returns, then the debugger couldn't do it's stuff and we default to the found handler. - // - if (found == LFH_NOT_FOUND) - { - retval = ExceptionContinueSearch; - // we need to be sure to switch back into Cooperative mode since we are going to - // jump to the exit: label and follow the normal return path (it is expected that - // CPFH_RealFirstPassHandler returns in COOP. - GCX_PREEMP_NO_DTOR_END(); - goto exit; - } - } -#endif - - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: handler found: %s\n", tct.pFunc->m_pszDebugMethodName)); - - CallRtlUnwindSafe(pEstablisherFrame, RtlUnwindCallback, pExceptionRecord, 0); - // on x86 at least, RtlUnwind always returns - - // The CallRtlUnwindSafe could have popped the explicit frame that the tct.pBottomFrame points to (UMThunkPrestubHandler - // does that). In such case, the tct.pBottomFrame needs to be updated to point to the first valid explicit frame. - Frame* frame = pThread->GetFrame(); - if ((tct.pBottomFrame != NULL) && (frame > tct.pBottomFrame)) - { - tct.pBottomFrame = frame; - } - // Note: we've completed the unwind pass up to the establisher frame, and we're headed off to finish our - // cleanup and end up back in jitted code. Any more FS0 handlers pushed from this point on out will _not_ be - // unwound. - // Note: we are still in Preemptive mode here and that is correct, COMPlusAfterUnwind will switch us back - // into Cooperative mode. - return COMPlusAfterUnwind(pExceptionRecord, pEstablisherFrame, tct); - } - -exit: - { - // We need to be in COOP if we get here - GCX_ASSERT_COOP(); - } - - // If we got as far as saving pExInfo, save the context pointer so it's available for the unwind. - if (pExInfo) - { - pExInfo->m_pContext = pContext; - // pExInfo->m_pExceptionPointers points to a local structure, which is now going out of scope. - pExInfo->m_pExceptionPointers = NULL; - } - -#if defined(USE_FEF) - if (bPopFaultingExceptionFrame) - { - faultingExceptionFrame.Pop(); - } -#endif // USE_FEF - - if (bPopNestedHandlerExRecord) - { - UNINSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg)); - } - return retval; -} // CPFH_RealFirstPassHandler() - - -//****************************************************************************** -// -void InitializeExceptionHandling() -{ - WRAPPER_NO_CONTRACT; - - CLRAddVectoredHandlers(); -} - -//****************************************************************************** -static inline EXCEPTION_DISPOSITION __cdecl -CPFH_FirstPassHandler(EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - CONTEXT *pContext, - DISPATCHER_CONTEXT *pDispatcherContext) -{ - WRAPPER_NO_CONTRACT; - EXCEPTION_DISPOSITION retval; - - _ASSERTE (!(pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))); - - DWORD exceptionCode = pExceptionRecord->ExceptionCode; - - Thread *pThread = GetThread(); - - STRESS_LOG4(LF_EH, LL_INFO100, - "CPFH_FirstPassHandler: pEstablisherFrame = %x EH code = %x EIP = %x with ESP = %x\n", - pEstablisherFrame, exceptionCode, pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0); - - EXCEPTION_POINTERS ptrs = { pExceptionRecord, pContext }; - - // Call to the vectored handler to give other parts of the Runtime a chance to jump in and take over an - // exception before we do too much with it. The most important point in the vectored handler is not to toggle - // the GC mode. - VEH_ACTION filter = CLRVectoredExceptionHandler(&ptrs); - - if (filter == VEH_CONTINUE_EXECUTION) - { - return ExceptionContinueExecution; - } - else if (filter == VEH_CONTINUE_SEARCH) - { - return ExceptionContinueSearch; - } - -#if defined(STRESS_HEAP) - // - // Check to see if this exception is due to GCStress. Since the GCStress mechanism only injects these faults - // into managed code, we only need to check for them in CPFH_FirstPassHandler. - // - if (IsGcMarker(pContext, pExceptionRecord)) - { - return ExceptionContinueExecution; - } -#endif // STRESS_HEAP - - // We always want to be in co-operative mode when we run this function and whenever we return - // from it, want to go to pre-emptive mode because are returning to OS. - BOOL disabled = pThread->PreemptiveGCDisabled(); - GCX_COOP_NO_DTOR(); - - BOOL bAsynchronousThreadStop = IsThreadHijackedForThreadStop(pThread, pExceptionRecord); - - if (bAsynchronousThreadStop) - { - // If we ever get here in preemptive mode, we're in trouble. We've - // changed the thread's IP to point at a little function that throws ... if - // the thread were to be in preemptive mode and a GC occurred, the stack - // crawl would have been all messed up (becuase we have no frame that points - // us back to the right place in managed code). - _ASSERTE(disabled); - - AdjustContextForThreadStop(pThread, pContext); - LOG((LF_EH, LL_INFO100, "CPFH_FirstPassHandler is Asynchronous Thread Stop or Abort\n")); - } - - pThread->ResetThrowControlForThread(); - - CPFH_VerifyThreadIsInValidState(pThread, exceptionCode, pEstablisherFrame); - - // If we were in cooperative mode when we came in here, then it's okay to see if we should do HandleManagedFault - // and push a FaultingExceptionFrame. If we weren't in coop mode coming in here, then it means that there's no - // way the exception could really be from managed code. It might look like it was from managed code, but in - // reality it's a rethrow from unmanaged code, either unmanaged user code, or unmanaged EE implementation. - if (disabled && ShouldHandleManagedFault(pExceptionRecord, pContext, pEstablisherFrame, pThread)) - { -#if defined(USE_FEF) - HandleManagedFault(pExceptionRecord, pContext); - retval = ExceptionContinueExecution; - goto exit; -#endif // USE_FEF - } - - // OK. We're finally ready to start the real work. Nobody else grabbed the exception in front of us. Now we can - // get started. - retval = CPFH_RealFirstPassHandler(pExceptionRecord, - pEstablisherFrame, - pContext, - pDispatcherContext, - bAsynchronousThreadStop, - disabled); - -#if defined(USE_FEF) // This label is only used in the HandleManagedFault() case above. -exit: -#endif - if (retval != ExceptionContinueExecution || !disabled) - { - GCX_PREEMP_NO_DTOR(); - } - - STRESS_LOG1(LF_EH, LL_INFO100, "CPFH_FirstPassHandler: exiting with retval %d\n", retval); - return retval; -} // CPFH_FirstPassHandler() - -//****************************************************************************** -inline void -CPFH_UnwindFrames1(Thread* pThread, EXCEPTION_REGISTRATION_RECORD* pEstablisherFrame, DWORD exceptionCode) -{ - WRAPPER_NO_CONTRACT; - - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - - // Ready to unwind the stack... - ThrowCallbackType tct; - tct.Init(); - tct.bIsUnwind = TRUE; - tct.pTopFrame = GetCurrFrame(pEstablisherFrame); // highest frame to search to - tct.pBottomFrame = NULL; - - #ifdef _DEBUG - tct.pCurrentExceptionRecord = pEstablisherFrame; - tct.pPrevExceptionRecord = GetPrevSEHRecord(pEstablisherFrame); - #endif - - #ifdef DEBUGGING_SUPPORTED - EXCEPTION_REGISTRATION_RECORD *pInterceptEstablisherFrame = NULL; - - // If the exception is intercepted, use information stored in the DebuggerExState to unwind the stack. - if (pExInfo->m_ExceptionFlags.DebuggerInterceptInfo()) - { - pExInfo->m_DebuggerExState.GetDebuggerInterceptInfo(&pInterceptEstablisherFrame, - NULL, // MethodDesc **ppFunc, - NULL, // int *pdHandler, - NULL, // BYTE **ppStack - NULL, // ULONG_PTR *pNativeOffset, - NULL // Frame **ppFrame) - ); - LOG((LF_EH, LL_INFO1000, "CPFH_UnwindFrames1: frames are Est 0x%X, Intercept 0x%X\n", - pEstablisherFrame, pInterceptEstablisherFrame)); - - // - // When we set up for the interception we store off the CPFH or CPNEH that we - // *know* will handle unwinding the destination of the intercept. - // - // However, a CPNEH with the same limiting Capital-F-rame could do the work - // and unwind us, so... - // - // If this is the exact frame handler we are supposed to search for, or - // if this frame handler services the same Capital-F-rame as the frame handler - // we are looking for (i.e. this frame handler may do the work that we would - // expect our frame handler to do), - // then - // we need to pass the interception destination during this unwind. - // - _ASSERTE(IsUnmanagedToManagedSEHHandler(pEstablisherFrame)); - - if ((pEstablisherFrame == pInterceptEstablisherFrame) || - (GetCurrFrame(pEstablisherFrame) == GetCurrFrame(pInterceptEstablisherFrame))) - { - pExInfo->m_DebuggerExState.GetDebuggerInterceptInfo(NULL, - &(tct.pFunc), - &(tct.dHandler), - &(tct.pStack), - NULL, - &(tct.pBottomFrame) - ); - - LOG((LF_EH, LL_INFO1000, "CPFH_UnwindFrames1: going to: pFunc:%#X, pStack:%#X\n", - tct.pFunc, tct.pStack)); - - } - - } - #endif - - UnwindFrames(pThread, &tct); - - LOG((LF_EH, LL_INFO1000, "CPFH_UnwindFrames1: after unwind ec:%#x, tct.pTopFrame:0x%p, pSearchBndry:0x%p\n" - " pEstFrame:0x%p, IsC+NestExRec:%d, !Nest||Active:%d\n", - exceptionCode, tct.pTopFrame, pExInfo->m_pSearchBoundary, pEstablisherFrame, - IsComPlusNestedExceptionRecord(pEstablisherFrame), - (!IsComPlusNestedExceptionRecord(pEstablisherFrame) || reinterpret_cast(pEstablisherFrame)->m_ActiveForUnwind))); - - if (tct.pTopFrame >= pExInfo->m_pSearchBoundary && - (!IsComPlusNestedExceptionRecord(pEstablisherFrame) || - reinterpret_cast(pEstablisherFrame)->m_ActiveForUnwind) ) - { - // If this is the search boundary, and we're not a nested handler, then - // this is the last time we'll see this exception. Time to unwind our - // exinfo. - STRESS_LOG0(LF_EH, LL_INFO100, "CPFH_UnwindFrames1: Exception unwind -- unmanaged catcher detected\n"); - pExInfo->UnwindExInfo((VOID*)pEstablisherFrame); - } -} // CPFH_UnwindFrames1() - -//****************************************************************************** -inline EXCEPTION_DISPOSITION __cdecl -CPFH_UnwindHandler(EXCEPTION_RECORD *pExceptionRecord, - EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, - CONTEXT *pContext, - void *pDispatcherContext) -{ - WRAPPER_NO_CONTRACT; - _ASSERTE (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)); - - #ifdef _DEBUG - // Note: you might be inclined to write "static int breakOnSecondPass = CLRConfig::GetConfigValue(...);", but - // you can't do that here. That causes C++ EH to be generated under the covers for this function, and this - // function isn't allowed to have any C++ EH in it because its never going to return. - static int breakOnSecondPass; // = 0 - static BOOL breakOnSecondPassSetup; // = FALSE - if (!breakOnSecondPassSetup) - { - breakOnSecondPass = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnSecondPass); - breakOnSecondPassSetup = TRUE; - } - if (breakOnSecondPass != 0) - { - _ASSERTE(!"Unwind handler"); - } - #endif - - DWORD exceptionCode = pExceptionRecord->ExceptionCode; - Thread *pThread = GetThread(); - - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - - STRESS_LOG4(LF_EH, LL_INFO100, "In CPFH_UnwindHandler EHCode = %x EIP = %x with ESP = %x, pEstablisherFrame = 0x%p\n", exceptionCode, - pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0, pEstablisherFrame); - - // We always want to be in co-operative mode when we run this function. Whenever we return - // from it, want to go to pre-emptive mode because are returning to OS. - - { - // needs to be in its own scope to avoid polluting the namespace, since - // we don't do a _END then we don't revert the state - GCX_COOP_NO_DTOR(); - } - - CPFH_VerifyThreadIsInValidState(pThread, exceptionCode, pEstablisherFrame); - - if (IsComPlusNestedExceptionRecord(pEstablisherFrame)) - { - NestedHandlerExRecord *pHandler = reinterpret_cast(pEstablisherFrame); - if (pHandler->m_pCurrentExInfo != NULL) - { - // See the comment at the end of COMPlusNestedExceptionHandler about nested exception. - // OS is going to skip the EstablisherFrame before our NestedHandler. - if (pHandler->m_pCurrentExInfo->m_pBottomMostHandler <= pHandler->m_pCurrentHandler) - { - // We're unwinding -- the bottom most handler is potentially off top-of-stack now. If - // it is, change it to the next CLR frame. (This one is not good, as it's about to - // disappear.) - EXCEPTION_REGISTRATION_RECORD *pNextBottomMost = GetNextCOMPlusSEHRecord(pHandler->m_pCurrentHandler); - - STRESS_LOG3(LF_EH, LL_INFO10000, "COMPlusNestedExceptionHandler: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", - pHandler->m_pCurrentExInfo, pHandler->m_pCurrentExInfo->m_pBottomMostHandler, pNextBottomMost); - - pHandler->m_pCurrentExInfo->m_pBottomMostHandler = pNextBottomMost; - } - } - } - - // this establishes a marker so can determine if are processing a nested exception - // don't want to use the current frame to limit search as it could have been unwound by - // the time get to nested handler (ie if find an exception, unwind to the call point and - // then resume in the catch and then get another exception) so make the nested handler - // have the same boundary as this one. If nested handler can't find a handler, we won't - // end up searching this frame list twice because the nested handler will set the search - // boundary in the thread and so if get back to this handler it will have a range that starts - // and ends at the same place. - NestedHandlerExRecord nestedHandlerExRecord; - nestedHandlerExRecord.Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, GetCurrFrame(pEstablisherFrame)); - - nestedHandlerExRecord.m_ActiveForUnwind = TRUE; - nestedHandlerExRecord.m_pCurrentExInfo = pExInfo; - nestedHandlerExRecord.m_pCurrentHandler = pEstablisherFrame; - - INSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg)); - - // Unwind the stack. The establisher frame sets the boundary. - CPFH_UnwindFrames1(pThread, pEstablisherFrame, exceptionCode); - - // We're unwinding -- the bottom most handler is potentially off top-of-stack now. If - // it is, change it to the next CLR frame. (This one is not good, as it's about to - // disappear.) - if (pExInfo->m_pBottomMostHandler && - pExInfo->m_pBottomMostHandler <= pEstablisherFrame) - { - EXCEPTION_REGISTRATION_RECORD *pNextBottomMost = GetNextCOMPlusSEHRecord(pEstablisherFrame); - - // If there is no previous CLR SEH handler, GetNextCOMPlusSEHRecord() will return -1. Much later, we will dereference that and AV. - _ASSERTE (pNextBottomMost != EXCEPTION_CHAIN_END); - - STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_UnwindHandler: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", - pExInfo, pExInfo->m_pBottomMostHandler, pNextBottomMost); - - pExInfo->m_pBottomMostHandler = pNextBottomMost; - } - - { - // needs to be in its own scope to avoid polluting the namespace, since - // we don't do a _END then we don't revert the state - GCX_PREEMP_NO_DTOR(); - } - UNINSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg)); - - // If we are here, then exception was not caught in managed code protected by this - // ComplusFrameHandler. Hence, reset thread abort state if this is the last personality routine, - // for managed code, on the stack. - ResetThreadAbortState(pThread, pEstablisherFrame); - - STRESS_LOG0(LF_EH, LL_INFO100, "CPFH_UnwindHandler: Leaving with ExceptionContinueSearch\n"); - return ExceptionContinueSearch; -} // CPFH_UnwindHandler() - -//****************************************************************************** -// This is the first handler that is called in the context of managed code -// It is the first level of defense and tries to find a handler in the user -// code to handle the exception -//------------------------------------------------------------------------- -// EXCEPTION_DISPOSITION __cdecl COMPlusFrameHandler( -// EXCEPTION_RECORD *pExceptionRecord, -// _EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, -// CONTEXT *pContext, -// DISPATCHER_CONTEXT *pDispatcherContext) -// -// See http://www.microsoft.com/msj/0197/exception/exception.aspx for a background piece on Windows -// unmanaged structured exception handling. -EXCEPTION_HANDLER_IMPL(COMPlusFrameHandler) -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(!DebugIsEECxxException(pExceptionRecord) && "EE C++ Exception leaked into managed code!"); - - STRESS_LOG5(LF_EH, LL_INFO100, "In COMPlusFrameHandler EH code = %x flag = %x EIP = %x with ESP = %x, pEstablisherFrame = 0x%p\n", - pExceptionRecord->ExceptionCode, pExceptionRecord->ExceptionFlags, - pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0, pEstablisherFrame); - - _ASSERTE((pContext == NULL) || ((pContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)); - - // Check if the exception represents a GCStress Marker. If it does, - // we shouldnt record its entry in the TLS as such exceptions are - // continuable and can confuse the VM to treat them as CSE, - // as they are implemented using illegal instruction exception. - - bool fIsGCMarker = false; - -#ifdef HAVE_GCCOVER // This is a debug only macro - if (GCStress::IsEnabled()) - { - // TlsGetValue trashes last error. When Complus_GCStress=4, GC is invoked - // on every allowable JITed instruction by means of our exception handling machanism - // it is very easy to trash the last error. For example, a p/invoke called a native method - // which sets last error. Before we getting the last error in the IL stub, it is trashed here - DWORD dwLastError = GetLastError(); - fIsGCMarker = IsGcMarker(pContext, pExceptionRecord); - if (!fIsGCMarker) - { - SaveCurrentExceptionInfo(pExceptionRecord, pContext); - } - SetLastError(dwLastError); - } - else -#endif - { - // GCStress does not exist on retail builds (see IsGcMarker implementation for details). - SaveCurrentExceptionInfo(pExceptionRecord, pContext); - } - - if (fIsGCMarker) - { - // If this was a GCStress marker exception, then return - // ExceptionContinueExecution to the OS. - return ExceptionContinueExecution; - } - - EXCEPTION_DISPOSITION retVal = ExceptionContinueSearch; - - Thread *pThread = GetThread(); - if ((pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) == 0) - { - if (pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) - { - EEPolicy::HandleStackOverflow(); - - // VC's unhandled exception filter plays with stack. It VirtualAlloc's a new stack, and - // then launch Watson from the new stack. When Watson asks CLR to save required data, we - // are not able to walk the stack. - // Setting Context in ExInfo so that our Watson dump routine knows how to walk this stack. - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - pExInfo->m_pContext = pContext; - - // Save the reference to the topmost handler we see during first pass when an SO goes past us. - // When an unwind gets triggered for the exception, we will reset the frame chain when we reach - // the topmost handler we saw during the first pass. - // - // This unifies, behaviour-wise, 32bit with 64bit. - if ((pExInfo->m_pTopMostHandlerDuringSO == NULL) || - (pEstablisherFrame > pExInfo->m_pTopMostHandlerDuringSO)) - { - pExInfo->m_pTopMostHandlerDuringSO = pEstablisherFrame; - } - - // Switch to preemp mode since we are returning back to the OS. - // We will do the quick switch since we are short of stack - InterlockedAnd((LONG*)&pThread->m_fPreemptiveGCDisabled, 0); - - return ExceptionContinueSearch; - } - } - else - { - DWORD exceptionCode = pExceptionRecord->ExceptionCode; - - if (exceptionCode == STATUS_UNWIND) - { - // If exceptionCode is STATUS_UNWIND, RtlUnwind is called with a NULL ExceptionRecord, - // therefore OS uses a faked ExceptionRecord with STATUS_UNWIND code. Then we need to - // look at our saved exception code. - exceptionCode = GetCurrentExceptionCode(); - } - - if (exceptionCode == STATUS_STACK_OVERFLOW) - { - // We saved the context during the first pass in case the stack overflow exception is - // unhandled and Watson dump code needs it. Now we are in the second pass, therefore - // either the exception is handled by user code, or we have finished unhandled exception - // filter process, and the OS is unwinding the stack. Either way, we don't need the - // context any more. It is very important to reset the context so that our code does not - // accidentally walk the frame using the dangling context in ExInfoWalker::WalkToPosition. - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - pExInfo->m_pContext = NULL; - - // We should have the reference to the topmost handler seen during the first pass of SO - _ASSERTE(pExInfo->m_pTopMostHandlerDuringSO != NULL); - - // Reset frame chain till we reach the topmost establisher frame we saw in the first pass. - // This will ensure that if any intermediary frame calls back into managed (e.g. native frame - // containing a __finally that reverse pinvokes into managed), then we have the correct - // explicit frame on the stack. Resetting the frame chain only when we reach the topmost - // personality routine seen in the first pass may not result in expected behaviour, - // specially during stack walks when crawl frame needs to be initialized from - // explicit frame. - if (pEstablisherFrame <= pExInfo->m_pTopMostHandlerDuringSO) - { - GCX_COOP_NO_DTOR(); - - if (pThread->GetFrame() < GetCurrFrame(pEstablisherFrame)) - { - // We are very short of stack. We avoid calling UnwindFrame which may - // run unknown code here. - pThread->SetFrame(GetCurrFrame(pEstablisherFrame)); - } - } - - // Switch to preemp mode since we are returning back to the OS. - // We will do the quick switch since we are short of stack - InterlockedAnd((LONG*)&pThread->m_fPreemptiveGCDisabled, 0); - - return ExceptionContinueSearch; - } - } - - if (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) - { - retVal = CPFH_UnwindHandler(pExceptionRecord, - pEstablisherFrame, - pContext, - pDispatcherContext); - } - else - { - - /* Make no assumptions about the current machine state. - @PERF: Only needs to be called by the very first handler invoked by SEH */ - ResetCurrentContext(); - - retVal = CPFH_FirstPassHandler(pExceptionRecord, - pEstablisherFrame, - pContext, - pDispatcherContext); - - } - - return retVal; -} // COMPlusFrameHandler() - - -//------------------------------------------------------------------------- -// This is called by the EE to restore the stack pointer if necessary. -//------------------------------------------------------------------------- - -// This can't be inlined into the caller to avoid introducing EH frame -NOINLINE LPVOID COMPlusEndCatchWorker(Thread * pThread) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch:called with " - "pThread:0x%x\n",pThread)); - - // indicate that we are out of the managed clause as early as possible - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE); - - void* esp = NULL; - - // Notify the profiler that the catcher has finished running - // IL stubs don't contain catch blocks so inability to perform this check does not matter. - // if (!pFunc->IsILStub()) - EEToProfilerExceptionInterfaceWrapper::ExceptionCatcherLeave(); - - // no need to set pExInfo->m_ClauseType = (DWORD)COR_PRF_CLAUSE_NONE now that the - // notification is done because the ExInfo record is about to be popped off anyway - - LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch:pThread:0x%x\n",pThread)); - -#ifdef _DEBUG - gLastResumedExceptionFunc = NULL; - gLastResumedExceptionHandler = 0; -#endif - // Set the thrown object to NULL as no longer needed. This also sets the last thrown object to NULL. - pThread->SafeSetThrowables(NULL); - - // reset the stashed exception info - pExInfo->m_pExceptionRecord = NULL; - pExInfo->m_pContext = NULL; - pExInfo->m_pExceptionPointers = NULL; - - if (pExInfo->m_pShadowSP) - { - *pExInfo->m_pShadowSP = 0; // Reset the shadow SP - } - - // pExInfo->m_dEsp was set in ResumeAtJITEH(). It is the Esp of the - // handler nesting level which catches the exception. - esp = (void*)(size_t)pExInfo->m_dEsp; - - pExInfo->UnwindExInfo(esp); - - // Prepare to sync managed exception state - // - // In a case when we're nested inside another catch block, the domain in which we're executing may not be the - // same as the one the domain of the throwable that was just made the current throwable above. Therefore, we - // make a special effort to preserve the domain of the throwable as we update the last thrown object. - // - // This function (COMPlusEndCatch) can also be called by the in-proc debugger helper thread on x86 when - // an attempt to SetIP takes place to set IP outside the catch clause. In such a case, managed thread object - // will not be available. Thus, we should reset the severity only if its not such a thread. - // - // This behaviour (of debugger doing SetIP) is not allowed on 64bit since the catch clauses are implemented - // as a separate funclet and it's just not allowed to set the IP across EH scopes, such as from inside a catch - // clause to outside of the catch clause. - bool fIsDebuggerHelperThread = (g_pDebugInterface == NULL) ? false : g_pDebugInterface->ThisIsHelperThread(); - - // Sync managed exception state, for the managed thread, based upon any active exception tracker - pThread->SyncManagedExceptionState(fIsDebuggerHelperThread); - - LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch: esp=%p\n", esp)); - - return esp; -} - -// -// This function works in conjunction with JIT_EndCatch. On input, the parameters are set as follows: -// ebp, ebx, edi, esi: the values of these registers at the end of the catch block -// *pRetAddress: the next instruction after the call to JIT_EndCatch -// -// On output, *pRetAddress is the instruction at which to resume execution. This may be user code, -// or it may be ThrowControlForThread (which will re-raise a pending ThreadAbortException). -// -// Returns the esp to set before resuming at *pRetAddress. -// -LPVOID STDCALL COMPlusEndCatch(LPVOID ebp, DWORD ebx, DWORD edi, DWORD esi, LPVOID* pRetAddress) -{ - // - // PopNestedExceptionRecords directly manipulates fs:[0] chain. This method can't have any EH! - // - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - ETW::ExceptionLog::ExceptionCatchEnd(); - ETW::ExceptionLog::ExceptionThrownEnd(); - - void* esp = COMPlusEndCatchWorker(GetThread()); - - // We are going to resume at a handler nesting level whose esp is dEsp. Pop off any SEH records below it. This - // would be the COMPlusNestedExceptionHandler we had inserted. - PopNestedExceptionRecords(esp); - - // - // Set up m_OSContext for the call to COMPlusCheckForAbort - // - Thread* pThread = GetThread(); - - SetIP(pThread->m_OSContext, (PCODE)*pRetAddress); - SetSP(pThread->m_OSContext, (TADDR)esp); - SetFP(pThread->m_OSContext, (TADDR)ebp); - pThread->m_OSContext->Ebx = ebx; - pThread->m_OSContext->Edi = edi; - pThread->m_OSContext->Esi = esi; - - LPVOID throwControl = COMPlusCheckForAbort((UINT_PTR)*pRetAddress); - if (throwControl) - *pRetAddress = throwControl; - - return esp; -} - -PEXCEPTION_REGISTRATION_RECORD GetFirstCOMPlusSEHRecord(Thread *pThread) { - WRAPPER_NO_CONTRACT; - EXCEPTION_REGISTRATION_RECORD *pEHR = *(pThread->GetExceptionListPtr()); - if (pEHR == EXCEPTION_CHAIN_END || IsUnmanagedToManagedSEHHandler(pEHR)) { - return pEHR; - } else { - return GetNextCOMPlusSEHRecord(pEHR); - } -} - - -PEXCEPTION_REGISTRATION_RECORD GetPrevSEHRecord(EXCEPTION_REGISTRATION_RECORD *next) -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(IsUnmanagedToManagedSEHHandler(next)); - - EXCEPTION_REGISTRATION_RECORD *pEHR = GetCurrentSEHRecord(); - _ASSERTE(pEHR != 0 && pEHR != EXCEPTION_CHAIN_END); - - EXCEPTION_REGISTRATION_RECORD *pBest = 0; - while (pEHR != next) { - if (IsUnmanagedToManagedSEHHandler(pEHR)) - pBest = pEHR; - pEHR = pEHR->Next; - _ASSERTE(pEHR != 0 && pEHR != EXCEPTION_CHAIN_END); - } - - return pBest; -} - -// -// Unwind pExinfo, pops FS:[0] handlers until the interception context SP, and -// resumes at interception context. -// -VOID UnwindExceptionTrackerAndResumeInInterceptionFrame(ExInfo* pExInfo, EHContext* context) -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE; - - _ASSERTE(pExInfo && context); - - pExInfo->UnwindExInfo((LPVOID)(size_t)context->Esp); - PopNestedExceptionRecords((LPVOID)(size_t)context->Esp); - - STRESS_LOG3(LF_EH|LF_CORDB, LL_INFO100, "UnwindExceptionTrackerAndResumeInInterceptionFrame: completing intercept at EIP = %p ESP = %p EBP = %p\n", context->Eip, context->Esp, context->Ebp); - - ResumeAtJitEHHelper(context); - UNREACHABLE_MSG("Should never return from ResumeAtJitEHHelper!"); -} - -// -// Pop SEH records below the given target ESP. This is only used to pop nested exception records. -// If bCheckForUnknownHandlers is set, it only checks for unknown FS:[0] handlers. -// -BOOL PopNestedExceptionRecords(LPVOID pTargetSP, BOOL bCheckForUnknownHandlers) -{ - // No CONTRACT here, because we can't run the risk of it pushing any SEH into the current method. - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - - PEXCEPTION_REGISTRATION_RECORD pEHR = GetCurrentSEHRecord(); - - while ((LPVOID)pEHR < pTargetSP) - { - // - // The only handler types we're allowed to have below the limit on the FS:0 chain in these cases are a - // nested exception record or a fast NExport record, so we verify that here. - // - // There is a special case, of course: for an unhandled exception, when the default handler does the exit - // unwind, we may have an exception that escapes a finally clause, thus replacing the original unhandled - // exception. If we find a catcher for that new exception, then we'll go ahead and do our own unwind, then - // jump to the catch. When we are called here, just before jumpping to the catch, we'll pop off our nested - // handlers, then we'll pop off one more handler: the handler that ntdll!ExecuteHandler2 pushed before - // calling our nested handler. We go ahead and pop off that handler, too. Its okay, its only there to catch - // exceptions from handlers and turn them into collided unwind status codes... there's no cleanup in the - // handler that we're removing, and that's the important point. The handler that ExecuteHandler2 pushes - // isn't a public export from ntdll, but its named "UnwindHandler" and is physically shortly after - // ExecuteHandler2 in ntdll. - // In this case, we don't want to pop off the NExportSEH handler since it's our outermost handler. - // - static HINSTANCE ExecuteHandler2Module = 0; - static BOOL ExecuteHandler2ModuleInited = FALSE; - - // Cache the handle to the dll with the handler pushed by ExecuteHandler2. - if (!ExecuteHandler2ModuleInited) - { - ExecuteHandler2Module = GetModuleHandle(W("ntdll.dll")); - ExecuteHandler2ModuleInited = TRUE; - } - - if (bCheckForUnknownHandlers) - { - if (!IsComPlusNestedExceptionRecord(pEHR) || - !((ExecuteHandler2Module != NULL) && IsIPInModule(ExecuteHandler2Module, (PCODE)pEHR->Handler))) - { - return TRUE; - } - } -#ifdef _DEBUG - else - { - // Note: if we can't find the module containing ExecuteHandler2, we'll just be really strict and require - // that we're only popping nested handlers or the FastNExportSEH handler. - _ASSERTE(FastNExportSEH(pEHR) || IsComPlusNestedExceptionRecord(pEHR) || - ((ExecuteHandler2Module != NULL) && IsIPInModule(ExecuteHandler2Module, (PCODE)pEHR->Handler))); - } -#endif // _DEBUG - - pEHR = pEHR->Next; - } - - if (!bCheckForUnknownHandlers) - { - SetCurrentSEHRecord(pEHR); - } - return FALSE; -} - -// -// This is implemented differently from the PopNestedExceptionRecords above because it's called in the context of -// the DebuggerRCThread to operate on the stack of another thread. -// -VOID PopNestedExceptionRecords(LPVOID pTargetSP, CONTEXT *pCtx, void *pSEH) -{ - // No CONTRACT here, because we can't run the risk of it pushing any SEH into the current method. - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - -#ifdef _DEBUG - LOG((LF_CORDB,LL_INFO1000, "\nPrintSEHRecords:\n")); - - EXCEPTION_REGISTRATION_RECORD *pEHR = (EXCEPTION_REGISTRATION_RECORD *)(size_t)*(DWORD *)pSEH; - - // check that all the eh frames are all greater than the current stack value. If not, the - // stack has been updated somehow w/o unwinding the SEH chain. - while (pEHR != NULL && pEHR != EXCEPTION_CHAIN_END) - { - LOG((LF_EH, LL_INFO1000000, "\t%08x: next:%08x handler:%x\n", pEHR, pEHR->Next, pEHR->Handler)); - pEHR = pEHR->Next; - } -#endif - - DWORD dwCur = *(DWORD*)pSEH; // 'EAX' in the original routine - DWORD dwPrev = (DWORD)(size_t)pSEH; - - while (dwCur < (DWORD)(size_t)pTargetSP) - { - // Watch for the OS handler - // for nested exceptions, or any C++ handlers for destructors in our call - // stack, or anything else. - if (dwCur < (DWORD)GetSP(pCtx)) - dwPrev = dwCur; - - dwCur = *(DWORD *)(size_t)dwCur; - - LOG((LF_CORDB,LL_INFO10000, "dwCur: 0x%x dwPrev:0x%x pTargetSP:0x%x\n", - dwCur, dwPrev, pTargetSP)); - } - - *(DWORD *)(size_t)dwPrev = dwCur; - -#ifdef _DEBUG - pEHR = (EXCEPTION_REGISTRATION_RECORD *)(size_t)*(DWORD *)pSEH; - // check that all the eh frames are all greater than the current stack value. If not, the - // stack has been updated somehow w/o unwinding the SEH chain. - - LOG((LF_CORDB,LL_INFO1000, "\nPopSEHRecords:\n")); - while (pEHR != NULL && pEHR != (void *)-1) - { - LOG((LF_EH, LL_INFO1000000, "\t%08x: next:%08x handler:%x\n", pEHR, pEHR->Next, pEHR->Handler)); - pEHR = pEHR->Next; - } -#endif -} - -//========================================================================== -// COMPlusThrowCallback -// -//========================================================================== - -/* - * - * COMPlusThrowCallbackHelper - * - * This function is a simple helper function for COMPlusThrowCallback. It is needed - * because of the EX_TRY macro. This macro does an alloca(), which allocates space - * off the stack, not free'ing it. Thus, doing a EX_TRY in a loop can easily result - * in a stack overflow error. By factoring out the EX_TRY into a separate function, - * we recover that stack space. - * - * Parameters: - * pJitManager - The JIT manager that will filter the EH. - * pCf - The frame to crawl. - * EHClausePtr - * nestingLevel - * pThread - Used to determine if the thread is throwable or not. - * - * Return: - * Exception status. - * - */ -int COMPlusThrowCallbackHelper(IJitManager *pJitManager, - CrawlFrame *pCf, - ThrowCallbackType* pData, - EE_ILEXCEPTION_CLAUSE *EHClausePtr, - DWORD nestingLevel, - OBJECTREF throwable, - Thread *pThread - ) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - int iFilt = 0; - - EX_TRY - { - GCPROTECT_BEGIN (throwable); - - // We want to call filters even if the thread is aborting, so suppress abort - // checks while the filter runs. - ThreadPreventAsyncHolder preventAbort; - - BYTE* startAddress = (BYTE*)pCf->GetCodeInfo()->GetStartAddress(); - iFilt = ::CallJitEHFilter(pCf, startAddress, EHClausePtr, nestingLevel, throwable); - - GCPROTECT_END(); - } - EX_CATCH - { - // We had an exception in filter invocation that remained unhandled. - // Sync managed exception state, for the managed thread, based upon the active exception tracker. - pThread->SyncManagedExceptionState(false); - - // - // Swallow exception. Treat as exception continue search. - // - iFilt = EXCEPTION_CONTINUE_SEARCH; - - } - EX_END_CATCH - - return iFilt; -} - -//****************************************************************************** -// The stack walk callback for exception handling on x86. -// Returns one of: -// SWA_CONTINUE = 0, // continue walking -// SWA_ABORT = 1, // stop walking, early out in "failure case" -// SWA_FAILED = 2 // couldn't walk stack -StackWalkAction COMPlusThrowCallback( // SWA value - CrawlFrame *pCf, // Data from StackWalkFramesEx - ThrowCallbackType *pData) // Context data passed through from CPFH -{ - // We don't want to use a runtime contract here since this codepath is used during - // the processing of a hard SO. Contracts use a significant amount of stack - // which we can't afford for those cases. - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - Frame *pFrame = pCf->GetFrame(); - MethodDesc *pFunc = pCf->GetFunction(); - - #if defined(_DEBUG) - #define METHODNAME(pFunc) (pFunc?pFunc->m_pszDebugMethodName:"") - #else - #define METHODNAME(pFunc) "" - #endif - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusThrowCallback: STACKCRAWL method:%pM ('%s'), Frame:%p, FrameIdentifier = %s\n", - pFunc, METHODNAME(pFunc), pFrame, pCf->IsFrameless()?0:Frame::GetFrameTypeName(pFrame->GetFrameIdentifier())); - #undef METHODNAME - - Thread *pThread = GetThread(); - - if (pFrame && pData->pTopFrame == pFrame) - /* Don't look past limiting frame if there is one */ - return SWA_ABORT; - - if (!pFunc) - return SWA_CONTINUE; - - if (pThread->IsRudeAbortInitiated()) - { - return SWA_CONTINUE; - } - - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - - _ASSERTE(!pData->bIsUnwind); -#ifdef _DEBUG - // It SHOULD be the case that any frames we consider live between this exception - // record and the previous one. - if (!pExInfo->m_pPrevNestedInfo) { - if (pData->pCurrentExceptionRecord) { - if (pFrame) _ASSERTE(pData->pCurrentExceptionRecord > pFrame); - // The FastNExport SEH handler can be in the frame we just unwound and as a result just out of range. - if (pCf->IsFrameless() && !FastNExportSEH((PEXCEPTION_REGISTRATION_RECORD)pData->pCurrentExceptionRecord)) - { - _ASSERTE((ULONG_PTR)pData->pCurrentExceptionRecord >= GetRegdisplaySP(pCf->GetRegisterSet())); - } - } - if (pData->pPrevExceptionRecord) { - // FCALLS have an extra SEH record in debug because of the desctructor - // associated with ForbidGC checking. This is benign, so just ignore it. - if (pFrame) _ASSERTE(pData->pPrevExceptionRecord < pFrame); - if (pCf->IsFrameless()) _ASSERTE((ULONG_PTR)pData->pPrevExceptionRecord <= GetRegdisplaySP(pCf->GetRegisterSet())); - } - } -#endif - - UINT_PTR currentIP = 0; - UINT_PTR currentSP = 0; - - if (pCf->IsFrameless()) - { - currentIP = (UINT_PTR)GetControlPC(pCf->GetRegisterSet()); - currentSP = (UINT_PTR)GetRegdisplaySP(pCf->GetRegisterSet()); - } - else if (InlinedCallFrame::FrameHasActiveCall(pFrame)) - { - // don't have the IP, SP for native code - currentIP = 0; - currentSP = 0; - } - else - { - currentIP = (UINT_PTR)(pCf->GetFrame()->GetIP()); - currentSP = 0; //Don't have an SP to get. - } - - if (!pFunc->IsDiagnosticsHidden()) - { - if (!pData->bSkipLastElement) - { - // Append the current frame to the stack trace and save the save trace to the managed Exception object. - StackTraceInfo::AppendElement(pThread->GetThrowableAsHandle(), currentIP, currentSP, pFunc, pCf); - } - } - else - { - LOG((LF_EH, LL_INFO1000, "COMPlusThrowCallback: Skipping AppendElement for IL stub MD %p\n", pFunc)); - } - - // Fire an exception thrown ETW event when an exception occurs - ETW::ExceptionLog::ExceptionThrown(pCf, pData->bSkipLastElement, pData->bIsNewException); - - // Reset the flags. These flags are set only once before each stack walk done by LookForHandler(), and - // they apply only to the first frame we append to the stack trace. Subsequent frames are always appended. - if (pData->bIsNewException) - { - pData->bIsNewException = FALSE; - } - if (pData->bSkipLastElement) - { - pData->bSkipLastElement = FALSE; - } - - // now we've got the stack trace, if we aren't allowed to catch this and we're first pass, return - if (pData->bDontCatch) - return SWA_CONTINUE; - - if (!pCf->IsFrameless()) - { - // For debugger, we may want to notify 1st chance exceptions if they're coming out of a stub. - // We recognize stubs as Frames with a M2U transition type. The debugger's stackwalker also - // recognizes these frames and publishes ICorDebugInternalFrames in the stackwalk. It's - // important to use pFrame as the stack address so that the Exception callback matches up - // w/ the ICorDebugInternalFrame stack range. - if (CORDebuggerAttached()) - { - Frame * pFrameStub = pCf->GetFrame(); - Frame::ETransitionType t = pFrameStub->GetTransitionType(); - if (t == Frame::TT_M2U) - { - // Use address of the frame as the stack address. - currentSP = (SIZE_T) ((void*) pFrameStub); - currentIP = 0; // no IP. - EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedException(pThread, (SIZE_T)currentIP, (SIZE_T)currentSP); - // Deliver the FirstChanceNotification after the debugger, if not already delivered. - if (!pExInfo->DeliveredFirstChanceNotification()) - { - ExceptionNotifications::DeliverFirstChanceNotification(); - } - } - } - return SWA_CONTINUE; - } - - bool fIsILStub = pFunc->IsILStub(); - bool fGiveDebuggerAndProfilerNotification = !pFunc->IsDiagnosticsHidden(); - BOOL fMethodCanHandleException = TRUE; - - MethodDesc * pUserMDForILStub = NULL; - Frame * pILStubFrame = NULL; - if (fIsILStub) - pUserMDForILStub = GetUserMethodForILStub(pThread, currentSP, pFunc, &pILStubFrame); - - // Let the profiler know that we are searching for a handler within this function instance - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pFunc); - - // The following debugger notification and AppDomain::FirstChanceNotification should be scoped together - // since the AD notification *must* follow immediately after the debugger's notification. - { -#ifdef DEBUGGING_SUPPORTED - // - // Go ahead and notify any debugger of this exception. - // - EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedException(pThread, (SIZE_T)currentIP, (SIZE_T)currentSP); - - if (CORDebuggerAttached() && pExInfo->m_ExceptionFlags.DebuggerInterceptInfo()) - { - return SWA_ABORT; - } -#endif // DEBUGGING_SUPPORTED - - // Attempt to deliver the first chance notification to the AD only *AFTER* the debugger - // has done that, provided we have not already done that. - if (!pExInfo->DeliveredFirstChanceNotification()) - { - ExceptionNotifications::DeliverFirstChanceNotification(); - } - } - - IJitManager* pJitManager = pCf->GetJitManager(); - _ASSERTE(pJitManager); - - EH_CLAUSE_ENUMERATOR pEnumState; - unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState); - - if (EHCount == 0) - { - // Inform the profiler that we're leaving, and what pass we're on - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc); - return SWA_CONTINUE; - } - - TypeHandle thrownType = TypeHandle(); - // if we are being called on an unwind for an exception that we did not try to catch, eg. - // an internal EE exception, then pThread->GetThrowable will be null - { - OBJECTREF throwable = pThread->GetThrowable(); - if (throwable != NULL) - { - throwable = PossiblyUnwrapThrowable(throwable, pCf->GetAssembly()); - thrownType = TypeHandle(throwable->GetMethodTable()); - } - } - - PREGDISPLAY regs = pCf->GetRegisterSet(); - BYTE *pStack = (BYTE *) GetRegdisplaySP(regs); -#ifdef DEBUGGING_SUPPORTED - BYTE *pHandlerEBP = (BYTE *) GetRegdisplayFP(regs); -#endif - - DWORD offs = (DWORD)pCf->GetRelOffset(); //= (BYTE*) (*regs->pPC) - (BYTE*) pCf->GetStartAddress(); - STRESS_LOG1(LF_EH, LL_INFO10000, "COMPlusThrowCallback: offset is %d\n", offs); - - EE_ILEXCEPTION_CLAUSE EHClause; - unsigned start_adjust, end_adjust; - - start_adjust = !(pCf->HasFaulted() || pCf->IsIPadjusted()); - end_adjust = pCf->IsActiveFunc(); - - for(ULONG i=0; i < EHCount; i++) - { - pJitManager->GetNextEHClause(&pEnumState, &EHClause); - _ASSERTE(IsValidClause(&EHClause)); - - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusThrowCallback: considering '%s' clause [%d,%d], ofs:%d\n", - (IsFault(&EHClause) ? "fault" : ( - IsFinally(&EHClause) ? "finally" : ( - IsFilterHandler(&EHClause) ? "filter" : ( - IsTypedHandler(&EHClause) ? "typed" : "unknown")))), - EHClause.TryStartPC, - EHClause.TryEndPC, - offs - ); - - // Checking the exception range is a bit tricky because - // on CPU faults (null pointer access, div 0, ..., the IP points - // to the faulting instruction, but on calls, the IP points - // to the next instruction. - // This means that we should not include the start point on calls - // as this would be a call just preceding the try block. - // Also, we should include the end point on calls, but not faults. - - // If we're in the FILTER part of a filter clause, then we - // want to stop crawling. It's going to be caught in a - // EX_CATCH just above us. If not, the exception - if ( IsFilterHandler(&EHClause) - && ( offs > EHClause.FilterOffset - || (offs == EHClause.FilterOffset && !start_adjust) ) - && ( offs < EHClause.HandlerStartPC - || (offs == EHClause.HandlerStartPC && !end_adjust) )) { - - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusThrowCallback: Fault inside filter [%d,%d] startAdj %d endAdj %d\n", - EHClause.FilterOffset, EHClause.HandlerStartPC, start_adjust, end_adjust); - - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc); - return SWA_ABORT; - } - - if ( (offs < EHClause.TryStartPC) || - (offs > EHClause.TryEndPC) || - (offs == EHClause.TryStartPC && start_adjust) || - (offs == EHClause.TryEndPC && end_adjust)) - continue; - - BOOL typeMatch = FALSE; - BOOL isTypedHandler = IsTypedHandler(&EHClause); - - if (isTypedHandler && !thrownType.IsNull()) - { - if (EHClause.TypeHandle == (void*)(size_t)mdTypeRefNil) - { - // this is a catch(...) - typeMatch = TRUE; - } - else - { - TypeHandle exnType = pJitManager->ResolveEHClause(&EHClause,pCf); - - // if doesn't have cached class then class wasn't loaded so couldn't have been thrown - typeMatch = !exnType.IsNull() && ExceptionIsOfRightType(exnType, thrownType); - } - } - - // @PERF: Is this too expensive? Consider storing the nesting level - // instead of the HandlerEndPC. - - // Determine the nesting level of EHClause. Just walk the table - // again, and find out how many handlers enclose it - DWORD nestingLevel = 0; - - if (IsFaultOrFinally(&EHClause)) - continue; - if (isTypedHandler) - { - LOG((LF_EH, LL_INFO100, "COMPlusThrowCallback: %s match for typed handler.\n", typeMatch?"Found":"Did not find")); - if (!typeMatch) - { - continue; - } - } - else - { - // Must be an exception filter (__except() part of __try{}__except(){}). - nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager, - pCf->GetMethodToken(), - EHClause.HandlerStartPC); - - // We just need *any* address within the method. This will let the debugger - // resolve the EnC version of the method. - PCODE pMethodAddr = GetControlPC(regs); - if (fGiveDebuggerAndProfilerNotification) - EEToDebuggerExceptionInterfaceWrapper::ExceptionFilter(pFunc, pMethodAddr, EHClause.FilterOffset, pHandlerEBP); - - UINT_PTR uStartAddress = (UINT_PTR)pCf->GetCodeInfo()->GetStartAddress(); - - // save clause information in the exinfo - pExInfo->m_EHClauseInfo.SetInfo(COR_PRF_CLAUSE_FILTER, - uStartAddress + EHClause.FilterOffset, - StackFrame((UINT_PTR)pHandlerEBP)); - - // Let the profiler know we are entering a filter - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFilterEnter(pFunc); - - STRESS_LOG3(LF_EH, LL_INFO10, "COMPlusThrowCallback: calling filter code, EHClausePtr:%08x, Start:%08x, End:%08x\n", - &EHClause, EHClause.HandlerStartPC, EHClause.HandlerEndPC); - - OBJECTREF throwable = PossiblyUnwrapThrowable(pThread->GetThrowable(), pCf->GetAssembly()); - - pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE); - - int iFilt = COMPlusThrowCallbackHelper(pJitManager, - pCf, - pData, - &EHClause, - nestingLevel, - throwable, - pThread); - - pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE); - - // Let the profiler know we are leaving a filter - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFilterLeave(); - - pExInfo->m_EHClauseInfo.ResetInfo(); - - if (pThread->IsRudeAbortInitiated()) - { - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc); - return SWA_CONTINUE; - } - - // If this filter didn't want the exception, keep looking. - if (EXCEPTION_EXECUTE_HANDLER != iFilt) - continue; - } - - // Record this location, to stop the unwind phase, later. - pData->pFunc = pFunc; - pData->dHandler = i; - pData->pStack = pStack; - - // Notify the profiler that a catcher has been found - if (fGiveDebuggerAndProfilerNotification) - { - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchCatcherFound(pFunc); - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc); - } - -#ifdef DEBUGGING_SUPPORTED - // - // Notify debugger that a catcher has been found. - // - if (fIsILStub) - { - EEToDebuggerExceptionInterfaceWrapper::NotifyOfCHFFilter(pExInfo->m_pExceptionPointers, pILStubFrame); - } - else - if (fGiveDebuggerAndProfilerNotification && - CORDebuggerAttached() && !pExInfo->m_ExceptionFlags.DebuggerInterceptInfo()) - { - _ASSERTE(pData); - // We just need *any* address within the method. This will let the debugger - // resolve the EnC version of the method. - PCODE pMethodAddr = GetControlPC(regs); - - EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedExceptionCatcherFound(pThread, - pData->pFunc, pMethodAddr, - (SIZE_T)pData->pStack, - &EHClause); - } -#endif // DEBUGGING_SUPPORTED - - return SWA_ABORT; - } - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc); - return SWA_CONTINUE; -} // StackWalkAction COMPlusThrowCallback() - - -//========================================================================== -// COMPlusUnwindCallback -//========================================================================== - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning (disable : 4740) // There is inline asm code in this function, which disables - // global optimizations. -#pragma warning (disable : 4731) -#endif -StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE; - - _ASSERTE(pData->bIsUnwind); - - Frame *pFrame = pCf->GetFrame(); - MethodDesc *pFunc = pCf->GetFunction(); - - #if defined(_DEBUG) - #define METHODNAME(pFunc) (pFunc?pFunc->m_pszDebugMethodName:"") - #else - #define METHODNAME(pFunc) "" - #endif - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: STACKCRAWL method:%pM ('%s'), Frame:%p, FrameIdentifier = %s\n", - pFunc, METHODNAME(pFunc), pFrame, pCf->IsFrameless()?0:Frame::GetFrameTypeName(pFrame->GetFrameIdentifier())); - #undef METHODNAME - - if (pFrame && pData->pTopFrame == pFrame) - /* Don't look past limiting frame if there is one */ - return SWA_ABORT; - - if (!pFunc) - return SWA_CONTINUE; - - if (!pCf->IsFrameless()) - return SWA_CONTINUE; - - Thread *pThread = GetThread(); - - // If the thread is being RudeAbort, we will not run any finally - if (pThread->IsRudeAbortInitiated()) - { - return SWA_CONTINUE; - } - - IJitManager* pJitManager = pCf->GetJitManager(); - _ASSERTE(pJitManager); - - ExInfo *pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - - PREGDISPLAY regs = pCf->GetRegisterSet(); - BYTE *pStack = (BYTE *) GetRegdisplaySP(regs); - - TypeHandle thrownType = TypeHandle(); - -#ifdef DEBUGGING_SUPPORTED - LOG((LF_EH, LL_INFO1000, "COMPlusUnwindCallback: Intercept %d, pData->pFunc 0x%X, pFunc 0x%X, pData->pStack 0x%X, pStack 0x%X\n", - pExInfo->m_ExceptionFlags.DebuggerInterceptInfo(), - pData->pFunc, - pFunc, - pData->pStack, - pStack)); - - // - // If the debugger wants to intercept this exception here, go do that. - // - if (pExInfo->m_ExceptionFlags.DebuggerInterceptInfo() && (pData->pFunc == pFunc) && (pData->pStack == pStack)) - { - goto LDoDebuggerIntercept; - } -#endif - - bool fGiveDebuggerAndProfilerNotification; - fGiveDebuggerAndProfilerNotification = !pFunc->IsDiagnosticsHidden(); - - // Notify the profiler of the function we're dealing with in the unwind phase - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pFunc); - - EH_CLAUSE_ENUMERATOR pEnumState; - unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState); - - if (EHCount == 0) - { - // Inform the profiler that we're leaving, and what pass we're on - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pFunc); - - return SWA_CONTINUE; - } - - // if we are being called on an unwind for an exception that we did not try to catch, eg. - // an internal EE exception, then pThread->GetThrowable will be null - { - OBJECTREF throwable = pThread->GetThrowable(); - if (throwable != NULL) - { - throwable = PossiblyUnwrapThrowable(throwable, pCf->GetAssembly()); - thrownType = TypeHandle(throwable->GetMethodTable()); - } - } -#ifdef DEBUGGING_SUPPORTED - BYTE *pHandlerEBP; - pHandlerEBP = (BYTE *) GetRegdisplayFP(regs); -#endif - - DWORD offs; - offs = (DWORD)pCf->GetRelOffset(); //= (BYTE*) (*regs->pPC) - (BYTE*) pCf->GetStartAddress(); - - LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback: current EIP offset in method 0x%x, \n", offs)); - - EE_ILEXCEPTION_CLAUSE EHClause; - unsigned start_adjust, end_adjust; - - start_adjust = !(pCf->HasFaulted() || pCf->IsIPadjusted()); - end_adjust = pCf->IsActiveFunc(); - - for(ULONG i=0; i < EHCount; i++) - { - pJitManager->GetNextEHClause(&pEnumState, &EHClause); - _ASSERTE(IsValidClause(&EHClause)); - - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: considering '%s' clause [%d,%d], offs:%d\n", - (IsFault(&EHClause) ? "fault" : ( - IsFinally(&EHClause) ? "finally" : ( - IsFilterHandler(&EHClause) ? "filter" : ( - IsTypedHandler(&EHClause) ? "typed" : "unknown")))), - EHClause.TryStartPC, - EHClause.TryEndPC, - offs - ); - - // Checking the exception range is a bit tricky because - // on CPU faults (null pointer access, div 0, ..., the IP points - // to the faulting instruction, but on calls, the IP points - // to the next instruction. - // This means that we should not include the start point on calls - // as this would be a call just preceding the try block. - // Also, we should include the end point on calls, but not faults. - - if ( IsFilterHandler(&EHClause) - && ( offs > EHClause.FilterOffset - || (offs == EHClause.FilterOffset && !start_adjust) ) - && ( offs < EHClause.HandlerStartPC - || (offs == EHClause.HandlerStartPC && !end_adjust) ) - ) { - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: Fault inside filter [%d,%d] startAdj %d endAdj %d\n", - EHClause.FilterOffset, EHClause.HandlerStartPC, start_adjust, end_adjust); - - // Make the filter as done. See comment in CallJitEHFilter - // on why we have to do it here. - Frame* pFilterFrame = pThread->GetFrame(); - _ASSERTE(pFilterFrame->GetFrameIdentifier() == FrameIdentifier::ExceptionFilterFrame); - ((ExceptionFilterFrame*)pFilterFrame)->SetFilterDone(); - - // Inform the profiler that we're leaving, and what pass we're on - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pFunc); - - return SWA_ABORT; - } - - if ( (offs < EHClause.TryStartPC) || - (offs > EHClause.TryEndPC) || - (offs == EHClause.TryStartPC && start_adjust) || - (offs == EHClause.TryEndPC && end_adjust)) - continue; - - // @PERF : Is this too expensive? Consider storing the nesting level - // instead of the HandlerEndPC. - - // Determine the nesting level of EHClause. Just walk the table - // again, and find out how many handlers enclose it - - DWORD nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager, - pCf->GetMethodToken(), - EHClause.HandlerStartPC); - - // We just need *any* address within the method. This will let the debugger - // resolve the EnC version of the method. - PCODE pMethodAddr = GetControlPC(regs); - - UINT_PTR uStartAddress = (UINT_PTR)pCf->GetCodeInfo()->GetStartAddress(); - - if (IsFaultOrFinally(&EHClause)) - { - if (fGiveDebuggerAndProfilerNotification) - EEToDebuggerExceptionInterfaceWrapper::ExceptionHandle(pFunc, pMethodAddr, EHClause.HandlerStartPC, pHandlerEBP); - - pExInfo->m_EHClauseInfo.SetInfo(COR_PRF_CLAUSE_FINALLY, - uStartAddress + EHClause.HandlerStartPC, - StackFrame((UINT_PTR)pHandlerEBP)); - - // Notify the profiler that we are about to execute the finally code - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFinallyEnter(pFunc); - - LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback: finally clause [%d,%d] - call\n", EHClause.TryStartPC, EHClause.TryEndPC)); - - pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE); - - ::CallJitEHFinally(pCf, (BYTE *)uStartAddress, &EHClause, nestingLevel); - - pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE); - - LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback: finally - returned\n")); - - // Notify the profiler that we are done with the finally code - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFinallyLeave(); - - pExInfo->m_EHClauseInfo.ResetInfo(); - - continue; - } - - // Current is not a finally, check if it's the catching handler (or filter). - if (pData->pFunc != pFunc || (ULONG)(pData->dHandler) != i || pData->pStack != pStack) - { - continue; - } - -#ifdef _DEBUG - gLastResumedExceptionFunc = pCf->GetFunction(); - gLastResumedExceptionHandler = i; -#endif - - // save clause information in the exinfo - pExInfo->m_EHClauseInfo.SetInfo(COR_PRF_CLAUSE_CATCH, - uStartAddress + EHClause.HandlerStartPC, - StackFrame((UINT_PTR)pHandlerEBP)); - - // Notify the profiler that we are about to resume at the catcher. - if (fGiveDebuggerAndProfilerNotification) - { - DACNotify::DoExceptionCatcherEnterNotification(pFunc, EHClause.HandlerStartPC); - - EEToProfilerExceptionInterfaceWrapper::ExceptionCatcherEnter(pThread, pFunc); - - EEToDebuggerExceptionInterfaceWrapper::ExceptionHandle(pFunc, pMethodAddr, EHClause.HandlerStartPC, pHandlerEBP); - } - - STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: offset 0x%x matches clause [0x%x, 0x%x) matches in method %pM\n", - offs, EHClause.TryStartPC, EHClause.TryEndPC, pFunc); - - // ResumeAtJitEH will set pExInfo->m_EHClauseInfo.m_fManagedCodeEntered = TRUE; at the appropriate time - ::ResumeAtJitEH(pCf, (BYTE *)uStartAddress, &EHClause, nestingLevel, pThread, pData->bUnwindStack); - //UNREACHABLE_MSG("ResumeAtJitEH shouldn't have returned!"); - - // we do not set pExInfo->m_EHClauseInfo.m_fManagedCodeEntered = FALSE here, - // that happens when the catch clause calls back to COMPlusEndCatch - - } - - STRESS_LOG1(LF_EH, LL_INFO100, "COMPlusUnwindCallback: no handler found in method %pM\n", pFunc); - if (fGiveDebuggerAndProfilerNotification) - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pFunc); - - return SWA_CONTINUE; - - -#ifdef DEBUGGING_SUPPORTED -LDoDebuggerIntercept: - - STRESS_LOG1(LF_EH|LF_CORDB, LL_INFO100, "COMPlusUnwindCallback: Intercepting in method %pM\n", pFunc); - - // - // Setup up the easy parts of the context to restart at. - // - EHContext context; - - // - // Note: EAX ECX EDX are scratch - // - context.Esp = (DWORD)(size_t)(GetRegdisplaySP(regs)); - context.Ebx = *regs->pEbx; - context.Esi = *regs->pEsi; - context.Edi = *regs->pEdi; - context.Ebp = *regs->pEbp; - - // - // Set scratch registers to 0 to avoid reporting incorrect values to GC in case of debugger changing the IP - // in the middle of a scratch register lifetime (see Dev10 754922) - // - context.Eax = 0; - context.Ecx = 0; - context.Edx = 0; - - // - // Ok, now set the target Eip to the address the debugger requested. - // - ULONG_PTR nativeOffset; - pExInfo->m_DebuggerExState.GetDebuggerInterceptInfo(NULL, NULL, NULL, NULL, &nativeOffset, NULL); - context.Eip = GetControlPC(regs) - (pCf->GetRelOffset() - nativeOffset); - - // - // Finally we need to get the correct Esp for this nested level - // - - context.Esp = pCf->GetCodeManager()->GetAmbientSP(regs, - pCf->GetCodeInfo(), - nativeOffset, - pData->dHandler - ); - // - // In case we see unknown FS:[0] handlers we delay the interception point until we reach the handler that protects the interception point. - // This way we have both FS:[0] handlers being poped up by RtlUnwind and managed capital F Frames being unwinded by managed stackwalker. - // - BOOL fCheckForUnknownHandler = TRUE; - if (PopNestedExceptionRecords((LPVOID)(size_t)context.Esp, fCheckForUnknownHandler)) - { - // Let ClrDebuggerDoUnwindAndIntercept RtlUnwind continue to unwind frames until we reach the handler protected by COMPlusNestedExceptionHandler. - pExInfo->m_InterceptionContext = context; - pExInfo->m_ValidInterceptionContext = TRUE; - STRESS_LOG0(LF_EH|LF_CORDB, LL_INFO100, "COMPlusUnwindCallback: Skip interception until unwinding reaches the actual handler protected by COMPlusNestedExceptionHandler\n"); - } - else - { - // - // Pop off all the Exception information up to this point in the stack - // - UnwindExceptionTrackerAndResumeInInterceptionFrame(pExInfo, &context); - } - return SWA_ABORT; -#endif // DEBUGGING_SUPPORTED -} // StackWalkAction COMPlusUnwindCallback () -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning (disable : 4740) // There is inline asm code in this function, which disables - // global optimizations. -#pragma warning (disable : 4731) -#endif -void ResumeAtJitEH(CrawlFrame* pCf, - BYTE* startPC, - EE_ILEXCEPTION_CLAUSE *EHClausePtr, - DWORD nestingLevel, - Thread *pThread, - BOOL unwindStack) -{ - // No dynamic contract here because this function doesn't return and destructors wouldn't be executed - WRAPPER_NO_CONTRACT; - - EHContext context; - - context.Setup(PCODE(startPC + EHClausePtr->HandlerStartPC), pCf->GetRegisterSet()); - - size_t * pShadowSP = NULL; // Write Esp to *pShadowSP before jumping to handler - size_t * pHandlerEnd = NULL; - - OBJECTREF throwable = PossiblyUnwrapThrowable(pThread->GetThrowable(), pCf->GetAssembly()); - - pCf->GetCodeManager()->FixContext(ICodeManager::CATCH_CONTEXT, - &context, - pCf->GetCodeInfo(), - EHClausePtr->HandlerStartPC, - nestingLevel, - throwable, - &pShadowSP, - &pHandlerEnd); - - if (pHandlerEnd) - { - *pHandlerEnd = EHClausePtr->HandlerEndPC; - } - - MethodDesc* pMethodDesc = pCf->GetCodeInfo()->GetMethodDesc(); - TADDR startAddress = pCf->GetCodeInfo()->GetStartAddress(); - if (InlinedCallFrame::FrameHasActiveCall(pThread->m_pFrame)) - { - // When unwinding an exception in ReadyToRun, the JIT_PInvokeEnd helper which unlinks the ICF from - // the thread will be skipped. This is because unlike jitted code, each pinvoke is wrapped by calls - // to the JIT_PInvokeBegin and JIT_PInvokeEnd helpers, which push and pop the ICF on the thread. The - // ICF is not linked at the method prolog and unlinked at the epilog when running R2R code. Since the - // JIT_PInvokeEnd helper will be skipped, we need to unlink the ICF here. If the executing method - // has another pinvoke, it will re-link the ICF again when the JIT_PInvokeBegin helper is called. - - // Check that the InlinedCallFrame is in the method with the exception handler. There can be other - // InlinedCallFrame somewhere up the call chain that is not related to the current exception - // handling. - - // See the usages for USE_PER_FRAME_PINVOKE_INIT for more information. - -#ifdef DEBUG - TADDR handlerFrameSP = pCf->GetRegisterSet()->SP; -#endif // DEBUG - // Find the ESP of the caller of the method with the exception handler. - bool unwindSuccess = pCf->GetCodeManager()->UnwindStackFrame(pCf->GetRegisterSet(), - pCf->GetCodeInfo(), - pCf->GetCodeManagerFlags()); - _ASSERTE(unwindSuccess); - - if (((TADDR)pThread->m_pFrame < pCf->GetRegisterSet()->SP)) - { - TADDR returnAddress = ((InlinedCallFrame*)pThread->m_pFrame)->m_pCallerReturnAddress; -#ifdef USE_PER_FRAME_PINVOKE_INIT - // If we're setting up the frame for each P/Invoke for the given platform, - // then we do this for all P/Invokes except ones in IL stubs. - if (returnAddress != NULL && !ExecutionManager::GetCodeMethodDesc(returnAddress)->IsILStub()) -#else - // If we aren't setting up the frame for each P/Invoke (instead setting up once per method), - // then ReadyToRun code is the only code using the per-P/Invoke logic. - if (ExecutionManager::IsReadyToRunCode(returnAddress)) -#endif - { - _ASSERTE((TADDR)pThread->m_pFrame >= handlerFrameSP); - pThread->m_pFrame->Pop(pThread); - } - } - } - - // save esp so that endcatch can restore it (it always restores, so want correct value) - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - pExInfo->m_dEsp = (LPVOID)context.GetSP(); - LOG((LF_EH, LL_INFO1000, "ResumeAtJitEH: current m_dEsp set to %p\n", context.GetSP())); - - PVOID dEsp = GetCurrentSP(); - - if (!unwindStack) - { - // If we don't want to unwind the stack, then the guard page had better not be gone! - _ASSERTE(pThread->DetermineIfGuardPagePresent()); - - // so down below won't really update esp - context.SetSP(dEsp); - pExInfo->m_pShadowSP = pShadowSP; // so that endcatch can zero it back - - if (pShadowSP) - { - *pShadowSP = (size_t)dEsp; - } - } - else - { - // so shadow SP has the real SP as we are going to unwind the stack - dEsp = (LPVOID)context.GetSP(); - - // BEGIN: pExInfo->UnwindExInfo(dEsp); - ExInfo *pPrevNestedInfo = pExInfo->m_pPrevNestedInfo; - - while (pPrevNestedInfo && pPrevNestedInfo->m_StackAddress < dEsp) - { - LOG((LF_EH, LL_INFO1000, "ResumeAtJitEH: popping nested ExInfo at 0x%p\n", pPrevNestedInfo->m_StackAddress)); - - pPrevNestedInfo->DestroyExceptionHandle(); - -#ifdef DEBUGGING_SUPPORTED - if (g_pDebugInterface != NULL) - { - g_pDebugInterface->DeleteInterceptContext(pPrevNestedInfo->m_DebuggerExState.GetDebuggerInterceptContext()); - } -#endif // DEBUGGING_SUPPORTED - - pPrevNestedInfo = pPrevNestedInfo->m_pPrevNestedInfo; - } - - pExInfo->m_pPrevNestedInfo = pPrevNestedInfo; - - _ASSERTE(pExInfo->m_pPrevNestedInfo == 0 || pExInfo->m_pPrevNestedInfo->m_StackAddress >= dEsp); - - // Before we unwind the SEH records, get the Frame from the top-most nested exception record. - Frame* pNestedFrame = GetCurrFrame(FindNestedEstablisherFrame(GetCurrentSEHRecord())); - - PopNestedExceptionRecords((LPVOID)(size_t)dEsp); - - EXCEPTION_REGISTRATION_RECORD* pNewBottomMostHandler = GetCurrentSEHRecord(); - - pExInfo->m_pShadowSP = pShadowSP; - - // The context and exception record are no longer any good. - _ASSERTE(pExInfo->m_pContext < dEsp); // It must be off the top of the stack. - pExInfo->m_pContext = 0; // Whack it. - pExInfo->m_pExceptionRecord = 0; - pExInfo->m_pExceptionPointers = 0; - - // We're going to put one nested record back on the stack before we resume. This is - // where it goes. - NestedHandlerExRecord *pNestedHandlerExRecord = (NestedHandlerExRecord*)((BYTE*)dEsp - ALIGN_UP(sizeof(NestedHandlerExRecord), STACK_ALIGN_SIZE)); - - // The point of no return. The next statement starts scribbling on the stack. It's - // deep enough that we won't hit our own locals. (That's important, 'cuz we're still - // using them.) - // - _ASSERTE(dEsp > &pCf); - pNestedHandlerExRecord->m_handlerInfo.m_hThrowable=NULL; // This is random memory. Handle - // must be initialized to null before - // calling Init(), as Init() will try - // to free any old handle. - pNestedHandlerExRecord->Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, pNestedFrame); - - INSTALL_EXCEPTION_HANDLING_RECORD(&(pNestedHandlerExRecord->m_ExReg)); - - context.SetSP(pNestedHandlerExRecord); - - // We might have moved the bottommost handler. The nested record itself is never - // the bottom most handler -- it's pushed after the fact. So we have to make the - // bottom-most handler the one BEFORE the nested record. - if (pExInfo->m_pBottomMostHandler < pNewBottomMostHandler) - { - STRESS_LOG3(LF_EH, LL_INFO10000, "ResumeAtJitEH: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", - pExInfo, pExInfo->m_pBottomMostHandler, pNewBottomMostHandler); - pExInfo->m_pBottomMostHandler = pNewBottomMostHandler; - } - - if (pShadowSP) - { - *pShadowSP = context.GetSP(); - } - } - - STRESS_LOG3(LF_EH, LL_INFO100, "ResumeAtJitEH: resuming at EIP = %p ESP = %p EBP = %p\n", - context.Eip, context.GetSP(), context.GetFP()); - -#ifdef STACK_GUARDS_DEBUG - // We are transitioning back to managed code, so ensure that we are in - // SO-tolerant mode before we do so. - RestoreSOToleranceState(); -#endif - - // we want this to happen as late as possible but certainly after the notification - // that the handle for the current ExInfo has been freed has been delivered - pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE); - - ETW::ExceptionLog::ExceptionCatchBegin(pMethodDesc, (PVOID)startAddress); - - ResumeAtJitEHHelper(&context); - UNREACHABLE_MSG("Should never return from ResumeAtJitEHHelper!"); - - // we do not set pExInfo->m_EHClauseInfo.m_fManagedCodeEntered = FALSE here, - // that happens when the catch clause calls back to COMPlusEndCatch - // we don't return to this point so it would be moot (see unreachable_msg above) - -} -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -// Must be in a separate function because INSTALL_COMPLUS_EXCEPTION_HANDLER has a filter -int CallJitEHFilterWorker(size_t *pShadowSP, EHContext *pContext) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - int retVal = EXCEPTION_CONTINUE_SEARCH; - - BEGIN_CALL_TO_MANAGED(); - - retVal = CallJitEHFilterHelper(pShadowSP, pContext); - - END_CALL_TO_MANAGED(); - - return retVal; -} - -int CallJitEHFilter(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, OBJECTREF thrownObj) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - int retVal = EXCEPTION_CONTINUE_SEARCH; - size_t * pShadowSP = NULL; - EHContext context; - - context.Setup(PCODE(startPC + EHClausePtr->FilterOffset), pCf->GetRegisterSet()); - - size_t * pEndFilter = NULL; // Write - pCf->GetCodeManager()->FixContext(ICodeManager::FILTER_CONTEXT, &context, pCf->GetCodeInfo(), - EHClausePtr->FilterOffset, nestingLevel, thrownObj, - &pShadowSP, &pEndFilter); - - // End of the filter is the same as start of handler - if (pEndFilter) - { - *pEndFilter = EHClausePtr->HandlerStartPC; - } - - // ExceptionFilterFrame serves two purposes: - // - // 1. It serves as a frame that stops the managed search for handler - // if we fault in the filter. ThrowCallbackType.pTopFrame is going point - // to this frame during search for exception handler inside filter. - // The search for handler needs a frame to stop. If we had no frame here, - // the exceptions in filters would not be swallowed correctly since we would - // walk past the EX_TRY/EX_CATCH block in COMPlusThrowCallbackHelper. - // - // 2. It allows setting of SHADOW_SP_FILTER_DONE flag in UnwindFrames() - // if we fault in the filter. We have to set this flag together with unwinding - // of the filter frame. Using a regular C++ holder to clear this flag here would cause - // GC holes. The stack would be in inconsistent state when we trigger gc just before - // returning from UnwindFrames. - - ExceptionFilterFrame exceptionFilterFrame(pShadowSP); - - ETW::ExceptionLog::ExceptionFilterBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress()); - - retVal = CallJitEHFilterWorker(pShadowSP, &context); - - ETW::ExceptionLog::ExceptionFilterEnd(); - - exceptionFilterFrame.Pop(); - - return retVal; -} - -void CallJitEHFinally(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel) -{ - WRAPPER_NO_CONTRACT; - - EHContext context; - context.Setup(PCODE(startPC + EHClausePtr->HandlerStartPC), pCf->GetRegisterSet()); - - size_t * pShadowSP = NULL; // Write Esp to *pShadowSP before jumping to handler - - size_t * pFinallyEnd = NULL; - pCf->GetCodeManager()->FixContext( - ICodeManager::FINALLY_CONTEXT, &context, pCf->GetCodeInfo(), - EHClausePtr->HandlerStartPC, nestingLevel, ObjectToOBJECTREF((Object *) NULL), - &pShadowSP, &pFinallyEnd); - - if (pFinallyEnd) - { - *pFinallyEnd = EHClausePtr->HandlerEndPC; - } - - ETW::ExceptionLog::ExceptionFinallyBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress()); - - CallJitEHFinallyHelper(pShadowSP, &context); - - ETW::ExceptionLog::ExceptionFinallyEnd(); - - // - // Update the registers using new context - // - // This is necessary to reflect GC pointer changes during the middle of a unwind inside a - // finally clause, because: - // 1. GC won't see the part of stack inside try (which has thrown an exception) that is already - // unwinded and thus GC won't update GC pointers for this portion of the stack, but rather the - // call stack in finally. - // 2. upon return of finally, the unwind process continues and unwinds stack based on the part - // of stack inside try and won't see the updated values in finally. - // As a result, we need to manually update the context using register values upon return of finally - // - // Note that we only update the registers for finally clause because - // 1. For filter handlers, stack walker is able to see the whole stack (including the try part) - // with the help of ExceptionFilterFrame as filter handlers are called in first pass - // 2. For catch handlers, the current unwinding is already finished - // - context.UpdateFrame(pCf->GetRegisterSet()); - - // This does not need to be guarded by a holder because the frame is dead if an exception gets thrown. Filters are different - // since they are run in the first pass, so we must update the shadowSP reset in CallJitEHFilter. - if (pShadowSP) { - *pShadowSP = 0; // reset the shadowSP to 0 - } -} -#if defined(_MSC_VER) -#pragma warning (default : 4731) -#endif - -//===================================================================== -// ********************************************************************* -BOOL ComPlusFrameSEH(EXCEPTION_REGISTRATION_RECORD* pEHR) -{ - LIMITED_METHOD_CONTRACT; - - return ((LPVOID)pEHR->Handler == (LPVOID)COMPlusFrameHandler || (LPVOID)pEHR->Handler == (LPVOID)COMPlusNestedExceptionHandler); -} - - -// -//------------------------------------------------------------------------- -// This is installed when we call COMPlusFrameHandler to provide a bound to -// determine when are within a nested exception -//------------------------------------------------------------------------- -EXCEPTION_HANDLER_IMPL(COMPlusNestedExceptionHandler) -{ - WRAPPER_NO_CONTRACT; - - if (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) - { - LOG((LF_EH, LL_INFO100, " COMPlusNestedHandler(unwind) with %x at %x\n", pExceptionRecord->ExceptionCode, - pContext ? GetIP(pContext) : 0)); - - - // We're unwinding past a nested exception record, which means that we've thrown - // a new exception out of a region in which we're handling a previous one. The - // previous exception is overridden -- and needs to be unwound. - - // The preceding is ALMOST true. There is one more case, where we use setjmp/longjmp - // from within a nested handler. We won't have a nested exception in that case -- just - // the unwind. - - Thread* pThread = GetThread(); - ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo); - ExInfo* pPrevNestedInfo = pExInfo->m_pPrevNestedInfo; - - if (pPrevNestedInfo == &((NestedHandlerExRecord*)pEstablisherFrame)->m_handlerInfo) - { - _ASSERTE(pPrevNestedInfo); - - LOG((LF_EH, LL_INFO100, "COMPlusNestedExceptionHandler: PopExInfo(): popping nested ExInfo at 0x%p\n", pPrevNestedInfo)); - - pPrevNestedInfo->DestroyExceptionHandle(); - -#ifdef DEBUGGING_SUPPORTED - if (g_pDebugInterface != NULL) - { - g_pDebugInterface->DeleteInterceptContext(pPrevNestedInfo->m_DebuggerExState.GetDebuggerInterceptContext()); - } -#endif // DEBUGGING_SUPPORTED - - pExInfo->m_pPrevNestedInfo = pPrevNestedInfo->m_pPrevNestedInfo; - - } else { - // The whacky setjmp/longjmp case. Nothing to do. - } - - } else { - LOG((LF_EH, LL_INFO100, " InCOMPlusNestedHandler with %x at %x\n", pExceptionRecord->ExceptionCode, - pContext ? GetIP(pContext) : 0)); - } - - - // There is a nasty "gotcha" in the way exception unwinding, finally's, and nested exceptions - // interact. Here's the scenario ... it involves two exceptions, one normal one, and one - // raised in a finally. - // - // The first exception occurs, and is caught by some handler way up the stack. That handler - // calls RtlUnwind -- and handlers that didn't catch this first exception are called again, with - // the UNWIND flag set. If, one of the handlers throws an exception during - // unwind (like, a throw from a finally) -- then that same handler is not called during - // the unwind pass of the second exception. [ASIDE: It is called on first-pass.] - // - // What that means is -- the COMPlusExceptionHandler, can't count on unwinding itself correctly - // if an exception is thrown from a finally. Instead, it relies on the NestedExceptionHandler - // that it pushes for this. - // - - EXCEPTION_DISPOSITION retval = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler); - LOG((LF_EH, LL_INFO100, "Leaving COMPlusNestedExceptionHandler with %d\n", retval)); - return retval; -} - -EXCEPTION_REGISTRATION_RECORD *FindNestedEstablisherFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) -{ - LIMITED_METHOD_CONTRACT; - - while (pEstablisherFrame->Handler != (PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler) { - pEstablisherFrame = pEstablisherFrame->Next; - _ASSERTE(pEstablisherFrame != EXCEPTION_CHAIN_END); // should always find one - } - return pEstablisherFrame; -} - -EXCEPTION_HANDLER_IMPL(FastNExportExceptHandler) -{ - WRAPPER_NO_CONTRACT; - - // Most of our logic is in commin with COMPlusFrameHandler. - EXCEPTION_DISPOSITION retval = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler); - -#ifdef _DEBUG - // If the exception is escaping the last CLR personality routine on the stack, - // then state a flag on the thread to indicate so. - if (retval == ExceptionContinueSearch) - { - SetReversePInvokeEscapingUnhandledExceptionStatus(IS_UNWINDING(pExceptionRecord->ExceptionFlags), pEstablisherFrame); - } -#endif // _DEBUG - - return retval; -} - -#ifdef FEATURE_COMINTEROP -// The reverse COM interop path needs to be sure to pop the ComMethodFrame that is pushed, but we do not want -// to have an additional FS:0 handler between the COM callsite and the call into managed. So we push this -// FS:0 handler, which will defer to the usual COMPlusFrameHandler and then perform the cleanup of the -// ComMethodFrame, if needed. -EXCEPTION_HANDLER_IMPL(COMPlusFrameHandlerRevCom) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_ANY; - - // Defer to COMPlusFrameHandler - EXCEPTION_DISPOSITION result = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler); - - if (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) - { - // Do cleanup as needed - ComMethodFrame::DoSecondPassHandlerCleanup(GetCurrFrame(pEstablisherFrame)); - } - - return result; -} -#endif // FEATURE_COMINTEROP -#endif // !DACCESS_COMPILE -#endif // !FEATURE_EH_FUNCLETS - PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(CONTEXT * pContext) { LIMITED_METHOD_DAC_CONTRACT; @@ -3233,21 +45,7 @@ PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(CONTEXT * pContext) #ifndef DACCESS_COMPILE LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv) { -#ifndef FEATURE_EH_FUNCLETS - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_ENTRY_POINT; - - LONG result = CLRVectoredExceptionHandler(pExceptionInfo); - - if (EXCEPTION_EXECUTE_HANDLER == result) - { - result = EXCEPTION_CONTINUE_SEARCH; - } - - return result; -#else // !FEATURE_EH_FUNCLETS return EXCEPTION_CONTINUE_SEARCH; -#endif // !FEATURE_EH_FUNCLETS } // Returns TRUE if caller should resume execution. diff --git a/src/coreclr/vm/i386/jithelp.asm b/src/coreclr/vm/i386/jithelp.asm index 58b4200a871b62..e131dee95a9312 100644 --- a/src/coreclr/vm/i386/jithelp.asm +++ b/src/coreclr/vm/i386/jithelp.asm @@ -73,10 +73,6 @@ EXTERN g_GCShadowEnd:DWORD INVALIDGCVALUE equ 0CCCCCCCDh endif -ifndef FEATURE_EH_FUNCLETS -EXTERN _COMPlusEndCatch@20:PROC -endif - .686P .XMM ; The following macro is needed because of a MASM issue with the @@ -1076,37 +1072,6 @@ _JIT_PatchedCodeEnd@0 proc public ret _JIT_PatchedCodeEnd@0 endp - -ifndef FEATURE_EH_FUNCLETS -; Note that the debugger skips this entirely when doing SetIP, -; since COMPlusCheckForAbort should always return 0. Excep.cpp:LeaveCatch -; asserts that to be true. If this ends up doing more work, then the -; debugger may need additional support. -; void __stdcall JIT_EndCatch(); -JIT_EndCatch PROC stdcall public - - ; make temp storage for return address, and push the address of that - ; as the last arg to COMPlusEndCatch - mov ecx, [esp] - push ecx; - push esp; - - ; push the rest of COMPlusEndCatch's args, right-to-left - push esi - push edi - push ebx - push ebp - - call _COMPlusEndCatch@20 ; returns old esp value in eax, stores jump address - ; now eax = new esp, [esp] = new eip - - pop edx ; edx = new eip - mov esp, eax ; esp = new esp - jmp edx ; eip = new eip - -JIT_EndCatch ENDP -endif - ; The following helper will access ("probe") a word on each page of the stack ; starting with the page right beneath esp down to the one pointed to by eax. ; The procedure is needed to make sure that the "guard" page is pushed down below the allocated stack frame. diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 9edf5b97eb33a1..cd97c0fe3d26df 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -54,9 +54,6 @@ #include "pgo_formatprocessing.h" #include "patchpointinfo.h" -#ifndef FEATURE_EH_FUNCLETS -#include "excep.h" -#endif #include "exinfo.h" #include "arraynative.inl" @@ -794,31 +791,11 @@ HCIMPL1(void, IL_Throw, Object* obj) FC_CAN_TRIGGER_GC(); -#ifdef FEATURE_EH_FUNCLETS if (oref == 0) DispatchManagedException(kNullReferenceException); NormalizeThrownObject(&oref); DispatchManagedException(oref, exceptionFrame.GetContext()); -#elif defined(TARGET_X86) - INSTALL_MANAGED_EXCEPTION_DISPATCHER; - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - -#if defined(_DEBUG) && defined(TARGET_X86) - g_ExceptionEIP = (PVOID)transitionBlock->m_ReturnAddress; -#endif // defined(_DEBUG) && defined(TARGET_X86) - - if (oref == 0) - COMPlusThrow(kNullReferenceException); - - NormalizeThrownObject(&oref); - RaiseTheExceptionInternalOnly(oref, FALSE); - - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; -#else // FEATURE_EH_FUNCLETS - PORTABILITY_ASSERT("IL_Throw"); -#endif // FEATURE_EH_FUNCLETS FC_CAN_TRIGGER_GC_END(); UNREACHABLE(); @@ -848,29 +825,7 @@ HCIMPL0(void, IL_Rethrow) FC_CAN_TRIGGER_GC(); -#ifdef FEATURE_EH_FUNCLETS DispatchRethrownManagedException(exceptionFrame.GetContext()); -#elif defined(TARGET_X86) - INSTALL_MANAGED_EXCEPTION_DISPATCHER; - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - - OBJECTREF throwable = GetThread()->GetThrowable(); - if (throwable != NULL) - { - RaiseTheExceptionInternalOnly(throwable, TRUE); - } - else - { - // This can only be the result of bad IL (or some internal EE failure). - _ASSERTE(!"No throwable on rethrow"); - RealCOMPlusThrow(kInvalidProgramException, (UINT)IDS_EE_RETHROW_NOT_ALLOWED); - } - - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; -#else // FEATURE_EH_FUNCLETS - PORTABILITY_ASSERT("IL_Rethrow"); -#endif // FEATURE_EH_FUNCLETS FC_CAN_TRIGGER_GC_END(); UNREACHABLE(); @@ -904,23 +859,7 @@ HCIMPL1(void, IL_ThrowExact, Object* obj) FC_CAN_TRIGGER_GC(); -#ifdef FEATURE_EH_FUNCLETS DispatchManagedException(oref, exceptionFrame.GetContext()); -#elif defined(TARGET_X86) - INSTALL_MANAGED_EXCEPTION_DISPATCHER; - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - -#if defined(_DEBUG) && defined(TARGET_X86) - g_ExceptionEIP = (PVOID)transitionBlock->m_ReturnAddress; -#endif // defined(_DEBUG) && defined(TARGET_X86) - - RaiseTheExceptionInternalOnly(oref, FALSE); - - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; -#else // FEATURE_EH_FUNCLETS - PORTABILITY_ASSERT("IL_ThrowExact"); -#endif // FEATURE_EH_FUNCLETS FC_CAN_TRIGGER_GC_END(); UNREACHABLE(); @@ -2265,10 +2204,6 @@ Thread * JIT_InitPInvokeFrame(InlinedCallFrame *pFrame) EXTERN_C void JIT_PInvokeBegin(InlinedCallFrame* pFrame); EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame); -#ifndef FEATURE_EH_FUNCLETS -EXCEPTION_HANDLER_DECL(FastNExportExceptHandler); -#endif - #ifdef DEBUGGING_SUPPORTED void DebuggerTraceCall(void* returnAddr, void* thunkDataMaybe) { @@ -2378,15 +2313,9 @@ HCIMPL3_RAW(void, JIT_ReversePInvokeEnterTrackTransitions, ReversePInvokeFrame* } #if defined(TARGET_X86) && defined(TARGET_WINDOWS) -#ifndef FEATURE_EH_FUNCLETS - frame->record.m_pEntryFrame = frame->currentThread->GetFrame(); - frame->record.m_ExReg.Handler = (PEXCEPTION_ROUTINE)FastNExportExceptHandler; - INSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg); -#else frame->m_ExReg.Handler = (PEXCEPTION_ROUTINE)ProcessCLRException; INSTALL_SEH_RECORD(&frame->m_ExReg); #endif -#endif } HCIMPLEND_RAW @@ -2416,15 +2345,9 @@ HCIMPL1_RAW(void, JIT_ReversePInvokeEnter, ReversePInvokeFrame* frame) } #if defined(TARGET_X86) && defined(TARGET_WINDOWS) -#ifndef FEATURE_EH_FUNCLETS - frame->record.m_pEntryFrame = frame->currentThread->GetFrame(); - frame->record.m_ExReg.Handler = (PEXCEPTION_ROUTINE)FastNExportExceptHandler; - INSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg); -#else frame->m_ExReg.Handler = (PEXCEPTION_ROUTINE)ProcessCLRException; INSTALL_SEH_RECORD(&frame->m_ExReg); #endif -#endif } HCIMPLEND_RAW @@ -2439,12 +2362,8 @@ HCIMPL1_RAW(void, JIT_ReversePInvokeExitTrackTransitions, ReversePInvokeFrame* f frame->currentThread->m_fPreemptiveGCDisabled.StoreWithoutBarrier(0); #if defined(TARGET_X86) && defined(TARGET_WINDOWS) -#ifndef FEATURE_EH_FUNCLETS - UNINSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg); -#else UNINSTALL_SEH_RECORD(&frame->m_ExReg); #endif -#endif #ifdef PROFILING_SUPPORTED if (CORProfilerTrackTransitions()) @@ -2466,12 +2385,8 @@ HCIMPL1_RAW(void, JIT_ReversePInvokeExit, ReversePInvokeFrame* frame) frame->currentThread->m_fPreemptiveGCDisabled.StoreWithoutBarrier(0); #if defined(TARGET_X86) && defined(TARGET_WINDOWS) -#ifndef FEATURE_EH_FUNCLETS - UNINSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg); -#else UNINSTALL_SEH_RECORD(&frame->m_ExReg); #endif -#endif } HCIMPLEND_RAW diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c1b7cf068f34c4..84c5fe782bed2a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11128,11 +11128,9 @@ void CEEJitInfo::WriteCode(EECodeGenManager * jitMgr) // Now that the code header was written to the final location, publish the code via the nibble map NibbleMapSet(); -#if defined(FEATURE_EH_FUNCLETS) // Publish the new unwind information in a way that the ETW stack crawler can find _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos); UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, ((CodeHeader*)m_CodeHeader)->GetUnwindInfo(0), m_totalUnwindInfos); -#endif // defined(FEATURE_EH_FUNCLETS) } /*********************************************************************/ @@ -11362,12 +11360,8 @@ void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs) pArgs->hotCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); } - m_jitManager->AllocCode(m_pMethodBeingCompiled, totalSize.Value(), 0, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap - , &m_pRealCodeHeader -#ifdef FEATURE_EH_FUNCLETS - , 0 -#endif - ); + m_jitManager->AllocCode(m_pMethodBeingCompiled, totalSize.Value(), 0, pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, + &m_codeWriteBufferSize, &m_pCodeHeap, &m_pRealCodeHeader, 0); BYTE* current = (BYTE *)((InterpreterCodeHeader*)m_CodeHeader)->GetCodeStartAddress(); @@ -11584,7 +11578,6 @@ void reservePersonalityRoutineSpace(uint32_t &unwindSize) // void CEEJitInfo::reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize) { -#ifdef FEATURE_EH_FUNCLETS CONTRACTL { NOTHROW; GC_NOTRIGGER; @@ -11609,10 +11602,6 @@ void CEEJitInfo::reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unw m_totalUnwindInfos++; EE_TO_JIT_TRANSITION_LEAF(); -#else // FEATURE_EH_FUNCLETS - LIMITED_METHOD_CONTRACT; - // Dummy implementation to make cross-platform altjit work -#endif // FEATURE_EH_FUNCLETS } // Allocate and initialize the .rdata and .pdata for this method or @@ -11645,7 +11634,6 @@ void CEEJitInfo::allocUnwindInfo ( CorJitFuncKind funcKind /* IN */ ) { -#ifdef FEATURE_EH_FUNCLETS CONTRACTL { THROWS; GC_TRIGGERS; @@ -11776,10 +11764,6 @@ void CEEJitInfo::allocUnwindInfo ( #endif EE_TO_JIT_TRANSITION(); -#else // FEATURE_EH_FUNCLETS - LIMITED_METHOD_CONTRACT; - // Dummy implementation to make cross-platform altjit work -#endif // FEATURE_EH_FUNCLETS } void CEEJitInfo::recordCallSite(uint32_t instrOffset, @@ -12693,10 +12677,8 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) totalSize += pArgs->roDataSize; } -#ifdef FEATURE_EH_FUNCLETS totalSize.AlignUp(sizeof(DWORD)); totalSize += m_totalUnwindSize; -#endif _ASSERTE(m_CodeHeader == 0 && // The jit-compiler sometimes tries to compile a method a second time @@ -12727,16 +12709,10 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId()); } - m_jitManager->AllocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap - , &m_pRealCodeHeader -#ifdef FEATURE_EH_FUNCLETS - , m_totalUnwindInfos -#endif - ); + m_jitManager->AllocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, + &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap, &m_pRealCodeHeader, m_totalUnwindInfos); -#ifdef FEATURE_EH_FUNCLETS m_moduleBase = m_pCodeHeap->GetModuleBase(); -#endif BYTE* current = (BYTE *)((CodeHeader*)m_CodeHeader)->GetCodeStartAddress(); size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader; @@ -12758,12 +12734,10 @@ void CEEJitInfo::allocMem (AllocMemArgs *pArgs) pArgs->roDataBlockRW = NULL; } -#ifdef FEATURE_EH_FUNCLETS current = (BYTE *)ALIGN_UP(current, sizeof(DWORD)); m_theUnwindBlock = current; current += m_totalUnwindSize; -#endif _ASSERTE((SIZE_T)(current - (BYTE *)((CodeHeader*)m_CodeHeader)->GetCodeStartAddress()) <= totalSize.Value()); @@ -15107,10 +15081,8 @@ EECodeInfo::EECodeInfo() m_pMD = NULL; m_relOffset = 0; -#ifdef FEATURE_EH_FUNCLETS m_pFunctionEntry = NULL; m_isFuncletCache = IsFuncletCache::NotSet; -#endif #ifdef TARGET_X86 m_hdrInfoTable = NULL; @@ -15135,9 +15107,7 @@ void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag) } CONTRACTL_END; m_codeAddress = codeAddress; -#ifdef FEATURE_EH_FUNCLETS m_isFuncletCache = IsFuncletCache::NotSet; -#endif #ifdef TARGET_X86 m_hdrInfoTable = NULL; @@ -15157,10 +15127,7 @@ void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag) m_pJM = NULL; m_pMD = NULL; m_relOffset = 0; - -#ifdef FEATURE_EH_FUNCLETS m_pFunctionEntry = NULL; -#endif } TADDR EECodeInfo::GetSavedMethodCode() @@ -15229,8 +15196,6 @@ NativeCodeVersion EECodeInfo::GetNativeCodeVersion() const return NativeCodeVersion(pMD); } -#if defined(FEATURE_EH_FUNCLETS) - // ---------------------------------------------------------------------------- // EECodeInfo::GetMainFunctionInfo // @@ -15250,9 +15215,7 @@ EECodeInfo EECodeInfo::GetMainFunctionInfo() result.m_relOffset = 0; result.m_codeAddress = this->GetStartAddress(); result.m_pFunctionEntry = NULL; -#ifdef FEATURE_EH_FUNCLETS result.m_isFuncletCache = IsFuncletCache::IsNotFunclet; -#endif return result; } @@ -15302,8 +15265,6 @@ BOOL EECodeInfo::HasFrameRegister() } #endif // defined(TARGET_AMD64) -#endif // defined(FEATURE_EH_FUNCLETS) - #if defined(TARGET_X86) PTR_CBYTE EECodeInfo::DecodeGCHdrInfoHelper(hdrInfo ** infoPtr) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index f996c133a03088..89fa3099cb653b 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1,12 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // =========================================================================== // File: JITinterface.H // - // =========================================================================== - #ifndef JITINTERFACE_H #define JITINTERFACE_H @@ -263,10 +262,6 @@ void ValidateWriteBarrierHelpers(); extern "C" { -#ifndef FEATURE_EH_FUNCLETS - void STDCALL JIT_EndCatch(); // JIThelp.asm/JIThelp.s -#endif // FEATURE_EH_FUNCLETS - void STDCALL JIT_ByRefWriteBarrier(); // JIThelp.asm/JIThelp.s #if defined(TARGET_X86) && !defined(UNIX_X86_ABI) @@ -741,14 +736,12 @@ class CEEJitInfo final : public CEECodeGenInfo m_pPatchpointInfoFromJit = NULL; #endif -#ifdef FEATURE_EH_FUNCLETS m_moduleBase = (TADDR)0; m_totalUnwindSize = 0; m_usedUnwindSize = 0; m_theUnwindBlock = NULL; m_totalUnwindInfos = 0; m_usedUnwindInfos = 0; -#endif // FEATURE_EH_FUNCLETS } #if defined(TARGET_AMD64) || defined(TARGET_RISCV64) @@ -829,14 +822,12 @@ class CEEJitInfo final : public CEECodeGenInfo CEEJitInfo(PrepareCodeConfig* config, MethodDesc* fd, COR_ILMETHOD_DECODER* header, EECodeGenManager* jm) : CEECodeGenInfo(config, fd, header, jm) -#ifdef FEATURE_EH_FUNCLETS , m_moduleBase(0), m_totalUnwindSize(0), m_usedUnwindSize(0), m_theUnwindBlock(NULL), m_totalUnwindInfos(0), m_usedUnwindInfos(0) -#endif #if defined(TARGET_AMD64) || defined(TARGET_RISCV64) , m_fAllowRel32(FALSE) #endif @@ -922,15 +913,12 @@ protected : ComputedPgoData* m_foundPgoData = nullptr; #endif - -#ifdef FEATURE_EH_FUNCLETS TADDR m_moduleBase; // Base for unwind Infos ULONG m_totalUnwindSize; // Total reserved unwind space uint32_t m_usedUnwindSize; // used space in m_theUnwindBlock BYTE * m_theUnwindBlock; // start of the unwind memory block ULONG m_totalUnwindInfos; // Number of RUNTIME_FUNCTION needed ULONG m_usedUnwindInfos; -#endif #if defined(TARGET_AMD64) || defined(TARGET_RISCV64) BOOL m_fAllowRel32; // Use 32-bit PC relative address modes diff --git a/src/coreclr/vm/loongarch64/excepcpu.h b/src/coreclr/vm/loongarch64/excepcpu.h index 8d2e1fdbbd2c07..acdb6cf2f9d58d 100644 --- a/src/coreclr/vm/loongarch64/excepcpu.h +++ b/src/coreclr/vm/loongarch64/excepcpu.h @@ -14,12 +14,6 @@ EXTERN_C void RedirectForThreadAbort(); class Thread; class FaultingExceptionFrame; -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) -// On LOONGARCH, the COMPlusFrameHandler's work is done by our personality routine. ??? -// -#define DECLARE_CPFH_EH_RECORD(pCurThread) - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 9394f6b9b8ad93..db92be31a188f3 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // =========================================================================== // File: Prestub.cpp // @@ -1733,13 +1734,10 @@ extern "C" size_t CallDescrWorkerInternalReturnAddressOffset; bool IsCallDescrWorkerInternalReturnAddress(PCODE pCode) { LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_EH_FUNCLETS + size_t CallDescrWorkerInternalReturnAddress = (size_t)CallDescrWorkerInternal + CallDescrWorkerInternalReturnAddressOffset; return pCode == CallDescrWorkerInternalReturnAddress; -#else // FEATURE_EH_FUNCLETS - return false; -#endif // FEATURE_EH_FUNCLETS } //============================================================================= diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index e9b57d15af94af..1b967e4b37cf0f 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -8022,10 +8022,7 @@ typedef struct _PROFILER_STACK_WALK_DATA ULONG32 infoFlags; ULONG32 contextFlags; void *clientData; - -#ifdef FEATURE_EH_FUNCLETS StackFrame sfParent; -#endif } PROFILER_STACK_WALK_DATA; @@ -8057,7 +8054,6 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D CONTEXT builtContext; #endif -#ifdef FEATURE_EH_FUNCLETS // // Skip all managed exception handling functions // @@ -8068,7 +8064,6 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D { return SWA_CONTINUE; } -#endif // FEATURE_EH_FUNCLETS // // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want @@ -8088,7 +8083,6 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D return SWA_CONTINUE; } -#ifdef FEATURE_EH_FUNCLETS if (!pCf->IsFrameless() && InlinedCallFrame::FrameHasActiveCall(pCf->GetFrame())) { // Skip new exception handling helpers @@ -8100,7 +8094,6 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D return SWA_CONTINUE; } } -#endif // FEATURE_EH_FUNCLETS // // If this is not a transition of any sort and not a managed @@ -8877,9 +8870,8 @@ HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread, data.infoFlags = infoFlags; data.contextFlags = 0; data.clientData = clientData; -#ifdef FEATURE_EH_FUNCLETS + data.sfParent.Clear(); -#endif // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions. // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 7c3e125b375aa2..de9009ad992fd0 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // Describes all of the P/Invokes to the special QCall module that resolves to internal runtime methods. + #include "common.h" // @@ -511,14 +513,12 @@ static const Entry s_QCall[] = DllImportEntry(ComWeakRefToObject) DllImportEntry(ObjectToComWeakRef) #endif -#ifdef FEATURE_EH_FUNCLETS DllImportEntry(SfiInit) DllImportEntry(SfiNext) DllImportEntry(CallFilterFunclet) DllImportEntry(EHEnumInitFromStackFrameIterator) DllImportEntry(EHEnumNext) DllImportEntry(AppendExceptionStackFrame) -#endif // FEATURE_EH_FUNCLETS DllImportEntry(InitClassHelper) DllImportEntry(ResolveVirtualFunctionPointer) DllImportEntry(GetThreadStaticsByMethodTable) diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index 4b678da07a0d13..3cd42e18b8ff5a 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -366,7 +366,7 @@ PTR_MethodDesc ReadyToRunInfo::GetMethodDescForEntryPointInNativeImage(PCODE ent } CONTRACTL_END; -#if defined(TARGET_AMD64) || (defined(TARGET_X86) && defined(FEATURE_EH_FUNCLETS)) +#if defined(TARGET_AMD64) || defined(TARGET_X86) // A normal method entry point is always 8 byte aligned, but a funclet can start at an odd address. // Since PtrHashMap can't handle odd pointers, check for this case and return NULL. if ((entryPoint & 0x1) != 0) diff --git a/src/coreclr/vm/riscv64/excepcpu.h b/src/coreclr/vm/riscv64/excepcpu.h index 416828487517d8..37e2dc6529ea8d 100644 --- a/src/coreclr/vm/riscv64/excepcpu.h +++ b/src/coreclr/vm/riscv64/excepcpu.h @@ -1,29 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// - #ifndef __excepcpu_h__ #define __excepcpu_h__ - #define THROW_CONTROL_FOR_THREAD_FUNCTION RedirectForThreadAbort EXTERN_C void RedirectForThreadAbort(); - #define STATUS_CLR_GCCOVER_CODE STATUS_ILLEGAL_INSTRUCTION class Thread; class FaultingExceptionFrame; -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) -// -// On ARM, the COMPlusFrameHandler's work is done by our personality routine. -// -#define DECLARE_CPFH_EH_RECORD(pCurThread) - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index d7bd9429af332a..4eb5c9aceedd7e 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1,8 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// STACKWALK.CPP - +// STACKWALK.CPP #include "common.h" #include "frames.h" @@ -315,7 +314,6 @@ void CrawlFrame::SetCurGSCookie(GSCookie * pGSCookie) #endif // !DACCESS_COMPILE } -#if defined(FEATURE_EH_FUNCLETS) bool CrawlFrame::IsFilterFunclet() { WRAPPER_NO_CONTRACT; @@ -334,102 +332,6 @@ bool CrawlFrame::IsFilterFunclet() return isFilterFunclet; } -#endif // FEATURE_EH_FUNCLETS - -//****************************************************************************** -#if defined(ELIMINATE_FEF) -//****************************************************************************** -// Advance to the next ExInfo. Typically done when an ExInfo has been used and -// should not be used again. -//****************************************************************************** -void ExInfoWalker::WalkOne() -{ - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - - if (m_pExInfo) - { - LOG((LF_EH, LL_INFO10000, "ExInfoWalker::WalkOne: advancing ExInfo chain: pExInfo:%p, pContext:%p; prev:%p, pContext:%p\n", - m_pExInfo, m_pExInfo->m_pContext, m_pExInfo->m_pPrevNestedInfo, m_pExInfo->m_pPrevNestedInfo?m_pExInfo->m_pPrevNestedInfo->m_pContext:0)); - m_pExInfo = m_pExInfo->m_pPrevNestedInfo; - } -} // void ExInfoWalker::WalkOne() - -//****************************************************************************** -// Attempt to find an ExInfo with a pContext that is higher (older) than -// a given minimum location. (It is the pContext's SP that is relevant.) -//****************************************************************************** -void ExInfoWalker::WalkToPosition( - TADDR taMinimum, // Starting point of stack walk. - BOOL bPopFrames) // If true, ResetUseExInfoForStackwalk on each exinfo. -{ - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - - while (m_pExInfo && - ((GetSPFromContext() < taMinimum) || - (GetSPFromContext() == NULL)) ) - { - // Try the next ExInfo, if there is one. - LOG((LF_EH, LL_INFO10000, - "ExInfoWalker::WalkToPosition: searching ExInfo chain: m_pExInfo:%p, pContext:%p; \ - prev:%p, pContext:%p; pStartFrame:%p\n", - m_pExInfo, - m_pExInfo->m_pContext, - m_pExInfo->m_pPrevNestedInfo, - (m_pExInfo->m_pPrevNestedInfo ? m_pExInfo->m_pPrevNestedInfo->m_pContext : 0), - taMinimum)); - - if (bPopFrames) - { // If caller asked for it, reset the bit which indicates that this ExInfo marks a fault from managed code. - // This is done so that the fault can be effectively "unwound" from the stack, similarly to how Frames - // are unlinked from the Frame chain. - m_pExInfo->m_ExceptionFlags.ResetUseExInfoForStackwalk(); - } - m_pExInfo = m_pExInfo->m_pPrevNestedInfo; - } - // At this point, m_pExInfo is NULL, or points to a pContext that is greater than taMinimum. -} // void ExInfoWalker::WalkToPosition() - -//****************************************************************************** -// Attempt to find an ExInfo with a pContext that has an IP in managed code. -//****************************************************************************** -void ExInfoWalker::WalkToManaged() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - - while (m_pExInfo) - { - // See if the current ExInfo has a CONTEXT that "returns" to managed code, and, if so, exit the loop. - if (m_pExInfo->m_ExceptionFlags.UseExInfoForStackwalk() && - GetContext() && - ExecutionManager::IsManagedCode(GetIP(GetContext()))) - { - break; - } - // No, so skip to next, if any. - LOG((LF_EH, LL_INFO1000, "ExInfoWalker::WalkToManaged: searching for ExInfo->managed: m_pExInfo:%p, pContext:%p, sp:%p; prev:%p, pContext:%p\n", - m_pExInfo, - GetContext(), - GetSPFromContext(), - m_pExInfo->m_pPrevNestedInfo, - m_pExInfo->m_pPrevNestedInfo?m_pExInfo->m_pPrevNestedInfo->m_pContext:0)); - m_pExInfo = m_pExInfo->m_pPrevNestedInfo; - } - // At this point, m_pExInfo is NULL, or points to a pContext that has an IP in managed code. -} // void ExInfoWalker::WalkToManaged() -#endif // defined(ELIMINATE_FEF) - -#ifdef FEATURE_EH_FUNCLETS - // static UINT_PTR Thread::VirtualUnwindCallFrame(PREGDISPLAY pRD, EECodeInfo* pCodeInfo /*= NULL*/) { @@ -783,7 +685,6 @@ UINT_PTR Thread::VirtualUnwindToFirstManagedCallFrame(T_CONTEXT* pContext) } #endif // !DACCESS_COMPILE -#endif // FEATURE_EH_FUNCLETS #ifdef _DEBUG void Thread::DebugLogStackWalkInfo(CrawlFrame* pCF, _In_z_ LPCSTR pszTag, UINT32 uFramesProcessed) @@ -794,13 +695,11 @@ void Thread::DebugLogStackWalkInfo(CrawlFrame* pCF, _In_z_ LPCSTR pszTag, UINT32 { LPCSTR pszType = ""; -#ifdef FEATURE_EH_FUNCLETS if (pCF->IsFunclet()) { pszType = "[funclet]"; } else -#endif // FEATURE_EH_FUNCLETS if (pCF->pFunc->IsNoMetadata()) { pszType = "[no metadata]"; @@ -878,11 +777,6 @@ StackWalkAction Thread::MakeStackwalkerCallback( } -#if !defined(DACCESS_COMPILE) && defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) -#define STACKWALKER_MAY_POP_FRAMES -#endif - - StackWalkAction Thread::StackWalkFramesEx( PREGDISPLAY pRD, // virtual register set at crawl start PSTACKWALKFRAMESCALLBACK pCallback, @@ -1105,16 +999,12 @@ void StackFrameIterator::CommonCtor(Thread * pThread, PTR_Frame pFrame, ULONG32 m_pCachedGSCookie = NULL; -#if defined(FEATURE_EH_FUNCLETS) m_sfParent = StackFrame(); ResetGCRefReportingState(); m_fDidFuncletReportGCReferences = true; m_isRuntimeWrappedExceptions = false; -#endif // FEATURE_EH_FUNCLETS m_fFoundFirstFunclet = false; -#if defined(RECORD_RESUMABLE_FRAME_SP) m_pvResumableFrameTargetSP = NULL; -#endif } // StackFrameIterator::CommonCtor() //--------------------------------------------------------------------------------------- @@ -1152,10 +1042,8 @@ BOOL StackFrameIterator::Init(Thread * pThread, _ASSERTE(pThread != NULL); _ASSERTE(pRegDisp != NULL); -#ifdef FEATURE_EH_FUNCLETS _ASSERTE(!(flags & POPFRAMES)); _ASSERTE(pRegDisp->pCurrentContext); -#endif // FEATURE_EH_FUNCLETS BEGIN_FORBID_TYPELOAD(); @@ -1199,17 +1087,7 @@ BOOL StackFrameIterator::Init(Thread * pThread, (((flags & (QUICKUNWIND | LIGHTUNWIND)) ? 0 : UpdateAllRegs) | ((flags & LIGHTUNWIND) ? LightUnwind : 0)); m_scanFlag = ExecutionManager::GetScanFlags(); -#if defined(ELIMINATE_FEF) - // Walk the ExInfo chain, past any specified starting frame. - m_exInfoWalk.Init(&(pThread->GetExceptionState()->m_currentExInfo)); - // false means don't reset UseExInfoForStackwalk - m_exInfoWalk.WalkToPosition(dac_cast(m_pStartFrame), false); -#endif // ELIMINATE_FEF - -#ifdef FEATURE_EH_FUNCLETS - m_pNextExInfo = (PTR_ExInfo)pThread->GetExceptionState()->GetCurrentExceptionTracker(); -#endif // FEATURE_EH_FUNCLETS // // These fields are used in the iteration and will be updated on a per-frame basis: @@ -1225,12 +1103,10 @@ BOOL StackFrameIterator::Init(Thread * pThread, // process the REGDISPLAY and stop at the first frame ProcessIp(GetControlPC(m_crawl.pRD)); -#ifdef FEATURE_EH_FUNCLETS if (m_crawl.isFrameless && !!(m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE)) { m_crawl.hasFaulted = true; } -#endif // FEATURE_EH_FUNCLETS ProcessCurrentFrame(); // advance to the next frame which matches the stackwalk flags @@ -1309,7 +1185,6 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, { TADDR curSP = GetRegdisplaySP(m_crawl.pRD); -#ifdef PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME if (m_crawl.IsFrameless()) { // On 64-bit and ARM, we stop at the explicit frames contained in a managed stack frame @@ -1317,7 +1192,6 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, m_crawl.GetCodeManager()->EnsureCallerContextIsValid(m_crawl.pRD, NULL, m_codeManFlags); curSP = GetSP(m_crawl.pRD->pCallerContext); } -#endif // PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME #if defined(TARGET_X86) // special processing on x86; see below for more information @@ -1401,13 +1275,6 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, } } -#if defined(ELIMINATE_FEF) - // Similarly, we need to walk the ExInfos. - m_exInfoWalk.Init(&(m_crawl.pThread->GetExceptionState()->m_currentExInfo)); - // false means don't reset UseExInfoForStackwalk - m_exInfoWalk.WalkToPosition(GetRegdisplaySP(m_crawl.pRD), false); -#endif // ELIMINATE_FEF - // now that everything is at where it should be, update the CrawlFrame ProcessCurrentFrame(); @@ -1453,12 +1320,10 @@ void StackFrameIterator::ResetCrawlFrame() m_crawl.taNoFrameTransitionMarker = (TADDR)NULL; -#if defined(FEATURE_EH_FUNCLETS) m_crawl.isFilterFunclet = false; m_crawl.isFilterFuncletCached = false; m_crawl.fShouldParentToFuncletSkipReportingGCReferences = false; m_crawl.fShouldParentFrameUseUnwindTargetPCforGCReporting = false; -#endif // FEATURE_EH_FUNCLETS m_crawl.pThread = this->m_pThread; @@ -1493,14 +1358,6 @@ BOOL StackFrameIterator::IsValid(void) return TRUE; } -#if defined(ELIMINATE_FEF) - // Not in managed code, and no frames left -- check for an ExInfo. - // @todo: check for exception? - m_exInfoWalk.WalkToManaged(); - if (m_exInfoWalk.GetContext()) - return TRUE; -#endif // ELIMINATE_FEF - #ifdef _DEBUG // Try to ensure that the frame chain did not change underneath us. // In particular, is thread's starting frame the same as it was when @@ -1542,7 +1399,6 @@ BOOL StackFrameIterator::IsValid(void) } // StackFrameIterator::IsValid() #ifndef DACCESS_COMPILE -#ifdef FEATURE_EH_FUNCLETS //--------------------------------------------------------------------------------------- // // Advance to the position that the other iterator is currently at. @@ -1610,7 +1466,6 @@ void StackFrameIterator::SkipTo(StackFrameIterator *pOtherStackFrameIterator) } SyncRegDisplayToCurrentContext(pRD); } -#endif // FEATURE_EH_FUNCLETS #endif // DACCESS_COMPILE //--------------------------------------------------------------------------------------- @@ -1668,10 +1523,8 @@ StackWalkAction StackFrameIterator::Filter(void) bool fStop = false; bool fSkippingFunclet = false; -#if defined(FEATURE_EH_FUNCLETS) bool fRecheckCurrentFrame = false; bool fSkipFuncletCallback = true; -#endif // defined(FEATURE_EH_FUNCLETS) StackWalkAction retVal = SWA_CONTINUE; @@ -1680,7 +1533,6 @@ StackWalkAction StackFrameIterator::Filter(void) fStop = false; fSkippingFunclet = false; -#if defined(FEATURE_EH_FUNCLETS) ExInfo* pExInfo = NULL; pExInfo = (PTR_ExInfo)m_crawl.pThread->GetExceptionState()->GetCurrentExceptionTracker(); @@ -1707,12 +1559,10 @@ StackWalkAction StackFrameIterator::Filter(void) // we are now skipping frames to get to the funclet's parent fSkippingFunclet = true; } -#endif // FEATURE_EH_FUNCLETS switch (m_frameState) { case SFITER_FRAMELESS_METHOD: -#if defined(FEATURE_EH_FUNCLETS) ProcessFuncletsForGCReporting: do { @@ -2134,22 +1984,6 @@ StackWalkAction StackFrameIterator::Filter(void) } } -#else // FEATURE_EH_FUNCLETS - // Skip IL stubs - if (m_flags & FUNCTIONSONLY) - { - if (m_crawl.pFunc->IsDiagnosticsHidden()) - { - LOG((LF_GCROOTS, LL_INFO100000, - "STACKWALK: IS_DIAGNOSTICS_HIDDEN: not making callback for this frame, m_crawl.pFunc = %s\n", - m_crawl.pFunc->m_pszDebugMethodName)); - - // don't stop here - break; - } - } -#endif // FEATURE_EH_FUNCLETS - fStop = true; break; @@ -2161,7 +1995,6 @@ StackWalkAction StackFrameIterator::Filter(void) case SFITER_SKIPPED_FRAME_FUNCTION: if (!fSkippingFunclet) { -#if defined(FEATURE_EH_FUNCLETS) if (m_flags & GC_FUNCLET_REFERENCE_REPORTING) { // If we are enumerating frames for GC reporting and we determined that @@ -2183,7 +2016,6 @@ StackWalkAction StackFrameIterator::Filter(void) break; } } -#endif // FEATURE_EH_FUNCLETS if ( (m_crawl.pFunc != NULL) || !(m_flags & FUNCTIONSONLY) ) { fStop = true; @@ -2336,16 +2168,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) } else { -#ifndef PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME - // On x86, we process a managed stack frame before processing any explicit frames contained in it. - // So when we are done with the skipped explicit frame, we have already processed the managed - // stack frame, and it is time to move onto the next stack frame. - PostProcessingForManagedFrames(); - if (m_frameState == SFITER_NATIVE_MARKER_FRAME) - { - goto Cleanup; - } -#else // !PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME // We are done handling the skipped explicit frame at this point. So move on to the // managed stack frame. m_crawl.isFrameless = true; @@ -2355,7 +2177,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) PreProcessingForManagedFrames(); goto Cleanup; -#endif // PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME } } else if (m_frameState == SFITER_FRAMELESS_METHOD) @@ -2412,13 +2233,11 @@ StackWalkAction StackFrameIterator::NextRaw(void) #endif // STACKWALKER_MAY_POP_FRAMES #endif // TARGET_X86 -#if !defined(ELIMINATE_FEF) // FaultingExceptionFrame is special case where it gets // pushed on the stack after the frame is running _ASSERTE((m_crawl.pFrame == FRAME_TOP) || ((TADDR)GetRegdisplaySP(m_crawl.pRD) < dac_cast(m_crawl.pFrame)) || (m_crawl.pFrame->GetFrameIdentifier() == FrameIdentifier::FaultingExceptionFrame)); -#endif // !defined(ELIMINATE_FEF) // Get rid of the frame (actually, it isn't really popped) @@ -2480,15 +2299,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) m_crawl.hasFaulted = false; m_crawl.isIPadjusted = false; -#ifndef PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME - // remember, x86 handles the managed stack frame before the explicit frames contained in it - if (CheckForSkippedFrames()) - { - _ASSERTE(m_frameState == SFITER_SKIPPED_FRAME_FUNCTION); - goto Cleanup; - } -#endif // !PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME - PostProcessingForManagedFrames(); if (m_frameState == SFITER_NATIVE_MARKER_FRAME) { @@ -2534,7 +2344,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) { m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD, m_flags & UNWIND_FLOATS); -#if defined(RECORD_RESUMABLE_FRAME_SP) CONSISTENCY_CHECK(NULL == m_pvResumableFrameTargetSP); if (m_crawl.isFirst) @@ -2555,14 +2364,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) m_crawl.GetCodeManager()->EnsureCallerContextIsValid(m_crawl.pRD, NULL, m_codeManFlags); m_pvResumableFrameTargetSP = (LPVOID)GetSP(m_crawl.pRD->pCallerContext); } -#endif // RECORD_RESUMABLE_FRAME_SP - - -#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && !defined(FEATURE_EH_FUNCLETS) - // We are transitioning from unmanaged code to managed code... lets do some validation of our - // EH mechanism on platforms that we can. - VerifyValidTransitionFromManagedCode(m_crawl.pThread, &m_crawl); -#endif // _DEBUG && !DACCESS_COMPILE && !FEATURE_EH_FUNCLETS } } @@ -2602,12 +2403,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) } } } -#if defined(ELIMINATE_FEF) - else if (m_frameState == SFITER_NO_FRAME_TRANSITION) - { - PostProcessingForNoFrameTransition(); - } -#endif // ELIMINATE_FEF else if (m_frameState == SFITER_NATIVE_MARKER_FRAME) { m_crawl.isNativeMarker = false; @@ -2732,85 +2527,6 @@ void StackFrameIterator::ProcessCurrentFrame(void) m_frameState = SFITER_UNINITIALIZED; } - // Check for the case of an exception in managed code, and resync the stack walk - // from the exception context. -#if defined(ELIMINATE_FEF) - if (!fDone && !m_crawl.IsFrameless() && m_exInfoWalk.GetExInfo()) - { - // We are currently walking ("lost") in unmanaged code. We can recover - // from a) the next Frame record, or b) an exception context. - // Recover from the exception context if all of these are true: - // - it "returns" to managed code - // - if is lower (newer) than the next Frame record - // - the stack walk has not already passed by it - // - // The ExInfo walker is initialized to be higher than the pStartFrame, and - // as we unwind managed (frameless) functions, we keep eliminating any - // ExInfos that are passed in the stackwalk. - // - // So, here we need to find the next ExInfo that "returns" to managed code, - // and then choose the lower of that ExInfo and the next Frame. - m_exInfoWalk.WalkToManaged(); - TADDR pContextSP = m_exInfoWalk.GetSPFromContext(); - - //@todo: check the exception code for a fault? - - // If there was a pContext that is higher than the SP and starting frame... - if (pContextSP) - { - PTR_CONTEXT pContext = m_exInfoWalk.GetContext(); - - LOG((LF_EH, LL_INFO10000, "STACKWALK: considering resync from pContext(%p), fault(%08X), sp(%p); \ - pStartFrame(%p); cf.pFrame(%p), cf.SP(%p)\n", - pContext, m_exInfoWalk.GetFault(), pContextSP, - m_pStartFrame, dac_cast(m_crawl.pFrame), GetRegdisplaySP(m_crawl.pRD))); - - // If the pContext is lower (newer) than the CrawlFrame's Frame*, try to use - // the pContext. - // There are still a few cases in which a FaultingExceptionFrame is linked in. If - // the next frame is one of them, we don't want to override it. THIS IS PROBABLY BAD!!! - if ( (pContextSP < dac_cast(m_crawl.pFrame)) && - ((m_crawl.GetFrame() == FRAME_TOP) || - (m_crawl.GetFrame()->GetFrameIdentifier() != FrameIdentifier::FaultingExceptionFrame ) ) ) - { - // - // If the REGDISPLAY represents an unmanaged stack frame above (closer to the leaf than) an - // ExInfo without any intervening managed stack frame, then we will stop at the no-frame - // transition protected by the ExInfo. However, if the unmanaged stack frame is the one - // immediately above the faulting managed stack frame, we want to continue the stackwalk - // with the faulting managed stack frame. So we do not stop in this case. - // - // However, just comparing EBP is not enough. The OS exception handler - // (KiUserExceptionDispatcher()) does not use an EBP frame. So if we just compare the EBP - // we will think that the OS exception handler is the one we want to claim. Instead, - // we should also check the current IP, which because of the way unwinding work and - // how the OS exception handler behaves is actually going to be the stack limit of the - // current thread. This is of course a workaround and is dependent on the OS behaviour. - // - - PCODE curPC = GetControlPC(m_crawl.pRD); - if ((m_crawl.pRD->pEbp != NULL ) && - (m_exInfoWalk.GetEBPFromContext() == GetRegdisplayFP(m_crawl.pRD)) && - ((m_crawl.pThread->GetCachedStackLimit() <= PTR_VOID(curPC)) && - (PTR_VOID(curPC) < m_crawl.pThread->GetCachedStackBase()))) - { - // restore the CONTEXT saved by the ExInfo and continue on to the faulting - // managed stack frame - PostProcessingForNoFrameTransition(); - } - else - { - // we stop stop at the no-frame transition - m_frameState = SFITER_NO_FRAME_TRANSITION; - m_crawl.isNoFrameTransition = true; - m_crawl.taNoFrameTransitionMarker = pContextSP; - fDone = true; - } - } - } - } -#endif // defined(ELIMINATE_FEF) - if (!fDone) { // returns SWA_DONE if there is no more frames to walk @@ -2889,16 +2605,13 @@ void StackFrameIterator::ProcessCurrentFrame(void) // This must be a JITed/managed native method. There is no explicit frame. //------------------------------------------------------------------------ -#if defined(FEATURE_EH_FUNCLETS) m_crawl.isFilterFuncletCached = false; -#endif // FEATURE_EH_FUNCLETS m_crawl.pFunc = m_crawl.codeInfo.GetMethodDesc(); // Cache values which may be updated by CheckForSkippedFrames() m_cachedCodeInfo = m_crawl.codeInfo; -#ifdef PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME // On non-X86, we want to process the skipped explicit frames before the managed stack frame // containing them. if (CheckForSkippedFrames()) @@ -2906,7 +2619,6 @@ void StackFrameIterator::ProcessCurrentFrame(void) _ASSERTE(m_frameState == SFITER_SKIPPED_FRAME_FUNCTION); } else -#endif // PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME { PreProcessingForManagedFrames(); _ASSERTE(m_frameState == SFITER_FRAMELESS_METHOD); @@ -2953,9 +2665,6 @@ BOOL StackFrameIterator::CheckForSkippedFrames(void) // Can the caller handle skipped frames; fHandleSkippedFrames = (m_flags & HANDLESKIPPEDFRAMES); -#ifndef PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME - pvReferenceSP = GetRegdisplaySP(m_crawl.pRD); -#else // !PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME // Order the Frames relative to the caller SP of the methods // this makes it so that any Frame that is in a managed call // frame will be reported before its containing method. @@ -2964,7 +2673,6 @@ BOOL StackFrameIterator::CheckForSkippedFrames(void) ICodeManager *pCodeManager = (m_crawl.isFrameless) ? m_crawl.GetCodeManager() : ExecutionManager::GetDefaultCodeManager(); pCodeManager->EnsureCallerContextIsValid(m_crawl.pRD, &m_cachedCodeInfo, m_codeManFlags); pvReferenceSP = GetSP(m_crawl.pRD->pCallerContext); -#endif // PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME if ( !( (m_crawl.pFrame != FRAME_TOP) && (dac_cast(m_crawl.pFrame) < pvReferenceSP) ) @@ -3042,7 +2750,6 @@ void StackFrameIterator::PreProcessingForManagedFrames(void) WRAPPER_NO_CONTRACT; SUPPORTS_DAC; -#if defined(RECORD_RESUMABLE_FRAME_SP) if (m_pvResumableFrameTargetSP) { // We expect that if we saw a resumable frame, the next managed @@ -3056,7 +2763,6 @@ void StackFrameIterator::PreProcessingForManagedFrames(void) m_pvResumableFrameTargetSP = NULL; m_crawl.isFirst = true; } -#endif // RECORD_RESUMABLE_FRAME_SP #if !defined(DACCESS_COMPILE) m_pCachedGSCookie = (GSCookie*)m_crawl.GetCodeManager()->GetGSCookieAddr( @@ -3072,39 +2778,6 @@ void StackFrameIterator::PreProcessingForManagedFrames(void) INDEBUG(m_crawl.pThread->DebugLogStackWalkInfo(&m_crawl, "CONSIDER", m_uFramesProcessed)); -#if defined(_DEBUG) && !defined(FEATURE_EH_FUNCLETS) && !defined(DACCESS_COMPILE) - // - // VM is responsible for synchronization on non-funclet EH model. - // - // m_crawl.GetThisPointer() requires full unwind - // In GC's relocate phase, objects is not verifiable - if ( !(m_flags & (LIGHTUNWIND | QUICKUNWIND | ALLOW_INVALID_OBJECTS)) && - m_crawl.pFunc->IsSynchronized() && - !m_crawl.pFunc->IsStatic() && - m_crawl.GetCodeManager()->IsInSynchronizedRegion(m_crawl.GetRelOffset(), - m_crawl.GetGCInfoToken(), - m_crawl.GetCodeManagerFlags())) - { - BEGIN_GCX_ASSERT_COOP; - - OBJECTREF obj = m_crawl.GetThisPointer(); - - _ASSERTE(obj != NULL); - VALIDATEOBJECTREF(obj); - - GCPROTECT_BEGIN(obj); - - DWORD owningThreadId = 0; - DWORD recursionLevel; - obj->GetSyncBlock()->TryGetLockInfo(&owningThreadId, &recursionLevel); - _ASSERTE(owningThreadId == m_crawl.pThread->GetThreadId()); - - GCPROTECT_END(); - - END_GCX_ASSERT_COOP; - } -#endif // _DEBUG && !FEATURE_EH_FUNCLETS && !DACCESS_COMPILE - m_frameState = SFITER_FRAMELESS_METHOD; } // StackFrameIterator::PreProcessingForManagedFrames() @@ -3125,16 +2798,6 @@ void StackFrameIterator::PostProcessingForManagedFrames(void) } CONTRACTL_END; - -#if defined(ELIMINATE_FEF) - // As with frames, we may have unwound past a ExInfo.pContext. This - // can happen when unwinding from a handler that rethrew the exception. - // Skip any ExInfo.pContext records that may no longer be valid. - // If Frames would be unlinked from the Frame chain, also reset the UseExInfoForStackwalk bit - // on the ExInfo. - m_exInfoWalk.WalkToPosition(GetRegdisplaySP(m_crawl.pRD), (m_flags & POPFRAMES)); -#endif // ELIMINATE_FEF - ProcessIp(GetControlPC(m_crawl.pRD)); // if we have unwound to a native stack frame, stop and set the frame state accordingly @@ -3162,56 +2825,8 @@ void StackFrameIterator::PostProcessingForNoFrameTransition() } CONTRACTL_END; -#if defined(ELIMINATE_FEF) - PTR_CONTEXT pContext = m_exInfoWalk.GetContext(); - - // Get the JitManager for the managed address. - m_crawl.codeInfo.Init(GetIP(pContext), m_scanFlag); - _ASSERTE(m_crawl.codeInfo.IsValid()); - - STRESS_LOG4(LF_EH, LL_INFO100, "STACKWALK: resync from pContext(%p); pStartFrame(%p), \ - cf.pFrame(%p), cf.SP(%p)\n", - dac_cast(pContext), dac_cast(m_pStartFrame), dac_cast(m_crawl.pFrame), - GetRegdisplaySP(m_crawl.pRD)); - - // Update the RegDisplay from the context info. - FillRegDisplay(m_crawl.pRD, pContext); - - // Now we know where we are, and it's "frameless", aka managed. - m_crawl.isFrameless = true; - - // Flags the same as from a FaultingExceptionFrame. - m_crawl.isInterrupted = true; - m_crawl.hasFaulted = (pContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0; - m_crawl.isIPadjusted = false; - if (!m_crawl.hasFaulted) - { - // If the context is from a hardware exception that happened in a helper where we have unwound - // the exception location to the caller of the helper, the frame needs to be marked as not - // being the first one. The COMPlusThrowCallback uses this information to decide whether - // the current IP should or should not be included in the try region range. The call to - // the helper that has fired the exception may be the last instruction in the try region. - m_crawl.isFirst = false; - } - -#if defined(STACKWALKER_MAY_POP_FRAMES) - // If Frames would be unlinked from the Frame chain, also reset the UseExInfoForStackwalk bit - // on the ExInfo. - if (m_flags & POPFRAMES) - { - m_exInfoWalk.GetExInfo()->m_ExceptionFlags.ResetUseExInfoForStackwalk(); - } -#endif // STACKWALKER_MAY_POP_FRAMES - - // Done with this ExInfo. - m_exInfoWalk.WalkOne(); - - m_crawl.isNoFrameTransition = false; - m_crawl.taNoFrameTransitionMarker = NULL; -#endif // ELIMINATE_FEF } // StackFrameIterator::PostProcessingForNoFrameTransition() -#ifdef FEATURE_EH_FUNCLETS void StackFrameIterator::ResetNextExInfoForSP(TADDR SP) { while (m_pNextExInfo && (SP > (TADDR)(m_pNextExInfo))) @@ -3219,7 +2834,6 @@ void StackFrameIterator::ResetNextExInfoForSP(TADDR SP) m_pNextExInfo = (PTR_ExInfo)m_pNextExInfo->m_pPrevNestedInfo; } } -#endif // FEATURE_EH_FUNCLETS //---------------------------------------------------------------------------- // diff --git a/src/coreclr/vm/stackwalk.h b/src/coreclr/vm/stackwalk.h index 5ea1c1f9cef945..c82738a33684ce 100644 --- a/src/coreclr/vm/stackwalk.h +++ b/src/coreclr/vm/stackwalk.h @@ -29,28 +29,7 @@ class ICodeManager; class IJitManager; struct EE_ILEXCEPTION; class AppDomain; -#ifdef FEATURE_EH_FUNCLETS struct ExInfo; -#endif - -// This define controls handling of faults in managed code. If it is defined, -// the exception is handled (retried, actually), with a FaultingExceptionFrame -// on the stack. The FEF is used for unwinding. If not defined, the unwinding -// uses the exception context. -#define USE_FEF // to mark where code needs to be changed to eliminate the FEF -#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) - #undef USE_FEF // Turn off the FEF use on x86. - #define ELIMINATE_FEF -#else - #if defined(ELIMINATE_FEF) - #undef ELIMINATE_FEF - #endif -#endif // TARGET_X86 && !FEATURE_EH_FUNCLETS - -#if defined(FEATURE_EH_FUNCLETS) -#define RECORD_RESUMABLE_FRAME_SP -#define PROCESS_EXPLICIT_FRAME_BEFORE_MANAGED_FRAME -#endif //************************************************************************ // Enumerate all functions. @@ -61,9 +40,7 @@ namespace AsmOffsetsAsserts class AsmOffsets; }; -#ifdef FEATURE_EH_FUNCLETS extern "C" void QCALLTYPE AppendExceptionStackFrame(QCall::ObjectHandleOnStack exceptionObj, SIZE_T ip, SIZE_T sp, int flags, ExInfo *pExInfo); -#endif class CrawlFrame { @@ -282,12 +259,10 @@ class CrawlFrame } } -#if defined(FEATURE_EH_FUNCLETS) if (ShouldParentToFuncletSkipReportingGCReferences()) { flags |= ParentOfFuncletStackFrame; } -#endif // defined(FEATURE_EH_FUNCLETS) return flags; } @@ -375,7 +350,6 @@ class CrawlFrame return pThread; } -#if defined(FEATURE_EH_FUNCLETS) bool IsFunclet() { WRAPPER_NO_CONTRACT; @@ -416,8 +390,6 @@ class CrawlFrame return ehClauseForCatch; } -#endif // FEATURE_EH_FUNCLETS - protected: // CrawlFrames are temporarily created by the enumerator. // Do not create one from C++. This protected constructor polices this rule. @@ -430,10 +402,8 @@ class CrawlFrame friend class Thread; friend class EECodeManager; friend class StackFrameIterator; -#ifdef FEATURE_EH_FUNCLETS friend struct ExInfo; friend void QCALLTYPE AppendExceptionStackFrame(QCall::ObjectHandleOnStack exceptionObj, SIZE_T ip, SIZE_T sp, int flags, ExInfo *pExInfo); -#endif // FEATURE_EH_FUNCLETS bool isFrameless; bool isFirst; @@ -455,14 +425,12 @@ class CrawlFrame PREGDISPLAY pRD; // "thread context"/"virtual register set" EECodeInfo codeInfo; -#if defined(FEATURE_EH_FUNCLETS) bool isFilterFunclet; bool isFilterFuncletCached; bool fShouldParentToFuncletSkipReportingGCReferences; bool fShouldCrawlframeReportGCReferences; bool fShouldParentFrameUseUnwindTargetPCforGCReporting; EE_ILEXCEPTION_CLAUSE ehClauseForCatch; -#endif //FEATURE_EH_FUNCLETS Thread* pThread; GSCookie *pCurGSCookie; @@ -475,58 +443,6 @@ class CrawlFrame void GcEnumObject(LPVOID pData, OBJECTREF *pObj); StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData); -#if defined(ELIMINATE_FEF) -//****************************************************************************** -// This class is used to help use exception context records to resync a -// stackwalk, when managed code has generated an exception (eg, AV, zerodiv.,,) -// Such an exception causes a transition from the managed code into unmanaged -// OS and runtime code, but without the benefit of any Frame. This code helps -// the stackwalker simulate the effect that such a frame would have. -// In particular, this class has methods to walk the chain of ExInfos, looking -// for records with pContext pointers with certain characteristics. The -// characteristics that are important are the location in the stack (ie, is a -// given pContext relevant at a particular point in the stack walk), and -// whether the pContext was generated in managed code. -//****************************************************************************** -class ExInfoWalker -{ -public: - ExInfoWalker() : m_pExInfo(0) { SUPPORTS_DAC; } - void Init (ExInfo *pExInfo) { SUPPORTS_DAC; m_pExInfo = pExInfo; } - // Skip one ExInfo. - void WalkOne(); - // Attempt to find an ExInfo with a pContext that is higher (older) than - // a given minimum location. - void WalkToPosition(TADDR taMinimum, BOOL bPopFrames); - // Attempt to find an ExInfo with a pContext that has an IP in managed code. - void WalkToManaged(); - // Return current ExInfo's m_pContext, or NULL if no m_pExInfo. - PTR_CONTEXT GetContext() { SUPPORTS_DAC; return m_pExInfo ? m_pExInfo->m_pContext : NULL; } - // Useful to see if there is more on the ExInfo chain. - ExInfo* GetExInfo() { SUPPORTS_DAC; return m_pExInfo; } - - // helper functions for retrieving information from the exception CONTEXT - TADDR GetSPFromContext() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - return dac_cast((m_pExInfo && m_pExInfo->m_pContext) ? GetSP(m_pExInfo->m_pContext) : PTR_NULL); - } - - TADDR GetEBPFromContext() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - return dac_cast((m_pExInfo && m_pExInfo->m_pContext) ? GetFP(m_pExInfo->m_pContext) : PTR_NULL); - } - - DWORD GetFault() { SUPPORTS_DAC; return m_pExInfo ? m_pExInfo->m_pExceptionRecord->ExceptionCode : 0; } - -private: - ExInfo *m_pExInfo; -}; // class ExInfoWalker -#endif // ELIMINATE_FEF - //--------------------------------------------------------------------------------------- // @@ -578,13 +494,10 @@ class StackFrameIterator StackWalkAction Next(void); #ifndef DACCESS_COMPILE -#ifdef FEATURE_EH_FUNCLETS // advance to the position that the other iterator is currently at void SkipTo(StackFrameIterator *pOtherStackFrameIterator); -#endif // FEATURE_EH_FUNCLETS #endif // DACCESS_COMPILE -#ifdef FEATURE_EH_FUNCLETS void ResetNextExInfoForSP(TADDR SP); ExInfo* GetNextExInfo() @@ -612,13 +525,11 @@ class StackFrameIterator } CONTRACTL_END -#if defined(FEATURE_EH_FUNCLETS) && !defined(DACCESS_COMPILE) +#ifndef DACCESS_COMPILE m_isRuntimeWrappedExceptions = (m_crawl.pFunc != NULL) && m_crawl.pFunc->GetModule()->IsRuntimeWrapExceptionsDuringEH(); -#endif // FEATURE_EH_FUNCLETS && !DACCESS_COMPILE +#endif // DACCESS_COMPILE } -#endif // FEATURE_EH_FUNCLETS - enum FrameState { SFITER_UNINITIALIZED, // uninitialized @@ -681,7 +592,6 @@ class StackFrameIterator // the CONTEXT stored in the ExInfo and updating the REGDISPLAY to the faulting managed stack frame. void PostProcessingForNoFrameTransition(void); -#if defined(FEATURE_EH_FUNCLETS) void ResetGCRefReportingState(bool ResetOnlyIntermediaryState = false) { LIMITED_METHOD_CONTRACT; @@ -695,7 +605,6 @@ class StackFrameIterator m_sfIntermediaryFuncletParent = StackFrame(); m_fProcessIntermediaryNonFilterFunclet = false; } -#endif // defined(FEATURE_EH_FUNCLETS) // Iteration state. FrameState m_frameState; @@ -718,11 +627,6 @@ class StackFrameIterator GSCookie * m_pCachedGSCookie; -#if defined(ELIMINATE_FEF) - ExInfoWalker m_exInfoWalk; -#endif // ELIMINATE_FEF - -#if defined(FEATURE_EH_FUNCLETS) // used in funclet-skipping StackFrame m_sfParent; @@ -733,7 +637,6 @@ class StackFrameIterator bool m_fProcessIntermediaryNonFilterFunclet; bool m_fDidFuncletReportGCReferences; bool m_isRuntimeWrappedExceptions; -#endif // FEATURE_EH_FUNCLETS // Indicates that the stack walk has moved past a funclet bool m_fFoundFirstFunclet; #ifdef FEATURE_INTERPRETER @@ -749,13 +652,9 @@ class StackFrameIterator #endif // TARGET_AMD64 && TARGET_WINDOWS #endif // FEATURE_INTERPRETER -#if defined(RECORD_RESUMABLE_FRAME_SP) LPVOID m_pvResumableFrameTargetSP; -#endif // RECORD_RESUMABLE_FRAME_SP -#ifdef FEATURE_EH_FUNCLETS ExInfo* m_pNextExInfo; TADDR m_AdjustedControlPC; -#endif // FEATURE_EH_FUNCLETS }; void SetUpRegdisplayForStackWalk(Thread * pThread, T_CONTEXT * pContext, REGDISPLAY * pRegdisplay); diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index 61afb0d2197745..48881d47a64d67 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -56,9 +56,7 @@ #include "perfmap.h" #endif -#ifdef FEATURE_EH_FUNCLETS #include "exinfo.h" -#endif #ifdef FEATURE_INTERPRETER #include "interpexec.h" @@ -1344,10 +1342,8 @@ Thread::Thread() m_pCreatingThrowableForException = NULL; -#ifdef FEATURE_EH_FUNCLETS m_dwIndexClauseForCatch = 0; m_sfEstablisherOfActualHandlerFrame.Clear(); -#endif // FEATURE_EH_FUNCLETS // Do not expose thread until it is fully constructed g_pThinLockThreadIdDispenser->NewId(this, this->m_ThreadId); @@ -2641,15 +2637,7 @@ void Thread::CooperativeCleanup() GCX_COOP(); // Clear any outstanding stale EH state that maybe still active on the thread. -#ifdef FEATURE_EH_FUNCLETS ExInfo::PopTrackers((void*)-1); -#else // !FEATURE_EH_FUNCLETS - PTR_ThreadExceptionState pExState = GetExceptionState(); - if (pExState->IsExceptionInProgress()) - { - pExState->GetCurrentExceptionTracker()->UnwindExInfo((void *)-1); - } -#endif // FEATURE_EH_FUNCLETS if (m_ThreadLocalDataPtr != NULL) { @@ -6112,9 +6100,7 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState) _ASSERTE(GetThreadNULLOk() != NULL); Thread *pThread = GetThread(); -#ifdef FEATURE_EH_FUNCLETS Frame *pFrame = pThread->m_pFrame; -#endif // FEATURE_EH_FUNCLETS // The sole purpose of having this frame is to tell the debugger that we have a catch handler here // which may swallow managed exceptions. The debugger needs this in order to send a @@ -6131,9 +6117,7 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState) BOOL *pfHadException; -#ifdef FEATURE_EH_FUNCLETS Frame *pFrame; -#endif // FEATURE_EH_FUNCLETS }args; args.pTryParam = ¶m; @@ -6142,9 +6126,7 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState) BOOL fHadException = TRUE; args.pfHadException = &fHadException; -#ifdef FEATURE_EH_FUNCLETS args.pFrame = pFrame; -#endif // FEATURE_EH_FUNCLETS PAL_TRY(TryArgs *, pArgs, &args) { @@ -6159,12 +6141,10 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState) // // If eCLRDeterminedPolicy, we only swallow for TA, RTA, and ADU exception. // For eHostDeterminedPolicy, we will swallow all the managed exception. - #ifdef FEATURE_EH_FUNCLETS // this must be done after the second pass has run, it does not // reference anything on the stack, so it is safe to run in an // SEH __except clause as well as a C++ catch clause. ExInfo::PopTrackers(pArgs->pFrame); - #endif // FEATURE_EH_FUNCLETS _ASSERTE(!pArgs->pThread->IsAbortRequested()); } diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index 660466a5cef7a1..7db7eb39268726 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -2193,7 +2193,6 @@ class Thread bool InitRegDisplay(const PREGDISPLAY, const PT_CONTEXT, bool validContext); void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, bool fLightUnwind = false); -#ifdef FEATURE_EH_FUNCLETS static PCODE VirtualUnwindCallFrame(T_CONTEXT* pContext, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers = NULL, EECodeInfo * pCodeInfo = NULL); static UINT_PTR VirtualUnwindCallFrame(PREGDISPLAY pRD, EECodeInfo * pCodeInfo = NULL); @@ -2201,7 +2200,6 @@ class Thread static PCODE VirtualUnwindLeafCallFrame(T_CONTEXT* pContext); static UINT_PTR VirtualUnwindToFirstManagedCallFrame(T_CONTEXT* pContext); #endif // DACCESS_COMPILE -#endif // FEATURE_EH_FUNCLETS // During a , this thread must not be asynchronously // stopped or interrupted. That would leave the class unavailable @@ -3513,10 +3511,8 @@ class Thread // So we save reference to the clause post which TA was reraised, which is used in ExInfo::ProcessManagedCallFrame // to make ThreadAbort proceed ahead instead of going in a loop. // This problem only happens on Win64 due to JIT64. The common scenario is VB's "On error resume next" -#ifdef FEATURE_EH_FUNCLETS DWORD m_dwIndexClauseForCatch; StackFrame m_sfEstablisherOfActualHandlerFrame; -#endif // FEATURE_EH_FUNCLETS private: @@ -3815,11 +3811,7 @@ struct cdac_data static_assert(std::is_same().m_ExceptionState), ThreadExceptionState>::value, "Thread::m_ExceptionState is of type ThreadExceptionState"); - #ifdef FEATURE_EH_FUNCLETS static constexpr size_t ExceptionTracker = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_pCurrentTracker); - #else - static constexpr size_t ExceptionTracker = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_currentExInfo); - #endif #ifndef TARGET_UNIX static constexpr size_t TEB = offsetof(Thread, m_pTEB); static constexpr size_t UEWatsonBucketTrackerBuckets = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_UEWatsonBucketTracker) diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index e413bdabeea712..5bae79b9da454c 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // threadsuspend.CPP // @@ -17,9 +18,7 @@ #include #include -#ifdef FEATURE_EH_FUNCLETS #include "exinfo.h" -#endif #define HIJACK_NONINTERRUPTIBLE_THREADS @@ -662,21 +661,6 @@ static StackWalkAction TAStackCrawlCallBackWorker(CrawlFrame* pCf, StackCrawlCon EE_ILEXCEPTION_CLAUSE EHClause; StackWalkAction action = SWA_CONTINUE; -#ifndef FEATURE_EH_FUNCLETS - // On X86, the EH encoding for catch clause is completely mess. - // If catch clause is in its own basic block, the end of catch includes everything in the basic block. - // For nested catch, the end of catch may include several jmp instructions after JIT_EndCatch call. - // To better decide if we are inside a nested catch, we check if offs-1 is in more than one catch clause. - DWORD countInCatch = 0; - BOOL fAtJitEndCatch = FALSE; - if (pData->pAbortee == GetThread() && - pData->pAbortee->ThrewControlForThread() == Thread::InducedThreadRedirectAtEndOfCatch && - GetControlPC(pCf->GetRegisterSet()) == (PCODE)GetIP(pData->pAbortee->GetAbortContext())) - { - fAtJitEndCatch = TRUE; - offs -= 1; - } -#endif // !FEATURE_EH_FUNCLETS for(ULONG i=0; i < EHCount; i++) { @@ -697,20 +681,6 @@ static StackWalkAction TAStackCrawlCallBackWorker(CrawlFrame* pCf, StackCrawlCon if (offs >= EHClause.HandlerStartPC && offs < EHClause.HandlerEndPC) { -#ifndef FEATURE_EH_FUNCLETS - if (fAtJitEndCatch) - { - // On X86, JIT's EH info may include the instruction after JIT_EndCatch inside the same catch - // clause if it is in the same basic block. - // So for this case, the offs is in at least one catch handler, but since we are at the end of - // catch, this one should not be counted. - countInCatch ++; - if (countInCatch == 1) - { - continue; - } - } -#endif // !FEATURE_EH_FUNCLETS pData->fWithinEHClause = true; // We're within an EH clause. If we're asking about CERs too then stop the stack walk if we've reached a conclusive // result or continue looking otherwise. Else we can stop the stackwalk now. @@ -726,14 +696,6 @@ static StackWalkAction TAStackCrawlCallBackWorker(CrawlFrame* pCf, StackCrawlCon } } -#ifndef FEATURE_EH_FUNCLETS -#ifdef _DEBUG - if (fAtJitEndCatch) - { - _ASSERTE (countInCatch > 0); - } -#endif // _DEBUG -#endif // !FEATURE_EH_FUNCLETS return action; } @@ -963,12 +925,10 @@ BOOL Thread::ReadyForAsyncException() return FALSE; } -#ifdef FEATURE_EH_FUNCLETS if (IsAbortPrevented()) { return FALSE; } -#endif // FEATURE_EH_FUNCLETS REGDISPLAY rd; @@ -1524,31 +1484,9 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout) | TS_Detached | TS_Unstarted))); -#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) - // TODO WIN64: consider this if there is a way to detect of managed code on stack. - if ((m_pFrame == FRAME_TOP) - && (GetFirstCOMPlusSEHRecord(this) == EXCEPTION_CHAIN_END) - ) - { -#ifndef DISABLE_THREADSUSPEND - ResumeThread(); -#endif -#ifdef _DEBUG - m_dwAbortPoint = 8; -#endif - - return S_OK; - } -#endif // TARGET_X86 - - if (!m_fPreemptiveGCDisabled) { - if ((m_pFrame != FRAME_TOP) && m_pFrame->IsTransitionToNativeFrame() -#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS) - && ((size_t) GetFirstCOMPlusSEHRecord(this) > ((size_t) m_pFrame) - 20) -#endif // TARGET_X86 - ) + if ((m_pFrame != FRAME_TOP) && m_pFrame->IsTransitionToNativeFrame()) { fOutOfRuntime = TRUE; } @@ -3781,8 +3719,6 @@ ThrowControlForThread( STRESS_LOG0(LF_SYNC, LL_INFO100, "ThrowControlForThread Aborting\n"); -#ifdef FEATURE_EH_FUNCLETS - GCX_COOP(); EXCEPTION_RECORD exceptionRecord = {0}; @@ -3793,12 +3729,6 @@ ThrowControlForThread( OBJECTREF throwable = ExInfo::CreateThrowable(&exceptionRecord, TRUE); pfef->GetExceptionContext()->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; DispatchManagedException(throwable, pfef->GetExceptionContext()); -#else // FEATURE_EH_FUNCLETS - // Here we raise an exception. - INSTALL_MANAGED_EXCEPTION_DISPATCHER - RaiseComPlusException(); - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER -#endif // FEATURE_EH_FUNCLETS } #if defined(FEATURE_HIJACK) && !defined(TARGET_UNIX) @@ -4722,7 +4652,6 @@ StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData) // return address for hijacking. if (!pES->m_IsInterruptible) { -#ifdef FEATURE_EH_FUNCLETS PREGDISPLAY pRDT = pCF->GetRegisterSet(); _ASSERTE(pRDT != NULL); @@ -4810,11 +4739,6 @@ StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData) PORTABILITY_ASSERT("Platform NYI"); #endif // _TARGET_???_ } -#else // FEATURE_EH_FUNCLETS - // peel off the next frame to expose the return address on the stack - pES->m_FirstPass = FALSE; - action = SWA_CONTINUE; -#endif // !FEATURE_EH_FUNCLETS } #endif // HIJACK_NONINTERRUPTIBLE_THREADS } diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index 6e990ea10b8619..f6fd1eac774627 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -1,11 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // vars.cpp - Global Var definitions // - - #include "common.h" #include "vars.hpp" #include "cordbpriv.h" @@ -104,11 +103,10 @@ GVAL_IMPL_INIT(DWORD, g_gcNotificationFlags, 0); MethodTable* g_pCastHelpers; -#ifdef FEATURE_EH_FUNCLETS + GPTR_IMPL(MethodTable, g_pEHClass); GPTR_IMPL(MethodTable, g_pExceptionServicesInternalCallsClass); GPTR_IMPL(MethodTable, g_pStackFrameIteratorClass); -#endif GVAL_IMPL_INIT(PTR_WSTR, g_EntryAssemblyPath, NULL); diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 08988b342e784b..246291fdeab900 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // vars.hpp // // Global variables // - #ifndef _VARS_HPP #define _VARS_HPP @@ -365,11 +365,9 @@ GVAL_DECL(DWORD, g_TlsIndex); GVAL_DECL(DWORD, g_offsetOfCurrentThreadInfo); GVAL_DECL(DWORD, g_gcNotificationFlags); -#ifdef FEATURE_EH_FUNCLETS GPTR_DECL(MethodTable, g_pEHClass); GPTR_DECL(MethodTable, g_pExceptionServicesInternalCallsClass); GPTR_DECL(MethodTable, g_pStackFrameIteratorClass); -#endif // Full path to the managed entry assembly - stored for ease of identifying the entry asssembly for diagnostics GVAL_DECL(PTR_WSTR, g_EntryAssemblyPath); diff --git a/src/coreclr/vm/wasm/excepcpu.h b/src/coreclr/vm/wasm/excepcpu.h index d3dd80fe7ec526..d91761ab082ad3 100644 --- a/src/coreclr/vm/wasm/excepcpu.h +++ b/src/coreclr/vm/wasm/excepcpu.h @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + // // copied from arm and left empty. wasm cannot do most of it @@ -13,10 +14,6 @@ class Thread; class FaultingExceptionFrame; -#define INSTALL_EXCEPTION_HANDLING_RECORD(record) -#define UNINSTALL_EXCEPTION_HANDLING_RECORD(record) -#define DECLARE_CPFH_EH_RECORD(pCurThread) - // // Retrieves the redirected CONTEXT* from the stack frame of one of the // RedirectedHandledJITCaseForXXX_Stub's. diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/GCInfoDecoding/GCInfo.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/GCInfoDecoding/GCInfo.cs index f58635691ac74b..3f474d1f2e33a2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/GCInfoDecoding/GCInfo.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/GCInfoDecoding/GCInfo.cs @@ -223,7 +223,6 @@ private uint CalculatePushedArgSize() case GcTransitionPointer gcTransitionPointer: if (gcTransitionPointer.Act == Action.PUSH) { - // FEATURE_EH_FUNCLETS implies fullArgInfo // when there is fullArgInfo, the current depth is incremented by the number of pushed arguments depth++; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/X86Unwinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/X86Unwinder.cs index 547f4c104c390e..72b3f1968404f0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/X86Unwinder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86/X86Unwinder.cs @@ -466,9 +466,6 @@ private bool UnwindEbpDoubleAlignFrame( context.Esp = (uint)baseSP + _pointerSize; return true; } - - /* The cDAC only supports FEATURE_EH_FUNCLETS and therefore does not - support unwinding filters without funclets. */ } //