1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
8 #ifndef __ExStateCommon_h__
9 #define __ExStateCommon_h__
11 #include "stackframe.h"
15 #ifdef DEBUGGING_SUPPORTED
16 //---------------------------------------------------------------------------------------
18 // This class stores information necessary to intercept an exception. It's basically a communication channel
19 // between the debugger and the EH subsystem. Each internal exception tracking structure
20 // (ExInfo on x86 and ExceptionTracker on WIN64) contains one DebuggerExState.
23 // This class actually stores more information on x86 than on WIN64 because the x86 EH subsystem
24 // has more work to do when unwinding the stack. WIN64 just asks the OS to do it.
31 //---------------------------------------------------------------------------------------
41 //---------------------------------------------------------------------------------------
43 // This function is simply used to initialize all the fields in the DebuggerExState.
48 m_sfDebuggerIndicatedFramePointer = StackFrame();
49 m_pDebuggerInterceptFunc = NULL;
50 m_sfDebuggerInterceptFramePointer = StackFrame();
51 m_pDebuggerContext = NULL;
52 m_pDebuggerInterceptNativeOffset = 0;
54 #ifndef WIN64EXCEPTIONS
55 // x86-specific fields
56 m_pDebuggerInterceptFrame = EXCEPTION_CHAIN_END;
57 #endif // !WIN64EXCEPTIONS
58 m_dDebuggerInterceptHandlerDepth = 0;
61 //---------------------------------------------------------------------------------------
63 // Retrieves the opaque token stored by the debugger.
66 // the stored opaque token for the debugger
69 void* GetDebuggerInterceptContext()
71 LIMITED_METHOD_CONTRACT;
72 return m_pDebuggerContext;
75 //---------------------------------------------------------------------------------------
77 // Stores an opaque token which is only used by the debugger.
80 // pContext - the token to be stored
83 void SetDebuggerInterceptContext(void* pContext)
85 LIMITED_METHOD_CONTRACT;
86 m_pDebuggerContext = pContext;
89 //---------------------------------------------------------------------------------------
91 // Marks the current stack frame visited by the EH subsystem during the first pass.
92 // This marker moves closer to the root of the stack while each stack frame is examined in the first pass.
93 // This continues until the end of the first pass.
96 // stackPointer - SP of the current stack frame
97 // bStorePointer - BSP of the current stack frame
100 void SetDebuggerIndicatedFramePointer(void* stackPointer)
102 LIMITED_METHOD_CONTRACT;
103 m_sfDebuggerIndicatedFramePointer = StackFrame((UINT_PTR)stackPointer);
106 // This function stores the information necessary to intercept an exception in the DebuggerExState.
107 BOOL SetDebuggerInterceptInfo(IJitManager *pJitManager,
109 const METHODTOKEN& methodToken,
110 MethodDesc *pMethDesc,
112 StackFrame sfDebuggerInterceptFramePointer,
113 ExceptionFlags* pFlags);
115 //---------------------------------------------------------------------------------------
117 // This function is basically just a getter to retrieve the information stored on the DebuggerExState.
118 // Refer to the comments for individual fields for more information.
121 // pEstablisherFrame - m_pDebuggerInterceptFrame
122 // ppFunc - m_pDebuggerInterceptFunc
123 // pdHandler - m_dDebuggerInterceptHandlerDepth
124 // ppStack - the SP of m_sfDebuggerInterceptFramePointer
125 // ppBStore - the BSP of m_sfDebuggerInterceptFramePointer
126 // pNativeOffset - m_pDebuggerInterceptNativeOffset;
127 // ppFrame - always set to NULL
130 // Everything is an out parameter.
132 // Apparently ppFrame is actually used on x86 to set tct.pBottomFrame to NULL.
135 void GetDebuggerInterceptInfo(
136 #ifndef WIN64EXCEPTIONS
137 PEXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
138 #endif // !WIN64EXCEPTIONS
142 ULONG_PTR *pNativeOffset,
145 LIMITED_METHOD_CONTRACT;
147 #ifndef WIN64EXCEPTIONS
148 if (pEstablisherFrame != NULL)
150 *pEstablisherFrame = m_pDebuggerInterceptFrame;
152 #endif // !WIN64EXCEPTIONS
156 *ppFunc = m_pDebuggerInterceptFunc;
159 if (pdHandler != NULL)
161 *pdHandler = m_dDebuggerInterceptHandlerDepth;
166 *ppStack = (BYTE *)m_sfDebuggerInterceptFramePointer.SP;
169 if (pNativeOffset != NULL)
171 *pNativeOffset = m_pDebuggerInterceptNativeOffset;
181 // This frame pointer marks the latest stack frame examined by the EH subsystem in the first pass.
182 // An exception cannot be intercepted closer to the root than this frame pointer.
183 StackFrame m_sfDebuggerIndicatedFramePointer;
185 // the method in which we are going to resume execution
186 MethodDesc* m_pDebuggerInterceptFunc;
188 // the frame pointer of the stack frame where we are intercepting the exception
189 StackFrame m_sfDebuggerInterceptFramePointer;
191 // opaque token used by the debugger
192 void* m_pDebuggerContext;
194 // the native offset at which to resume execution
195 ULONG_PTR m_pDebuggerInterceptNativeOffset;
197 // The remaining fields are only used on x86.
198 #ifndef WIN64EXCEPTIONS
199 // the exception registration record covering the stack range containing the interception point
200 PEXCEPTION_REGISTRATION_RECORD m_pDebuggerInterceptFrame;
201 #endif // !WIN64EXCEPTIONS
203 // the nesting level at which we want to resume execution
204 int m_dDebuggerInterceptHandlerDepth;
206 #endif // DEBUGGING_SUPPORTED
213 LIMITED_METHOD_CONTRACT;
215 // For the profiler, other clause fields are not valid if m_ClauseType is COR_PRF_CLAUSE_NONE.
216 m_ClauseType = COR_PRF_CLAUSE_NONE;
218 m_sfForEHClause.Clear();
219 m_csfEHClause.Clear();
220 m_fManagedCodeEntered = FALSE;
223 void SetEHClauseType(COR_PRF_CLAUSE_TYPE EHClauseType)
225 LIMITED_METHOD_CONTRACT;
226 m_ClauseType = EHClauseType;
229 void SetInfo(COR_PRF_CLAUSE_TYPE EHClauseType,
230 UINT_PTR uIPForEHClause,
231 StackFrame sfForEHClause)
233 LIMITED_METHOD_CONTRACT;
235 m_ClauseType = EHClauseType;
236 m_IPForEHClause = uIPForEHClause;
237 m_sfForEHClause = sfForEHClause;
242 LIMITED_METHOD_CONTRACT;
244 // For the profiler, other clause fields are not valid if m_ClauseType is COR_PRF_CLAUSE_NONE.
245 m_ClauseType = COR_PRF_CLAUSE_NONE;
247 m_sfForEHClause.Clear();
248 m_csfEHClause.Clear();
251 void SetManagedCodeEntered(BOOL fEntered)
253 LIMITED_METHOD_CONTRACT;
254 m_fManagedCodeEntered = fEntered;
257 void SetCallerStackFrame(CallerStackFrame csfEHClause)
259 LIMITED_METHOD_CONTRACT;
260 m_csfEHClause = csfEHClause;
263 COR_PRF_CLAUSE_TYPE GetClauseType() { LIMITED_METHOD_CONTRACT; return m_ClauseType; }
265 UINT_PTR GetIPForEHClause() { LIMITED_METHOD_CONTRACT; return m_IPForEHClause; }
266 UINT_PTR GetFramePointerForEHClause() { LIMITED_METHOD_CONTRACT; return m_sfForEHClause.SP; }
268 BOOL IsManagedCodeEntered() { LIMITED_METHOD_CONTRACT; return m_fManagedCodeEntered; }
270 StackFrame GetStackFrameForEHClause() { LIMITED_METHOD_CONTRACT; return m_sfForEHClause; }
271 CallerStackFrame GetCallerStackFrameForEHClause(){ LIMITED_METHOD_CONTRACT; return m_csfEHClause; }
273 // On some platforms, we make the call to the funclets via an assembly helper. The reference to the field
274 // containing the stack pointer is passed to the assembly helper so that it can update
275 // it with correct SP value once its prolog has executed.
277 // This method is used to get the field reference
278 CallerStackFrame* GetCallerStackFrameForEHClauseReference()
280 LIMITED_METHOD_CONTRACT;
281 return &m_csfEHClause;
285 UINT_PTR m_IPForEHClause; // the entry point of the current notified exception clause
286 StackFrame m_sfForEHClause; // the assocated frame pointer of the current notified exception clause
287 CallerStackFrame m_csfEHClause; // the caller SP of the funclet; only used on WIN64
289 COR_PRF_CLAUSE_TYPE m_ClauseType; // this has a value from COR_PRF_CLAUSE_TYPE while an exception notification is pending
290 BOOL m_fManagedCodeEntered; // this flag indicates that we have called the managed code for the current EH clause
301 #if defined(WIN64EXCEPTIONS)
302 ExceptionFlags(bool fReadOnly)
308 m_flags |= Ex_FlagsAreReadOnly;
309 m_debugFlags |= Ex_FlagsAreReadOnly;
313 #endif // defined(WIN64EXCEPTIONS)
315 void AssertIfReadOnly()
319 #if defined(WIN64EXCEPTIONS) && defined(_DEBUG)
320 if ((m_flags & Ex_FlagsAreReadOnly) || (m_debugFlags & Ex_FlagsAreReadOnly))
322 _ASSERTE(!"Tried to update read-only flags!");
324 #endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG)
335 BOOL IsRethrown() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsRethrown; }
336 void SetIsRethrown() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsRethrown; }
337 void ResetIsRethrown() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_IsRethrown; }
339 BOOL UnwindHasStarted() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_UnwindHasStarted; }
340 void SetUnwindHasStarted() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UnwindHasStarted; }
341 void ResetUnwindHasStarted() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UnwindHasStarted; }
343 BOOL UnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_UnwindingToFindResumeFrame; }
344 void SetUnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UnwindingToFindResumeFrame; }
345 void ResetUnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UnwindingToFindResumeFrame; }
347 BOOL UseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_UseExInfoForStackwalk; }
348 void SetUseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UseExInfoForStackwalk; }
349 void ResetUseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UseExInfoForStackwalk; }
352 BOOL ReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; return m_debugFlags & Ex_RPInvokeEscapingException; }
353 void SetReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_debugFlags |= Ex_RPInvokeEscapingException; }
354 void ResetReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_debugFlags &= ~Ex_RPInvokeEscapingException; }
357 #ifdef DEBUGGING_SUPPORTED
358 BOOL SentDebugUserFirstChance() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUserFirstChance; }
359 void SetSentDebugUserFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUserFirstChance; }
361 BOOL SentDebugFirstChance() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugFirstChance; }
362 void SetSentDebugFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugFirstChance; }
364 BOOL SentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnwindBegin; }
365 void SetSentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnwindBegin; }
367 BOOL DebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebugCatchHandlerFound; }
368 void SetDebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebugCatchHandlerFound; }
370 BOOL SentDebugUnhandled() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnhandled; }
371 void SetSentDebugUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnhandled; }
373 BOOL IsUnhandled() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsUnhandled; }
374 void SetUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsUnhandled; }
376 BOOL DebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebuggerInterceptNotPossible; }
377 void SetDebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptNotPossible; }
379 BOOL DebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_DebuggerInterceptInfo; }
380 void SetDebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptInfo; }
383 BOOL WasThrownByUs() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_WasThrownByUs; }
384 void SetWasThrownByUs() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_WasThrownByUs; }
385 void ResetWasThrownByUs() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_WasThrownByUs; }
387 BOOL GotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_GotWatsonBucketInfo; }
388 void SetGotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_GotWatsonBucketInfo; }
389 void ResetGotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_GotWatsonBucketInfo; }
394 Ex_IsRethrown = 0x00000001,
395 Ex_UnwindingToFindResumeFrame = 0x00000002,
396 Ex_UnwindHasStarted = 0x00000004,
397 Ex_UseExInfoForStackwalk = 0x00000008, // Use this ExInfo to unwind a fault (AV, zerodiv) back to managed code?
399 #ifdef DEBUGGING_SUPPORTED
400 Ex_SentDebugUserFirstChance = 0x00000010,
401 Ex_SentDebugFirstChance = 0x00000020,
402 Ex_SentDebugUnwindBegin = 0x00000040,
403 Ex_DebugCatchHandlerFound = 0x00000080,
404 Ex_SentDebugUnhandled = 0x00000100,
405 Ex_DebuggerInterceptInfo = 0x00000200,
406 Ex_DebuggerInterceptNotPossible = 0x00000400,
407 Ex_IsUnhandled = 0x00000800,
409 // Unused = 0x00001000,
411 Ex_WasThrownByUs = 0x00002000,
413 Ex_GotWatsonBucketInfo = 0x00004000,
415 #if defined(WIN64EXCEPTIONS) && defined(_DEBUG)
416 Ex_FlagsAreReadOnly = 0x80000000
417 #endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG)
426 Ex_RPInvokeEscapingException = 0x40000000
432 //------------------------------------------------------------------------------
433 // Error reporting (unhandled exception, fatal error, user breakpoint
434 class TypeOfReportedError
437 enum Type {INVALID, UnhandledException, FatalError, UserBreakpoint, NativeThreadUnhandledException, NativeBreakpoint, StackOverflowException};
439 TypeOfReportedError(Type t) : m_type(t) {}
441 BOOL IsUnhandledException() { LIMITED_METHOD_CONTRACT; return (m_type == UnhandledException) || (m_type == NativeThreadUnhandledException) || (m_type == StackOverflowException); }
442 BOOL IsFatalError() { return (m_type == FatalError); }
443 BOOL IsUserBreakpoint() {return (m_type == UserBreakpoint); }
444 BOOL IsBreakpoint() {return (m_type == UserBreakpoint) || (m_type == NativeBreakpoint); }
445 BOOL IsException() { LIMITED_METHOD_CONTRACT; return IsUnhandledException() || (m_type == NativeBreakpoint) || (m_type == StackOverflowException); }
447 Type GetType() { return m_type; }
448 void SetType(Type t) { m_type = t; }
456 // This class is used to track Watson bucketing information for an exception.
457 typedef DPTR(class EHWatsonBucketTracker) PTR_EHWatsonBucketTracker;
458 class EHWatsonBucketTracker
463 PTR_VOID m_pUnhandledBuckets;
464 UINT_PTR m_UnhandledIp;
465 } m_WatsonUnhandledInfo;
470 // Bucket details were captured for ThreadAbort
471 Wb_CapturedForThreadAbort = 1,
473 // Bucket details were captured at AD Transition
474 Wb_CapturedAtADTransition = 2,
476 // Bucket details were captured during Reflection invocation
477 Wb_CapturedAtReflectionInvocation = 4
484 EHWatsonBucketTracker();
486 void CopyEHWatsonBucketTracker(const EHWatsonBucketTracker& srcTracker);
487 void CopyBucketsFromThrowable(OBJECTREF oThrowable);
488 void SaveIpForWatsonBucket(UINT_PTR ip);
489 UINT_PTR RetrieveWatsonBucketIp();
490 PTR_VOID RetrieveWatsonBuckets();
491 void ClearWatsonBucketDetails();
492 void CaptureUnhandledInfoForWatson(TypeOfReportedError tore, Thread * pThread, OBJECTREF * pThrowable);
495 void ResetFlags() { LIMITED_METHOD_CONTRACT; m_DebugFlags = 0; }
496 BOOL CapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedForThreadAbort; }
497 void SetCapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedForThreadAbort; }
498 void ResetCapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedForThreadAbort; }
500 BOOL CapturedAtADTransition() { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedAtADTransition; }
501 void SetCapturedAtADTransition() { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedAtADTransition; }
502 void ResetCapturedAtADTransition() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedAtADTransition; }
504 BOOL CapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedAtReflectionInvocation; }
505 void SetCapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedAtReflectionInvocation; }
506 void ResetCapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedAtReflectionInvocation; }
510 void SetStateForWatsonBucketing(BOOL fIsRethrownException, OBJECTHANDLE ohOriginalException);
511 BOOL CopyWatsonBucketsToThrowable(PTR_VOID pUnmanagedBuckets, OBJECTREF oTargetThrowable = NULL);
512 void CopyWatsonBucketsFromThrowableToCurrentThrowable(OBJECTREF oThrowableFrom);
513 void CopyWatsonBucketsBetweenThrowables(OBJECTREF oThrowableFrom, OBJECTREF oThrowableTo = NULL);
514 void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp);
515 BOOL SetupWatsonBucketsForFailFast(EXCEPTIONREF refException);
516 void SetupWatsonBucketsForUEF(BOOL fUseLastThrownObject);
517 BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions();
518 BOOL SetupWatsonBucketsForNonPreallocatedExceptions(OBJECTREF oThrowable = NULL);
519 PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, BOOL fCaptureBucketsIfNotPresent,
520 BOOL fStartSearchFromPreviousTracker = FALSE);
521 BOOL IsThrowableThreadAbortException(OBJECTREF oThrowable);
522 #endif // !FEATURE_PAL
524 #endif // __ExStateCommon_h__