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.
14 #include "comutilnative.h" // for assertions only
17 OBJECTHANDLE ThreadExceptionState::GetThrowableAsHandle()
21 #ifdef WIN64EXCEPTIONS
22 if (m_pCurrentTracker)
24 return m_pCurrentTracker->m_hThrowable;
28 #else // WIN64EXCEPTIONS
29 return m_currentExInfo.m_hThrowable;
30 #endif // WIN64EXCEPTIONS
34 ThreadExceptionState::ThreadExceptionState()
36 #ifdef WIN64EXCEPTIONS
37 m_pCurrentTracker = NULL;
38 #endif // WIN64EXCEPTIONS
43 // Init the UE Watson BucketTracker
44 m_UEWatsonBucketTracker.Init();
45 #endif // !FEATURE_PAL
47 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
48 // Initialize the default exception severity to NotCorrupting
49 m_LastActiveExceptionCorruptionSeverity = NotSet;
50 m_fCanReflectionTargetHandleException = FALSE;
51 #endif // FEATURE_CORRUPTING_EXCEPTIONS
55 ThreadExceptionState::~ThreadExceptionState()
58 // Init the UE Watson BucketTracker
59 m_UEWatsonBucketTracker.ClearWatsonBucketDetails();
60 #endif // !FEATURE_PAL
64 void ThreadExceptionState::AssertStackTraceInfo(StackTraceInfo *pSTI)
66 LIMITED_METHOD_CONTRACT;
67 #if defined(WIN64EXCEPTIONS)
69 _ASSERTE(pSTI == &(m_pCurrentTracker->m_StackTraceInfo) || pSTI == &(m_OOMTracker.m_StackTraceInfo));
71 #else // win64exceptions
73 _ASSERTE(pSTI == &(m_currentExInfo.m_StackTraceInfo));
75 #endif // win64exceptions
76 } // void ThreadExceptionState::AssertStackTraceInfo()
79 #ifndef DACCESS_COMPILE
81 Thread* ThreadExceptionState::GetMyThread()
83 return (Thread*)(((BYTE*)this) - offsetof(Thread, m_ExceptionState));
87 void ThreadExceptionState::FreeAllStackTraces()
91 #ifdef WIN64EXCEPTIONS
92 ExceptionTracker* pNode = m_pCurrentTracker;
93 #else // WIN64EXCEPTIONS
94 ExInfo* pNode = &m_currentExInfo;
95 #endif // WIN64EXCEPTIONS
99 pNode = pNode->m_pPrevNestedInfo)
101 pNode->m_StackTraceInfo.FreeStackTrace();
105 void ThreadExceptionState::ClearThrowablesForUnload(IGCHandleStore* handleStore)
109 #ifdef WIN64EXCEPTIONS
110 ExceptionTracker* pNode = m_pCurrentTracker;
111 #else // WIN64EXCEPTIONS
112 ExInfo* pNode = &m_currentExInfo;
113 #endif // WIN64EXCEPTIONS
117 pNode = pNode->m_pPrevNestedInfo)
119 if (handleStore->ContainsHandle(pNode->m_hThrowable))
121 pNode->DestroyExceptionHandle();
127 // After unwinding from an SO, there may be stale exception state.
128 void ThreadExceptionState::ClearExceptionStateAfterSO(void* pStackFrameSP)
132 #if defined(WIN64EXCEPTIONS)
133 ExceptionTracker::PopTrackers(pStackFrameSP);
135 // After unwinding from an SO, there may be stale exception state. We need to
136 // get rid of any state that assumes the handlers that have been unwound/unlinked.
138 // Because the ExState chains to entries that may be on the stack, and the
139 // stack has been unwound, it may not be safe to reference any entries
140 // other than the one of the Thread object.
142 // Consequently, we will simply Init() the ExInfo on the Thread object.
143 m_currentExInfo.Init();
145 } // void ThreadExceptionState::ClearExceptionStateAfterSO()
147 OBJECTREF ThreadExceptionState::GetThrowable()
157 #ifdef WIN64EXCEPTIONS
158 if (m_pCurrentTracker && m_pCurrentTracker->m_hThrowable)
160 return ObjectFromHandle(m_pCurrentTracker->m_hThrowable);
162 #else // WIN64EXCEPTIONS
163 if (m_currentExInfo.m_hThrowable)
165 return ObjectFromHandle(m_currentExInfo.m_hThrowable);
167 #endif // WIN64EXCEPTIONS
172 void ThreadExceptionState::SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowableErrorChecking stecFlags))
176 if ((throwable == NULL) || CLRException::IsPreallocatedExceptionObject(throwable)) NOTHROW; else THROWS; // From CreateHandle
178 if (throwable == NULL) MODE_ANY; else MODE_COOPERATIVE;
182 #ifdef WIN64EXCEPTIONS
183 if (m_pCurrentTracker)
185 m_pCurrentTracker->DestroyExceptionHandle();
187 #else // WIN64EXCEPTIONS
188 m_currentExInfo.DestroyExceptionHandle();
189 #endif // WIN64EXCEPTIONS
191 if (throwable != NULL)
193 // Non-compliant exceptions are always wrapped.
194 // The use of the ExceptionNative:: helper here (rather than the global ::IsException helper)
195 // is hokey, but we need a GC_NOTRIGGER version and it's only for an ASSERT.
196 _ASSERTE(IsException(throwable->GetMethodTable()));
198 OBJECTHANDLE hNewThrowable;
200 // If we're tracking one of the preallocated exception objects, then just use the global handle that
201 // matches it rather than creating a new one.
202 if (CLRException::IsPreallocatedExceptionObject(throwable))
204 hNewThrowable = CLRException::GetPreallocatedHandleForObject(throwable);
208 AppDomain* pDomain = GetMyThread()->GetDomain();
209 PREFIX_ASSUME(pDomain != NULL);
210 hNewThrowable = pDomain->CreateHandle(throwable);
213 #ifdef WIN64EXCEPTIONS
216 // Fatal stack overflow policy ends up short-circuiting the normal exception handling
217 // flow such that there could be no Tracker for this SO that is in flight. In this
218 // situation there is no place to store the throwable in the exception state, and instead
219 // it is presumed that the handle to the SO exception is elsewhere. (Current knowledge
220 // as of 7/15/05 is that it is stored in Thread::m_LastThrownObjectHandle;
222 if (stecFlags != STEC_CurrentTrackerEqualNullOkHackForFatalStackOverflow
223 #ifdef FEATURE_INTERPRETER
224 && stecFlags != STEC_CurrentTrackerEqualNullOkForInterpreter
225 #endif // FEATURE_INTERPRETER
228 CONSISTENCY_CHECK(CheckPointer(m_pCurrentTracker));
232 if (m_pCurrentTracker != NULL)
234 m_pCurrentTracker->m_hThrowable = hNewThrowable;
236 #else // WIN64EXCEPTIONS
237 m_currentExInfo.m_hThrowable = hNewThrowable;
238 #endif // WIN64EXCEPTIONS
242 DWORD ThreadExceptionState::GetExceptionCode()
244 LIMITED_METHOD_CONTRACT;
246 #ifdef WIN64EXCEPTIONS
247 _ASSERTE(m_pCurrentTracker);
248 return m_pCurrentTracker->m_ExceptionCode;
249 #else // WIN64EXCEPTIONS
250 return m_currentExInfo.m_ExceptionCode;
251 #endif // WIN64EXCEPTIONS
254 BOOL ThreadExceptionState::IsComPlusException()
256 STATIC_CONTRACT_NOTHROW;
257 STATIC_CONTRACT_GC_NOTRIGGER;
258 STATIC_CONTRACT_FORBID_FAULT;
260 if (GetExceptionCode() != EXCEPTION_COMPLUS)
265 _ASSERTE(IsInstanceTaggedSEHCode(GetExceptionCode()));
269 return GetFlags()->WasThrownByUs();
273 #endif // !DACCESS_COMPILE
275 BOOL ThreadExceptionState::IsExceptionInProgress()
277 LIMITED_METHOD_DAC_CONTRACT;
279 #ifdef WIN64EXCEPTIONS
280 return (m_pCurrentTracker != NULL);
281 #else // WIN64EXCEPTIONS
282 return (m_currentExInfo.m_pBottomMostHandler != NULL);
283 #endif // WIN64EXCEPTIONS
286 #if !defined(DACCESS_COMPILE)
288 void ThreadExceptionState::GetLeafFrameInfo(StackTraceElement* pStackTraceElement)
292 #ifdef WIN64EXCEPTIONS
293 m_pCurrentTracker->m_StackTraceInfo.GetLeafFrameInfo(pStackTraceElement);
295 m_currentExInfo.m_StackTraceInfo.GetLeafFrameInfo(pStackTraceElement);
299 EXCEPTION_POINTERS* ThreadExceptionState::GetExceptionPointers()
301 LIMITED_METHOD_CONTRACT;
303 #ifdef WIN64EXCEPTIONS
304 if (m_pCurrentTracker)
306 return (EXCEPTION_POINTERS*)&(m_pCurrentTracker->m_ptrs);
312 #else // WIN64EXCEPTIONS
313 return m_currentExInfo.m_pExceptionPointers;
314 #endif // WIN64EXCEPTIONS
317 //-----------------------------------------------------------------------------
318 // SetExceptionPointers -- accessor to set pointer to EXCEPTION_POINTERS
323 #if !defined(WIN64EXCEPTIONS)
324 void ThreadExceptionState::SetExceptionPointers(
325 EXCEPTION_POINTERS *pExceptionPointers) // Value to set
327 m_currentExInfo.m_pExceptionPointers = pExceptionPointers;
328 } // void ThreadExceptionState::SetExceptionPointers()
331 #endif // !DACCESS_COMPILE
333 PTR_EXCEPTION_RECORD ThreadExceptionState::GetExceptionRecord()
335 LIMITED_METHOD_DAC_CONTRACT;
337 #ifdef WIN64EXCEPTIONS
338 if (m_pCurrentTracker)
340 return m_pCurrentTracker->m_ptrs.ExceptionRecord;
346 #else // WIN64EXCEPTIONS
347 return m_currentExInfo.m_pExceptionRecord;
348 #endif // WIN64EXCEPTIONS
351 PTR_CONTEXT ThreadExceptionState::GetContextRecord()
353 LIMITED_METHOD_DAC_CONTRACT;
355 #ifdef WIN64EXCEPTIONS
356 if (m_pCurrentTracker)
358 return m_pCurrentTracker->m_ptrs.ContextRecord;
364 #else // WIN64EXCEPTIONS
365 return m_currentExInfo.m_pContext;
366 #endif // WIN64EXCEPTIONS
369 ExceptionFlags* ThreadExceptionState::GetFlags()
371 #ifdef WIN64EXCEPTIONS
373 if (m_pCurrentTracker)
375 return &(m_pCurrentTracker->m_ExceptionFlags);
379 _ASSERTE(!"GetFlags() called when there is no current exception");
383 #else // WIN64EXCEPTIONS
385 return &(m_currentExInfo.m_ExceptionFlags);
387 #endif // WIN64EXCEPTIONS
390 #if !defined(DACCESS_COMPILE)
392 #ifdef DEBUGGING_SUPPORTED
393 DebuggerExState* ThreadExceptionState::GetDebuggerState()
395 #ifdef WIN64EXCEPTIONS
396 if (m_pCurrentTracker)
398 return &(m_pCurrentTracker->m_DebuggerExState);
402 _ASSERTE(!"unexpected use of GetDebuggerState() when no exception in flight");
403 #if defined(_MSC_VER)
404 #pragma warning(disable : 4640)
406 static DebuggerExState m_emptyDebuggerExState;
408 #if defined(_MSC_VER)
409 #pragma warning(default : 4640)
411 return &m_emptyDebuggerExState;
413 #else // WIN64EXCEPTIONS
414 return &(m_currentExInfo.m_DebuggerExState);
415 #endif // WIN64EXCEPTIONS
418 BOOL ThreadExceptionState::IsDebuggerInterceptable()
420 LIMITED_METHOD_CONTRACT;
421 DWORD ExceptionCode = GetExceptionCode();
422 return (BOOL)((ExceptionCode != STATUS_STACK_OVERFLOW) &&
423 (ExceptionCode != EXCEPTION_BREAKPOINT) &&
424 (ExceptionCode != EXCEPTION_SINGLE_STEP) &&
425 !GetFlags()->UnwindHasStarted() &&
426 !GetFlags()->DebuggerInterceptNotPossible());
430 PEXCEPTION_REGISTRATION_RECORD GetClrSEHRecordServicingStackPointer(Thread *pThread, void *pStackPointer);
431 #endif // _TARGET_X86_
433 //---------------------------------------------------------------------------------------
435 // This function is called by the debugger to store information necessary to intercept the current exception.
436 // This information is consumed by the EH subsystem to start the unwind and resume execution without
437 // finding and executing a catch clause.
440 // pJitManager - the JIT manager for the method where we are going to intercept the exception
441 // pThread - the thread on which the interception is taking place
442 // methodToken - the MethodDef token of the interception method
443 // pFunc - the MethodDesc of the interception method
444 // natOffset - the native offset at which we are going to resume execution
445 // sfDebuggerInterceptFramePointer
446 // - the frame pointer of the interception method frame
447 // pFlags - flags on the current exception (ExInfo on x86 and ExceptionTracker on WIN64);
448 // to be set by this function to indicate that an interception is going on
451 // whether the operation is successful
454 BOOL DebuggerExState::SetDebuggerInterceptInfo(IJitManager *pJitManager,
456 const METHODTOKEN& methodToken,
459 StackFrame sfDebuggerInterceptFramePointer,
460 ExceptionFlags* pFlags)
465 // Verify parameters are non-NULL
467 if ((pJitManager == NULL) ||
469 (methodToken.IsNull()) ||
471 (natOffset == (TADDR)0) ||
472 (sfDebuggerInterceptFramePointer.IsNull()))
478 // You can only call this function on the currently active exception.
480 if (this != pThread->GetExceptionState()->GetDebuggerState())
486 // Check that the stack pointer is less than as far as we have searched so far.
488 if (sfDebuggerInterceptFramePointer > m_sfDebuggerIndicatedFramePointer)
493 int nestingLevel = 0;
495 #ifndef WIN64EXCEPTIONS
497 // Get the SEH frame that covers this location on the stack. Note: we pass a skip count of 1. We know that when
498 // this is called, there is a nested exception handler on pThread's stack that is only there during exception
499 // processing, and it won't be there when we go to do the interception. Therefore, we skip that nested record,
500 // and pick the next valid record above it.
502 m_pDebuggerInterceptFrame = GetClrSEHRecordServicingStackPointer(pThread, (LPVOID)sfDebuggerInterceptFramePointer.SP);
503 if (m_pDebuggerInterceptFrame == EXCEPTION_CHAIN_END)
509 // Now we need to search and find the function information for this entry on the stack.
511 nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager,
514 #endif // !WIN64EXCEPTIONS
517 // These values will override the normal information used by the EH subsystem to handle the exception.
518 // They are retrieved by GetDebuggerInterceptInfo().
520 m_pDebuggerInterceptFunc = pFunc;
521 m_dDebuggerInterceptHandlerDepth = nestingLevel;
522 m_sfDebuggerInterceptFramePointer = sfDebuggerInterceptFramePointer;
523 m_pDebuggerInterceptNativeOffset = natOffset;
525 // set a flag on the exception tracking struct to indicate that an interception is in progress
526 pFlags->SetDebuggerInterceptInfo();
529 #endif // DEBUGGING_SUPPORTED
531 #endif // DACCESS_COMPILE
533 EHClauseInfo* ThreadExceptionState::GetCurrentEHClauseInfo()
535 #ifdef WIN64EXCEPTIONS
536 if (m_pCurrentTracker)
538 return &(m_pCurrentTracker->m_EHClauseInfo);
542 _ASSERTE(!"unexpected use of GetCurrentEHClauseInfo() when no exception in flight");
543 #if defined(_MSC_VER)
544 #pragma warning(disable : 4640)
545 #endif // defined(_MSC_VER)
547 static EHClauseInfo m_emptyEHClauseInfo;
549 #if defined(_MSC_VER)
550 #pragma warning(default : 4640)
551 #endif // defined(_MSC_VER)
553 return &m_emptyEHClauseInfo;
555 #else // WIN64EXCEPTIONS
556 return &(m_currentExInfo.m_EHClauseInfo);
557 #endif // WIN64EXCEPTIONS
560 void ThreadExceptionState::SetThreadExceptionFlag(ThreadExceptionFlag flag)
562 LIMITED_METHOD_CONTRACT;
564 m_flag = (ThreadExceptionFlag)((DWORD)m_flag | flag);
567 void ThreadExceptionState::ResetThreadExceptionFlag(ThreadExceptionFlag flag)
569 LIMITED_METHOD_CONTRACT;
571 m_flag = (ThreadExceptionFlag)((DWORD)m_flag & ~flag);
574 BOOL ThreadExceptionState::HasThreadExceptionFlag(ThreadExceptionFlag flag)
576 LIMITED_METHOD_CONTRACT;
578 return ((DWORD)m_flag & flag);
581 ThreadExceptionFlagHolder::ThreadExceptionFlagHolder(ThreadExceptionState::ThreadExceptionFlag flag)
585 Thread* pThread = GetThread();
588 m_pExState = pThread->GetExceptionState();
591 m_pExState->SetThreadExceptionFlag(m_flag);
594 ThreadExceptionFlagHolder::~ThreadExceptionFlagHolder()
598 _ASSERTE(m_pExState);
599 m_pExState->ResetThreadExceptionFlag(m_flag);
602 #ifdef DACCESS_COMPILE
605 ThreadExceptionState::EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags)
607 #ifdef WIN64EXCEPTIONS
608 ExceptionTracker* head = m_pCurrentTracker;
615 #else // WIN64EXCEPTIONS
616 ExInfo* head = &m_currentExInfo;
617 #endif // WIN64EXCEPTIONS
621 head->EnumMemoryRegions(flags);
623 if (!head->m_pPrevNestedInfo.IsValid())
628 head->m_pPrevNestedInfo.EnumMem();
629 head = head->m_pPrevNestedInfo;
634 #endif // DACCESS_COMPILE