summaryrefslogtreecommitdiff
path: root/src/vm/exstatecommon.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/exstatecommon.h')
-rw-r--r--src/vm/exstatecommon.h528
1 files changed, 528 insertions, 0 deletions
diff --git a/src/vm/exstatecommon.h b/src/vm/exstatecommon.h
new file mode 100644
index 0000000000..a0f5a0bb3d
--- /dev/null
+++ b/src/vm/exstatecommon.h
@@ -0,0 +1,528 @@
+// 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 __ExStateCommon_h__
+#define __ExStateCommon_h__
+
+#include "stackframe.h"
+
+class ExceptionFlags;
+
+#ifdef DEBUGGING_SUPPORTED
+//---------------------------------------------------------------------------------------
+//
+// This class stores information necessary to intercept an exception. It's basically a communication channel
+// between the debugger and the EH subsystem. Each internal exception tracking structure
+// (ExInfo on x86 and ExceptionTracker on WIN64) contains one DebuggerExState.
+//
+// Notes:
+// This class actually stores more information on x86 than on WIN64 because the x86 EH subsystem
+// has more work to do when unwinding the stack. WIN64 just asks the OS to do it.
+//
+
+class DebuggerExState
+{
+public:
+
+ //---------------------------------------------------------------------------------------
+ //
+ // constructor
+ //
+
+ DebuggerExState()
+ {
+ Init();
+ }
+
+ //---------------------------------------------------------------------------------------
+ //
+ // This function is simply used to initialize all the fields in the DebuggerExState.
+ //
+
+ void Init()
+ {
+ m_sfDebuggerIndicatedFramePointer = StackFrame();
+ m_pDebuggerInterceptFunc = NULL;
+ m_sfDebuggerInterceptFramePointer = StackFrame();
+ m_pDebuggerContext = NULL;
+ m_pDebuggerInterceptNativeOffset = 0;
+
+ // x86-specific fields
+ #if defined(_TARGET_X86_)
+ m_pDebuggerInterceptFrame = EXCEPTION_CHAIN_END;
+ #endif // defined(_TARGET_X86_)
+ m_dDebuggerInterceptHandlerDepth = 0;
+ }
+
+ //---------------------------------------------------------------------------------------
+ //
+ // Retrieves the opaque token stored by the debugger.
+ //
+ // Return Value:
+ // the stored opaque token for the debugger
+ //
+
+ void* GetDebuggerInterceptContext()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pDebuggerContext;
+ }
+
+ //---------------------------------------------------------------------------------------
+ //
+ // Stores an opaque token which is only used by the debugger.
+ //
+ // Arguments:
+ // pContext - the token to be stored
+ //
+
+ void SetDebuggerInterceptContext(void* pContext)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pDebuggerContext = pContext;
+ }
+
+ //---------------------------------------------------------------------------------------
+ //
+ // Marks the current stack frame visited by the EH subsystem during the first pass.
+ // This marker moves closer to the root of the stack while each stack frame is examined in the first pass.
+ // This continues until the end of the first pass.
+ //
+ // Arguments:
+ // stackPointer - SP of the current stack frame
+ // bStorePointer - BSP of the current stack frame
+ //
+
+ void SetDebuggerIndicatedFramePointer(void* stackPointer)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_sfDebuggerIndicatedFramePointer = StackFrame((UINT_PTR)stackPointer);
+ }
+
+ // This function stores the information necessary to intercept an exception in the DebuggerExState.
+ BOOL SetDebuggerInterceptInfo(IJitManager *pJitManager,
+ Thread *pThread,
+ const METHODTOKEN& methodToken,
+ MethodDesc *pMethDesc,
+ ULONG_PTR natOffset,
+ StackFrame sfDebuggerInterceptFramePointer,
+ ExceptionFlags* pFlags);
+
+ //---------------------------------------------------------------------------------------
+ //
+ // This function is basically just a getter to retrieve the information stored on the DebuggerExState.
+ // Refer to the comments for individual fields for more information.
+ //
+ // Arguments:
+ // pEstablisherFrame - m_pDebuggerInterceptFrame
+ // ppFunc - m_pDebuggerInterceptFunc
+ // pdHandler - m_dDebuggerInterceptHandlerDepth
+ // ppStack - the SP of m_sfDebuggerInterceptFramePointer
+ // ppBStore - the BSP of m_sfDebuggerInterceptFramePointer
+ // pNativeOffset - m_pDebuggerInterceptNativeOffset;
+ // ppFrame - always set to NULL
+ //
+ // Notes:
+ // Everything is an out parameter.
+ //
+ // Apparently ppFrame is actually used on x86 to set tct.pBottomFrame to NULL.
+ //
+
+ void GetDebuggerInterceptInfo(
+ #if defined(_TARGET_X86_)
+ PEXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
+ #endif // _TARGET_X86_
+ MethodDesc **ppFunc,
+ int *pdHandler,
+ BYTE **ppStack,
+ ULONG_PTR *pNativeOffset,
+ Frame **ppFrame)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+#if defined(_TARGET_X86_)
+ if (pEstablisherFrame != NULL)
+ {
+ *pEstablisherFrame = m_pDebuggerInterceptFrame;
+ }
+#endif // _TARGET_X86_
+
+ if (ppFunc != NULL)
+ {
+ *ppFunc = m_pDebuggerInterceptFunc;
+ }
+
+ if (pdHandler != NULL)
+ {
+ *pdHandler = m_dDebuggerInterceptHandlerDepth;
+ }
+
+ if (ppStack != NULL)
+ {
+ *ppStack = (BYTE *)m_sfDebuggerInterceptFramePointer.SP;
+ }
+
+ if (pNativeOffset != NULL)
+ {
+ *pNativeOffset = m_pDebuggerInterceptNativeOffset;
+ }
+
+ if (ppFrame != NULL)
+ {
+ *ppFrame = NULL;
+ }
+ }
+
+private:
+ // This frame pointer marks the latest stack frame examined by the EH subsystem in the first pass.
+ // An exception cannot be intercepted closer to the root than this frame pointer.
+ StackFrame m_sfDebuggerIndicatedFramePointer;
+
+ // the method in which we are going to resume execution
+ MethodDesc* m_pDebuggerInterceptFunc;
+
+ // the frame pointer of the stack frame where we are intercepting the exception
+ StackFrame m_sfDebuggerInterceptFramePointer;
+
+ // opaque token used by the debugger
+ void* m_pDebuggerContext;
+
+ // the native offset at which to resume execution
+ ULONG_PTR m_pDebuggerInterceptNativeOffset;
+
+ // The remaining fields are only used on x86.
+#if defined(_TARGET_X86_)
+ // the exception registration record covering the stack range containing the interception point
+ PEXCEPTION_REGISTRATION_RECORD m_pDebuggerInterceptFrame;
+#endif // defined(_TARGET_X86_)
+
+ // the nesting level at which we want to resume execution
+ int m_dDebuggerInterceptHandlerDepth;
+};
+#endif // DEBUGGING_SUPPORTED
+
+class EHClauseInfo
+{
+public:
+ EHClauseInfo()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // For the profiler, other clause fields are not valid if m_ClauseType is COR_PRF_CLAUSE_NONE.
+ m_ClauseType = COR_PRF_CLAUSE_NONE;
+ m_IPForEHClause = 0;
+ m_sfForEHClause.Clear();
+ m_csfEHClause.Clear();
+ m_fManagedCodeEntered = FALSE;
+ }
+
+ void SetEHClauseType(COR_PRF_CLAUSE_TYPE EHClauseType)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_ClauseType = EHClauseType;
+ }
+
+ void SetInfo(COR_PRF_CLAUSE_TYPE EHClauseType,
+ UINT_PTR uIPForEHClause,
+ StackFrame sfForEHClause)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_ClauseType = EHClauseType;
+ m_IPForEHClause = uIPForEHClause;
+ m_sfForEHClause = sfForEHClause;
+ }
+
+ void ResetInfo()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // For the profiler, other clause fields are not valid if m_ClauseType is COR_PRF_CLAUSE_NONE.
+ m_ClauseType = COR_PRF_CLAUSE_NONE;
+ m_IPForEHClause = 0;
+ m_sfForEHClause.Clear();
+ m_csfEHClause.Clear();
+ }
+
+ void SetManagedCodeEntered(BOOL fEntered)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_fManagedCodeEntered = fEntered;
+ }
+
+ void SetCallerStackFrame(CallerStackFrame csfEHClause)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_csfEHClause = csfEHClause;
+ }
+
+ COR_PRF_CLAUSE_TYPE GetClauseType() { LIMITED_METHOD_CONTRACT; return m_ClauseType; }
+
+ UINT_PTR GetIPForEHClause() { LIMITED_METHOD_CONTRACT; return m_IPForEHClause; }
+ UINT_PTR GetFramePointerForEHClause() { LIMITED_METHOD_CONTRACT; return m_sfForEHClause.SP; }
+
+ BOOL IsManagedCodeEntered() { LIMITED_METHOD_CONTRACT; return m_fManagedCodeEntered; }
+
+ StackFrame GetStackFrameForEHClause() { LIMITED_METHOD_CONTRACT; return m_sfForEHClause; }
+ CallerStackFrame GetCallerStackFrameForEHClause(){ LIMITED_METHOD_CONTRACT; return m_csfEHClause; }
+
+ // On some platforms, we make the call to the funclets via an assembly helper. The reference to the field
+ // containing the stack pointer is passed to the assembly helper so that it can update
+ // it with correct SP value once its prolog has executed.
+ //
+ // This method is used to get the field reference
+ CallerStackFrame* GetCallerStackFrameForEHClauseReference()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return &m_csfEHClause;
+ }
+
+private:
+ UINT_PTR m_IPForEHClause; // the entry point of the current notified exception clause
+ StackFrame m_sfForEHClause; // the assocated frame pointer of the current notified exception clause
+ CallerStackFrame m_csfEHClause; // the caller SP of the funclet; only used on WIN64
+
+ COR_PRF_CLAUSE_TYPE m_ClauseType; // this has a value from COR_PRF_CLAUSE_TYPE while an exception notification is pending
+ BOOL m_fManagedCodeEntered; // this flag indicates that we have called the managed code for the current EH clause
+};
+
+class ExceptionFlags
+{
+public:
+ ExceptionFlags()
+ {
+ Init();
+ }
+
+#if defined(WIN64EXCEPTIONS)
+ ExceptionFlags(bool fReadOnly)
+ {
+ Init();
+#ifdef _DEBUG
+ if (fReadOnly)
+ {
+ m_flags |= Ex_FlagsAreReadOnly;
+ m_debugFlags |= Ex_FlagsAreReadOnly;
+ }
+#endif // _DEBUG
+ }
+#endif // defined(WIN64EXCEPTIONS)
+
+ void AssertIfReadOnly()
+ {
+ SUPPORTS_DAC;
+
+#if defined(WIN64EXCEPTIONS) && defined(_DEBUG)
+ if ((m_flags & Ex_FlagsAreReadOnly) || (m_debugFlags & Ex_FlagsAreReadOnly))
+ {
+ _ASSERTE(!"Tried to update read-only flags!");
+ }
+#endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG)
+ }
+
+ void Init()
+ {
+ m_flags = 0;
+#ifdef _DEBUG
+ m_debugFlags = 0;
+#endif // _DEBUG
+ }
+
+ BOOL IsRethrown() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsRethrown; }
+ void SetIsRethrown() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsRethrown; }
+ void ResetIsRethrown() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_IsRethrown; }
+
+ BOOL UnwindHasStarted() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_UnwindHasStarted; }
+ void SetUnwindHasStarted() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UnwindHasStarted; }
+ void ResetUnwindHasStarted() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UnwindHasStarted; }
+
+ BOOL UnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_UnwindingToFindResumeFrame; }
+ void SetUnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UnwindingToFindResumeFrame; }
+ void ResetUnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UnwindingToFindResumeFrame; }
+
+ BOOL UseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_UseExInfoForStackwalk; }
+ void SetUseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UseExInfoForStackwalk; }
+ void ResetUseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UseExInfoForStackwalk; }
+
+#ifdef _DEBUG
+ BOOL ReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; return m_debugFlags & Ex_RPInvokeEscapingException; }
+ void SetReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_debugFlags |= Ex_RPInvokeEscapingException; }
+ void ResetReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_debugFlags &= ~Ex_RPInvokeEscapingException; }
+#endif // _DEBUG
+
+#ifdef DEBUGGING_SUPPORTED
+ BOOL SentDebugUserFirstChance() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUserFirstChance; }
+ void SetSentDebugUserFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUserFirstChance; }
+
+ BOOL SentDebugFirstChance() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugFirstChance; }
+ void SetSentDebugFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugFirstChance; }
+
+ BOOL SentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnwindBegin; }
+ void SetSentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnwindBegin; }
+
+ BOOL DebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebugCatchHandlerFound; }
+ void SetDebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebugCatchHandlerFound; }
+
+ BOOL SentDebugUnhandled() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnhandled; }
+ void SetSentDebugUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnhandled; }
+
+ BOOL IsUnhandled() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsUnhandled; }
+ void SetUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsUnhandled; }
+
+ BOOL DebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebuggerInterceptNotPossible; }
+ void SetDebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptNotPossible; }
+
+ BOOL DebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_DebuggerInterceptInfo; }
+ void SetDebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptInfo; }
+#endif
+
+ BOOL ImpersonationTokenSet() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_ImpersonationTokenSet; }
+ void SetImpersonationTokenSet() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_ImpersonationTokenSet; }
+ void ResetImpersonationTokenSet() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_ImpersonationTokenSet; }
+
+ BOOL WasThrownByUs() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_WasThrownByUs; }
+ void SetWasThrownByUs() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_WasThrownByUs; }
+ void ResetWasThrownByUs() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_WasThrownByUs; }
+
+ BOOL GotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_GotWatsonBucketInfo; }
+ void SetGotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_GotWatsonBucketInfo; }
+ void ResetGotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_GotWatsonBucketInfo; }
+
+private:
+ enum
+ {
+ Ex_IsRethrown = 0x00000001,
+ Ex_UnwindingToFindResumeFrame = 0x00000002,
+ Ex_UnwindHasStarted = 0x00000004,
+ Ex_UseExInfoForStackwalk = 0x00000008, // Use this ExInfo to unwind a fault (AV, zerodiv) back to managed code?
+
+#ifdef DEBUGGING_SUPPORTED
+ Ex_SentDebugUserFirstChance = 0x00000010,
+ Ex_SentDebugFirstChance = 0x00000020,
+ Ex_SentDebugUnwindBegin = 0x00000040,
+ Ex_DebugCatchHandlerFound = 0x00000080,
+ Ex_SentDebugUnhandled = 0x00000100,
+ Ex_DebuggerInterceptInfo = 0x00000200,
+ Ex_DebuggerInterceptNotPossible = 0x00000400,
+ Ex_IsUnhandled = 0x00000800,
+#endif
+ Ex_ImpersonationTokenSet = 0x00001000,
+
+ Ex_WasThrownByUs = 0x00002000,
+
+ Ex_GotWatsonBucketInfo = 0x00004000,
+
+#if defined(WIN64EXCEPTIONS) && defined(_DEBUG)
+ Ex_FlagsAreReadOnly = 0x80000000
+#endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG)
+
+ };
+
+ UINT32 m_flags;
+
+#ifdef _DEBUG
+ enum
+ {
+ Ex_RPInvokeEscapingException = 0x40000000
+ };
+ UINT32 m_debugFlags;
+#endif // _DEBUG
+};
+
+//------------------------------------------------------------------------------
+// Error reporting (unhandled exception, fatal error, user breakpoint
+class TypeOfReportedError
+{
+public:
+ enum Type {INVALID, UnhandledException, FatalError, UserBreakpoint, NativeThreadUnhandledException, NativeBreakpoint, StackOverflowException};
+
+ TypeOfReportedError(Type t) : m_type(t) {}
+
+ BOOL IsUnhandledException() { LIMITED_METHOD_CONTRACT; return (m_type == UnhandledException) || (m_type == NativeThreadUnhandledException) || (m_type == StackOverflowException); }
+ BOOL IsFatalError() { return (m_type == FatalError); }
+ BOOL IsUserBreakpoint() {return (m_type == UserBreakpoint); }
+ BOOL IsBreakpoint() {return (m_type == UserBreakpoint) || (m_type == NativeBreakpoint); }
+ BOOL IsException() { LIMITED_METHOD_CONTRACT; return IsUnhandledException() || (m_type == NativeBreakpoint) || (m_type == StackOverflowException); }
+
+ Type GetType() { return m_type; }
+ void SetType(Type t) { m_type = t; }
+
+private:
+ Type m_type;
+};
+
+
+#ifndef FEATURE_PAL
+// This class is used to track Watson bucketing information for an exception.
+typedef DPTR(class EHWatsonBucketTracker) PTR_EHWatsonBucketTracker;
+class EHWatsonBucketTracker
+{
+private:
+ struct
+ {
+ PTR_VOID m_pUnhandledBuckets;
+ UINT_PTR m_UnhandledIp;
+ } m_WatsonUnhandledInfo;
+
+#ifdef _DEBUG
+ enum
+ {
+ // Bucket details were captured for ThreadAbort
+ Wb_CapturedForThreadAbort = 1,
+
+ // Bucket details were captured at AD Transition
+ Wb_CapturedAtADTransition = 2,
+
+ // Bucket details were captured during Reflection invocation
+ Wb_CapturedAtReflectionInvocation = 4
+ };
+
+ DWORD m_DebugFlags;
+#endif // _DEBUG
+
+public:
+ EHWatsonBucketTracker();
+ void Init();
+ void CopyEHWatsonBucketTracker(const EHWatsonBucketTracker& srcTracker);
+ void CopyBucketsFromThrowable(OBJECTREF oThrowable);
+ void SaveIpForWatsonBucket(UINT_PTR ip);
+ UINT_PTR RetrieveWatsonBucketIp();
+ PTR_VOID RetrieveWatsonBuckets();
+ void ClearWatsonBucketDetails();
+ void CaptureUnhandledInfoForWatson(TypeOfReportedError tore, Thread * pThread, OBJECTREF * pThrowable);
+
+#ifdef _DEBUG
+ void ResetFlags() { LIMITED_METHOD_CONTRACT; m_DebugFlags = 0; }
+ BOOL CapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedForThreadAbort; }
+ void SetCapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedForThreadAbort; }
+ void ResetCapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedForThreadAbort; }
+
+ BOOL CapturedAtADTransition() { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedAtADTransition; }
+ void SetCapturedAtADTransition() { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedAtADTransition; }
+ void ResetCapturedAtADTransition() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedAtADTransition; }
+
+ BOOL CapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedAtReflectionInvocation; }
+ void SetCapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedAtReflectionInvocation; }
+ void ResetCapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedAtReflectionInvocation; }
+#endif // _DEBUG
+};
+
+void SetStateForWatsonBucketing(BOOL fIsRethrownException, OBJECTHANDLE ohOriginalException);
+BOOL CopyWatsonBucketsToThrowable(PTR_VOID pUnmanagedBuckets, OBJECTREF oTargetThrowable = NULL);
+void CopyWatsonBucketsFromThrowableToCurrentThrowable(OBJECTREF oThrowableFrom);
+void CopyWatsonBucketsBetweenThrowables(OBJECTREF oThrowableFrom, OBJECTREF oThrowableTo = NULL);
+void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp);
+BOOL SetupWatsonBucketsForFailFast(EXCEPTIONREF refException);
+void SetupWatsonBucketsForUEF(BOOL fUseLastThrownObject);
+BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions();
+BOOL SetupWatsonBucketsForNonPreallocatedExceptions(OBJECTREF oThrowable = NULL);
+PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, BOOL fCaptureBucketsIfNotPresent,
+ BOOL fStartSearchFromPreviousTracker = FALSE);
+BOOL IsThrowableThreadAbortException(OBJECTREF oThrowable);
+#endif // !FEATURE_PAL
+
+#endif // __ExStateCommon_h__