diff options
Diffstat (limited to 'src/vm/exstate.h')
-rw-r--r-- | src/vm/exstate.h | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/vm/exstate.h b/src/vm/exstate.h new file mode 100644 index 0000000000..50e71ed79b --- /dev/null +++ b/src/vm/exstate.h @@ -0,0 +1,373 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +// + +#ifndef __ExState_h__ +#define __ExState_h__ + +class ExceptionFlags; +class DebuggerExState; +class EHClauseInfo; + +#include "exceptionhandling.h" + +#if !defined(WIN64EXCEPTIONS) +// ExInfo contains definitions for 32bit +#include "exinfo.h" +#endif // !defined(WIN64EXCEPTIONS) + +#if !defined(DACCESS_COMPILE) +#define PRESERVE_WATSON_ACROSS_CONTEXTS 1 +#endif + +extern LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo); +extern StackWalkAction COMPlusUnwindCallback(CrawlFrame *pCf, ThrowCallbackType *pData); + +// +// This class serves as a forwarding and abstraction layer for the EH subsystem. +// Since we have two different implementations, this class is needed to unify +// the EE's view of EH. Ideally, this is just a step along the way to a unified +// EH subsystem. +// +typedef DPTR(class ThreadExceptionState) PTR_ThreadExceptionState; +class ThreadExceptionState +{ + friend class ClrDataExceptionState; + friend class CheckAsmOffsets; + friend class StackFrameIterator; + +#ifdef DACCESS_COMPILE + friend class ClrDataAccess; +#endif // DACCESS_COMPILE + + // ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo needs access so that it can fetch the + // ExceptionTracker or the ExInfo as appropriate for the platform + friend class ProfToEEInterfaceImpl; + +#ifdef WIN64EXCEPTIONS + friend class ExceptionTracker; +#else + friend class ExInfo; +#endif // WIN64EXCEPTIONS + +public: + + void FreeAllStackTraces(); + void ClearThrowablesForUnload(HandleTableBucket* pHndTblBucket); + +#ifdef _DEBUG + typedef enum + { + STEC_All, + STEC_CurrentTrackerEqualNullOkHackForFatalStackOverflow, +#ifdef FEATURE_INTERPRETER + STEC_CurrentTrackerEqualNullOkForInterpreter, +#endif // FEATURE_INTERPRETER + } SetThrowableErrorChecking; +#endif + + void SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowableErrorChecking stecFlags = STEC_All)); + OBJECTREF GetThrowable(); + OBJECTHANDLE GetThrowableAsHandle(); + DWORD GetExceptionCode(); + BOOL IsComPlusException(); + EXCEPTION_POINTERS* GetExceptionPointers(); + PTR_EXCEPTION_RECORD GetExceptionRecord(); + PTR_CONTEXT GetContextRecord(); + BOOL IsExceptionInProgress(); + void GetLeafFrameInfo(StackTraceElement* pStackTrace); + + ExceptionFlags* GetFlags(); + + ThreadExceptionState(); + ~ThreadExceptionState(); + +#if !defined(WIN64EXCEPTIONS) + void SetExceptionPointers(EXCEPTION_POINTERS *pExceptionPointers); +#endif + + +#ifdef DEBUGGING_SUPPORTED + // DebuggerExState stores information necessary for intercepting an exception + DebuggerExState* GetDebuggerState(); + + // check to see if the current exception is interceptable + BOOL IsDebuggerInterceptable(); +#endif // DEBUGGING_SUPPORTED + + EHClauseInfo* GetCurrentEHClauseInfo(); + +#ifdef DACCESS_COMPILE + void EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags); +#endif // DACCESS_COMPILE + + // After unwinding from an SO, there may be stale exception state. + void ClearExceptionStateAfterSO(void* pStackFrameSP); + + enum ThreadExceptionFlag + { + TEF_None = 0x00000000, + + // Right now this flag is only used on WIN64. We set this flag near the end of the second pass when we pop + // the ExceptionTracker for the current exception but before we actually resume execution. It is unsafe + // to start a funclet-skipping stackwalk in this time window. + TEF_InconsistentExceptionState = 0x00000001, + +#if defined(FEATURE_EXCEPTIONDISPATCHINFO) + TEF_ForeignExceptionRaise = 0x00000002, +#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO) + }; + + void SetThreadExceptionFlag(ThreadExceptionFlag flag); + void ResetThreadExceptionFlag(ThreadExceptionFlag flag); + BOOL HasThreadExceptionFlag(ThreadExceptionFlag flag); + +#if defined(FEATURE_EXCEPTIONDISPATCHINFO) + inline void SetRaisingForeignException() + { + LIMITED_METHOD_CONTRACT; + SetThreadExceptionFlag(TEF_ForeignExceptionRaise); + } + + inline BOOL IsRaisingForeignException() + { + LIMITED_METHOD_CONTRACT; + return HasThreadExceptionFlag(TEF_ForeignExceptionRaise); + } + + inline void ResetRaisingForeignException() + { + LIMITED_METHOD_CONTRACT; + ResetThreadExceptionFlag(TEF_ForeignExceptionRaise); + } +#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO) + +#if defined(_DEBUG) + void AssertStackTraceInfo(StackTraceInfo *pSTI); +#endif // _debug + +private: + Thread* GetMyThread(); + +#ifdef WIN64EXCEPTIONS + PTR_ExceptionTracker m_pCurrentTracker; + ExceptionTracker m_OOMTracker; +public: + PTR_ExceptionTracker GetCurrentExceptionTracker() + { + LIMITED_METHOD_CONTRACT; + return m_pCurrentTracker; + } +#else + ExInfo m_currentExInfo; +public: + PTR_ExInfo GetCurrentExceptionTracker() + { + LIMITED_METHOD_CONTRACT; + return PTR_ExInfo(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_currentExInfo)); + } +#endif + +#ifdef FEATURE_CORRUPTING_EXCEPTIONS +private: + CorruptionSeverity m_LastActiveExceptionCorruptionSeverity; + BOOL m_fCanReflectionTargetHandleException; + +public: + // Returns the corruption severity of the last active exception + inline CorruptionSeverity GetLastActiveExceptionCorruptionSeverity() + { + LIMITED_METHOD_CONTRACT; + + return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity); + } + + // Set the corruption severity of the last active exception + inline void SetLastActiveExceptionCorruptionSeverity(CorruptionSeverity severityToSet) + { + LIMITED_METHOD_CONTRACT; + + m_LastActiveExceptionCorruptionSeverity = severityToSet; + } + + // Returns a bool indicating if the last active exception's corruption severity should + // be used when exception is reraised (e.g. Reflection Invocation, AD transition, etc) + inline BOOL ShouldLastActiveExceptionCorruptionSeverityBeReused() + { + LIMITED_METHOD_CONTRACT; + + return CAN_REUSE_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity); + } + + // Returns a BOOL to indicate if reflection target can handle CSE or not. + // This is used in DispatchInfo::CanIDispatchTargetHandleException. + inline BOOL CanReflectionTargetHandleException() + { + LIMITED_METHOD_CONTRACT; + + return m_fCanReflectionTargetHandleException; + } + + // Sets a BOOL indicate if the Reflection invocation target can handle exception or not. + // Used in ReflectionInvocation.cpp. + inline void SetCanReflectionTargetHandleException(BOOL fCanReflectionTargetHandleException) + { + LIMITED_METHOD_CONTRACT; + + m_fCanReflectionTargetHandleException = fCanReflectionTargetHandleException; + } +#endif // FEATURE_CORRUPTING_EXCEPTIONS + +private: + ThreadExceptionFlag m_flag; + +#ifndef FEATURE_PAL +private: + EHWatsonBucketTracker m_UEWatsonBucketTracker; +public: + PTR_EHWatsonBucketTracker GetUEWatsonBucketTracker() + { + LIMITED_METHOD_CONTRACT; + return PTR_EHWatsonBucketTracker(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_UEWatsonBucketTracker)); + } +#endif // !FEATURE_PAL + +private: + +#ifndef WIN64EXCEPTIONS + + // + // @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 LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo); + + 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 // WIN64EXCEPTIONS + +}; + + +// <WARNING> +// This holder is not thread safe. +// </WARNING> +class ThreadExceptionFlagHolder +{ +public: + ThreadExceptionFlagHolder(ThreadExceptionState::ThreadExceptionFlag flag); + ~ThreadExceptionFlagHolder(); + +private: + ThreadExceptionState* m_pExState; + ThreadExceptionState::ThreadExceptionFlag m_flag; +}; + +extern BOOL IsWatsonEnabled(); + +#ifndef FEATURE_PAL +// This preprocessor definition is used to capture watson buckets +// at AppDomain transition boundary in END_DOMAIN_TRANSITION macro. +// +// This essentially copies the watson bucket details from the current exception tracker +// to the UE watson bucket tracker only if it is preallocated exception and NOT +// thread abort. For preallocated thread abort, UE Watson bucket tracker would already have the +// bucket details. +// +// It also captures buckets for non-preallocated exceptions (including non-preallocated threadabort) since +// the object would have the IP inside it. +#define CAPTURE_BUCKETS_AT_TRANSITION(pThread, oThrowable) \ + if (IsWatsonEnabled()) \ + { \ + /* Switch to COOP mode */ \ + GCX_COOP(); \ + \ + /* oThrowable is actually GET_THROWABLE macro; so extract the actual throwable for once and for all */ \ + OBJECTREF throwable = oThrowable; \ + if (CLRException::IsPreallocatedExceptionObject(throwable)) \ + { \ + if (pThread->GetExceptionState()->GetCurrentExceptionTracker() != NULL) \ + { \ + if (!IsThrowableThreadAbortException(throwable)) \ + { \ + PTR_EHWatsonBucketTracker pWatsonBucketTracker = GetWatsonBucketTrackerForPreallocatedException(throwable, FALSE); \ + if (pWatsonBucketTracker != NULL) \ + { \ + pThread->GetExceptionState()->GetUEWatsonBucketTracker()->CopyEHWatsonBucketTracker(*(pWatsonBucketTracker)); \ + pThread->GetExceptionState()->GetUEWatsonBucketTracker()->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, NULL); \ + DEBUG_STMT(pThread->GetExceptionState()->GetUEWatsonBucketTracker()->SetCapturedAtADTransition();) \ + } \ + } \ + } \ + } \ + else \ + { \ + SetupWatsonBucketsForNonPreallocatedExceptions(throwable); \ + } \ + } +#else // !FEATURE_PAL +#define CAPTURE_BUCKETS_AT_TRANSITION(pThread, oThrowable) +#endif // FEATURE_PAL + +#endif // __ExState_h__ |