[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / exstate.cpp
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
9 #include "common.h"
10 #include "exstate.h"
11 #include "exinfo.h"
12
13 #ifdef _DEBUG
14 #include "comutilnative.h"      // for assertions only
15 #endif
16
17 OBJECTHANDLE ThreadExceptionState::GetThrowableAsHandle()
18 {
19     WRAPPER_NO_CONTRACT;
20     
21 #ifdef WIN64EXCEPTIONS
22     if (m_pCurrentTracker)
23     {
24         return m_pCurrentTracker->m_hThrowable;
25     }
26
27     return NULL;
28 #else // WIN64EXCEPTIONS
29     return m_currentExInfo.m_hThrowable;
30 #endif // WIN64EXCEPTIONS    
31 }
32
33
34 ThreadExceptionState::ThreadExceptionState()
35 {
36 #ifdef WIN64EXCEPTIONS
37     m_pCurrentTracker = NULL;
38 #endif // WIN64EXCEPTIONS
39
40     m_flag = TEF_None;
41
42 #ifndef FEATURE_PAL
43     // Init the UE Watson BucketTracker
44     m_UEWatsonBucketTracker.Init();
45 #endif // !FEATURE_PAL
46
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
52
53 }
54
55 ThreadExceptionState::~ThreadExceptionState()
56 {
57 #ifndef FEATURE_PAL
58     // Init the UE Watson BucketTracker
59     m_UEWatsonBucketTracker.ClearWatsonBucketDetails();
60 #endif // !FEATURE_PAL
61 }
62
63 #if defined(_DEBUG)
64 void ThreadExceptionState::AssertStackTraceInfo(StackTraceInfo *pSTI)
65 {
66     LIMITED_METHOD_CONTRACT;
67 #if defined(WIN64EXCEPTIONS)
68
69     _ASSERTE(pSTI == &(m_pCurrentTracker->m_StackTraceInfo) || pSTI == &(m_OOMTracker.m_StackTraceInfo));
70
71 #else  // win64exceptions
72
73     _ASSERTE(pSTI == &(m_currentExInfo.m_StackTraceInfo));
74
75 #endif // win64exceptions
76 } // void ThreadExceptionState::AssertStackTraceInfo()
77 #endif // _debug
78
79 #ifndef DACCESS_COMPILE
80
81 Thread* ThreadExceptionState::GetMyThread()
82 {
83     return (Thread*)(((BYTE*)this) - offsetof(Thread, m_ExceptionState));
84 }
85
86
87 void ThreadExceptionState::FreeAllStackTraces()
88 {
89     WRAPPER_NO_CONTRACT;
90
91 #ifdef WIN64EXCEPTIONS
92     ExceptionTracker* pNode = m_pCurrentTracker;
93 #else // WIN64EXCEPTIONS
94     ExInfo*           pNode = &m_currentExInfo;
95 #endif // WIN64EXCEPTIONS
96
97     for ( ;
98           pNode != NULL;
99           pNode = pNode->m_pPrevNestedInfo)
100     {
101         pNode->m_StackTraceInfo.FreeStackTrace();
102     }
103 }
104
105 void ThreadExceptionState::ClearThrowablesForUnload(IGCHandleStore* handleStore)
106 {
107     WRAPPER_NO_CONTRACT;
108
109 #ifdef WIN64EXCEPTIONS
110     ExceptionTracker* pNode = m_pCurrentTracker;
111 #else // WIN64EXCEPTIONS
112     ExInfo*           pNode = &m_currentExInfo;
113 #endif // WIN64EXCEPTIONS
114
115     for ( ;
116           pNode != NULL;
117           pNode = pNode->m_pPrevNestedInfo)
118     {
119         if (handleStore->ContainsHandle(pNode->m_hThrowable))
120         {
121             pNode->DestroyExceptionHandle();
122         }
123     }
124 }
125
126
127 // After unwinding from an SO, there may be stale exception state.
128 void ThreadExceptionState::ClearExceptionStateAfterSO(void* pStackFrameSP)
129 {
130     WRAPPER_NO_CONTRACT;
131
132     #if defined(WIN64EXCEPTIONS)
133         ExceptionTracker::PopTrackers(pStackFrameSP);
134     #else
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.
137         // 
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.
141         //
142         // Consequently, we will simply Init() the ExInfo on the Thread object.
143         m_currentExInfo.Init();
144     #endif
145 } // void ThreadExceptionState::ClearExceptionStateAfterSO()
146
147 OBJECTREF ThreadExceptionState::GetThrowable()
148 {
149     CONTRACTL
150     {
151         MODE_COOPERATIVE;
152         NOTHROW;
153         GC_NOTRIGGER;
154     }
155     CONTRACTL_END;
156     
157 #ifdef WIN64EXCEPTIONS
158     if (m_pCurrentTracker && m_pCurrentTracker->m_hThrowable)
159     {
160         return ObjectFromHandle(m_pCurrentTracker->m_hThrowable);
161     }
162 #else // WIN64EXCEPTIONS
163     if (m_currentExInfo.m_hThrowable)
164     {
165         return ObjectFromHandle(m_currentExInfo.m_hThrowable);
166     }
167 #endif // WIN64EXCEPTIONS    
168
169     return NULL;
170 }
171
172 void ThreadExceptionState::SetThrowable(OBJECTREF throwable DEBUG_ARG(SetThrowableErrorChecking stecFlags))
173 {
174     CONTRACTL
175     {
176         if ((throwable == NULL) || CLRException::IsPreallocatedExceptionObject(throwable)) NOTHROW; else THROWS; // From CreateHandle
177         GC_NOTRIGGER;
178         if (throwable == NULL) MODE_ANY; else MODE_COOPERATIVE;
179     }
180     CONTRACTL_END;
181
182 #ifdef WIN64EXCEPTIONS
183     if (m_pCurrentTracker)
184     {
185         m_pCurrentTracker->DestroyExceptionHandle();
186     }
187 #else // WIN64EXCEPTIONS
188     m_currentExInfo.DestroyExceptionHandle();
189 #endif // WIN64EXCEPTIONS
190     
191     if (throwable != NULL)
192     {
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()));
197
198         OBJECTHANDLE hNewThrowable;
199         
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))
203         {
204             hNewThrowable = CLRException::GetPreallocatedHandleForObject(throwable);
205         }
206         else
207         {
208             AppDomain* pDomain = GetMyThread()->GetDomain();
209             PREFIX_ASSUME(pDomain != NULL);
210             hNewThrowable = pDomain->CreateHandle(throwable);
211         }
212
213 #ifdef WIN64EXCEPTIONS
214 #ifdef _DEBUG
215         //
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;
221         //
222         if (stecFlags != STEC_CurrentTrackerEqualNullOkHackForFatalStackOverflow
223 #ifdef FEATURE_INTERPRETER
224             && stecFlags != STEC_CurrentTrackerEqualNullOkForInterpreter
225 #endif // FEATURE_INTERPRETER
226             )
227         {
228             CONSISTENCY_CHECK(CheckPointer(m_pCurrentTracker));
229         }
230 #endif
231
232         if (m_pCurrentTracker != NULL)
233         {
234             m_pCurrentTracker->m_hThrowable = hNewThrowable; 
235         }
236 #else // WIN64EXCEPTIONS
237         m_currentExInfo.m_hThrowable = hNewThrowable;
238 #endif // WIN64EXCEPTIONS
239     }
240 }
241
242 DWORD ThreadExceptionState::GetExceptionCode()
243 {
244     LIMITED_METHOD_CONTRACT;
245     
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
252 }
253
254 BOOL ThreadExceptionState::IsComPlusException()
255 {
256     STATIC_CONTRACT_NOTHROW;
257     STATIC_CONTRACT_GC_NOTRIGGER;
258     STATIC_CONTRACT_FORBID_FAULT;
259
260     if (GetExceptionCode() != EXCEPTION_COMPLUS)
261     {
262         return FALSE;
263     }
264
265     _ASSERTE(IsInstanceTaggedSEHCode(GetExceptionCode()));
266
267
268
269     return GetFlags()->WasThrownByUs();
270 }
271
272
273 #endif // !DACCESS_COMPILE
274
275 BOOL ThreadExceptionState::IsExceptionInProgress()
276 {
277     LIMITED_METHOD_DAC_CONTRACT;
278     
279 #ifdef WIN64EXCEPTIONS
280     return (m_pCurrentTracker != NULL);
281 #else // WIN64EXCEPTIONS
282     return (m_currentExInfo.m_pBottomMostHandler != NULL);
283 #endif // WIN64EXCEPTIONS
284 }
285
286 #if !defined(DACCESS_COMPILE)
287
288 void ThreadExceptionState::GetLeafFrameInfo(StackTraceElement* pStackTraceElement)
289 {
290     WRAPPER_NO_CONTRACT;
291
292 #ifdef WIN64EXCEPTIONS
293     m_pCurrentTracker->m_StackTraceInfo.GetLeafFrameInfo(pStackTraceElement);
294 #else
295     m_currentExInfo.m_StackTraceInfo.GetLeafFrameInfo(pStackTraceElement);
296 #endif
297 }
298
299 EXCEPTION_POINTERS* ThreadExceptionState::GetExceptionPointers()
300 {
301     LIMITED_METHOD_CONTRACT;
302     
303 #ifdef WIN64EXCEPTIONS
304     if (m_pCurrentTracker)
305     {
306         return (EXCEPTION_POINTERS*)&(m_pCurrentTracker->m_ptrs);
307     }
308     else
309     {
310         return NULL;
311     }
312 #else // WIN64EXCEPTIONS
313     return m_currentExInfo.m_pExceptionPointers;
314 #endif // WIN64EXCEPTIONS
315 }
316
317 //-----------------------------------------------------------------------------
318 // SetExceptionPointers -- accessor to set pointer to EXCEPTION_POINTERS
319 //   member.
320 //
321 //  only x86
322 //
323 #if !defined(WIN64EXCEPTIONS)
324 void ThreadExceptionState::SetExceptionPointers(
325     EXCEPTION_POINTERS *pExceptionPointers) // Value to set
326 {
327     m_currentExInfo.m_pExceptionPointers = pExceptionPointers;
328 } // void ThreadExceptionState::SetExceptionPointers()
329 #endif
330
331 #endif // !DACCESS_COMPILE
332
333 PTR_EXCEPTION_RECORD ThreadExceptionState::GetExceptionRecord()
334 {
335     LIMITED_METHOD_DAC_CONTRACT;
336     
337 #ifdef WIN64EXCEPTIONS
338     if (m_pCurrentTracker)
339     {
340         return m_pCurrentTracker->m_ptrs.ExceptionRecord;
341     }
342     else
343     {
344         return NULL;
345     }
346 #else // WIN64EXCEPTIONS
347     return m_currentExInfo.m_pExceptionRecord;
348 #endif // WIN64EXCEPTIONS
349 }
350
351 PTR_CONTEXT ThreadExceptionState::GetContextRecord()
352 {
353     LIMITED_METHOD_DAC_CONTRACT;
354     
355 #ifdef WIN64EXCEPTIONS
356     if (m_pCurrentTracker)
357     {
358         return m_pCurrentTracker->m_ptrs.ContextRecord;
359     }
360     else
361     {
362         return NULL;
363     }
364 #else // WIN64EXCEPTIONS
365     return m_currentExInfo.m_pContext;
366 #endif // WIN64EXCEPTIONS
367 }
368
369 ExceptionFlags* ThreadExceptionState::GetFlags()
370 {
371 #ifdef WIN64EXCEPTIONS
372
373     if (m_pCurrentTracker)
374     {
375         return &(m_pCurrentTracker->m_ExceptionFlags);
376     }
377     else
378     {
379         _ASSERTE(!"GetFlags() called when there is no current exception");
380         return NULL;
381     }
382
383 #else // WIN64EXCEPTIONS
384
385     return &(m_currentExInfo.m_ExceptionFlags);
386
387 #endif // WIN64EXCEPTIONS
388 }
389
390 #if !defined(DACCESS_COMPILE)
391
392 #ifdef DEBUGGING_SUPPORTED    
393 DebuggerExState*    ThreadExceptionState::GetDebuggerState()
394 {
395 #ifdef WIN64EXCEPTIONS
396     if (m_pCurrentTracker)
397     {
398         return &(m_pCurrentTracker->m_DebuggerExState);
399     }
400     else
401     {
402         _ASSERTE(!"unexpected use of GetDebuggerState() when no exception in flight");
403 #if defined(_MSC_VER)        
404         #pragma warning(disable : 4640)
405 #endif         
406         static DebuggerExState   m_emptyDebuggerExState;
407         
408 #if defined(_MSC_VER)          
409         #pragma warning(default : 4640)
410 #endif
411         return &m_emptyDebuggerExState;
412     }
413 #else // WIN64EXCEPTIONS
414     return &(m_currentExInfo.m_DebuggerExState);
415 #endif // WIN64EXCEPTIONS
416 }
417
418 BOOL ThreadExceptionState::IsDebuggerInterceptable()
419 {
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());
427 }
428
429 #ifdef _TARGET_X86_
430 PEXCEPTION_REGISTRATION_RECORD GetClrSEHRecordServicingStackPointer(Thread *pThread, void *pStackPointer);
431 #endif // _TARGET_X86_
432
433 //---------------------------------------------------------------------------------------
434 //
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.
438 //
439 // Arguments:
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
449 //
450 // Return Value:
451 //    whether the operation is successful
452 //
453
454 BOOL DebuggerExState::SetDebuggerInterceptInfo(IJitManager *pJitManager,
455                                       Thread *pThread,
456                                       const METHODTOKEN& methodToken,
457                                       MethodDesc *pFunc,
458                                       ULONG_PTR natOffset,
459                                       StackFrame sfDebuggerInterceptFramePointer,
460                                       ExceptionFlags* pFlags)
461 {
462     WRAPPER_NO_CONTRACT;
463
464     //
465     // Verify parameters are non-NULL
466     //
467     if ((pJitManager == NULL) ||
468         (pThread == NULL) ||
469         (methodToken.IsNull()) ||
470         (pFunc == NULL) ||
471         (natOffset == (TADDR)0) ||
472         (sfDebuggerInterceptFramePointer.IsNull()))
473     {
474         return FALSE;
475     }
476
477     //
478     // You can only call this function on the currently active exception.
479     //
480     if (this != pThread->GetExceptionState()->GetDebuggerState())
481     {
482         return FALSE;
483     }
484
485     //
486     // Check that the stack pointer is less than as far as we have searched so far.
487     //
488     if (sfDebuggerInterceptFramePointer > m_sfDebuggerIndicatedFramePointer)
489     {
490         return FALSE;
491     }
492
493     int nestingLevel = 0;
494     
495 #ifndef WIN64EXCEPTIONS
496     //
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.
501     //
502     m_pDebuggerInterceptFrame = GetClrSEHRecordServicingStackPointer(pThread, (LPVOID)sfDebuggerInterceptFramePointer.SP);
503     if (m_pDebuggerInterceptFrame == EXCEPTION_CHAIN_END)
504     {
505         return FALSE;
506     }
507
508     //
509     // Now we need to search and find the function information for this entry on the stack.
510     //
511     nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager,
512                                                            methodToken,
513                                                            natOffset);
514 #endif // !WIN64EXCEPTIONS
515
516     //
517     // These values will override the normal information used by the EH subsystem to handle the exception.
518     // They are retrieved by GetDebuggerInterceptInfo().
519     //
520     m_pDebuggerInterceptFunc = pFunc;
521     m_dDebuggerInterceptHandlerDepth  = nestingLevel;
522     m_sfDebuggerInterceptFramePointer = sfDebuggerInterceptFramePointer;
523     m_pDebuggerInterceptNativeOffset  = natOffset;
524
525     // set a flag on the exception tracking struct to indicate that an interception is in progress
526     pFlags->SetDebuggerInterceptInfo();
527     return TRUE;
528 }
529 #endif // DEBUGGING_SUPPORTED
530
531 #endif // DACCESS_COMPILE
532
533 EHClauseInfo* ThreadExceptionState::GetCurrentEHClauseInfo()
534 {
535 #ifdef WIN64EXCEPTIONS
536     if (m_pCurrentTracker)
537     {
538         return &(m_pCurrentTracker->m_EHClauseInfo);
539     }
540     else
541     {
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) 
546
547         static EHClauseInfo m_emptyEHClauseInfo;
548
549 #if defined(_MSC_VER)         
550         #pragma warning(default : 4640)
551 #endif // defined(_MSC_VER) 
552
553         return &m_emptyEHClauseInfo;
554     }
555 #else // WIN64EXCEPTIONS
556     return &(m_currentExInfo.m_EHClauseInfo);
557 #endif // WIN64EXCEPTIONS
558 }
559
560 void ThreadExceptionState::SetThreadExceptionFlag(ThreadExceptionFlag flag)
561 {
562     LIMITED_METHOD_CONTRACT;
563
564     m_flag = (ThreadExceptionFlag)((DWORD)m_flag | flag);
565 }
566
567 void ThreadExceptionState::ResetThreadExceptionFlag(ThreadExceptionFlag flag)
568 {
569     LIMITED_METHOD_CONTRACT;
570
571     m_flag = (ThreadExceptionFlag)((DWORD)m_flag & ~flag);
572 }
573
574 BOOL ThreadExceptionState::HasThreadExceptionFlag(ThreadExceptionFlag flag)
575 {
576     LIMITED_METHOD_CONTRACT;
577
578     return ((DWORD)m_flag & flag);
579 }
580
581 ThreadExceptionFlagHolder::ThreadExceptionFlagHolder(ThreadExceptionState::ThreadExceptionFlag flag)
582 {
583     WRAPPER_NO_CONTRACT;
584
585     Thread* pThread = GetThread();
586     _ASSERTE(pThread);
587
588     m_pExState = pThread->GetExceptionState();
589
590     m_flag = flag;
591     m_pExState->SetThreadExceptionFlag(m_flag);
592 }
593
594 ThreadExceptionFlagHolder::~ThreadExceptionFlagHolder()
595 {
596     WRAPPER_NO_CONTRACT;
597
598     _ASSERTE(m_pExState);
599     m_pExState->ResetThreadExceptionFlag(m_flag);
600 }
601
602 #ifdef DACCESS_COMPILE
603
604 void
605 ThreadExceptionState::EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags)
606 {
607 #ifdef WIN64EXCEPTIONS
608     ExceptionTracker* head = m_pCurrentTracker;
609
610     if (head == NULL)
611     {
612         return;
613     }
614     
615 #else // WIN64EXCEPTIONS
616     ExInfo*           head = &m_currentExInfo;
617 #endif // WIN64EXCEPTIONS
618     
619     for (;;)
620     {
621         head->EnumMemoryRegions(flags);
622
623         if (!head->m_pPrevNestedInfo.IsValid())
624         {
625             break;
626         }
627         
628         head->m_pPrevNestedInfo.EnumMem();
629         head = head->m_pPrevNestedInfo;
630     }
631 }
632
633
634 #endif // DACCESS_COMPILE
635
636
637