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.
4//
5
6//
7
8#ifndef __ExStateCommon_h__
9#define __ExStateCommon_h__
10
11#include "stackframe.h"
12
13class ExceptionFlags;
14
15#ifdef DEBUGGING_SUPPORTED
16//---------------------------------------------------------------------------------------
17//
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.
21//
22// Notes:
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.
25//
26
27class DebuggerExState
28{
29public:
30
31 //---------------------------------------------------------------------------------------
32 //
33 // constructor
34 //
35
36 DebuggerExState()
37 {
38 Init();
39 }
40
41 //---------------------------------------------------------------------------------------
42 //
43 // This function is simply used to initialize all the fields in the DebuggerExState.
44 //
45
46 void Init()
47 {
48 m_sfDebuggerIndicatedFramePointer = StackFrame();
49 m_pDebuggerInterceptFunc = NULL;
50 m_sfDebuggerInterceptFramePointer = StackFrame();
51 m_pDebuggerContext = NULL;
52 m_pDebuggerInterceptNativeOffset = 0;
53
54 #ifndef WIN64EXCEPTIONS
55 // x86-specific fields
56 m_pDebuggerInterceptFrame = EXCEPTION_CHAIN_END;
57 #endif // !WIN64EXCEPTIONS
58 m_dDebuggerInterceptHandlerDepth = 0;
59 }
60
61 //---------------------------------------------------------------------------------------
62 //
63 // Retrieves the opaque token stored by the debugger.
64 //
65 // Return Value:
66 // the stored opaque token for the debugger
67 //
68
69 void* GetDebuggerInterceptContext()
70 {
71 LIMITED_METHOD_CONTRACT;
72 return m_pDebuggerContext;
73 }
74
75 //---------------------------------------------------------------------------------------
76 //
77 // Stores an opaque token which is only used by the debugger.
78 //
79 // Arguments:
80 // pContext - the token to be stored
81 //
82
83 void SetDebuggerInterceptContext(void* pContext)
84 {
85 LIMITED_METHOD_CONTRACT;
86 m_pDebuggerContext = pContext;
87 }
88
89 //---------------------------------------------------------------------------------------
90 //
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.
94 //
95 // Arguments:
96 // stackPointer - SP of the current stack frame
97 // bStorePointer - BSP of the current stack frame
98 //
99
100 void SetDebuggerIndicatedFramePointer(void* stackPointer)
101 {
102 LIMITED_METHOD_CONTRACT;
103 m_sfDebuggerIndicatedFramePointer = StackFrame((UINT_PTR)stackPointer);
104 }
105
106 // This function stores the information necessary to intercept an exception in the DebuggerExState.
107 BOOL SetDebuggerInterceptInfo(IJitManager *pJitManager,
108 Thread *pThread,
109 const METHODTOKEN& methodToken,
110 MethodDesc *pMethDesc,
111 ULONG_PTR natOffset,
112 StackFrame sfDebuggerInterceptFramePointer,
113 ExceptionFlags* pFlags);
114
115 //---------------------------------------------------------------------------------------
116 //
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.
119 //
120 // Arguments:
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
128 //
129 // Notes:
130 // Everything is an out parameter.
131 //
132 // Apparently ppFrame is actually used on x86 to set tct.pBottomFrame to NULL.
133 //
134
135 void GetDebuggerInterceptInfo(
136 #ifndef WIN64EXCEPTIONS
137 PEXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
138 #endif // !WIN64EXCEPTIONS
139 MethodDesc **ppFunc,
140 int *pdHandler,
141 BYTE **ppStack,
142 ULONG_PTR *pNativeOffset,
143 Frame **ppFrame)
144 {
145 LIMITED_METHOD_CONTRACT;
146
147#ifndef WIN64EXCEPTIONS
148 if (pEstablisherFrame != NULL)
149 {
150 *pEstablisherFrame = m_pDebuggerInterceptFrame;
151 }
152#endif // !WIN64EXCEPTIONS
153
154 if (ppFunc != NULL)
155 {
156 *ppFunc = m_pDebuggerInterceptFunc;
157 }
158
159 if (pdHandler != NULL)
160 {
161 *pdHandler = m_dDebuggerInterceptHandlerDepth;
162 }
163
164 if (ppStack != NULL)
165 {
166 *ppStack = (BYTE *)m_sfDebuggerInterceptFramePointer.SP;
167 }
168
169 if (pNativeOffset != NULL)
170 {
171 *pNativeOffset = m_pDebuggerInterceptNativeOffset;
172 }
173
174 if (ppFrame != NULL)
175 {
176 *ppFrame = NULL;
177 }
178 }
179
180private:
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;
184
185 // the method in which we are going to resume execution
186 MethodDesc* m_pDebuggerInterceptFunc;
187
188 // the frame pointer of the stack frame where we are intercepting the exception
189 StackFrame m_sfDebuggerInterceptFramePointer;
190
191 // opaque token used by the debugger
192 void* m_pDebuggerContext;
193
194 // the native offset at which to resume execution
195 ULONG_PTR m_pDebuggerInterceptNativeOffset;
196
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
202
203 // the nesting level at which we want to resume execution
204 int m_dDebuggerInterceptHandlerDepth;
205};
206#endif // DEBUGGING_SUPPORTED
207
208class EHClauseInfo
209{
210public:
211 EHClauseInfo()
212 {
213 LIMITED_METHOD_CONTRACT;
214
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;
217 m_IPForEHClause = 0;
218 m_sfForEHClause.Clear();
219 m_csfEHClause.Clear();
220 m_fManagedCodeEntered = FALSE;
221 }
222
223 void SetEHClauseType(COR_PRF_CLAUSE_TYPE EHClauseType)
224 {
225 LIMITED_METHOD_CONTRACT;
226 m_ClauseType = EHClauseType;
227 }
228
229 void SetInfo(COR_PRF_CLAUSE_TYPE EHClauseType,
230 UINT_PTR uIPForEHClause,
231 StackFrame sfForEHClause)
232 {
233 LIMITED_METHOD_CONTRACT;
234
235 m_ClauseType = EHClauseType;
236 m_IPForEHClause = uIPForEHClause;
237 m_sfForEHClause = sfForEHClause;
238 }
239
240 void ResetInfo()
241 {
242 LIMITED_METHOD_CONTRACT;
243
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;
246 m_IPForEHClause = 0;
247 m_sfForEHClause.Clear();
248 m_csfEHClause.Clear();
249 }
250
251 void SetManagedCodeEntered(BOOL fEntered)
252 {
253 LIMITED_METHOD_CONTRACT;
254 m_fManagedCodeEntered = fEntered;
255 }
256
257 void SetCallerStackFrame(CallerStackFrame csfEHClause)
258 {
259 LIMITED_METHOD_CONTRACT;
260 m_csfEHClause = csfEHClause;
261 }
262
263 COR_PRF_CLAUSE_TYPE GetClauseType() { LIMITED_METHOD_CONTRACT; return m_ClauseType; }
264
265 UINT_PTR GetIPForEHClause() { LIMITED_METHOD_CONTRACT; return m_IPForEHClause; }
266 UINT_PTR GetFramePointerForEHClause() { LIMITED_METHOD_CONTRACT; return m_sfForEHClause.SP; }
267
268 BOOL IsManagedCodeEntered() { LIMITED_METHOD_CONTRACT; return m_fManagedCodeEntered; }
269
270 StackFrame GetStackFrameForEHClause() { LIMITED_METHOD_CONTRACT; return m_sfForEHClause; }
271 CallerStackFrame GetCallerStackFrameForEHClause(){ LIMITED_METHOD_CONTRACT; return m_csfEHClause; }
272
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.
276 //
277 // This method is used to get the field reference
278 CallerStackFrame* GetCallerStackFrameForEHClauseReference()
279 {
280 LIMITED_METHOD_CONTRACT;
281 return &m_csfEHClause;
282 }
283
284private:
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
288
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
291};
292
293class ExceptionFlags
294{
295public:
296 ExceptionFlags()
297 {
298 Init();
299 }
300
301#if defined(WIN64EXCEPTIONS)
302 ExceptionFlags(bool fReadOnly)
303 {
304 Init();
305#ifdef _DEBUG
306 if (fReadOnly)
307 {
308 m_flags |= Ex_FlagsAreReadOnly;
309 m_debugFlags |= Ex_FlagsAreReadOnly;
310 }
311#endif // _DEBUG
312 }
313#endif // defined(WIN64EXCEPTIONS)
314
315 void AssertIfReadOnly()
316 {
317 SUPPORTS_DAC;
318
319#if defined(WIN64EXCEPTIONS) && defined(_DEBUG)
320 if ((m_flags & Ex_FlagsAreReadOnly) || (m_debugFlags & Ex_FlagsAreReadOnly))
321 {
322 _ASSERTE(!"Tried to update read-only flags!");
323 }
324#endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG)
325 }
326
327 void Init()
328 {
329 m_flags = 0;
330#ifdef _DEBUG
331 m_debugFlags = 0;
332#endif // _DEBUG
333 }
334
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; }
338
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; }
342
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; }
346
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; }
350
351#ifdef _DEBUG
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; }
355#endif // _DEBUG
356
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; }
360
361 BOOL SentDebugFirstChance() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugFirstChance; }
362 void SetSentDebugFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugFirstChance; }
363
364 BOOL SentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnwindBegin; }
365 void SetSentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnwindBegin; }
366
367 BOOL DebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebugCatchHandlerFound; }
368 void SetDebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebugCatchHandlerFound; }
369
370 BOOL SentDebugUnhandled() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnhandled; }
371 void SetSentDebugUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnhandled; }
372
373 BOOL IsUnhandled() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsUnhandled; }
374 void SetUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsUnhandled; }
375
376 BOOL DebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebuggerInterceptNotPossible; }
377 void SetDebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptNotPossible; }
378
379 BOOL DebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_DebuggerInterceptInfo; }
380 void SetDebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptInfo; }
381#endif
382
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; }
386
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; }
390
391private:
392 enum
393 {
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?
398
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,
408#endif
409 // Unused = 0x00001000,
410
411 Ex_WasThrownByUs = 0x00002000,
412
413 Ex_GotWatsonBucketInfo = 0x00004000,
414
415#if defined(WIN64EXCEPTIONS) && defined(_DEBUG)
416 Ex_FlagsAreReadOnly = 0x80000000
417#endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG)
418
419 };
420
421 UINT32 m_flags;
422
423#ifdef _DEBUG
424 enum
425 {
426 Ex_RPInvokeEscapingException = 0x40000000
427 };
428 UINT32 m_debugFlags;
429#endif // _DEBUG
430};
431
432//------------------------------------------------------------------------------
433// Error reporting (unhandled exception, fatal error, user breakpoint
434class TypeOfReportedError
435{
436public:
437 enum Type {INVALID, UnhandledException, FatalError, UserBreakpoint, NativeThreadUnhandledException, NativeBreakpoint, StackOverflowException};
438
439 TypeOfReportedError(Type t) : m_type(t) {}
440
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); }
446
447 Type GetType() { return m_type; }
448 void SetType(Type t) { m_type = t; }
449
450private:
451 Type m_type;
452};
453
454
455#ifndef FEATURE_PAL
456// This class is used to track Watson bucketing information for an exception.
457typedef DPTR(class EHWatsonBucketTracker) PTR_EHWatsonBucketTracker;
458class EHWatsonBucketTracker
459{
460private:
461 struct
462 {
463 PTR_VOID m_pUnhandledBuckets;
464 UINT_PTR m_UnhandledIp;
465 } m_WatsonUnhandledInfo;
466
467#ifdef _DEBUG
468 enum
469 {
470 // Bucket details were captured for ThreadAbort
471 Wb_CapturedForThreadAbort = 1,
472
473 // Bucket details were captured at AD Transition
474 Wb_CapturedAtADTransition = 2,
475
476 // Bucket details were captured during Reflection invocation
477 Wb_CapturedAtReflectionInvocation = 4
478 };
479
480 DWORD m_DebugFlags;
481#endif // _DEBUG
482
483public:
484 EHWatsonBucketTracker();
485 void Init();
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);
493
494#ifdef _DEBUG
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; }
499
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; }
503
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; }
507#endif // _DEBUG
508};
509
510void SetStateForWatsonBucketing(BOOL fIsRethrownException, OBJECTHANDLE ohOriginalException);
511BOOL CopyWatsonBucketsToThrowable(PTR_VOID pUnmanagedBuckets, OBJECTREF oTargetThrowable = NULL);
512void CopyWatsonBucketsFromThrowableToCurrentThrowable(OBJECTREF oThrowableFrom);
513void CopyWatsonBucketsBetweenThrowables(OBJECTREF oThrowableFrom, OBJECTREF oThrowableTo = NULL);
514void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp);
515BOOL SetupWatsonBucketsForFailFast(EXCEPTIONREF refException);
516void SetupWatsonBucketsForUEF(BOOL fUseLastThrownObject);
517BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions();
518BOOL SetupWatsonBucketsForNonPreallocatedExceptions(OBJECTREF oThrowable = NULL);
519PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, BOOL fCaptureBucketsIfNotPresent,
520 BOOL fStartSearchFromPreviousTracker = FALSE);
521BOOL IsThrowableThreadAbortException(OBJECTREF oThrowable);
522#endif // !FEATURE_PAL
523
524#endif // __ExStateCommon_h__
525