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 __ExState_h__
9#define __ExState_h__
10
11class ExceptionFlags;
12class DebuggerExState;
13class EHClauseInfo;
14
15#include "exceptionhandling.h"
16
17#if !defined(WIN64EXCEPTIONS)
18// ExInfo contains definitions for 32bit
19#include "exinfo.h"
20#endif // !defined(WIN64EXCEPTIONS)
21
22#if !defined(DACCESS_COMPILE)
23#define PRESERVE_WATSON_ACROSS_CONTEXTS 1
24#endif
25
26extern StackWalkAction COMPlusUnwindCallback(CrawlFrame *pCf, ThrowCallbackType *pData);
27
28//
29// This class serves as a forwarding and abstraction layer for the EH subsystem.
30// Since we have two different implementations, this class is needed to unify
31// the EE's view of EH. Ideally, this is just a step along the way to a unified
32// EH subsystem.
33//
34typedef DPTR(class ThreadExceptionState) PTR_ThreadExceptionState;
35class ThreadExceptionState
36{
37 friend class ClrDataExceptionState;
38 friend class CheckAsmOffsets;
39 friend class StackFrameIterator;
40
41#ifdef DACCESS_COMPILE
42 friend class ClrDataAccess;
43#endif // DACCESS_COMPILE
44
45 // ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo needs access so that it can fetch the
46 // ExceptionTracker or the ExInfo as appropriate for the platform
47 friend class ProfToEEInterfaceImpl;
48
49#ifdef WIN64EXCEPTIONS
50 friend class ExceptionTracker;
51#else
52 friend class ExInfo;
53#endif // WIN64EXCEPTIONS
54
55public:
56
57 void FreeAllStackTraces();
58 void ClearThrowablesForUnload(IGCHandleStore* handleStore);
59
60#ifdef _DEBUG
61 typedef enum
62 {
63 STEC_All,
64 STEC_CurrentTrackerEqualNullOkHackForFatalStackOverflow,
65#ifdef FEATURE_INTERPRETER
66 STEC_CurrentTrackerEqualNullOkForInterpreter,
67#endif // FEATURE_INTERPRETER
68 } SetThrowableErrorChecking;
69#endif
70
71 void SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowableErrorChecking stecFlags = STEC_All));
72 OBJECTREF GetThrowable();
73 OBJECTHANDLE GetThrowableAsHandle();
74 DWORD GetExceptionCode();
75 BOOL IsComPlusException();
76 EXCEPTION_POINTERS* GetExceptionPointers();
77 PTR_EXCEPTION_RECORD GetExceptionRecord();
78 PTR_CONTEXT GetContextRecord();
79 BOOL IsExceptionInProgress();
80 void GetLeafFrameInfo(StackTraceElement* pStackTrace);
81
82 ExceptionFlags* GetFlags();
83
84 ThreadExceptionState();
85 ~ThreadExceptionState();
86
87#if !defined(WIN64EXCEPTIONS)
88 void SetExceptionPointers(EXCEPTION_POINTERS *pExceptionPointers);
89#endif
90
91
92#ifdef DEBUGGING_SUPPORTED
93 // DebuggerExState stores information necessary for intercepting an exception
94 DebuggerExState* GetDebuggerState();
95
96 // check to see if the current exception is interceptable
97 BOOL IsDebuggerInterceptable();
98#endif // DEBUGGING_SUPPORTED
99
100 EHClauseInfo* GetCurrentEHClauseInfo();
101
102#ifdef DACCESS_COMPILE
103 void EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags);
104#endif // DACCESS_COMPILE
105
106 // After unwinding from an SO, there may be stale exception state.
107 void ClearExceptionStateAfterSO(void* pStackFrameSP);
108
109 enum ThreadExceptionFlag
110 {
111 TEF_None = 0x00000000,
112
113 // Right now this flag is only used on WIN64. We set this flag near the end of the second pass when we pop
114 // the ExceptionTracker for the current exception but before we actually resume execution. It is unsafe
115 // to start a funclet-skipping stackwalk in this time window.
116 TEF_InconsistentExceptionState = 0x00000001,
117
118 TEF_ForeignExceptionRaise = 0x00000002,
119 };
120
121 void SetThreadExceptionFlag(ThreadExceptionFlag flag);
122 void ResetThreadExceptionFlag(ThreadExceptionFlag flag);
123 BOOL HasThreadExceptionFlag(ThreadExceptionFlag flag);
124
125 inline void SetRaisingForeignException()
126 {
127 LIMITED_METHOD_CONTRACT;
128 SetThreadExceptionFlag(TEF_ForeignExceptionRaise);
129 }
130
131 inline BOOL IsRaisingForeignException()
132 {
133 LIMITED_METHOD_CONTRACT;
134 return HasThreadExceptionFlag(TEF_ForeignExceptionRaise);
135 }
136
137 inline void ResetRaisingForeignException()
138 {
139 LIMITED_METHOD_CONTRACT;
140 ResetThreadExceptionFlag(TEF_ForeignExceptionRaise);
141 }
142
143#if defined(_DEBUG)
144 void AssertStackTraceInfo(StackTraceInfo *pSTI);
145#endif // _debug
146
147private:
148 Thread* GetMyThread();
149
150#ifdef WIN64EXCEPTIONS
151 PTR_ExceptionTracker m_pCurrentTracker;
152 ExceptionTracker m_OOMTracker;
153public:
154 PTR_ExceptionTracker GetCurrentExceptionTracker()
155 {
156 LIMITED_METHOD_CONTRACT;
157 return m_pCurrentTracker;
158 }
159#else
160 ExInfo m_currentExInfo;
161public:
162 PTR_ExInfo GetCurrentExceptionTracker()
163 {
164 LIMITED_METHOD_CONTRACT;
165 return PTR_ExInfo(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_currentExInfo));
166 }
167#endif
168
169#ifdef FEATURE_CORRUPTING_EXCEPTIONS
170private:
171 CorruptionSeverity m_LastActiveExceptionCorruptionSeverity;
172 BOOL m_fCanReflectionTargetHandleException;
173
174public:
175 // Returns the corruption severity of the last active exception
176 inline CorruptionSeverity GetLastActiveExceptionCorruptionSeverity()
177 {
178 LIMITED_METHOD_CONTRACT;
179
180 return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity);
181 }
182
183 // Set the corruption severity of the last active exception
184 inline void SetLastActiveExceptionCorruptionSeverity(CorruptionSeverity severityToSet)
185 {
186 LIMITED_METHOD_CONTRACT;
187
188 m_LastActiveExceptionCorruptionSeverity = severityToSet;
189 }
190
191 // Returns a bool indicating if the last active exception's corruption severity should
192 // be used when exception is reraised (e.g. Reflection Invocation, AD transition, etc)
193 inline BOOL ShouldLastActiveExceptionCorruptionSeverityBeReused()
194 {
195 LIMITED_METHOD_CONTRACT;
196
197 return CAN_REUSE_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity);
198 }
199
200 // Returns a BOOL to indicate if reflection target can handle CSE or not.
201 // This is used in DispatchInfo::CanIDispatchTargetHandleException.
202 inline BOOL CanReflectionTargetHandleException()
203 {
204 LIMITED_METHOD_CONTRACT;
205
206 return m_fCanReflectionTargetHandleException;
207 }
208
209 // Sets a BOOL indicate if the Reflection invocation target can handle exception or not.
210 // Used in ReflectionInvocation.cpp.
211 inline void SetCanReflectionTargetHandleException(BOOL fCanReflectionTargetHandleException)
212 {
213 LIMITED_METHOD_CONTRACT;
214
215 m_fCanReflectionTargetHandleException = fCanReflectionTargetHandleException;
216 }
217#endif // FEATURE_CORRUPTING_EXCEPTIONS
218
219private:
220 ThreadExceptionFlag m_flag;
221
222#ifndef FEATURE_PAL
223private:
224 EHWatsonBucketTracker m_UEWatsonBucketTracker;
225public:
226 PTR_EHWatsonBucketTracker GetUEWatsonBucketTracker()
227 {
228 LIMITED_METHOD_CONTRACT;
229 return PTR_EHWatsonBucketTracker(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_UEWatsonBucketTracker));
230 }
231#endif // !FEATURE_PAL
232
233private:
234
235#ifndef WIN64EXCEPTIONS
236
237 //
238 // @NICE: Ideally, these friends shouldn't all be enumerated like this. If they were all part of the same
239 // class, that would be nice. I'm trying to avoid adding x86-specific accessors to this class as well as
240 // trying to limit the visibility of the ExInfo struct since Win64 doesn't use ExInfo.
241 //
242 friend EXCEPTION_DISPOSITION COMPlusAfterUnwind(
243 EXCEPTION_RECORD *pExceptionRecord,
244 EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
245 ThrowCallbackType& tct);
246 friend EXCEPTION_DISPOSITION COMPlusAfterUnwind(
247 EXCEPTION_RECORD *pExceptionRecord,
248 EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
249 ThrowCallbackType& tct,
250 Frame *pStartFrame);
251
252 friend EXCEPTION_HANDLER_IMPL(COMPlusFrameHandler);
253
254 friend EXCEPTION_DISPOSITION __cdecl
255 CPFH_RealFirstPassHandler(EXCEPTION_RECORD *pExceptionRecord,
256 EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
257 CONTEXT *pContext,
258 void *pDispatcherContext,
259 BOOL bAsynchronousThreadStop,
260 BOOL fPGCDisabledOnEntry);
261
262 friend EXCEPTION_DISPOSITION __cdecl
263 CPFH_UnwindHandler(EXCEPTION_RECORD *pExceptionRecord,
264 EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
265 CONTEXT *pContext,
266 void *pDispatcherContext);
267
268 friend void CPFH_UnwindFrames1(Thread* pThread,
269 EXCEPTION_REGISTRATION_RECORD* pEstablisherFrame,
270 DWORD exceptionCode);
271
272#ifdef _TARGET_X86_
273 friend LPVOID COMPlusEndCatchWorker(Thread * pThread);
274#endif
275
276 friend StackWalkAction COMPlusThrowCallback(CrawlFrame *pCf, ThrowCallbackType *pData);
277
278 friend StackWalkAction COMPlusUnwindCallback(CrawlFrame *pCf, ThrowCallbackType *pData);
279
280#if defined(_TARGET_X86_)
281 friend void ResumeAtJitEH(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHClausePtr,
282 DWORD nestingLevel, Thread *pThread, BOOL unwindStack);
283#endif // _TARGET_X86_
284
285 friend _EXCEPTION_HANDLER_DECL(COMPlusNestedExceptionHandler);
286
287 friend void COMPlusCooperativeTransitionHandler(Frame* pFrame);
288
289 friend bool ShouldHandleManagedFault(
290 EXCEPTION_RECORD* pExceptionRecord,
291 CONTEXT* pContext,
292 EXCEPTION_REGISTRATION_RECORD* pEstablisherFrame,
293 Thread* pThread);
294
295 friend class Thread;
296 // It it the following method that needs to be a friend. But the prototype pulls in a lot more stuff,
297 // so just make the Thread class a friend.
298 // friend StackWalkAction Thread::StackWalkFramesEx(PREGDISPLAY pRD, PSTACKWALKFRAMESCALLBACK pCallback,
299 // VOID *pData, unsigned flags, Frame *pStartFrame);
300
301#endif // WIN64EXCEPTIONS
302
303};
304
305
306// <WARNING>
307// This holder is not thread safe.
308// </WARNING>
309class ThreadExceptionFlagHolder
310{
311public:
312 ThreadExceptionFlagHolder(ThreadExceptionState::ThreadExceptionFlag flag);
313 ~ThreadExceptionFlagHolder();
314
315private:
316 ThreadExceptionState* m_pExState;
317 ThreadExceptionState::ThreadExceptionFlag m_flag;
318};
319
320extern BOOL IsWatsonEnabled();
321
322#ifndef FEATURE_PAL
323// This preprocessor definition is used to capture watson buckets
324// at AppDomain transition boundary in END_DOMAIN_TRANSITION macro.
325//
326// This essentially copies the watson bucket details from the current exception tracker
327// to the UE watson bucket tracker only if it is preallocated exception and NOT
328// thread abort. For preallocated thread abort, UE Watson bucket tracker would already have the
329// bucket details.
330//
331// It also captures buckets for non-preallocated exceptions (including non-preallocated threadabort) since
332// the object would have the IP inside it.
333#define CAPTURE_BUCKETS_AT_TRANSITION(pThread, oThrowable) \
334 if (IsWatsonEnabled()) \
335 { \
336 /* Switch to COOP mode */ \
337 GCX_COOP(); \
338 \
339 /* oThrowable is actually GET_THROWABLE macro; so extract the actual throwable for once and for all */ \
340 OBJECTREF throwable = oThrowable; \
341 if (CLRException::IsPreallocatedExceptionObject(throwable)) \
342 { \
343 if (pThread->GetExceptionState()->GetCurrentExceptionTracker() != NULL) \
344 { \
345 if (!IsThrowableThreadAbortException(throwable)) \
346 { \
347 PTR_EHWatsonBucketTracker pWatsonBucketTracker = GetWatsonBucketTrackerForPreallocatedException(throwable, FALSE); \
348 if (pWatsonBucketTracker != NULL) \
349 { \
350 pThread->GetExceptionState()->GetUEWatsonBucketTracker()->CopyEHWatsonBucketTracker(*(pWatsonBucketTracker)); \
351 pThread->GetExceptionState()->GetUEWatsonBucketTracker()->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, NULL); \
352 DEBUG_STMT(pThread->GetExceptionState()->GetUEWatsonBucketTracker()->SetCapturedAtADTransition();) \
353 } \
354 } \
355 } \
356 } \
357 else \
358 { \
359 SetupWatsonBucketsForNonPreallocatedExceptions(throwable); \
360 } \
361 }
362#else // !FEATURE_PAL
363#define CAPTURE_BUCKETS_AT_TRANSITION(pThread, oThrowable)
364#endif // FEATURE_PAL
365
366#endif // __ExState_h__
367