Fix hijacking for ARM/ARM64/x86 on Unix (#20042)
[platform/upstream/coreclr.git] / src / vm / excep.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 /*  EXCEP.CPP:
9  *
10  */
11
12 #include "common.h"
13
14 #include "frames.h"
15 #include "threads.h"
16 #include "excep.h"
17 #include "object.h"
18 #include "field.h"
19 #include "dbginterface.h"
20 #include "cgensys.h"
21 #include "comutilnative.h"
22 #include "siginfo.hpp"
23 #include "gcheaputilities.h"
24 #include "eedbginterfaceimpl.h" //so we can clearexception in RealCOMPlusThrow
25 #include "perfcounters.h"
26 #include "dllimportcallback.h"
27 #include "stackwalk.h" //for CrawlFrame, in SetIPFromSrcToDst
28 #include "shimload.h"
29 #include "eeconfig.h"
30 #include "virtualcallstub.h"
31 #include "typestring.h"
32
33 #ifndef FEATURE_PAL
34 #include "dwreport.h"
35 #endif // !FEATURE_PAL
36
37 #include "eventreporter.h"
38
39 #ifdef FEATURE_COMINTEROP
40 #include<roerrorapi.h>
41 #endif
42 #ifdef WIN64EXCEPTIONS
43 #include "exceptionhandling.h"
44 #endif
45
46 #include <errorrep.h>
47 #ifndef FEATURE_PAL
48 // Include definition of GenericModeBlock
49 #include <msodw.h>
50 #endif // FEATURE_PAL
51
52
53 // Support for extracting MethodDesc of a delegate.
54 #include "comdelegate.h"
55
56
57 #ifndef FEATURE_PAL
58 // Windows uses 64kB as the null-reference area
59 #define NULL_AREA_SIZE   (64 * 1024)
60 #else // !FEATURE_PAL
61 #define NULL_AREA_SIZE   GetOsPageSize()
62 #endif // !FEATURE_PAL
63
64 #ifndef CROSSGEN_COMPILE
65
66 BOOL IsIPInEE(void *ip);
67
68 //----------------------------------------------------------------------------
69 //
70 // IsExceptionFromManagedCode - determine if pExceptionRecord points to a managed exception
71 //
72 // Arguments:
73 //    pExceptionRecord - pointer to exception record
74 //
75 // Return Value:
76 //    TRUE or FALSE
77 //
78 //----------------------------------------------------------------------------
79 BOOL IsExceptionFromManagedCode(const EXCEPTION_RECORD * pExceptionRecord)
80 {
81     CONTRACTL {
82         NOTHROW;
83         GC_NOTRIGGER;
84         SO_TOLERANT;
85         SUPPORTS_DAC;
86         PRECONDITION(CheckPointer(pExceptionRecord));
87     } CONTRACTL_END;
88
89     if (pExceptionRecord == NULL)
90     {
91         return FALSE;
92     }
93
94     DACCOP_IGNORE(FieldAccess, "EXCEPTION_RECORD is a OS structure, and ExceptionAddress is actually a target address here.");
95     UINT_PTR address = reinterpret_cast<UINT_PTR>(pExceptionRecord->ExceptionAddress);
96
97     // An exception code of EXCEPTION_COMPLUS indicates a managed exception
98     // has occurred (most likely due to executing a "throw" instruction).
99     //
100     // Also, a hardware level exception may not have an exception code of
101     // EXCEPTION_COMPLUS. In this case, an exception address that resides in
102     // managed code indicates a managed exception has occurred.
103     return (IsComPlusException(pExceptionRecord) ||
104             (ExecutionManager::IsManagedCode((PCODE)address)));
105 }
106
107
108 #ifndef DACCESS_COMPILE
109
110 #define SZ_UNHANDLED_EXCEPTION W("Unhandled Exception:")
111 #define SZ_UNHANDLED_EXCEPTION_CHARLEN ((sizeof(SZ_UNHANDLED_EXCEPTION) / sizeof(WCHAR)))
112
113
114 typedef struct {
115     OBJECTREF pThrowable;
116     STRINGREF s1;
117     OBJECTREF pTmpThrowable;
118 } ProtectArgsStruct;
119
120 PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord();
121 BOOL IsUnmanagedToManagedSEHHandler(EXCEPTION_REGISTRATION_RECORD*);
122
123 VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow
124 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
125                                         , CorruptionSeverity severity = NotCorrupting
126 #endif // FEATURE_CORRUPTING_EXCEPTIONS
127                                         );
128
129 //-------------------------------------------------------------------------------
130 // Basically, this asks whether the exception is a managed exception thrown by
131 // this instance of the CLR.
132 //
133 // The way the result is used, however, is to decide whether this instance is the
134 // one to throw up the Watson box.
135 //-------------------------------------------------------------------------------
136 BOOL ShouldOurUEFDisplayUI(PEXCEPTION_POINTERS pExceptionInfo)
137 {
138     STATIC_CONTRACT_NOTHROW;
139     STATIC_CONTRACT_GC_NOTRIGGER;
140     STATIC_CONTRACT_FORBID_FAULT;
141
142     // Test first for the canned SO EXCEPTION_POINTERS structure as it has a NULL context record and will break the code below.
143     extern EXCEPTION_POINTERS g_SOExceptionPointers;
144     if (pExceptionInfo == &g_SOExceptionPointers)
145     {
146         return TRUE;
147     }
148     return IsComPlusException(pExceptionInfo->ExceptionRecord) || ExecutionManager::IsManagedCode(GetIP(pExceptionInfo->ContextRecord));
149 }
150
151 BOOL NotifyAppDomainsOfUnhandledException(
152     PEXCEPTION_POINTERS pExceptionPointers,
153     OBJECTREF   *pThrowableIn,
154     BOOL        useLastThrownObject,
155     BOOL        isTerminating);
156
157 VOID SetManagedUnhandledExceptionBit(
158     BOOL        useLastThrownObject);
159
160
161 void COMPlusThrowBoot(HRESULT hr)
162 {
163     STATIC_CONTRACT_THROWS;
164
165     _ASSERTE(g_fEEShutDown >= ShutDown_Finalize2 || !"This should not be called unless we are in the last phase of shutdown!");
166     ULONG_PTR arg = hr;
167     RaiseException(BOOTUP_EXCEPTION_COMPLUS, EXCEPTION_NONCONTINUABLE, 1, &arg);
168 }
169
170
171 //-------------------------------------------------------------------------------
172 // This simply tests to see if the exception object is a subclass of
173 // the descriminating class specified in the exception clause.
174 //-------------------------------------------------------------------------------
175 BOOL ExceptionIsOfRightType(TypeHandle clauseType, TypeHandle thrownType)
176 {
177     CONTRACTL
178     {
179         NOTHROW;
180         GC_NOTRIGGER;
181         MODE_ANY;
182         FORBID_FAULT;
183     }
184     CONTRACTL_END;
185
186     // if not resolved to, then it wasn't loaded and couldn't have been thrown
187     if (clauseType.IsNull())
188         return FALSE;
189
190     if (clauseType == thrownType)
191         return TRUE;
192
193     // now look for parent match
194     TypeHandle superType = thrownType;
195     while (!superType.IsNull()) {
196         if (superType == clauseType) {
197             break;
198         }
199         superType = superType.GetParent();
200     }
201
202     return !superType.IsNull();
203 }
204
205 //===========================================================================
206 // Gets the message text from an exception
207 //===========================================================================
208 ULONG GetExceptionMessage(OBJECTREF throwable,
209                           __inout_ecount(bufferLength) LPWSTR buffer,
210                           ULONG bufferLength)
211 {
212     CONTRACTL
213     {
214         THROWS;
215         GC_TRIGGERS;
216         MODE_COOPERATIVE;
217         INJECT_FAULT(ThrowOutOfMemory());
218     }
219     CONTRACTL_END;
220
221     // Prefast buffer sanity check.  Don't call the API with a zero length buffer.
222     if (bufferLength == 0)
223     {
224         _ASSERTE(bufferLength > 0);
225         return 0;
226     }
227
228     StackSString result;
229     GetExceptionMessage(throwable, result);
230
231     ULONG length = result.GetCount();
232     LPCWSTR chars = result.GetUnicode();
233
234     if (length < bufferLength)
235     {
236         wcsncpy_s(buffer, bufferLength, chars, length);
237     }
238     else
239     {
240         wcsncpy_s(buffer, bufferLength, chars, bufferLength-1);
241     }
242
243     return length;
244 }
245
246 //-----------------------------------------------------------------------------
247 // Given an object, get the "message" from it.  If the object is an Exception
248 //  call Exception.InternalToString, otherwise, call Object.ToString
249 //-----------------------------------------------------------------------------
250 void GetExceptionMessage(OBJECTREF throwable, SString &result)
251 {
252     CONTRACTL
253     {
254         THROWS;
255         GC_TRIGGERS;
256         MODE_COOPERATIVE;
257         INJECT_FAULT(ThrowOutOfMemory());
258     }
259     CONTRACTL_END;
260
261     STRINGREF pString = GetExceptionMessage(throwable);
262
263     // If call returned NULL (not empty), oh well, no message.
264     if (pString != NULL)
265         pString->GetSString(result);
266 } // void GetExceptionMessage()
267
268 #if FEATURE_COMINTEROP
269 // This method returns IRestrictedErrorInfo associated with the ErrorObject.
270 // It checks whether the given managed exception object has __HasRestrictedLanguageErrorObject set
271 // in which case it returns the IRestrictedErrorInfo associated with the __RestrictedErrorObject.
272 IRestrictedErrorInfo* GetRestrictedErrorInfoFromErrorObject(OBJECTREF throwable)
273 {
274     CONTRACTL
275     {
276         THROWS;
277         GC_TRIGGERS;
278         MODE_COOPERATIVE;
279         INJECT_FAULT(ThrowOutOfMemory());
280     }
281     CONTRACTL_END;
282
283     IRestrictedErrorInfo* pRestrictedErrorInfo = NULL;
284
285     // If there is no object, there is no restricted error.
286     if (throwable == NULL)
287         return NULL;
288
289     _ASSERTE(IsException(throwable->GetMethodTable()));        // what is the pathway here?
290     if (!IsException(throwable->GetMethodTable()))
291     {
292         return NULL;
293     }
294
295     struct _gc {
296         OBJECTREF Throwable;
297         OBJECTREF RestrictedErrorInfoObjRef;
298     } gc;
299
300     ZeroMemory(&gc, sizeof(gc));
301     GCPROTECT_BEGIN(gc);
302
303     gc.Throwable = throwable;
304
305     // Get the MethodDesc on which we'll call.
306     MethodDescCallSite getRestrictedLanguageErrorObject(METHOD__EXCEPTION__TRY_GET_RESTRICTED_LANGUAGE_ERROR_OBJECT, &gc.Throwable);
307
308     // Make the call.
309     ARG_SLOT Args[] = 
310     {
311         ObjToArgSlot(gc.Throwable),
312         PtrToArgSlot(&gc.RestrictedErrorInfoObjRef)
313     };
314
315     BOOL bHasLanguageRestrictedErrorObject = (BOOL)getRestrictedLanguageErrorObject.Call_RetBool(Args);
316
317     if(bHasLanguageRestrictedErrorObject)
318     {
319         // The __RestrictedErrorObject represents IRestrictedErrorInfo RCW of a non-CLR platform. Lets get the corresponding IRestrictedErrorInfo for it.   
320         pRestrictedErrorInfo = (IRestrictedErrorInfo *)GetComIPFromObjectRef(&gc.RestrictedErrorInfoObjRef, IID_IRestrictedErrorInfo);
321     }
322
323     GCPROTECT_END();
324
325     return pRestrictedErrorInfo;
326 }
327 #endif
328
329 STRINGREF GetExceptionMessage(OBJECTREF throwable)
330 {
331     CONTRACTL
332     {
333         THROWS;
334         GC_TRIGGERS;
335         MODE_COOPERATIVE;
336         INJECT_FAULT(ThrowOutOfMemory());
337     }
338     CONTRACTL_END;
339
340     // If there is no object, there is no message.
341     if (throwable == NULL)
342         return NULL;
343
344     // Assume we're calling Exception.InternalToString() ...
345     BinderMethodID sigID = METHOD__EXCEPTION__INTERNAL_TO_STRING;
346
347     // ... but if it isn't an exception, call Object.ToString().
348     _ASSERTE(IsException(throwable->GetMethodTable()));        // what is the pathway here?
349     if (!IsException(throwable->GetMethodTable()))
350     {
351         sigID = METHOD__OBJECT__TO_STRING;
352     }
353
354     // Return value.
355     STRINGREF pString = NULL;
356
357     GCPROTECT_BEGIN(throwable);
358
359     // Get the MethodDesc on which we'll call.
360     MethodDescCallSite toString(sigID, &throwable);
361
362     // Make the call.
363     ARG_SLOT arg[1] = {ObjToArgSlot(throwable)};
364     pString = toString.Call_RetSTRINGREF(arg);
365
366     GCPROTECT_END();
367
368     return pString;
369 }
370
371 HRESULT GetExceptionHResult(OBJECTREF throwable)
372 {
373     CONTRACTL
374     {
375         NOTHROW;
376         GC_NOTRIGGER;
377         MODE_COOPERATIVE;
378         SO_TOLERANT;
379     }
380     CONTRACTL_END;
381
382     HRESULT hr = E_FAIL;
383     if (throwable == NULL)
384         return hr;
385
386     // Since any object can be thrown in managed code, not only instances of System.Exception subclasses
387     // we need to check to see if we are dealing with an exception before attempting to retrieve
388     // the HRESULT field. If we are not dealing with an exception, then we will simply return E_FAIL.
389     _ASSERTE(IsException(throwable->GetMethodTable()));        // what is the pathway here?
390     if (IsException(throwable->GetMethodTable()))
391     {
392         hr = ((EXCEPTIONREF)throwable)->GetHResult();
393     }
394
395     return hr;
396 } // HRESULT GetExceptionHResult()
397
398 DWORD GetExceptionXCode(OBJECTREF throwable)
399 {
400     CONTRACTL
401     {
402         NOTHROW;
403         GC_NOTRIGGER;
404         MODE_COOPERATIVE;
405         SO_TOLERANT;
406     }
407     CONTRACTL_END;
408
409     HRESULT hr = E_FAIL;
410     if (throwable == NULL)
411         return hr;
412
413     // Since any object can be thrown in managed code, not only instances of System.Exception subclasses
414     // we need to check to see if we are dealing with an exception before attempting to retrieve
415     // the HRESULT field. If we are not dealing with an exception, then we will simply return E_FAIL.
416     _ASSERTE(IsException(throwable->GetMethodTable()));        // what is the pathway here?
417     if (IsException(throwable->GetMethodTable()))
418     {
419         hr = ((EXCEPTIONREF)throwable)->GetXCode();
420     }
421
422     return hr;
423 } // DWORD GetExceptionXCode()
424
425 //------------------------------------------------------------------------------
426 // This function will extract some information from an Access Violation SEH
427 //  exception, and store it in the System.AccessViolationException object.
428 // - the faulting instruction's IP.
429 // - the target address of the faulting instruction.
430 // - a code indicating attempted read vs write
431 //------------------------------------------------------------------------------
432 void SetExceptionAVParameters(              // No return.
433     OBJECTREF throwable,                    // The object into which to set the values.
434     EXCEPTION_RECORD *pExceptionRecord)     // The SEH exception information.
435 {
436     CONTRACTL
437     {
438         THROWS;
439         GC_TRIGGERS;
440         MODE_COOPERATIVE;
441         PRECONDITION(throwable != NULL);
442     }
443     CONTRACTL_END;
444
445     GCPROTECT_BEGIN(throwable)
446     {
447         // This should only be called for AccessViolationException
448         _ASSERTE(MscorlibBinder::GetException(kAccessViolationException) == throwable->GetMethodTable());
449
450         FieldDesc *pFD_ip = MscorlibBinder::GetField(FIELD__ACCESS_VIOLATION_EXCEPTION__IP);
451         FieldDesc *pFD_target = MscorlibBinder::GetField(FIELD__ACCESS_VIOLATION_EXCEPTION__TARGET);
452         FieldDesc *pFD_access = MscorlibBinder::GetField(FIELD__ACCESS_VIOLATION_EXCEPTION__ACCESSTYPE);
453
454         _ASSERTE(pFD_ip->GetFieldType() == ELEMENT_TYPE_I);
455         _ASSERTE(pFD_target->GetFieldType() == ELEMENT_TYPE_I);
456         _ASSERTE(pFD_access->GetFieldType() == ELEMENT_TYPE_I4);
457
458         void *ip     = pExceptionRecord->ExceptionAddress;
459         void *target = (void*)(pExceptionRecord->ExceptionInformation[1]);
460         DWORD access = (DWORD)(pExceptionRecord->ExceptionInformation[0]);
461
462         pFD_ip->SetValuePtr(throwable, ip);
463         pFD_target->SetValuePtr(throwable, target);
464         pFD_access->SetValue32(throwable, access);
465
466     }
467     GCPROTECT_END();
468
469 } // void SetExceptionAVParameters()
470
471 //------------------------------------------------------------------------------
472 // This will call InternalPreserveStackTrace (if the throwable derives from
473 //  System.Exception), to copy the stack trace to the _remoteStackTraceString.
474 // Doing so allows the stack trace of an exception caught by the runtime, and
475 //  rethrown with COMPlusThrow(OBJECTREF thowable), to be preserved.  Otherwise
476 //  the exception handling code may clear the stack trace.  (Generally, we see
477 //  the stack trace preserved on win32 and cleared on win64.)
478 //------------------------------------------------------------------------------
479 void ExceptionPreserveStackTrace(   // No return.
480     OBJECTREF throwable)            // Object about to be thrown.
481 {
482     CONTRACTL
483     {
484         THROWS;
485         GC_TRIGGERS;
486         MODE_COOPERATIVE;
487         INJECT_FAULT(ThrowOutOfMemory());
488     }
489     CONTRACTL_END;
490
491     // If there is no object, there is no stack trace to save.
492     if (throwable == NULL)
493         return;
494
495     GCPROTECT_BEGIN(throwable);
496
497     // Make sure it is derived from System.Exception, that it is not one of the
498     //  preallocated exception objects, and that it has a stack trace to save.
499     if (IsException(throwable->GetMethodTable()) &&
500         !CLRException::IsPreallocatedExceptionObject(throwable))
501     {
502         LOG((LF_EH, LL_INFO1000, "ExceptionPreserveStackTrace called\n"));
503
504         // We're calling Exception.InternalPreserveStackTrace() ...
505         BinderMethodID sigID = METHOD__EXCEPTION__INTERNAL_PRESERVE_STACK_TRACE;
506
507
508         // Get the MethodDesc on which we'll call.
509         MethodDescCallSite preserveStackTrace(sigID, &throwable);
510
511         // Make the call.
512         ARG_SLOT arg[1] = {ObjToArgSlot(throwable)};
513         preserveStackTrace.Call(arg);
514     }
515
516     GCPROTECT_END();
517
518 } // void ExceptionPreserveStackTrace()
519
520
521 // We have to cache the MethodTable and FieldDesc for wrapped non-compliant exceptions the first
522 // time we wrap, because we cannot tolerate a GC when it comes time to detect and unwrap one.
523
524 static MethodTable *pMT_RuntimeWrappedException;
525 static FieldDesc   *pFD_WrappedException;
526
527 // Non-compliant exceptions are immediately wrapped in a RuntimeWrappedException instance.  The entire
528 // exception system can now ignore the possibility of these cases except:
529 //
530 // 1) IL_Throw, which must wrap via this API
531 // 2) Calls to Filters & Catch handlers, which must unwrap based on whether the assembly is on the legacy
532 //    plan.
533 //
534 void WrapNonCompliantException(OBJECTREF *ppThrowable)
535 {
536     CONTRACTL
537     {
538         THROWS;
539         GC_TRIGGERS;
540         MODE_COOPERATIVE;
541         PRECONDITION(IsProtectedByGCFrame(ppThrowable));
542     }
543     CONTRACTL_END;
544
545     _ASSERTE(!IsException((*ppThrowable)->GetMethodTable()));
546
547     EX_TRY
548     {
549         // idempotent operations, so the race condition is okay.
550         if (pMT_RuntimeWrappedException == NULL)
551             pMT_RuntimeWrappedException = MscorlibBinder::GetException(kRuntimeWrappedException);
552
553         if (pFD_WrappedException == NULL)
554             pFD_WrappedException = MscorlibBinder::GetField(FIELD__RUNTIME_WRAPPED_EXCEPTION__WRAPPED_EXCEPTION);
555
556         OBJECTREF orWrapper = AllocateObject(MscorlibBinder::GetException(kRuntimeWrappedException));
557
558         GCPROTECT_BEGIN(orWrapper);
559
560         MethodDescCallSite ctor(METHOD__RUNTIME_WRAPPED_EXCEPTION__OBJ_CTOR, &orWrapper);
561
562         ARG_SLOT args[] =
563         {
564             ObjToArgSlot(orWrapper),
565             ObjToArgSlot(*ppThrowable)
566         };
567
568         ctor.Call(args);
569
570         *ppThrowable = orWrapper;
571
572         GCPROTECT_END();
573     }
574     EX_CATCH
575     {
576         // If we took an exception while binding, or running the constructor of the RuntimeWrappedException
577         // instance, we know that this new exception is CLS compliant.  In fact, it's likely to be
578         // OutOfMemoryException, StackOverflowException or ThreadAbortException.
579         OBJECTREF orReplacement = GET_THROWABLE();
580
581         _ASSERTE(IsException(orReplacement->GetMethodTable()));
582
583         *ppThrowable = orReplacement;
584
585     } EX_END_CATCH(SwallowAllExceptions);
586 }
587
588 // Before presenting an exception object to a handler (filter or catch, not finally or fault), it
589 // may be necessary to turn it back into a non-compliant exception.  This is conditioned on an
590 // assembly level setting.
591 OBJECTREF PossiblyUnwrapThrowable(OBJECTREF throwable, Assembly *pAssembly)
592 {
593     // Check if we are required to compute the RuntimeWrapExceptions status.
594     BOOL fIsRuntimeWrappedException = ((throwable != NULL) && (throwable->GetMethodTable() == pMT_RuntimeWrappedException));
595     BOOL fRequiresComputingRuntimeWrapExceptionsStatus = (fIsRuntimeWrappedException &&
596                                                           (!(pAssembly->GetManifestModule()->IsRuntimeWrapExceptionsStatusComputed())));
597
598     CONTRACTL
599     {
600         THROWS;
601         // If we are required to compute the status of RuntimeWrapExceptions, then the operation could trigger a GC.
602         // Thus, conditionally setup the contract.
603         if (fRequiresComputingRuntimeWrapExceptionsStatus) GC_TRIGGERS; else GC_NOTRIGGER;
604         MODE_COOPERATIVE;
605         PRECONDITION(CheckPointer(pAssembly));
606     }
607     CONTRACTL_END;
608
609     if (fIsRuntimeWrappedException && (!pAssembly->GetManifestModule()->IsRuntimeWrapExceptions()))
610     {
611         // We already created the instance, fetched the field.  We know it is
612         // not marshal by ref, or any of the other cases that might trigger GC.
613         ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
614
615         throwable = pFD_WrappedException->GetRefValue(throwable);
616     }
617
618     return throwable;
619 }
620
621
622 // This is used by a holder in CreateTypeInitializationExceptionObject to
623 // reset the state as appropriate.
624 void ResetTypeInitializationExceptionState(BOOL isAlreadyCreating)
625 {
626     LIMITED_METHOD_CONTRACT;
627     if (!isAlreadyCreating)
628         GetThread()->ResetIsCreatingTypeInitException();
629 }
630
631 void CreateTypeInitializationExceptionObject(LPCWSTR pTypeThatFailed,
632                                              OBJECTREF *pInnerException,
633                                              OBJECTREF *pInitException,
634                                              OBJECTREF *pThrowable)
635 {
636     CONTRACTL {
637         NOTHROW;
638         GC_TRIGGERS;
639         MODE_COOPERATIVE;
640         PRECONDITION(CheckPointer(pInnerException, NULL_OK));
641         PRECONDITION(CheckPointer(pInitException));
642         PRECONDITION(CheckPointer(pThrowable));
643         PRECONDITION(IsProtectedByGCFrame(pInnerException));
644         PRECONDITION(IsProtectedByGCFrame(pInitException));
645         PRECONDITION(IsProtectedByGCFrame(pThrowable));
646         PRECONDITION(CheckPointer(GetThread()));
647     } CONTRACTL_END;
648
649     Thread *pThread  = GetThread();
650     *pThrowable = NULL;
651
652     // This will make sure to put the thread back to its original state if something
653     // throws out of this function (like an OOM exception or something)
654     Holder< BOOL, DoNothing< BOOL >, ResetTypeInitializationExceptionState, FALSE, NoNull< BOOL > >
655         isAlreadyCreating(pThread->IsCreatingTypeInitException());
656
657     EX_TRY {
658         // This will contain the type of exception we want to create. Read comment below
659         // on why we'd want to create an exception other than TypeInitException
660         MethodTable *pMT;
661         BinderMethodID methodID;
662
663         // If we are already in the midst of creating a TypeInitializationException object,
664         // and we get here, it means there was an exception thrown while initializing the
665         // TypeInitializationException type itself, or one of the types used by its class
666         // constructor. In this case, we're going to back down and use a SystemException
667         // object in its place. It is *KNOWN* that both these exception types have identical
668         // .ctor sigs "void instance (string, exception)" so both can be used interchangeably
669         // in the code that follows.
670         if (!isAlreadyCreating.GetValue()) {
671             pThread->SetIsCreatingTypeInitException();
672             pMT = MscorlibBinder::GetException(kTypeInitializationException);
673             methodID = METHOD__TYPE_INIT_EXCEPTION__STR_EX_CTOR;
674         }
675         else {
676             // If we ever hit one of these asserts, then it is bad
677             // because we do not know what exception to return then.
678             _ASSERTE(pInnerException != NULL);
679             _ASSERTE(*pInnerException != NULL);
680             *pThrowable = *pInnerException;
681             *pInitException = *pInnerException;
682             goto ErrExit;
683         }
684
685         // Allocate the exception object
686         *pThrowable = AllocateObject(pMT);
687
688         MethodDescCallSite ctor(methodID, pThrowable);
689
690         // Since the inner exception object in the .ctor is of type Exception, make sure
691         // that the object we're passed in derives from Exception. If not, pass NULL.
692         BOOL isException = FALSE;
693         if (pInnerException != NULL)
694             isException = IsException((*pInnerException)->GetMethodTable());
695
696         _ASSERTE(isException);      // What pathway can give us non-compliant exceptions?
697
698         STRINGREF sType = StringObject::NewString(pTypeThatFailed);
699
700         // If the inner object derives from exception, set it as the third argument.
701         ARG_SLOT args[] = { ObjToArgSlot(*pThrowable),
702                             ObjToArgSlot(sType),
703                             ObjToArgSlot(isException ? *pInnerException : NULL) };
704
705         // Call the .ctor
706         ctor.Call(args);
707
708         // On success, set the init exception.
709         *pInitException = *pThrowable;
710     }
711     EX_CATCH {
712         // If calling the constructor fails, then we'll call ourselves again, and this time
713         // through we will try and create an EEException object. If that fails, then the
714         // else block of this will be executed.
715         if (!isAlreadyCreating.GetValue()) {
716             CreateTypeInitializationExceptionObject(pTypeThatFailed, pInnerException, pInitException, pThrowable);
717         }
718
719         // If we were already in the middle of creating a type init
720         // exception when we were called, we would have tried to create an EEException instead
721         // of a TypeInitException.
722         else {
723             // If we're recursing, then we should be calling ourselves from DoRunClassInitThrowing,
724             // in which case we're guaranteed that we're passing in all three arguments.
725             *pInitException = pInnerException ? *pInnerException : NULL;
726             *pThrowable = GET_THROWABLE();
727         }
728     } EX_END_CATCH(SwallowAllExceptions);
729
730     CONSISTENCY_CHECK(*pInitException != NULL || !pInnerException);
731
732  ErrExit:
733     ;
734 }
735
736 // ==========================================================================
737 // ComputeEnclosingHandlerNestingLevel
738 //
739 //  This is code factored out of COMPlusThrowCallback to figure out
740 //  what the number of nested exception handlers is.
741 // ==========================================================================
742 DWORD ComputeEnclosingHandlerNestingLevel(IJitManager *pIJM,
743                                           const METHODTOKEN& mdTok,
744                                           SIZE_T offsNat)
745 {
746     CONTRACTL
747     {
748         NOTHROW;
749         GC_NOTRIGGER;
750         MODE_ANY;
751         FORBID_FAULT;
752     }
753     CONTRACTL_END;
754
755     // Determine the nesting level of EHClause. Just walk the table
756     // again, and find out how many handlers enclose it
757     DWORD nestingLevel = 0;
758     EH_CLAUSE_ENUMERATOR pEnumState;
759     unsigned EHCount = pIJM->InitializeEHEnumeration(mdTok, &pEnumState);
760
761     for (unsigned j=0; j<EHCount; j++)
762     {
763         EE_ILEXCEPTION_CLAUSE EHClause;
764     
765         pIJM->GetNextEHClause(&pEnumState,&EHClause);
766         _ASSERTE(EHClause.HandlerEndPC != (DWORD) -1);  // <TODO> remove, only protects against a deprecated convention</TODO>
767
768         if ((offsNat > EHClause.HandlerStartPC) &&
769             (offsNat < EHClause.HandlerEndPC))
770         {
771             nestingLevel++;
772         }
773     }
774
775     return nestingLevel;
776 }
777
778 // ******************************* EHRangeTreeNode ************************** //
779 EHRangeTreeNode::EHRangeTreeNode(void)
780 {
781     WRAPPER_NO_CONTRACT;
782     CommonCtor(0, false);
783 }
784
785 EHRangeTreeNode::EHRangeTreeNode(DWORD offset, bool fIsRange /* = false */)
786 {
787     WRAPPER_NO_CONTRACT;
788     CommonCtor(offset, fIsRange);
789 }
790
791 void EHRangeTreeNode::CommonCtor(DWORD offset, bool fIsRange)
792 {
793     LIMITED_METHOD_CONTRACT;
794
795     m_pTree = NULL;
796     m_clause = NULL;
797
798     m_pContainedBy = NULL;
799
800     m_offset   = offset;
801     m_fIsRange = fIsRange;
802     m_fIsRoot  = false;      // must set this flag explicitly
803 }
804
805 inline bool EHRangeTreeNode::IsRange()
806 {
807     // Please see the header file for an explanation of this assertion.
808     _ASSERTE(m_fIsRoot || m_clause != NULL || !m_fIsRange);
809     return m_fIsRange;
810 }
811
812 void EHRangeTreeNode::MarkAsRange()
813 {
814     m_offset   = 0;
815     m_fIsRange = true;
816     m_fIsRoot  = false;
817 }
818
819 inline bool EHRangeTreeNode::IsRoot()
820 {
821     // Please see the header file for an explanation of this assertion.
822     _ASSERTE(m_fIsRoot || m_clause != NULL || !m_fIsRange);
823     return m_fIsRoot;
824 }
825
826 void EHRangeTreeNode::MarkAsRoot(DWORD offset)
827 {
828     m_offset   = offset;
829     m_fIsRange = true;
830     m_fIsRoot  = true;
831 }
832
833 inline DWORD EHRangeTreeNode::GetOffset()
834 {
835     _ASSERTE(m_clause == NULL);
836     _ASSERTE(IsRoot() || !IsRange());
837     return m_offset;
838 }
839
840 inline DWORD EHRangeTreeNode::GetTryStart()
841 {
842     _ASSERTE(IsRange());
843     _ASSERTE(!IsRoot());
844     if (IsRoot())
845     {
846         return 0;
847     }
848     else
849     {
850         return m_clause->TryStartPC;
851     }
852 }
853
854 inline DWORD EHRangeTreeNode::GetTryEnd()
855 {
856     _ASSERTE(IsRange());
857     _ASSERTE(!IsRoot());
858     if (IsRoot())
859     {
860         return GetOffset();
861     }
862     else
863     {
864         return m_clause->TryEndPC;
865     }
866 }
867
868 inline DWORD EHRangeTreeNode::GetHandlerStart()
869 {
870     _ASSERTE(IsRange());
871     _ASSERTE(!IsRoot());
872     if (IsRoot())
873     {
874         return 0;
875     }
876     else
877     {
878         return m_clause->HandlerStartPC;
879     }
880 }
881
882 inline DWORD EHRangeTreeNode::GetHandlerEnd()
883 {
884     _ASSERTE(IsRange());
885     _ASSERTE(!IsRoot());
886     if (IsRoot())
887     {
888         return GetOffset();
889     }
890     else
891     {
892         return m_clause->HandlerEndPC;
893     }
894 }
895
896 inline DWORD EHRangeTreeNode::GetFilterStart()
897 {
898     _ASSERTE(IsRange());
899     _ASSERTE(!IsRoot());
900     if (IsRoot())
901     {
902         return 0;
903     }
904     else
905     {
906         return m_clause->FilterOffset;
907     }
908 }
909
910 // Get the end offset of the filter clause.  This offset is exclusive.
911 inline DWORD EHRangeTreeNode::GetFilterEnd()
912 {
913     _ASSERTE(IsRange());
914     _ASSERTE(!IsRoot());
915     if (IsRoot())
916     {
917         // We should never get here if the "this" node is the root.
918         // By definition, the root contains everything.  No checking is necessary.
919         return 0;
920     }
921     else
922     {
923         return m_FilterEndPC;
924     }
925 }
926
927 bool EHRangeTreeNode::Contains(DWORD offset)
928 {
929     WRAPPER_NO_CONTRACT;
930
931     EHRangeTreeNode node(offset);
932     return Contains(&node);
933 }
934
935 bool EHRangeTreeNode::TryContains(DWORD offset)
936 {
937     WRAPPER_NO_CONTRACT;
938
939     EHRangeTreeNode node(offset);
940     return TryContains(&node);
941 }
942
943 bool EHRangeTreeNode::HandlerContains(DWORD offset)
944 {
945     WRAPPER_NO_CONTRACT;
946
947     EHRangeTreeNode node(offset);
948     return HandlerContains(&node);
949 }
950
951 bool EHRangeTreeNode::FilterContains(DWORD offset)
952 {
953     WRAPPER_NO_CONTRACT;
954
955     EHRangeTreeNode node(offset);
956     return FilterContains(&node);
957 }
958
959 bool EHRangeTreeNode::Contains(EHRangeTreeNode* pNode)
960 {
961     LIMITED_METHOD_CONTRACT;
962
963     // If we are checking a range of address, then we should check the end address inclusively.
964     if (pNode->IsRoot())
965     {
966         // No node contains the root node.
967         return false;
968     }
969     else if (this->IsRoot())
970     {
971         return (pNode->IsRange() ?
972                   (pNode->GetTryEnd() <= this->GetOffset()) && (pNode->GetHandlerEnd() <= this->GetOffset())
973                 : (pNode->GetOffset() < this->GetOffset()) );
974     }
975     else
976     {
977         return (this->TryContains(pNode) || this->HandlerContains(pNode) || this->FilterContains(pNode));
978     }
979 }
980
981 bool EHRangeTreeNode::TryContains(EHRangeTreeNode* pNode)
982 {
983     LIMITED_METHOD_CONTRACT;
984
985     _ASSERTE(this->IsRange());
986
987     if (pNode->IsRoot())
988     {
989         // No node contains the root node.
990         return false;
991     }
992     else if (this->IsRoot())
993     {
994         // We will only get here from GetTcf() to determine if an address is in a try clause.
995         // In this case we want to return false.
996         return false;
997     }
998     else
999     {
1000         DWORD tryStart = this->GetTryStart();
1001         DWORD tryEnd   = this->GetTryEnd();
1002
1003         // If we are checking a range of address, then we should check the end address inclusively.
1004         if (pNode->IsRange())
1005         {
1006             DWORD start = pNode->GetTryStart();
1007             DWORD end   = pNode->GetTryEnd();
1008
1009             if (start == tryStart && end == tryEnd)
1010             {
1011                 return false;
1012             }
1013             else if (start == end)
1014             {
1015                 // This is effectively a single offset.
1016                 if ((tryStart <= start) && (end < tryEnd))
1017                 {
1018                     return true;
1019                 }
1020             }
1021             else if ((tryStart <= start) && (end <= tryEnd))
1022             {
1023                 return true;
1024             }
1025         }
1026         else
1027         {
1028             DWORD offset = pNode->GetOffset();
1029             if ((tryStart <= offset) && (offset < tryEnd))
1030             {
1031                 return true;
1032             }
1033         }
1034     }
1035
1036 #ifdef WIN64EXCEPTIONS
1037     // If we are boot-strapping the tree, don't recurse down because the result could be unreliable.  Note that
1038     // even if we don't recurse, given a particular node, we can still always find its most specific container with
1039     // the logic above, i.e. it's always safe to do one depth level of checking.
1040     //
1041     // To build the tree, all we need to know is the most specific container of a particular node.  This can be
1042     // done by just comparing the offsets of the try regions.  However, funclets create a problem because even if
1043     // a funclet is conceptually contained in a try region, we cannot determine this fact just by comparing the offsets.
1044     // This is when we need to recurse the tree.  Here is a classic example:
1045     // try
1046     // {
1047     //     try
1048     //     {
1049     //     }
1050     //     catch
1051     //     {
1052     //         // If the offset is here, then we need to recurse.
1053     //     }
1054     // }
1055     // catch
1056     // {
1057     // }
1058     if (!m_pTree->m_fInitializing)
1059     {
1060         // Iterate all the contained clauses, and for the ones which are contained in the try region,
1061         // ask if the requested range is contained by it.
1062         USHORT i        = 0;
1063         USHORT numNodes = m_containees.Count();
1064         EHRangeTreeNode** ppNodes = NULL;
1065         for (i = 0, ppNodes = m_containees.Table(); i < numNodes; i++, ppNodes++)
1066         {
1067             // This variable is purely used for readability.
1068             EHRangeTreeNode* pNodeCur = *ppNodes;
1069
1070             // it's possible for nested try blocks to have the same beginning and end offsets
1071             if ( ( this->GetTryStart()   <= pNodeCur->GetTryStart() ) &&
1072                  ( pNodeCur->GetTryEnd() <=  this->GetTryEnd()       ) )
1073             {
1074                 if (pNodeCur->Contains(pNode))
1075                 {
1076                     return true;
1077                 }
1078             }
1079         }
1080     }
1081 #endif // WIN64EXCEPTIONS
1082
1083     return false;
1084 }
1085
1086 bool EHRangeTreeNode::HandlerContains(EHRangeTreeNode* pNode)
1087 {
1088     LIMITED_METHOD_CONTRACT;
1089
1090     _ASSERTE(this->IsRange());
1091
1092     if (pNode->IsRoot())
1093     {
1094         // No node contains the root node.
1095         return false;
1096     }
1097     else if (this->IsRoot())
1098     {
1099         // We will only get here from GetTcf() to determine if an address is in a try clause.
1100         // In this case we want to return false.
1101         return false;
1102     }
1103     else
1104     {
1105         DWORD handlerStart = this->GetHandlerStart();
1106         DWORD handlerEnd   = this->GetHandlerEnd();
1107
1108         // If we are checking a range of address, then we should check the end address inclusively.
1109         if (pNode->IsRange())
1110         {
1111             DWORD start = pNode->GetTryStart();
1112             DWORD end   = pNode->GetTryEnd();
1113
1114             if (start == handlerStart && end == handlerEnd)
1115             {
1116                 return false;
1117             }
1118             else if ((handlerStart <= start) && (end <= handlerEnd))
1119             {
1120                 return true;
1121             }
1122         }
1123         else
1124         {
1125             DWORD offset = pNode->GetOffset();
1126             if ((handlerStart <= offset) && (offset < handlerEnd))
1127             {
1128                 return true;
1129             }
1130         }
1131     }
1132
1133 #ifdef WIN64EXCEPTIONS
1134     // Refer to the comment in TryContains().
1135     if (!m_pTree->m_fInitializing)
1136     {
1137         // Iterate all the contained clauses, and for the ones which are contained in the try region,
1138         // ask if the requested range is contained by it.
1139         USHORT i        = 0;
1140         USHORT numNodes = m_containees.Count();
1141         EHRangeTreeNode** ppNodes = NULL;
1142         for (i = 0, ppNodes = m_containees.Table(); i < numNodes; i++, ppNodes++)
1143         {
1144             // This variable is purely used for readability.
1145             EHRangeTreeNode* pNodeCur = *ppNodes;
1146
1147             if ( ( this->GetHandlerStart() <= pNodeCur->GetTryStart() ) &&
1148                  ( pNodeCur->GetTryEnd()   <  this->GetHandlerEnd()   ) )
1149             {
1150                 if (pNodeCur->Contains(pNode))
1151                 {
1152                     return true;
1153                 }
1154             }
1155         }
1156     }
1157 #endif // WIN64EXCEPTIONS
1158
1159     return false;
1160 }
1161
1162 bool EHRangeTreeNode::FilterContains(EHRangeTreeNode* pNode)
1163 {
1164     LIMITED_METHOD_CONTRACT;
1165
1166     _ASSERTE(this->IsRange());
1167
1168     if (pNode->IsRoot())
1169     {
1170         // No node contains the root node.
1171         return false;
1172     }
1173     else if (this->IsRoot() || !IsFilterHandler(this->m_clause))
1174     {
1175         // We will only get here from GetTcf() to determine if an address is in a try clause.
1176         // In this case we want to return false.
1177         return false;
1178     }
1179     else
1180     {
1181         DWORD filterStart = this->GetFilterStart();
1182         DWORD filterEnd   = this->GetFilterEnd();
1183
1184         // If we are checking a range of address, then we should check the end address inclusively.
1185         if (pNode->IsRange())
1186         {
1187             DWORD start = pNode->GetTryStart();
1188             DWORD end   = pNode->GetTryEnd();
1189
1190             if (start == filterStart && end == filterEnd)
1191             {
1192                 return false;
1193             }
1194             else if ((filterStart <= start) && (end <= filterEnd))
1195             {
1196                 return true;
1197             }
1198         }
1199         else
1200         {
1201             DWORD offset = pNode->GetOffset();
1202             if ((filterStart <= offset) && (offset < filterEnd))
1203             {
1204                 return true;
1205             }
1206         }
1207     }
1208
1209 #ifdef WIN64EXCEPTIONS
1210     // Refer to the comment in TryContains().
1211     if (!m_pTree->m_fInitializing)
1212     {
1213         // Iterate all the contained clauses, and for the ones which are contained in the try region,
1214         // ask if the requested range is contained by it.
1215         USHORT i        = 0;
1216         USHORT numNodes = m_containees.Count();
1217         EHRangeTreeNode** ppNodes = NULL;
1218         for (i = 0, ppNodes = m_containees.Table(); i < numNodes; i++, ppNodes++)
1219         {
1220             // This variable is purely used for readability.
1221             EHRangeTreeNode* pNodeCur = *ppNodes;
1222
1223             if ( ( this->GetFilterStart() <= pNodeCur->GetTryStart() ) &&
1224                  ( pNodeCur->GetTryEnd()  <  this->GetFilterEnd() ) )
1225             {
1226                 if (pNodeCur->Contains(pNode))
1227                 {
1228                     return true;
1229                 }
1230             }
1231         }
1232     }
1233 #endif // WIN64EXCEPTIONS
1234
1235     return false;
1236 }
1237
1238 EHRangeTreeNode* EHRangeTreeNode::GetContainer()
1239 {
1240     return m_pContainedBy;
1241 }
1242
1243 HRESULT EHRangeTreeNode::AddNode(EHRangeTreeNode *pNode)
1244 {
1245     CONTRACTL
1246     {
1247         NOTHROW;
1248         GC_NOTRIGGER;
1249         MODE_ANY;
1250         INJECT_FAULT(return E_OUTOFMEMORY;);
1251         PRECONDITION(pNode != NULL);
1252     }
1253     CONTRACTL_END;
1254
1255     EHRangeTreeNode **ppEH = m_containees.Append();
1256
1257     if (ppEH == NULL)
1258         return E_OUTOFMEMORY;
1259
1260     (*ppEH) = pNode;
1261     return S_OK;
1262 }
1263
1264 // ******************************* EHRangeTree ************************** //
1265
1266 EHRangeTree::EHRangeTree(IJitManager* pIJM,
1267                          const METHODTOKEN& methodToken,
1268                          DWORD         methodSize,
1269                          int           cFunclet,
1270                          const DWORD * rgFunclet)
1271 {
1272     LIMITED_METHOD_CONTRACT;
1273
1274     LOG((LF_CORDB, LL_INFO10000, "EHRT::ERHT: already loaded!\n"));
1275
1276     EH_CLAUSE_ENUMERATOR pEnumState;
1277     m_EHCount = pIJM->InitializeEHEnumeration(methodToken, &pEnumState);
1278
1279     _ASSERTE(m_EHCount != 0xFFFFFFFF);
1280
1281     ULONG i = 0;
1282
1283     m_rgClauses = NULL;
1284     m_rgNodes = NULL;
1285     m_root = NULL;
1286     m_hrInit = S_OK;
1287     m_fInitializing = true;
1288
1289     if (m_EHCount > 0)
1290     {
1291         m_rgClauses = new (nothrow) EE_ILEXCEPTION_CLAUSE[m_EHCount];
1292         if (m_rgClauses == NULL)
1293         {
1294            m_hrInit = E_OUTOFMEMORY;
1295            goto LError;
1296         }
1297     }
1298
1299     LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: m_ehcount:0x%x, m_rgClauses:0%x\n",
1300          m_EHCount, m_rgClauses));
1301
1302     m_rgNodes = new (nothrow) EHRangeTreeNode[m_EHCount+1];
1303     if (m_rgNodes == NULL)
1304     {
1305        m_hrInit = E_OUTOFMEMORY;
1306        goto LError;
1307     }
1308
1309     //this contains everything, even stuff on the last IP
1310     m_root = &(m_rgNodes[m_EHCount]);
1311     m_root->MarkAsRoot(methodSize + 1);
1312
1313     LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: rgNodes:0x%x\n", m_rgNodes));
1314
1315     if (m_EHCount ==0)
1316     {
1317         LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: About to leave!\n"));
1318         goto LSuccess;
1319     }
1320
1321     LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: Sticking around!\n"));
1322
1323     // First, load all the EH clauses into the object.
1324     for (i = 0; i < m_EHCount; i++)
1325     {
1326         EE_ILEXCEPTION_CLAUSE * pEHClause = &(m_rgClauses[i]);
1327
1328         LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: i:0x%x!\n", i));
1329
1330         pIJM->GetNextEHClause(&pEnumState, pEHClause);
1331
1332         LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: EHRTT_JIT_MANAGER got clause\n", i));
1333
1334         LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: clause 0x%x,"
1335                     "addrof:0x%x\n", i, pEHClause ));
1336
1337         _ASSERTE(pEHClause->HandlerEndPC != (DWORD) -1);  // <TODO> remove, only protects against a deprecated convention</TODO>
1338
1339         EHRangeTreeNode * pNodeCur = &(m_rgNodes[i]);
1340
1341         pNodeCur->m_pTree = this;
1342         pNodeCur->m_clause = pEHClause;
1343
1344         if (pEHClause->Flags == COR_ILEXCEPTION_CLAUSE_FILTER)
1345         {
1346 #ifdef WIN64EXCEPTIONS
1347             // Because of funclets, there is no way to guarantee the placement of a filter.
1348             // Thus, we need to loop through the funclets to find the end offset.
1349             for (int f = 0; f < cFunclet; f++)
1350             {
1351                 // Check the start offset of the filter funclet.
1352                 if (pEHClause->FilterOffset == rgFunclet[f])
1353                 {
1354                     if (f < (cFunclet - 1))
1355                     {
1356                         // If it's NOT the last funclet, use the start offset of the next funclet.
1357                         pNodeCur->m_FilterEndPC = rgFunclet[f + 1];
1358                     }
1359                     else
1360                     {
1361                         // If it's the last funclet, use the size of the method.
1362                         pNodeCur->m_FilterEndPC = methodSize;
1363                     }
1364                     break;
1365                 }
1366             }
1367 #else  // WIN64EXCEPTIONS
1368             // On x86, since the filter doesn't have an end FilterPC, the only way we can know the size
1369             // of the filter is if it's located immediately prior to it's handler and immediately after
1370             // its try region.  We assume that this is, and if it isn't, we're so amazingly hosed that
1371             // we can't continue.
1372             if ((pEHClause->FilterOffset >= pEHClause->HandlerStartPC) ||
1373                 (pEHClause->FilterOffset < pEHClause->TryEndPC))
1374         {
1375             m_hrInit = CORDBG_E_SET_IP_IMPOSSIBLE;
1376             goto LError;
1377         }
1378             pNodeCur->m_FilterEndPC = pEHClause->HandlerStartPC;
1379 #endif // WIN64EXCEPTIONS
1380         }
1381
1382         pNodeCur->MarkAsRange();
1383     }
1384
1385     LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: about to do the second pass\n"));
1386
1387
1388     // Second, for each EH, find it's most limited, containing clause
1389     // On WIN64, we have duplicate clauses.  There are two types of duplicate clauses.
1390     //
1391     // The first type is described in ExceptionHandling.cpp.  This type doesn't add additional information to the
1392     // EH tree structure.  For example, if an offset is in the try region of a duplicate clause of this type,
1393     // then some clause which comes before the duplicate clause should contain the offset in its handler region.
1394     // Therefore, even though this type of duplicate clauses are added to the EH tree, they should never be used.
1395     //
1396     // The second type is what's called the protected clause.  These clauses are used to mark the cloned finally
1397     // region.  They have an empty try region.  Here's an example:
1398     //
1399     // // C# code
1400     // try
1401     // {
1402     //     A
1403     // }
1404     // finally
1405     // {
1406     //     B
1407     // }
1408     //
1409     // // jitted code
1410     // parent
1411     // -------
1412     // A
1413     // B'
1414     // -------
1415     //
1416     // funclet
1417     // -------
1418     // B
1419     // -------
1420     //
1421     // A protected clause covers the B' region in the parent method.  In essence you can think of the method as
1422     // having two try/finally regions, and that's exactly how protected clauses are handled in the EH tree.
1423     // They are added to the EH tree just like any other EH clauses.
1424     for (i = 0; i < m_EHCount; i++)
1425     {
1426         LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: SP:0x%x\n", i));
1427
1428         EHRangeTreeNode * pNodeCur = &(m_rgNodes[i]);
1429
1430         EHRangeTreeNode *pNodeCandidate = NULL;
1431         pNodeCandidate = FindContainer(pNodeCur);
1432         _ASSERTE(pNodeCandidate != NULL);
1433
1434         pNodeCur->m_pContainedBy = pNodeCandidate;
1435
1436         LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: SP: about to add to tree\n"));
1437
1438         HRESULT hr = pNodeCandidate->AddNode(pNodeCur);
1439         if (FAILED(hr))
1440         {
1441             m_hrInit = hr;
1442             goto LError;
1443         }
1444     }
1445
1446 LSuccess:
1447     m_fInitializing = false;
1448     return;
1449
1450 LError:
1451     LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: LError - something went wrong!\n"));
1452
1453     if (m_rgClauses != NULL)
1454     {
1455         delete [] m_rgClauses;
1456         m_rgClauses = NULL;
1457     }
1458
1459     if (m_rgNodes != NULL)
1460     {
1461         delete [] m_rgNodes;
1462         m_rgNodes = NULL;
1463     }
1464
1465     m_fInitializing = false;
1466
1467     LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: Falling off of LError!\n"));
1468 } // Ctor Core
1469
1470 EHRangeTree::~EHRangeTree()
1471 {
1472     LIMITED_METHOD_CONTRACT;
1473
1474     if (m_rgNodes != NULL)
1475         delete [] m_rgNodes;
1476
1477     if (m_rgClauses != NULL)
1478         delete [] m_rgClauses;
1479 } //Dtor
1480
1481 EHRangeTreeNode *EHRangeTree::FindContainer(EHRangeTreeNode *pNodeSearch)
1482 {
1483     LIMITED_METHOD_CONTRACT;
1484
1485     EHRangeTreeNode *pNodeCandidate = NULL;
1486
1487     // Examine the root, too.
1488     for (ULONG iInner = 0; iInner < m_EHCount+1; iInner++)
1489     {
1490         EHRangeTreeNode *pNodeCur = &(m_rgNodes[iInner]);
1491
1492         // Check if the current node contains the node we are searching for.
1493         if ((pNodeSearch != pNodeCur) &&
1494             pNodeCur->Contains(pNodeSearch))
1495         {
1496             // Update the candidate node if it is NULL or if it contains the current node
1497             // (i.e. the current node is more specific than the candidate node).
1498             if ((pNodeCandidate == NULL) ||
1499                 pNodeCandidate->Contains(pNodeCur))
1500             {
1501                 pNodeCandidate = pNodeCur;
1502             }
1503         }
1504     }
1505
1506     return pNodeCandidate;
1507 }
1508
1509 EHRangeTreeNode *EHRangeTree::FindMostSpecificContainer(DWORD addr)
1510 {
1511     WRAPPER_NO_CONTRACT;
1512
1513     EHRangeTreeNode node(addr);
1514     return FindContainer(&node);
1515 }
1516
1517 EHRangeTreeNode *EHRangeTree::FindNextMostSpecificContainer(EHRangeTreeNode *pNodeSearch, DWORD addr)
1518 {
1519     WRAPPER_NO_CONTRACT;
1520
1521     _ASSERTE(!m_fInitializing);
1522
1523     EHRangeTreeNode **rgpNodes = pNodeSearch->m_containees.Table();
1524
1525     if (NULL == rgpNodes)
1526         return pNodeSearch;
1527
1528     // It's possible that no subrange contains the desired address, so
1529     // keep a reasonable default around.
1530     EHRangeTreeNode *pNodeCandidate = pNodeSearch;
1531
1532     USHORT cSubRanges = pNodeSearch->m_containees.Count();
1533     EHRangeTreeNode **ppNodeCur = pNodeSearch->m_containees.Table();
1534
1535     for (int i = 0; i < cSubRanges; i++, ppNodeCur++)
1536     {
1537         if ((*ppNodeCur)->Contains(addr) &&
1538             pNodeCandidate->Contains((*ppNodeCur)))
1539         {
1540             pNodeCandidate = (*ppNodeCur);
1541         }
1542     }
1543
1544     return pNodeCandidate;
1545 }
1546
1547 BOOL EHRangeTree::isAtStartOfCatch(DWORD offset)
1548 {
1549     LIMITED_METHOD_CONTRACT;
1550
1551     if (NULL != m_rgNodes && m_EHCount != 0)
1552     {
1553         for(unsigned i = 0; i < m_EHCount;i++)
1554         {
1555             if (m_rgNodes[i].m_clause->HandlerStartPC == offset &&
1556                 (!IsFilterHandler(m_rgNodes[i].m_clause) && !IsFaultOrFinally(m_rgNodes[i].m_clause)))
1557                 return TRUE;
1558         }
1559     }
1560
1561     return FALSE;
1562 }
1563
1564 enum TRY_CATCH_FINALLY
1565 {
1566     TCF_NONE= 0,
1567     TCF_TRY,
1568     TCF_FILTER,
1569     TCF_CATCH,
1570     TCF_FINALLY,
1571     TCF_COUNT, //count of all elements, not an element itself
1572 };
1573
1574 #ifdef LOGGING
1575 const char *TCFStringFromConst(TRY_CATCH_FINALLY tcf)
1576 {
1577     LIMITED_METHOD_CONTRACT;
1578
1579     switch( tcf )
1580     {
1581         case TCF_NONE:
1582             return "TCFS_NONE";
1583             break;
1584         case TCF_TRY:
1585             return "TCFS_TRY";
1586             break;
1587         case TCF_FILTER:
1588             return "TCF_FILTER";
1589             break;
1590         case TCF_CATCH:
1591             return "TCFS_CATCH";
1592             break;
1593         case TCF_FINALLY:
1594             return "TCFS_FINALLY";
1595             break;
1596         case TCF_COUNT:
1597             return "TCFS_COUNT";
1598             break;
1599         default:
1600             return "INVALID TCFS VALUE";
1601             break;
1602     }
1603 }
1604 #endif //LOGGING
1605
1606 #ifndef WIN64EXCEPTIONS
1607 // We're unwinding if we'll return to the EE's code.  Otherwise
1608 // we'll return to someplace in the current code.  Anywhere outside
1609 // this function is "EE code".
1610 bool FinallyIsUnwinding(EHRangeTreeNode *pNode,
1611                         ICodeManager* pEECM,
1612                         PREGDISPLAY pReg,
1613                         SLOT addrStart)
1614 {
1615     CONTRACTL
1616     {
1617         NOTHROW;
1618         GC_NOTRIGGER;
1619         MODE_ANY;
1620         FORBID_FAULT;
1621     }
1622     CONTRACTL_END;
1623
1624     const BYTE *pbRetAddr = pEECM->GetFinallyReturnAddr(pReg);
1625
1626     if (pbRetAddr < (const BYTE *)addrStart)
1627         return true;
1628
1629     DWORD offset = (DWORD)(size_t)(pbRetAddr - addrStart);
1630     EHRangeTreeNode *pRoot = pNode->m_pTree->m_root;
1631
1632     if (!pRoot->Contains(offset))
1633         return true;
1634     else
1635         return false;
1636 }
1637
1638 BOOL LeaveCatch(ICodeManager* pEECM,
1639                 Thread *pThread,
1640                 CONTEXT *pCtx,
1641                 GCInfoToken gcInfoToken,
1642                 unsigned offset)
1643 {
1644     CONTRACTL
1645     {
1646         THROWS;
1647         GC_TRIGGERS;
1648         MODE_ANY;
1649     }
1650     CONTRACTL_END;
1651
1652     // We can assert these things here, and skip a call
1653     // to COMPlusCheckForAbort later.
1654
1655             // If no abort has been requested,
1656     _ASSERTE((pThread->GetThrowable() != NULL) ||
1657             // or if there is a pending exception.
1658             (!pThread->IsAbortRequested()) );
1659
1660     LPVOID esp = COMPlusEndCatchWorker(pThread);
1661
1662     PopNestedExceptionRecords(esp, pCtx, pThread->GetExceptionListPtr());
1663
1664     // Do JIT-specific work
1665     pEECM->LeaveCatch(gcInfoToken, offset, pCtx);
1666
1667     SetSP(pCtx, (UINT_PTR)esp);
1668     return TRUE;
1669 }
1670 #endif // WIN64EXCEPTIONS
1671
1672 TRY_CATCH_FINALLY GetTcf(EHRangeTreeNode *pNode,
1673                          unsigned offset)
1674 {
1675     CONTRACTL
1676     {
1677         NOTHROW;
1678         GC_NOTRIGGER;
1679         MODE_ANY;
1680         FORBID_FAULT;
1681     }
1682     CONTRACTL_END;
1683
1684     _ASSERTE(pNode->IsRange() && !pNode->IsRoot());
1685
1686     TRY_CATCH_FINALLY tcf;
1687
1688     if (!pNode->Contains(offset))
1689     {
1690         tcf = TCF_NONE;
1691     }
1692     else if (pNode->TryContains(offset))
1693     {
1694         tcf = TCF_TRY;
1695     }
1696     else if (pNode->FilterContains(offset))
1697     {
1698         tcf = TCF_FILTER;
1699     }
1700     else
1701     {
1702         _ASSERTE(pNode->HandlerContains(offset));
1703         if (IsFaultOrFinally(pNode->m_clause))
1704             tcf = TCF_FINALLY;
1705         else
1706             tcf = TCF_CATCH;
1707     }
1708
1709     return tcf;
1710 }
1711
1712 const DWORD bEnter = 0x01;
1713 const DWORD bLeave = 0x02;
1714
1715 HRESULT IsLegalTransition(Thread *pThread,
1716                           bool fCanSetIPOnly,
1717                           DWORD fEnter,
1718                           EHRangeTreeNode *pNode,
1719                           DWORD offFrom,
1720                           DWORD offTo,
1721                           ICodeManager* pEECM,
1722                           PREGDISPLAY pReg,
1723                           SLOT addrStart,
1724                           GCInfoToken gcInfoToken,
1725                           PCONTEXT pCtx)
1726 {
1727     CONTRACTL
1728     {
1729         THROWS;
1730         GC_TRIGGERS;
1731         MODE_ANY;
1732     }
1733     CONTRACTL_END;
1734
1735 #ifdef _DEBUG
1736     if (fEnter & bEnter)
1737     {
1738         _ASSERTE(pNode->Contains(offTo));
1739     }
1740     if (fEnter & bLeave)
1741     {
1742         _ASSERTE(pNode->Contains(offFrom));
1743     }
1744 #endif //_DEBUG
1745
1746     // First, figure out where we're coming from/going to
1747     TRY_CATCH_FINALLY tcfFrom = GetTcf(pNode,
1748                                        offFrom);
1749
1750     TRY_CATCH_FINALLY tcfTo =  GetTcf(pNode,
1751                                       offTo);
1752
1753     LOG((LF_CORDB, LL_INFO10000, "ILT: from %s to %s\n",
1754         TCFStringFromConst(tcfFrom),
1755         TCFStringFromConst(tcfTo)));
1756
1757     // Now we'll consider, case-by-case, the various permutations that
1758     // can arise
1759     switch(tcfFrom)
1760     {
1761         case TCF_NONE:
1762         case TCF_TRY:
1763         {
1764             switch(tcfTo)
1765             {
1766                 case TCF_NONE:
1767                 case TCF_TRY:
1768                 {
1769                     return S_OK;
1770                     break;
1771                 }
1772
1773                 case TCF_FILTER:
1774                 {
1775                     return CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER;
1776                     break;
1777                 }
1778
1779                 case TCF_CATCH:
1780                 {
1781                     return CORDBG_E_CANT_SET_IP_INTO_CATCH;
1782                     break;
1783                 }
1784
1785                 case TCF_FINALLY:
1786                 {
1787                     return CORDBG_E_CANT_SET_IP_INTO_FINALLY;
1788                     break;
1789                 }
1790                 default:
1791                     break;
1792             }
1793             break;
1794         }
1795
1796         case TCF_FILTER:
1797         {
1798             switch(tcfTo)
1799             {
1800                 case TCF_NONE:
1801                 case TCF_TRY:
1802                 case TCF_CATCH:
1803                 case TCF_FINALLY:
1804                 {
1805                     return CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER;
1806                     break;
1807                 }
1808                 case TCF_FILTER:
1809                 {
1810                     return S_OK;
1811                     break;
1812                 }
1813                 default:
1814                     break;
1815
1816             }
1817             break;
1818         }
1819
1820         case TCF_CATCH:
1821         {
1822             switch(tcfTo)
1823             {
1824                 case TCF_NONE:
1825                 case TCF_TRY:
1826                 {
1827 #if !defined(WIN64EXCEPTIONS)
1828                     CONTEXT *pFilterCtx = pThread->GetFilterContext();
1829                     if (pFilterCtx == NULL)
1830                         return CORDBG_E_SET_IP_IMPOSSIBLE;
1831
1832                     if (!fCanSetIPOnly)
1833                     {
1834                         if (!LeaveCatch(pEECM,
1835                                         pThread,
1836                                         pFilterCtx,
1837                                         gcInfoToken,
1838                                         offFrom))
1839                             return E_FAIL;
1840                     }
1841                     return S_OK;
1842 #else  // WIN64EXCEPTIONS
1843                     // <NOTE>
1844                     // Setting IP out of a catch clause is not supported for WIN64EXCEPTIONS because of funclets.
1845                     // This scenario is disabled with approval from VS because it's not considered to
1846                     // be a common user scenario.
1847                     // </NOTE>
1848                     return CORDBG_E_CANT_SET_IP_OUT_OF_CATCH_ON_WIN64;
1849 #endif // !WIN64EXCEPTIONS
1850                     break;
1851                 }
1852
1853                 case TCF_FILTER:
1854                 {
1855                     return CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER;
1856                     break;
1857                 }
1858
1859                 case TCF_CATCH:
1860                 {
1861                     return S_OK;
1862                     break;
1863                 }
1864
1865                 case TCF_FINALLY:
1866                 {
1867                     return CORDBG_E_CANT_SET_IP_INTO_FINALLY;
1868                     break;
1869                 }
1870                 default:
1871                     break;
1872             }
1873             break;
1874         }
1875
1876         case TCF_FINALLY:
1877         {
1878             switch(tcfTo)
1879             {
1880                 case TCF_NONE:
1881                 case TCF_TRY:
1882                 {
1883 #ifndef WIN64EXCEPTIONS
1884                     if (!FinallyIsUnwinding(pNode, pEECM, pReg, addrStart))
1885                     {
1886                         CONTEXT *pFilterCtx = pThread->GetFilterContext();
1887                         if (pFilterCtx == NULL)
1888                             return CORDBG_E_SET_IP_IMPOSSIBLE;
1889
1890                         if (!fCanSetIPOnly)
1891                         {
1892                             if (!pEECM->LeaveFinally(gcInfoToken,
1893                                                      offFrom,
1894                                                      pFilterCtx))
1895                                 return E_FAIL;
1896                         }
1897                         return S_OK;
1898                     }
1899                     else
1900                     {
1901                         return CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY;
1902                     }
1903 #else // !WIN64EXCEPTIONS
1904                     // <NOTE>
1905                     // Setting IP out of a non-unwinding finally clause is not supported on WIN64EXCEPTIONS because of funclets.
1906                     // This scenario is disabled with approval from VS because it's not considered to be a common user
1907                     // scenario.
1908                     // </NOTE>
1909                     return CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY_ON_WIN64;
1910 #endif // WIN64EXCEPTIONS
1911
1912                     break;
1913                 }
1914
1915                 case TCF_FILTER:
1916                 {
1917                     return CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER;
1918                     break;
1919                 }
1920
1921                 case TCF_CATCH:
1922                 {
1923                     return CORDBG_E_CANT_SET_IP_INTO_CATCH;
1924                     break;
1925                 }
1926
1927                 case TCF_FINALLY:
1928                 {
1929                     return S_OK;
1930                     break;
1931                 }
1932                 default:
1933                     break;
1934             }
1935             break;
1936         }
1937        break;
1938        default:
1939         break;
1940     }
1941
1942     _ASSERTE( !"IsLegalTransition: We should never reach this point!" );
1943
1944     return CORDBG_E_SET_IP_IMPOSSIBLE;
1945 }
1946
1947 // We need this to determine what
1948 // to do based on whether the stack in general is empty
1949 HRESULT DestinationIsValid(void *pDjiToken,
1950                            DWORD offTo,
1951                            EHRangeTree *pEHRT)
1952 {
1953     CONTRACTL
1954     {
1955         NOTHROW;
1956         GC_NOTRIGGER;
1957         MODE_ANY;
1958         FORBID_FAULT;
1959     }
1960     CONTRACTL_END;
1961
1962     // We'll add a call to the DebugInterface that takes this
1963     // & tells us if the destination is a stack empty point.
1964 //    DebuggerJitInfo *pDji = (DebuggerJitInfo *)pDjiToken;
1965
1966     if (pEHRT->isAtStartOfCatch(offTo))
1967         return CORDBG_S_BAD_START_SEQUENCE_POINT;
1968     else
1969         return S_OK;
1970 } // HRESULT DestinationIsValid()
1971
1972 // We want to keep the 'worst' HRESULT - if one has failed (..._E_...) & the
1973 // other hasn't, take the failing one.  If they've both/neither failed, then
1974 // it doesn't matter which we take.
1975 // Note that this macro favors retaining the first argument
1976 #define WORST_HR(hr1,hr2) (FAILED(hr1)?hr1:hr2)
1977 HRESULT SetIPFromSrcToDst(Thread *pThread,
1978                           SLOT addrStart,       // base address of method
1979                           DWORD offFrom,        // native offset
1980                           DWORD offTo,          // native offset
1981                           bool fCanSetIPOnly,   // if true, don't do any real work
1982                           PREGDISPLAY pReg,
1983                           PCONTEXT pCtx,
1984                           void *pDji,
1985                           EHRangeTree *pEHRT)
1986 {
1987     CONTRACTL
1988     {
1989         THROWS;
1990         GC_TRIGGERS;
1991         MODE_ANY;
1992         INJECT_FAULT(return E_OUTOFMEMORY;);
1993     }
1994     CONTRACTL_END;
1995
1996     HRESULT         hr = S_OK;
1997     HRESULT         hrReturn = S_OK;
1998     bool            fCheckOnly = true;
1999
2000     EECodeInfo codeInfo((TADDR)(addrStart));
2001
2002     ICodeManager * pEECM = codeInfo.GetCodeManager();
2003     GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
2004
2005     // Do both checks here so compiler doesn't complain about skipping
2006     // initialization b/c of goto.
2007     if (fCanSetIPOnly && !pEECM->IsGcSafe(&codeInfo, offFrom))
2008     {
2009         hrReturn = WORST_HR(hrReturn, CORDBG_E_SET_IP_IMPOSSIBLE);
2010     }
2011
2012     if (fCanSetIPOnly && !pEECM->IsGcSafe(&codeInfo, offTo))
2013     {
2014         hrReturn = WORST_HR(hrReturn, CORDBG_E_SET_IP_IMPOSSIBLE);
2015     }
2016
2017     if ((hr = DestinationIsValid(pDji, offTo, pEHRT)) != S_OK
2018         && fCanSetIPOnly)
2019     {
2020         hrReturn = WORST_HR(hrReturn,hr);
2021     }
2022
2023     // The basic approach is this:  We'll start with the most specific (smallest)
2024     // EHClause that contains the starting address.  We'll 'back out', to larger
2025     // and larger ranges, until we either find an EHClause that contains both
2026     // the from and to addresses, or until we reach the root EHRangeTreeNode,
2027     // which contains all addresses within it.  At each step, we check/do work
2028     // that the various transitions (from inside to outside a catch, etc).
2029     // At that point, we do the reverse process  - we go from the EHClause that
2030     // encompasses both from and to, and narrow down to the smallest EHClause that
2031     // encompasses the to point.  We use our nifty data structure to manage
2032     // the tree structure inherent in this process.
2033     //
2034     // NOTE:  We do this process twice, once to check that we're not doing an
2035     //        overall illegal transition, such as ultimately set the IP into
2036     //        a catch, which is never allowed.  We're doing this because VS
2037     //        calls SetIP without calling CanSetIP first, and so we should be able
2038     //        to return an error code and have the stack in the same condition
2039     //        as the start of the call, and so we shouldn't back out of clauses
2040     //        or move into them until we're sure that can be done.
2041
2042 retryForCommit:
2043
2044     EHRangeTreeNode *node;
2045     EHRangeTreeNode *nodeNext;
2046     node = pEHRT->FindMostSpecificContainer(offFrom);
2047
2048     while (!node->Contains(offTo))
2049     {
2050         hr = IsLegalTransition(pThread,
2051                                fCheckOnly,
2052                                bLeave,
2053                                node,
2054                                offFrom,
2055                                offTo,
2056                                pEECM,
2057                                pReg,
2058                                addrStart,
2059                                gcInfoToken,
2060                                pCtx);
2061
2062         if (FAILED(hr))
2063         {
2064             hrReturn = WORST_HR(hrReturn,hr);
2065         }
2066
2067         node = node->GetContainer();
2068         // m_root prevents node from ever being NULL.
2069     }
2070
2071     if (node != pEHRT->m_root)
2072     {
2073         hr = IsLegalTransition(pThread,
2074                                fCheckOnly,
2075                                bEnter|bLeave,
2076                                node,
2077                                offFrom,
2078                                offTo,
2079                                pEECM,
2080                                pReg,
2081                                addrStart,
2082                                gcInfoToken,
2083                                pCtx);
2084
2085         if (FAILED(hr))
2086         {
2087             hrReturn = WORST_HR(hrReturn,hr);
2088         }
2089     }
2090
2091     nodeNext = pEHRT->FindNextMostSpecificContainer(node,
2092                                                     offTo);
2093
2094     while(nodeNext != node)
2095     {
2096         hr = IsLegalTransition(pThread,
2097                                fCheckOnly,
2098                                bEnter,
2099                                nodeNext,
2100                                offFrom,
2101                                offTo,
2102                                pEECM,
2103                                pReg,
2104                                addrStart,
2105                                gcInfoToken,
2106                                pCtx);
2107
2108         if (FAILED(hr))
2109         {
2110             hrReturn = WORST_HR(hrReturn, hr);
2111         }
2112
2113         node = nodeNext;
2114         nodeNext = pEHRT->FindNextMostSpecificContainer(node,
2115                                                         offTo);
2116     }
2117
2118     // If it was the intention to actually set the IP and the above transition checks succeeded,
2119     // then go back and do it all again but this time widen and narrow the thread's actual scope
2120     if (!fCanSetIPOnly && fCheckOnly && SUCCEEDED(hrReturn))
2121     {
2122         fCheckOnly = false;
2123         goto retryForCommit;
2124     }
2125
2126     return hrReturn;
2127 } // HRESULT SetIPFromSrcToDst()
2128
2129 // This function should only be called if the thread is suspended and sitting in jitted code
2130 BOOL IsInFirstFrameOfHandler(Thread *pThread, IJitManager *pJitManager, const METHODTOKEN& MethodToken, DWORD offset)
2131 {
2132     CONTRACTL
2133     {
2134         NOTHROW;
2135         GC_NOTRIGGER;
2136         MODE_ANY;
2137         FORBID_FAULT;
2138     }
2139     CONTRACTL_END;
2140
2141     // if don't have a throwable the aren't processing an exception
2142     if (IsHandleNullUnchecked(pThread->GetThrowableAsHandle()))
2143         return FALSE;
2144
2145     EH_CLAUSE_ENUMERATOR pEnumState;
2146     unsigned EHCount = pJitManager->InitializeEHEnumeration(MethodToken, &pEnumState);
2147
2148     for(ULONG i=0; i < EHCount; i++)
2149     {
2150         EE_ILEXCEPTION_CLAUSE EHClause;
2151         pJitManager->GetNextEHClause(&pEnumState, &EHClause);
2152         _ASSERTE(IsValidClause(&EHClause));
2153
2154         if ( offset >= EHClause.HandlerStartPC && offset < EHClause.HandlerEndPC)
2155             return TRUE;
2156
2157         // check if it's in the filter itself if we're not in the handler
2158         if (IsFilterHandler(&EHClause) && offset >= EHClause.FilterOffset && offset < EHClause.HandlerStartPC)
2159             return TRUE;
2160     }
2161     return FALSE;
2162 } // BOOL IsInFirstFrameOfHandler()
2163
2164
2165 #if !defined(WIN64EXCEPTIONS)
2166
2167 //******************************************************************************
2168 // LookForHandler -- search for a function that will handle the exception.
2169 //******************************************************************************
2170 LFH LookForHandler(                         // LFH return types
2171     const EXCEPTION_POINTERS *pExceptionPointers, // The ExceptionRecord and ExceptionContext
2172     Thread      *pThread,                   // Thread on which to look (always current?)
2173     ThrowCallbackType *tct)                 // Structure to pass back to callback functions.
2174 {
2175     // We don't want to use a runtime contract here since this codepath is used during
2176     // the processing of a hard SO. Contracts use a significant amount of stack
2177     // which we can't afford for those cases.
2178     STATIC_CONTRACT_THROWS;
2179     STATIC_CONTRACT_GC_TRIGGERS;
2180     STATIC_CONTRACT_MODE_COOPERATIVE;
2181
2182     // go through to find if anyone handles the exception
2183     StackWalkAction action = pThread->StackWalkFrames((PSTACKWALKFRAMESCALLBACK)COMPlusThrowCallback,
2184                                  tct,
2185                                  0,     //can't use FUNCTIONSONLY because the callback uses non-function frames to stop the walk
2186                                  tct->pBottomFrame);
2187
2188     // If someone handles it, the action will be SWA_ABORT with pFunc and dHandler indicating the
2189         // function and handler that is handling the exception. Debugger can put a hook in here.
2190     if (action == SWA_ABORT && tct->pFunc != NULL)
2191         return LFH_FOUND;
2192
2193     // nobody is handling it
2194     return LFH_NOT_FOUND;
2195 } // LFH LookForHandler()
2196
2197 StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData);
2198
2199 //******************************************************************************
2200 //  UnwindFrames
2201 //******************************************************************************
2202 void UnwindFrames(                      // No return value.
2203     Thread      *pThread,               // Thread to unwind.
2204     ThrowCallbackType *tct)             // Structure to pass back to callback function.
2205 {
2206     STATIC_CONTRACT_THROWS;
2207     STATIC_CONTRACT_GC_NOTRIGGER;
2208     STATIC_CONTRACT_MODE_COOPERATIVE;
2209
2210     if (pThread->IsExceptionInProgress())
2211     {
2212         pThread->GetExceptionState()->GetFlags()->SetUnwindHasStarted();
2213     }
2214
2215     #ifdef DEBUGGING_SUPPORTED
2216         //
2217         // If a debugger is attached, notify it that unwinding is going on.
2218         //
2219         if (CORDebuggerAttached())
2220         {
2221             g_pDebugInterface->ManagedExceptionUnwindBegin(pThread);
2222         }
2223     #endif // DEBUGGING_SUPPORTED
2224
2225     LOG((LF_EH, LL_INFO1000, "UnwindFrames: going to: pFunc:%#X, pStack:%#X\n",
2226         tct->pFunc, tct->pStack));
2227
2228     pThread->StackWalkFrames((PSTACKWALKFRAMESCALLBACK)COMPlusUnwindCallback,
2229                              tct,
2230                              POPFRAMES,
2231                              tct->pBottomFrame);
2232 } // void UnwindFrames()
2233
2234 #endif // !defined(WIN64EXCEPTIONS)
2235
2236 void StackTraceInfo::SaveStackTrace(BOOL bAllowAllocMem, OBJECTHANDLE hThrowable, BOOL bReplaceStack, BOOL bSkipLastElement)
2237 {
2238     CONTRACTL
2239     {
2240         NOTHROW;
2241         GC_TRIGGERS;
2242         MODE_COOPERATIVE;
2243     }
2244     CONTRACTL_END;
2245
2246     // Do not save stacktrace to preallocated exception.  These are shared.
2247     if (CLRException::IsPreallocatedExceptionHandle(hThrowable))
2248     {
2249         // Preallocated exceptions will never have this flag set. However, its possible
2250         // that after this flag is set for a regular exception but before we throw, we have an async
2251         // exception like a RudeThreadAbort, which will replace the exception
2252         // containing the restored stack trace.
2253         //
2254         // In such a case, we should clear the flag as the throwable representing the
2255         // preallocated exception will not have the restored (or any) stack trace.
2256         PTR_ThreadExceptionState pCurTES = GetThread()->GetExceptionState();
2257         pCurTES->ResetRaisingForeignException();
2258
2259         return;
2260     }
2261
2262     LOG((LF_EH, LL_INFO1000, "StackTraceInfo::SaveStackTrace (%p), alloc = %d, replace = %d, skiplast = %d\n", this, bAllowAllocMem, bReplaceStack, bSkipLastElement));
2263
2264     // if have bSkipLastElement, must also keep the stack
2265     _ASSERTE(! bSkipLastElement || ! bReplaceStack);
2266
2267     bool         fSuccess = false;
2268     MethodTable* pMT      = ObjectFromHandle(hThrowable)->GetTrueMethodTable();
2269
2270     // Check if the flag indicating foreign exception raise has been setup or not,
2271     // and then reset it so that subsequent processing of managed frames proceeds
2272     // normally.
2273     PTR_ThreadExceptionState pCurTES = GetThread()->GetExceptionState();
2274     BOOL fRaisingForeignException = pCurTES->IsRaisingForeignException();
2275     pCurTES->ResetRaisingForeignException();
2276
2277     if (bAllowAllocMem && m_dFrameCount != 0)
2278     {
2279         EX_TRY
2280         {
2281             // Only save stack trace info on exceptions
2282             _ASSERTE(IsException(pMT));     // what is the pathway here?
2283             if (!IsException(pMT))
2284             {
2285                 fSuccess = true;
2286             }
2287             else
2288             {
2289                 // If the stack trace contains DynamicMethodDescs, we need to save the corrosponding
2290                 // System.Resolver objects in the Exception._dynamicMethods field. Failing to do that
2291                 // will cause an AV in the runtime when we try to visit those MethodDescs in the
2292                 // Exception._stackTrace field, because they have been recycled or destroyed.
2293                 unsigned    iNumDynamics      = 0;
2294
2295                 // How many DynamicMethodDescs do we need to keep alive?
2296                 for (unsigned iElement=0; iElement < m_dFrameCount; iElement++)
2297                 {
2298                     MethodDesc *pMethod = m_pStackTrace[iElement].pFunc;
2299                     _ASSERTE(pMethod);
2300
2301                     if (pMethod->IsLCGMethod())
2302                     {
2303                         // Increment the number of new dynamic methods we have found
2304                         iNumDynamics++;
2305                     }
2306                     else
2307                     if (pMethod->GetMethodTable()->Collectible())
2308                     {
2309                         iNumDynamics++;
2310                     }
2311                 }
2312
2313                 struct _gc
2314                 {
2315                     StackTraceArray stackTrace;
2316                     StackTraceArray stackTraceTemp;
2317                     PTRARRAYREF dynamicMethodsArrayTemp;
2318                     PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers
2319                     PTRARRAYREF pOrigDynamicArray;
2320
2321                     _gc()
2322                         : stackTrace()
2323                         , stackTraceTemp()
2324                         , dynamicMethodsArrayTemp(static_cast<PTRArray *>(NULL))
2325                         , dynamicMethodsArray(static_cast<PTRArray *>(NULL))
2326                         , pOrigDynamicArray(static_cast<PTRArray *>(NULL))
2327                     {}
2328                 };
2329
2330                 _gc gc;
2331                 GCPROTECT_BEGIN(gc);
2332
2333                 // If the flag indicating foreign exception raise has been setup, then check 
2334                 // if the exception object has stacktrace or not. If we have an async non-preallocated
2335                 // exception after setting this flag but before we throw, then the new
2336                 // exception will not have any stack trace set and thus, we should behave as if
2337                 // the flag was not setup.
2338                 if (fRaisingForeignException)
2339                 {
2340                     // Get the reference to stack trace and reset our flag if applicable.
2341                     ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->GetStackTrace(gc.stackTraceTemp);
2342                     if (gc.stackTraceTemp.Size() == 0)
2343                     {
2344                         fRaisingForeignException = FALSE;
2345                     }
2346                 }
2347
2348                 // Replace stack (i.e. build a new stack trace) only if we are not raising a foreign exception.
2349                 // If we are, then we will continue to extend the existing stack trace.
2350                 if (bReplaceStack
2351                     && (!fRaisingForeignException)
2352                     )
2353                 {
2354                     // Cleanup previous info
2355                     gc.stackTrace.Append(m_pStackTrace, m_pStackTrace + m_dFrameCount);
2356
2357                     if (iNumDynamics)
2358                     {
2359                         // Adjust the allocation size of the array, if required
2360                         if (iNumDynamics > m_cDynamicMethodItems)
2361                         {
2362                             S_UINT32 cNewSize = S_UINT32(2) * S_UINT32(iNumDynamics);
2363                             if (cNewSize.IsOverflow())
2364                             {
2365                                 // Overflow here implies we cannot allocate memory anymore
2366                                 LOG((LF_EH, LL_INFO100, "StackTraceInfo::SaveStackTrace - Cannot calculate initial resolver array size due to overflow!\n"));
2367                                 COMPlusThrowOM();
2368                             }
2369
2370                             m_cDynamicMethodItems = cNewSize.Value();
2371                         }
2372
2373                         gc.dynamicMethodsArray = (PTRARRAYREF)AllocateObjectArray(m_cDynamicMethodItems, g_pObjectClass);
2374                         LOG((LF_EH, LL_INFO100, "StackTraceInfo::SaveStackTrace - allocated dynamic array for first frame of size %lu\n",
2375                             m_cDynamicMethodItems));
2376                     }
2377
2378                     m_dCurrentDynamicIndex = 0;
2379                 }
2380                 else
2381                 {
2382                     // Fetch the stacktrace and the dynamic method array
2383                     ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->GetStackTrace(gc.stackTrace, &gc.pOrigDynamicArray);
2384
2385                     if (fRaisingForeignException)
2386                     {
2387                         // Just before we append to the stack trace, mark the last recorded frame to be from
2388                         // the foreign thread so that we can insert an annotation indicating so when building 
2389                         // the stack trace string.
2390                         size_t numCurrentFrames = gc.stackTrace.Size();
2391                         if (numCurrentFrames > 0)
2392                         {
2393                             // "numCurrentFrames" can be zero if the user created an EDI using
2394                             // an unthrown exception.
2395                             StackTraceElement & refLastElementFromForeignStackTrace = gc.stackTrace[numCurrentFrames - 1];
2396                             refLastElementFromForeignStackTrace.fIsLastFrameFromForeignStackTrace = TRUE;
2397                         }
2398                     }
2399
2400                     if (!bSkipLastElement)
2401                         gc.stackTrace.Append(m_pStackTrace, m_pStackTrace + m_dFrameCount);
2402
2403                     //////////////////////////////
2404
2405                     unsigned   cOrigDynamic = 0;    // number of objects in the old array
2406                     if (gc.pOrigDynamicArray != NULL)
2407                     {
2408                         cOrigDynamic = gc.pOrigDynamicArray->GetNumComponents();
2409                     }
2410                     else
2411                     {
2412                         // Since there is no dynamic method array, reset the corresponding state variables
2413                         m_dCurrentDynamicIndex = 0;
2414                         m_cDynamicMethodItems = 0;
2415                     }
2416
2417                     if ((gc.pOrigDynamicArray != NULL)
2418                     || (fRaisingForeignException)
2419                     )
2420                     {
2421                         // Since we have just restored the dynamic method array as well,
2422                         // calculate the dynamic array index which would be the total 
2423                         // number of dynamic methods present in the stack trace.
2424                         //
2425                         // In addition to the ForeignException scenario, we need to reset these
2426                         // values incase the exception object in question is being thrown by
2427                         // multiple threads in parallel and thus, could have potentially different
2428                         // dynamic method array contents/size as opposed to the current state of
2429                         // StackTraceInfo.
2430
2431                         unsigned iStackTraceElements = (unsigned)gc.stackTrace.Size();
2432                         m_dCurrentDynamicIndex = 0;
2433                         for (unsigned iIndex = 0; iIndex < iStackTraceElements; iIndex++)
2434                         {
2435                             MethodDesc *pMethod = gc.stackTrace[iIndex].pFunc;
2436                             if (pMethod)
2437                             {
2438                                 if ((pMethod->IsLCGMethod()) || (pMethod->GetMethodTable()->Collectible()))
2439                                 {
2440                                     // Increment the number of new dynamic methods we have found
2441                                     m_dCurrentDynamicIndex++;
2442                                 }
2443                             }
2444                         }
2445
2446                         // Total number of elements in the dynamic method array should also be
2447                         // reset based upon the restored array size.
2448                         m_cDynamicMethodItems = cOrigDynamic;
2449                     }
2450
2451                     // Make the dynamic Array field reference the original array we got from the
2452                     // Exception object. If, below, we have to add new entries, we will add it to the
2453                     // array if it is allocated, or else, we will allocate it before doing so.
2454                     gc.dynamicMethodsArray = gc.pOrigDynamicArray;
2455
2456                     // Create an object array if we have new dynamic method entries AND
2457                     // if we are at the (or went past) the current size limit
2458                     if (iNumDynamics > 0)
2459                     {
2460                         // Reallocate the array if we are at the (or went past) the current size limit
2461                         unsigned cTotalDynamicMethodCount = m_dCurrentDynamicIndex;
2462
2463                         S_UINT32 cNewSum = S_UINT32(cTotalDynamicMethodCount) + S_UINT32(iNumDynamics);
2464                         if (cNewSum.IsOverflow())
2465                         {
2466                             // If the current size is already the UINT32 max size, then we
2467                             // cannot go further. Overflow here implies we cannot allocate memory anymore.
2468                             LOG((LF_EH, LL_INFO100, "StackTraceInfo::SaveStackTrace - Cannot calculate resolver array size due to overflow!\n"));
2469                             COMPlusThrowOM();
2470                         }
2471
2472                         cTotalDynamicMethodCount = cNewSum.Value();
2473
2474                         if (cTotalDynamicMethodCount > m_cDynamicMethodItems)
2475                         {
2476                             // Double the current limit of the array.
2477                             S_UINT32 cNewSize = S_UINT32(2) * S_UINT32(cTotalDynamicMethodCount);
2478                             if (cNewSize.IsOverflow())
2479                             {
2480                                 // Overflow here implies that we cannot allocate any more memory
2481                                 LOG((LF_EH, LL_INFO100, "StackTraceInfo::SaveStackTrace - Cannot resize resolver array beyond max size due to overflow!\n"));
2482                                 COMPlusThrowOM();
2483                             }
2484
2485                             m_cDynamicMethodItems = cNewSize.Value();
2486                             gc.dynamicMethodsArray = (PTRARRAYREF)AllocateObjectArray(m_cDynamicMethodItems,
2487                                                                                       g_pObjectClass);
2488
2489                             _ASSERTE(!(cOrigDynamic && !gc.pOrigDynamicArray));
2490
2491                             LOG((LF_EH, LL_INFO100, "StackTraceInfo::SaveStackTrace - resized dynamic array to size %lu\n",
2492                             m_cDynamicMethodItems));
2493
2494                             // Copy previous entries if there are any, and update iCurDynamic to point
2495                             // to the following index.
2496                             if (cOrigDynamic && (gc.pOrigDynamicArray != NULL))
2497                             {
2498                                 memmoveGCRefs(gc.dynamicMethodsArray->GetDataPtr(),
2499                                               gc.pOrigDynamicArray->GetDataPtr(),
2500                                               cOrigDynamic * sizeof(Object *));
2501
2502                                 // m_dCurrentDynamicIndex is already referring to the correct index
2503                                 // at which the next resolver object will be saved
2504                             }
2505                         }
2506                         else
2507                         {
2508                             // We are adding objects to the existing array.
2509                             //
2510                             // We have new dynamic method entries for which
2511                             // resolver objects need to be saved. Ensure
2512                             // that we have the array to store them
2513                             if (gc.dynamicMethodsArray == NULL)
2514                             {
2515                                 _ASSERTE(m_cDynamicMethodItems > 0);
2516
2517                                 gc.dynamicMethodsArray = (PTRARRAYREF)AllocateObjectArray(m_cDynamicMethodItems,
2518                                                                                           g_pObjectClass);
2519                                 m_dCurrentDynamicIndex = 0;
2520                                 LOG((LF_EH, LL_INFO100, "StackTraceInfo::SaveStackTrace - allocated dynamic array of size %lu\n",
2521                                     m_cDynamicMethodItems));
2522                             }
2523                             else
2524                             {
2525                                 // The array exists for storing resolver objects.
2526                                 // Simply set the index at which the next resolver
2527                                 // will be stored in it.
2528                             }
2529                         }
2530                     }
2531                 }
2532
2533                 // Update _dynamicMethods field
2534                 if (iNumDynamics)
2535                 {
2536                     // At this point, we should be having a valid array for storage
2537                     _ASSERTE(gc.dynamicMethodsArray != NULL);
2538
2539                     // Assert that we are in valid range of the array in which resolver objects will be saved.
2540                     // We subtract 1 below since storage will start from m_dCurrentDynamicIndex onwards and not
2541                     // from (m_dCurrentDynamicIndex + 1).
2542                     _ASSERTE((m_dCurrentDynamicIndex + iNumDynamics - 1) < gc.dynamicMethodsArray->GetNumComponents());
2543
2544                     for (unsigned i=0; i < m_dFrameCount; i++)
2545                     {
2546                         MethodDesc *pMethod = m_pStackTrace[i].pFunc;
2547                         _ASSERTE(pMethod);
2548
2549                         if (pMethod->IsLCGMethod())
2550                         {
2551                             // We need to append the corresponding System.Resolver for
2552                             // this DynamicMethodDesc to keep it alive.
2553                             DynamicMethodDesc *pDMD = (DynamicMethodDesc *) pMethod;
2554                             OBJECTREF pResolver = pDMD->GetLCGMethodResolver()->GetManagedResolver();
2555
2556                             _ASSERTE(pResolver != NULL);
2557
2558                             // Store Resolver information in the array
2559                             gc.dynamicMethodsArray->SetAt(m_dCurrentDynamicIndex++, pResolver);
2560                         }
2561                         else
2562                         if (pMethod->GetMethodTable()->Collectible())
2563                         {
2564                             OBJECTREF pLoaderAllocator = pMethod->GetMethodTable()->GetLoaderAllocator()->GetExposedObject();
2565                             _ASSERTE(pLoaderAllocator != NULL);
2566                             gc.dynamicMethodsArray->SetAt (m_dCurrentDynamicIndex++, pLoaderAllocator);
2567                         }
2568                     }
2569                 }
2570
2571                 ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->SetStackTrace(gc.stackTrace, gc.dynamicMethodsArray);
2572                 
2573                 // Update _stackTraceString field.
2574                 ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->SetStackTraceString(NULL);
2575                 fSuccess = true;
2576
2577                 GCPROTECT_END();    // gc
2578             }
2579         }
2580         EX_CATCH
2581         {
2582         }
2583         EX_END_CATCH(SwallowAllExceptions)
2584     }
2585
2586     ClearStackTrace();
2587
2588     if (!fSuccess)
2589     {
2590         EX_TRY
2591         {
2592             _ASSERTE(IsException(pMT));         // what is the pathway here?
2593             if (bReplaceStack && IsException(pMT))
2594                 ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->ClearStackTraceForThrow();
2595         }
2596         EX_CATCH
2597         {
2598             // Do nothing
2599         }
2600         EX_END_CATCH(SwallowAllExceptions);
2601     }
2602 }
2603
2604 // Copy a context record, being careful about whether or not the target
2605 // is large enough to support CONTEXT_EXTENDED_REGISTERS.
2606 //
2607 // NOTE: this function can ONLY be used when a filter function will return
2608 // EXCEPTION_CONTINUE_EXECUTION.  On AMD64, replacing the CONTEXT in any other
2609 // situation may break exception unwinding.
2610 //
2611 // NOTE: this function MUST be used on AMD64.  During exception handling,
2612 // parts of the CONTEXT struct must not be modified.
2613
2614
2615 // High 2 bytes are machine type.  Low 2 bytes are register subset.
2616 #define CONTEXT_EXTENDED_BIT (CONTEXT_EXTENDED_REGISTERS & 0xffff)
2617
2618 VOID
2619 ReplaceExceptionContextRecord(CONTEXT *pTarget, CONTEXT *pSource)
2620 {
2621     LIMITED_METHOD_CONTRACT;
2622
2623     _ASSERTE(pTarget);
2624     _ASSERTE(pSource);
2625
2626 #if defined(_TARGET_X86_)
2627     //<TODO>
2628     // @TODO IA64: CONTEXT_DEBUG_REGISTERS not defined on IA64, may need updated SDK
2629     //</TODO>
2630
2631     // Want CONTROL, INTEGER, SEGMENTS.  If we have Floating Point, fine.
2632     _ASSERTE((pSource->ContextFlags & CONTEXT_FULL) == CONTEXT_FULL);
2633 #endif // _TARGET_X86_
2634
2635 #ifdef CONTEXT_EXTENDED_REGISTERS
2636
2637     if (pSource->ContextFlags & CONTEXT_EXTENDED_BIT)
2638     {
2639         if (pTarget->ContextFlags & CONTEXT_EXTENDED_BIT)
2640         {   // Source and Target have EXTENDED bit set.
2641             *pTarget = *pSource;
2642         }
2643         else
2644         {   // Source has but Target doesn't have EXTENDED bit set.  (Target is shorter than Source.)
2645             //  Copy non-extended part of the struct, and reset the bit on the Target, as it was.
2646             memcpy(pTarget, pSource, offsetof(CONTEXT, ExtendedRegisters));
2647             pTarget->ContextFlags &= ~CONTEXT_EXTENDED_BIT;  // Target was short.  Reset the extended bit.
2648         }
2649     }
2650     else
2651     {   // Source does not have EXTENDED bit.  Copy only non-extended part of the struct.
2652         memcpy(pTarget, pSource, offsetof(CONTEXT, ExtendedRegisters));
2653     }
2654     STRESS_LOG3(LF_SYNC, LL_INFO1000, "ReSet thread context EIP = %p ESP = %p EBP = %p\n",
2655         GetIP((CONTEXT*)pTarget), GetSP((CONTEXT*)pTarget), GetFP((CONTEXT*)pTarget));
2656
2657 #else // !CONTEXT_EXTENDED_REGISTERS
2658
2659     // Everything that's left
2660     *pTarget = *pSource;
2661
2662 #endif // !CONTEXT_EXTENDED_REGISTERS
2663 }
2664
2665 VOID FixupOnRethrow(Thread* pCurThread, EXCEPTION_POINTERS* pExceptionPointers)
2666 {
2667     WRAPPER_NO_CONTRACT;
2668
2669     ThreadExceptionState* pExState = pCurThread->GetExceptionState();
2670
2671 #ifdef FEATURE_INTERPRETER
2672     // Abort if we don't have any state from the original exception.
2673     if (!pExState->IsExceptionInProgress())
2674     {
2675         return;
2676     }
2677 #endif // FEATURE_INTERPRETER
2678
2679     // Don't allow rethrow of a STATUS_STACK_OVERFLOW -- it's a new throw of the COM+ exception.
2680     if (pExState->GetExceptionCode() == STATUS_STACK_OVERFLOW)
2681     {
2682         return;
2683     }
2684
2685     // For COMPLUS exceptions, we don't need the original context for our rethrow.
2686     if (!(pExState->IsComPlusException()))
2687     {
2688         _ASSERTE(pExState->GetExceptionRecord());
2689
2690         // don't copy parm args as have already supplied them on the throw
2691         memcpy((void*)pExceptionPointers->ExceptionRecord,
2692                (void*)pExState->GetExceptionRecord(),
2693                offsetof(EXCEPTION_RECORD, ExceptionInformation));
2694
2695 // Replacing the exception context breaks unwinding on AMD64.  It also breaks exception dispatch on IA64.
2696 // The info saved by pExState will be given to exception filters.
2697 #ifndef WIN64EXCEPTIONS
2698         // Restore original context if available.
2699         if (pExState->GetContextRecord())
2700         {
2701             ReplaceExceptionContextRecord(pExceptionPointers->ContextRecord,
2702                                           pExState->GetContextRecord());
2703         }
2704 #endif // !WIN64EXCEPTIONS
2705     }
2706
2707     pExState->GetFlags()->SetIsRethrown();
2708 }
2709
2710 struct RaiseExceptionFilterParam
2711 {
2712     BOOL isRethrown;
2713 };
2714
2715 LONG RaiseExceptionFilter(EXCEPTION_POINTERS* ep, LPVOID pv)
2716 {
2717     STATIC_CONTRACT_NOTHROW;
2718     STATIC_CONTRACT_GC_NOTRIGGER;
2719     STATIC_CONTRACT_MODE_ANY;
2720
2721     RaiseExceptionFilterParam *pParam = (RaiseExceptionFilterParam *) pv;
2722
2723     if (1 == pParam->isRethrown)
2724     {
2725         // need to reset the EH info back to the original thrown exception
2726         FixupOnRethrow(GetThread(), ep);
2727 #ifdef WIN64EXCEPTIONS
2728         // only do this once
2729         pParam->isRethrown++;
2730 #endif // WIN64EXCEPTIONS
2731     }
2732     else
2733     {
2734         CONSISTENCY_CHECK((2 == pParam->isRethrown) || (0 == pParam->isRethrown));
2735     }
2736
2737     return EXCEPTION_CONTINUE_SEARCH;
2738 }
2739
2740 //==========================================================================
2741 // Throw an object.
2742 //==========================================================================
2743 VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow
2744 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2745                                          , CorruptionSeverity severity
2746 #endif // FEATURE_CORRUPTING_EXCEPTIONS
2747                                          )
2748 {
2749     STATIC_CONTRACT_THROWS;
2750     STATIC_CONTRACT_GC_TRIGGERS;
2751     STATIC_CONTRACT_MODE_COOPERATIVE;
2752
2753     LOG((LF_EH, LL_INFO100, "RealCOMPlusThrow throwing %s\n",
2754         throwable->GetTrueMethodTable()->GetDebugClassName()));
2755
2756     if (throwable == NULL)
2757     {
2758         _ASSERTE(!"RealCOMPlusThrow(OBJECTREF) called with NULL argument. Somebody forgot to post an exception!");
2759         EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
2760     }
2761
2762     if (g_CLRPolicyRequested &&
2763         throwable->GetMethodTable() == g_pOutOfMemoryExceptionClass)
2764     {
2765         // We depends on UNINSTALL_UNWIND_AND_CONTINUE_HANDLER to handle out of memory escalation.
2766         // We should throw c++ exception instead.
2767         ThrowOutOfMemory();
2768     }
2769 #ifdef FEATURE_STACK_PROBE
2770     else if (throwable == CLRException::GetPreallocatedStackOverflowException())
2771     {
2772         ThrowStackOverflow();
2773     }
2774 #else
2775     _ASSERTE(throwable != CLRException::GetPreallocatedStackOverflowException());
2776 #endif
2777
2778 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2779     if (!g_pConfig->LegacyCorruptedStateExceptionsPolicy())
2780     {
2781         // This is Scenario 3 described in clrex.h around the definition of SET_CE_RETHROW_FLAG_FOR_EX_CATCH macro.
2782         //
2783         // We are here because the VM is attempting to throw a managed exception. It is posssible this exception
2784         // may not be seen by CLR's exception handler for managed code (e.g. there maybe an EX_CATCH up the stack
2785         // that will swallow or rethrow this exception). In the following scenario:
2786         //
2787         // [VM1 - RethrowCSE] -> [VM2 - RethrowCSE] -> [VM3 - RethrowCSE] -> <managed code>
2788         //
2789         // When managed code throws a CSE (e.g. TargetInvocationException flagged as CSE), [VM3] will rethrow it and we will
2790         // enter EX_CATCH in VM2 which is supposed to rethrow it as well. Two things can happen:
2791         //
2792         // 1) The implementation of EX_CATCH in VM2 throws a new managed exception *before* rethrow policy is applied and control
2793         //     will reach EX_CATCH in VM1, OR
2794         //
2795         // 2) EX_CATCH in VM2 swallows the exception, comes out of the catch block and later throws a new managed exception that
2796         //    will be caught by EX_CATCH in VM1.
2797         //
2798         // In either of the cases, rethrow in VM1 should be on the basis of the new managed exception's corruption severity.
2799         //
2800         // To support this scenario, we set corruption severity of the managed exception VM is throwing. If its a rethrow,
2801         // it implies we are rethrowing the last exception that was seen by CLR's managed code exception handler. In such a case,
2802         // we will copy over the corruption severity of that exception.
2803
2804         // If throwable indicates corrupted state, forcibly set the severity.
2805         if (CEHelper::IsProcessCorruptedStateException(throwable))
2806         {
2807             severity = ProcessCorrupting;
2808         }
2809
2810         // No one should have passed us an invalid severity.
2811         _ASSERTE(severity > NotSet);
2812
2813         if (severity == NotSet)
2814         {
2815             severity = NotCorrupting;
2816         }
2817
2818         // Update the corruption severity of the exception being thrown by the VM.
2819         GetThread()->GetExceptionState()->SetLastActiveExceptionCorruptionSeverity(severity);
2820
2821         // Exception's corruption severity should be reused in reraise if this exception leaks out from the VM
2822         // into managed code
2823         CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse();
2824
2825         LOG((LF_EH, LL_INFO100, "RaiseTheException - Set VM thrown managed exception severity to %d.\n", severity));
2826     }
2827
2828 #endif // FEATURE_CORRUPTING_EXCEPTIONS
2829
2830     RaiseTheExceptionInternalOnly(throwable,rethrow);
2831 }
2832
2833 HRESULT GetHRFromThrowable(OBJECTREF throwable)
2834 {
2835     STATIC_CONTRACT_THROWS;
2836     STATIC_CONTRACT_GC_TRIGGERS;
2837     STATIC_CONTRACT_MODE_ANY;
2838
2839     HRESULT    hr  = E_FAIL;
2840     MethodTable *pMT = throwable->GetTrueMethodTable();
2841
2842     // Only Exception objects have a HResult field
2843     // So don't fetch the field unless we have an exception
2844
2845     _ASSERTE(IsException(pMT));     // what is the pathway here?
2846     if (IsException(pMT))
2847     {
2848         hr = ((EXCEPTIONREF)throwable)->GetHResult();
2849     }
2850
2851     return hr;
2852 }
2853
2854
2855 VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL rethrow, BOOL fForStackOverflow)
2856 {
2857     STATIC_CONTRACT_THROWS;
2858     STATIC_CONTRACT_GC_TRIGGERS;
2859     STATIC_CONTRACT_MODE_COOPERATIVE;
2860
2861     STRESS_LOG3(LF_EH, LL_INFO100, "******* MANAGED EXCEPTION THROWN: Object thrown: %p MT %pT rethrow %d\n",
2862                 OBJECTREFToObject(throwable), (throwable!=0)?throwable->GetMethodTable():0, rethrow);
2863
2864 #ifdef STRESS_LOG
2865     // Any object could have been thrown, but System.Exception objects have useful information for the stress log
2866     if (!NingenEnabled() && throwable == CLRException::GetPreallocatedStackOverflowException())
2867     {
2868         // if are handling an SO, don't try to get all that other goop.  It isn't there anyway,
2869         // and it could cause us to take another SO.
2870         STRESS_LOG1(LF_EH, LL_INFO100, "Exception HRESULT = 0x%x \n", COR_E_STACKOVERFLOW);
2871     }
2872     else if (throwable != 0)
2873     {
2874         _ASSERTE(IsException(throwable->GetMethodTable()));
2875
2876         int hr = ((EXCEPTIONREF)throwable)->GetHResult();
2877         STRINGREF message = ((EXCEPTIONREF)throwable)->GetMessage();
2878         OBJECTREF innerEH = ((EXCEPTIONREF)throwable)->GetInnerException();
2879
2880         STRESS_LOG4(LF_EH, LL_INFO100, "Exception HRESULT = 0x%x Message String 0x%p (db will display) InnerException %p MT %pT\n",
2881             hr, OBJECTREFToObject(message), OBJECTREFToObject(innerEH), (innerEH!=0)?innerEH->GetMethodTable():0);
2882     }
2883 #endif
2884
2885     struct Param : RaiseExceptionFilterParam
2886     {
2887         OBJECTREF throwable;
2888         BOOL fForStackOverflow;
2889         ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE];
2890         Thread *pThread;
2891         ThreadExceptionState* pExState;
2892     } param;
2893     param.isRethrown = rethrow ? 1 : 0; // normalize because we use it as a count in RaiseExceptionFilter
2894     param.throwable = throwable;
2895     param.fForStackOverflow = fForStackOverflow;
2896     param.pThread = GetThread();
2897
2898     _ASSERTE(param.pThread);
2899     param.pExState = param.pThread->GetExceptionState();
2900
2901     if (param.pThread->IsRudeAbortInitiated())
2902     {
2903         // Nobody should be able to swallow rude thread abort.
2904         param.throwable = CLRException::GetPreallocatedRudeThreadAbortException();
2905     }
2906
2907 #if 0
2908     // TODO: enable this after we change RealCOMPlusThrow
2909 #ifdef _DEBUG
2910     // If ThreadAbort exception is thrown, the thread should be marked with AbortRequest.
2911     // If not, we may see unhandled exception.
2912     if (param.throwable->GetTrueMethodTable() == g_pThreadAbortExceptionClass)
2913     {
2914         _ASSERTE(GetThread()->IsAbortRequested()
2915 #ifdef _TARGET_X86_
2916                  ||
2917                  GetFirstCOMPlusSEHRecord(this) == EXCEPTION_CHAIN_END
2918 #endif
2919                  );
2920     }
2921 #endif
2922 #endif
2923
2924     // raise
2925     PAL_TRY(Param *, pParam, &param)
2926     {
2927         //_ASSERTE(! pParam->isRethrown || pParam->pExState->m_pExceptionRecord);
2928         ULONG_PTR *args = NULL;
2929         ULONG argCount = 0;
2930         ULONG flags = 0;
2931         ULONG code = 0;
2932
2933         // Always save the current object in the handle so on rethrow we can reuse it. This is important as it
2934         // contains stack trace info.
2935         //
2936         // Note: we use SafeSetLastThrownObject, which will try to set the throwable and if there are any problems,
2937         // it will set the throwable to something appropiate (like OOM exception) and return the new
2938         // exception. Thus, the user's exception object can be replaced here.
2939         pParam->throwable = NingenEnabled() ? NULL : pParam->pThread->SafeSetLastThrownObject(pParam->throwable);
2940
2941         if (!pParam->isRethrown ||
2942 #ifdef FEATURE_INTERPRETER
2943             !pParam->pExState->IsExceptionInProgress() ||
2944 #endif // FEATURE_INTERPRETER
2945              pParam->pExState->IsComPlusException() ||
2946             (pParam->pExState->GetExceptionCode() == STATUS_STACK_OVERFLOW))
2947         {
2948             ULONG_PTR hr = NingenEnabled() ? E_FAIL : GetHRFromThrowable(pParam->throwable);
2949
2950             args = pParam->exceptionArgs;
2951             argCount = MarkAsThrownByUs(args, hr);
2952             flags = EXCEPTION_NONCONTINUABLE;
2953             code = EXCEPTION_COMPLUS;
2954         }
2955         else
2956         {
2957             // Exception code should be consistent.
2958             _ASSERTE((DWORD)(pParam->pExState->GetExceptionRecord()->ExceptionCode) == pParam->pExState->GetExceptionCode());
2959
2960             args     = pParam->pExState->GetExceptionRecord()->ExceptionInformation;
2961             argCount = pParam->pExState->GetExceptionRecord()->NumberParameters;
2962             flags    = pParam->pExState->GetExceptionRecord()->ExceptionFlags;
2963             code     = pParam->pExState->GetExceptionRecord()->ExceptionCode;
2964         }
2965
2966         if (pParam->pThread->IsAbortInitiated () && IsExceptionOfType(kThreadAbortException,&pParam->throwable))
2967         {
2968             pParam->pThread->ResetPreparingAbort();
2969
2970             if (pParam->pThread->GetFrame() == FRAME_TOP)
2971             {
2972                 // There is no more managed code on stack.
2973                 pParam->pThread->EEResetAbort(Thread::TAR_ALL);
2974             }
2975         }
2976
2977         // Can't access the exception object when are in pre-emptive, so find out before
2978         // if its an SO.
2979         BOOL fIsStackOverflow = IsExceptionOfType(kStackOverflowException, &pParam->throwable);
2980
2981         if (fIsStackOverflow || pParam->fForStackOverflow)
2982         {
2983             // Don't probe if we're already handling an SO.  Just throw the exception.
2984             RaiseException(code, flags, argCount, args);
2985         }
2986
2987         // Probe for sufficient stack.
2988         PUSH_STACK_PROBE_FOR_THROW(pParam->pThread);
2989
2990 #ifndef STACK_GUARDS_DEBUG
2991         // This needs to be both here and inside the handler below
2992         // enable preemptive mode before call into OS
2993         GCX_PREEMP_NO_DTOR();
2994
2995         // In non-debug, we can just raise the exception once we've probed.
2996         RaiseException(code, flags, argCount, args);
2997
2998 #else
2999         // In a debug build, we need to unwind our probe structure off the stack.
3000         BaseStackGuard *pThrowGuard = NULL;
3001         // Stach away the address of the guard we just pushed above in PUSH_STACK_PROBE_FOR_THROW
3002         SAVE_ADDRESS_OF_STACK_PROBE_FOR_THROW(pThrowGuard);
3003
3004         // Add the stack guard reference to the structure below so that it can be accessed within
3005         // PAL_TRY as well
3006         struct ParamInner
3007         {
3008             ULONG code;
3009             ULONG flags;
3010             ULONG argCount;
3011             ULONG_PTR *args;
3012             BaseStackGuard *pGuard;
3013         } param;
3014         param.code = code;
3015         param.flags = flags;
3016         param.argCount = argCount;
3017         param.args = args;
3018         param.pGuard = pThrowGuard;
3019
3020         PAL_TRY(ParamInner *, pParam, &param)
3021         {
3022             // enable preemptive mode before call into OS
3023             GCX_PREEMP_NO_DTOR();
3024
3025             RaiseException(pParam->code, pParam->flags, pParam->argCount, pParam->args);
3026
3027             // We never return from RaiseException, so shouldn't have to call SetNoException.
3028             // However, in the debugger we can, and if we don't call SetNoException we get
3029             // a short-circuit return assert.
3030             RESET_EXCEPTION_FROM_STACK_PROBE_FOR_THROW(pParam->pGuard);
3031         }
3032         PAL_FINALLY
3033         {
3034             // pop the guard that we pushed above in PUSH_STACK_PROBE_FOR_THROW
3035             POP_STACK_PROBE_FOR_THROW(pThrowGuard);
3036         }
3037         PAL_ENDTRY
3038 #endif
3039     }
3040     PAL_EXCEPT_FILTER (RaiseExceptionFilter)
3041     {
3042     }
3043     PAL_ENDTRY
3044     _ASSERTE(!"Cannot continue after COM+ exception");      // Debugger can bring you here.
3045     // For example,
3046     // Debugger breaks in due to second chance exception (unhandled)
3047     // User hits 'g'
3048     // Then debugger can bring us here.
3049     EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
3050 }
3051
3052
3053 // INSTALL_COMPLUS_EXCEPTION_HANDLER has a filter, so must put the call in a separate fcn
3054 static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL rethrow
3055 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3056                                                      , CorruptionSeverity severity
3057 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3058 ) {
3059     STATIC_CONTRACT_THROWS;
3060     STATIC_CONTRACT_GC_TRIGGERS;
3061     STATIC_CONTRACT_MODE_ANY;
3062
3063     // RaiseTheException will throw C++ OOM and SO, so that our escalation policy can kick in.
3064     // Unfortunately, COMPlusFrameHandler installed here, will try to create managed exception object.
3065     // We may hit a recursion.
3066
3067     if (g_CLRPolicyRequested &&
3068         throwable->GetMethodTable() == g_pOutOfMemoryExceptionClass)
3069     {
3070         // We depends on UNINSTALL_UNWIND_AND_CONTINUE_HANDLER to handle out of memory escalation.
3071         // We should throw c++ exception instead.
3072         ThrowOutOfMemory();
3073     }
3074 #ifdef FEATURE_STACK_PROBE
3075     else if (throwable == CLRException::GetPreallocatedStackOverflowException())
3076     {
3077         ThrowStackOverflow();
3078     }
3079 #else
3080     _ASSERTE(throwable != CLRException::GetPreallocatedStackOverflowException());
3081 #endif
3082
3083     // TODO: Do we need to install COMPlusFrameHandler here?
3084     INSTALL_COMPLUS_EXCEPTION_HANDLER();
3085     RaiseTheException(throwable, rethrow
3086 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3087         , severity
3088 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3089         );
3090     UNINSTALL_COMPLUS_EXCEPTION_HANDLER();
3091 }
3092
3093
3094 VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow
3095 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3096                                         , CorruptionSeverity severity
3097 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3098 ) {
3099     STATIC_CONTRACT_THROWS;
3100     STATIC_CONTRACT_GC_TRIGGERS;
3101     STATIC_CONTRACT_MODE_ANY;
3102     GCPROTECT_BEGIN(throwable);
3103
3104     _ASSERTE(IsException(throwable->GetMethodTable()));
3105
3106     // This may look a bit odd, but there is an explaination.  The rethrow boolean
3107     //  means that an actual RaiseException(EXCEPTION_COMPLUS,...) is being re-thrown,
3108     //  and that the exception context saved on the Thread object should replace
3109     //  the exception context from the upcoming RaiseException().  There is logic
3110     //  in the stack trace code to preserve MOST of the stack trace, but to drop the
3111     //  last element of the stack trace (has to do with having the address of the rethrow
3112     //  instead of the address of the original call in the stack trace.  That is
3113     //  controversial itself, but we won't get into that here.)
3114     // However, if this is not re-raising that original exception, but rather a new
3115     //  os exception for what may be an existing exception object, it is generally
3116     //  a good thing to preserve the stack trace.
3117     if (!rethrow)
3118     {
3119         ExceptionPreserveStackTrace(throwable);
3120     }
3121
3122     RealCOMPlusThrowWorker(throwable, rethrow
3123 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3124         , severity
3125 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3126         );
3127
3128     GCPROTECT_END();
3129 }
3130
3131 VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable
3132 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3133                                         , CorruptionSeverity severity
3134 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3135                                         )
3136 {
3137     CONTRACTL
3138     {
3139         THROWS;
3140         GC_TRIGGERS;
3141         MODE_COOPERATIVE;
3142     }
3143     CONTRACTL_END;
3144
3145     RealCOMPlusThrow(throwable, FALSE
3146 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3147         , severity
3148 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3149         );
3150 }
3151
3152 // this function finds the managed callback to get a resource
3153 // string from the then current local domain and calls it
3154 // this could be a lot of work
3155 STRINGREF GetResourceStringFromManaged(STRINGREF key)
3156 {
3157     CONTRACTL
3158     {
3159         THROWS;
3160         GC_TRIGGERS;
3161         MODE_COOPERATIVE;
3162         PRECONDITION(key != NULL);
3163     }
3164     CONTRACTL_END;
3165
3166     struct xx {
3167         STRINGREF key;
3168         STRINGREF ret;
3169     } gc;
3170
3171     gc.key = key;
3172     gc.ret = NULL;
3173
3174     // The standard probe isn't good enough here. It's possible that we only have ~14 pages of stack
3175     // left. By the time we transition to the default domain and start fetching this resource string,
3176     // another 12 page probe could fail.
3177     // This failing probe would cause us to unload the default appdomain, which would cause us
3178     // to take down the process.
3179
3180     // Instead, let's probe for a lots more stack to make sure that doesn' happen.
3181
3182     // We need to have enough stack to survive 2 more probes... the original entrypoint back
3183     // into mscorwks after we go into managed code, and a "large" probe that protects the GC
3184
3185     INTERIOR_STACK_PROBE_FOR(GetThread(), DEFAULT_ENTRY_PROBE_AMOUNT * 2);
3186     GCPROTECT_BEGIN(gc);
3187
3188     MethodDescCallSite getResourceStringLocal(METHOD__ENVIRONMENT__GET_RESOURCE_STRING_LOCAL);
3189
3190     // Call Environment::GetResourceStringLocal(String name).  Returns String value (or maybe null)
3191
3192     ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD);
3193
3194     // Don't need to GCPROTECT pArgs, since it's not used after the function call.
3195
3196     ARG_SLOT pArgs[1] = { ObjToArgSlot(gc.key) };
3197     gc.ret = getResourceStringLocal.Call_RetSTRINGREF(pArgs);
3198
3199     END_DOMAIN_TRANSITION;
3200
3201     GCPROTECT_END();
3202
3203     END_INTERIOR_STACK_PROBE;
3204
3205
3206     return gc.ret;
3207 }
3208
3209 // This function does poentially a LOT of work (loading possibly 50 classes).
3210 // The return value is an un-GC-protected string ref, or possibly NULL.
3211 void ResMgrGetString(LPCWSTR wszResourceName, STRINGREF * ppMessage)
3212 {
3213     CONTRACTL
3214     {
3215         THROWS;
3216         GC_TRIGGERS;
3217         MODE_COOPERATIVE;
3218     }
3219     CONTRACTL_END;
3220
3221     _ASSERTE(ppMessage != NULL);
3222
3223     if (wszResourceName == NULL || *wszResourceName == W('\0'))
3224     {
3225         ppMessage = NULL;
3226         return;
3227     }
3228
3229     // this function never looks at name again after
3230     // calling the helper so no need to GCPROTECT it
3231     STRINGREF name = StringObject::NewString(wszResourceName);
3232
3233     if (wszResourceName != NULL)
3234     {
3235         STRINGREF value = GetResourceStringFromManaged(name);
3236
3237         _ASSERTE(value!=NULL || !"Resource string lookup failed - possible misspelling or .resources missing or out of date?");
3238         *ppMessage = value;
3239     }
3240 }
3241
3242 // GetResourceFromDefault
3243 // transition to the default domain and get a resource there
3244 FCIMPL1(Object*, GetResourceFromDefault, StringObject* keyUnsafe)
3245 {
3246     FCALL_CONTRACT;
3247
3248     STRINGREF ret = NULL;
3249     STRINGREF key = (STRINGREF)keyUnsafe;
3250
3251     HELPER_METHOD_FRAME_BEGIN_RET_2(ret, key);
3252
3253     ret = GetResourceStringFromManaged(key);
3254
3255     HELPER_METHOD_FRAME_END();
3256
3257     return OBJECTREFToObject(ret);
3258 }
3259 FCIMPLEND
3260
3261 void FreeExceptionData(ExceptionData *pedata)
3262 {
3263     CONTRACTL
3264     {
3265         NOTHROW; 
3266         GC_TRIGGERS; 
3267         SO_TOLERANT; 
3268     }
3269     CONTRACTL_END;
3270
3271     _ASSERTE(pedata != NULL);
3272
3273     // <TODO>@NICE: At one point, we had the comment:
3274     //     (DM) Remove this when shutdown works better.</TODO>
3275     // This test may no longer be necessary.  Remove at own peril.
3276     Thread *pThread = GetThread();
3277     if (!pThread)
3278         return;
3279
3280     if (pedata->bstrSource)
3281         SysFreeString(pedata->bstrSource);
3282     if (pedata->bstrDescription)
3283         SysFreeString(pedata->bstrDescription);
3284     if (pedata->bstrHelpFile)
3285         SysFreeString(pedata->bstrHelpFile);
3286 #ifdef FEATURE_COMINTEROP
3287     if (pedata->bstrRestrictedError)
3288         SysFreeString(pedata->bstrRestrictedError);
3289     if (pedata->bstrReference)
3290         SysFreeString(pedata->bstrReference);
3291     if (pedata->bstrCapabilitySid)
3292         SysFreeString(pedata->bstrCapabilitySid);
3293     if (pedata->pRestrictedErrorInfo)
3294     {
3295         ULONG cbRef = SafeRelease(pedata->pRestrictedErrorInfo);
3296         LogInteropRelease(pedata->pRestrictedErrorInfo, cbRef, "IRestrictedErrorInfo");    
3297     }
3298 #endif // FEATURE_COMINTEROP    
3299 }
3300
3301 void GetExceptionForHR(HRESULT hr, IErrorInfo* pErrInfo, bool fUseCOMException, OBJECTREF* pProtectedThrowable, IRestrictedErrorInfo *pResErrorInfo, BOOL bHasLangRestrictedErrInfo)
3302 {
3303     CONTRACTL
3304     {
3305         THROWS;
3306         GC_TRIGGERS;
3307         MODE_COOPERATIVE;
3308         PRECONDITION(IsProtectedByGCFrame(pProtectedThrowable));
3309     }
3310     CONTRACTL_END;
3311
3312     // Initialize
3313     *pProtectedThrowable = NULL;
3314
3315 #if defined(FEATURE_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3316     if (pErrInfo != NULL)
3317     {
3318         // If this represents a managed object...
3319         // ...then get the managed exception object and also check if it is a __ComObject...
3320         if (IsManagedObject(pErrInfo))
3321         {
3322             GetObjectRefFromComIP(pProtectedThrowable, pErrInfo);
3323             if ((*pProtectedThrowable) != NULL)
3324             {
3325                 // ...if it is, then we'll just default to an exception based on the IErrorInfo.
3326                 if ((*pProtectedThrowable)->GetMethodTable()->IsComObjectType())
3327                 {
3328                     (*pProtectedThrowable) = NULL;
3329                 }
3330                 else
3331                 {
3332                     // We have created an exception. Release the IErrorInfo
3333                     ULONG cbRef = SafeRelease(pErrInfo);
3334                     LogInteropRelease(pErrInfo, cbRef, "IErrorInfo release");
3335                     return;
3336                 }
3337             }
3338         }
3339
3340         // If we got here and we don't have an exception object, we have a native IErrorInfo or
3341         // a managed __ComObject based IErrorInfo, so we'll just create an exception based on
3342         // the native IErrorInfo.
3343         if ((*pProtectedThrowable) == NULL)
3344         {
3345             EECOMException ex(hr, pErrInfo, fUseCOMException, pResErrorInfo, bHasLangRestrictedErrInfo COMMA_INDEBUG(FALSE));
3346             (*pProtectedThrowable) = ex.GetThrowable();
3347         }
3348     }
3349 #endif // defined(FEATURE_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3350
3351     // If we made it here and we don't have an exception object, we didn't have a valid IErrorInfo
3352     // so we'll create an exception based solely on the hresult.
3353     if ((*pProtectedThrowable) == NULL)
3354     {
3355         EEMessageException ex(hr, fUseCOMException);
3356         (*pProtectedThrowable) = ex.GetThrowable();
3357     }
3358 }
3359
3360 void GetExceptionForHR(HRESULT hr, IErrorInfo* pErrInfo, OBJECTREF* pProtectedThrowable)
3361 {
3362     WRAPPER_NO_CONTRACT;
3363
3364     GetExceptionForHR(hr, pErrInfo, true, pProtectedThrowable);
3365 }
3366
3367 void GetExceptionForHR(HRESULT hr, OBJECTREF* pProtectedThrowable)
3368 {
3369     CONTRACTL
3370     {
3371         THROWS;
3372         GC_TRIGGERS;        // because of IErrorInfo
3373         MODE_ANY;
3374     }
3375     CONTRACTL_END;
3376
3377     // Get an IErrorInfo if one is available.
3378     IErrorInfo *pErrInfo = NULL;
3379 #ifndef CROSSGEN_COMPILE
3380     if (SafeGetErrorInfo(&pErrInfo) != S_OK)
3381         pErrInfo = NULL;
3382 #endif
3383
3384     GetExceptionForHR(hr, pErrInfo, true, pProtectedThrowable);
3385 }
3386
3387
3388 //
3389 // Maps a Win32 fault to a COM+ Exception enumeration code
3390 //
3391 DWORD MapWin32FaultToCOMPlusException(EXCEPTION_RECORD *pExceptionRecord)
3392 {
3393     WRAPPER_NO_CONTRACT;
3394
3395     switch (pExceptionRecord->ExceptionCode)
3396     {
3397         case STATUS_FLOAT_INEXACT_RESULT:
3398         case STATUS_FLOAT_INVALID_OPERATION:
3399         case STATUS_FLOAT_STACK_CHECK:
3400         case STATUS_FLOAT_UNDERFLOW:
3401             return (DWORD) kArithmeticException;
3402         case STATUS_FLOAT_OVERFLOW:
3403         case STATUS_INTEGER_OVERFLOW:
3404             return (DWORD) kOverflowException;
3405
3406         case STATUS_FLOAT_DIVIDE_BY_ZERO:
3407         case STATUS_INTEGER_DIVIDE_BY_ZERO:
3408             return (DWORD) kDivideByZeroException;
3409
3410         case STATUS_FLOAT_DENORMAL_OPERAND:
3411             return (DWORD) kFormatException;
3412
3413         case STATUS_ACCESS_VIOLATION:
3414             {
3415                 // We have a config key, InsecurelyTreatAVsAsNullReference, that ensures we always translate to
3416                 // NullReferenceException instead of doing the new AV translation logic.
3417                 if ((g_pConfig != NULL) && !g_pConfig->LegacyNullReferenceExceptionPolicy())
3418                 {
3419 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
3420                     // If we got the exception on a redirect function it means the original exception happened in managed code:
3421                     if (Thread::IsAddrOfRedirectFunc(pExceptionRecord->ExceptionAddress))
3422                         return (DWORD) kNullReferenceException;
3423
3424                     if (pExceptionRecord->ExceptionAddress == (LPVOID)GetEEFuncEntryPoint(THROW_CONTROL_FOR_THREAD_FUNCTION))
3425                     {
3426                         return (DWORD) kNullReferenceException;
3427                     }
3428 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
3429
3430                     // If the IP of the AV is not in managed code, then its an AccessViolationException.
3431                     if (!ExecutionManager::IsManagedCode((PCODE)pExceptionRecord->ExceptionAddress))
3432                     {
3433                         return (DWORD) kAccessViolationException;
3434                     }
3435
3436                     // If the address accessed is above 64k (Windows) or page size (PAL), then its an AccessViolationException.
3437                     // Note: Win9x is a little different... it never gives you the proper address of the read or write that caused
3438                     // the fault. It always gives -1, so we can't use it as part of the decision... just give
3439                     // NullReferenceException instead.
3440                     if (pExceptionRecord->ExceptionInformation[1] >= NULL_AREA_SIZE)
3441                     {
3442                         return (DWORD) kAccessViolationException;
3443                     }
3444                 }
3445
3446             return (DWORD) kNullReferenceException;
3447             }
3448
3449         case STATUS_ARRAY_BOUNDS_EXCEEDED:
3450             return (DWORD) kIndexOutOfRangeException;
3451
3452         case STATUS_NO_MEMORY:
3453             return (DWORD) kOutOfMemoryException;
3454
3455         case STATUS_STACK_OVERFLOW:
3456             return (DWORD) kStackOverflowException;
3457
3458 #ifdef ALIGN_ACCESS
3459         case STATUS_DATATYPE_MISALIGNMENT:
3460             return (DWORD) kDataMisalignedException;
3461 #endif // ALIGN_ACCESS
3462
3463         default:
3464             return kSEHException;
3465     }
3466 }
3467
3468 #ifdef _DEBUG
3469 #ifndef WIN64EXCEPTIONS
3470 // check if anyone has written to the stack above the handler which would wipe out the EH registration
3471 void CheckStackBarrier(EXCEPTION_REGISTRATION_RECORD *exRecord)
3472 {
3473     LIMITED_METHOD_CONTRACT;
3474
3475     if (exRecord->Handler != (PEXCEPTION_ROUTINE)COMPlusFrameHandler)
3476         return;
3477
3478     DWORD *stackOverwriteBarrier = (DWORD *)((BYTE*)exRecord - offsetof(FrameHandlerExRecordWithBarrier, m_ExRecord));
3479     for (int i =0; i < STACK_OVERWRITE_BARRIER_SIZE; i++) {
3480         if (*(stackOverwriteBarrier+i) != STACK_OVERWRITE_BARRIER_VALUE) {
3481             // to debug this error, you must determine who erroneously overwrote the stack
3482             _ASSERTE(!"Fatal error: the stack has been overwritten");
3483         }
3484     }
3485 }
3486 #endif // WIN64EXCEPTIONS
3487 #endif // _DEBUG
3488
3489 //-------------------------------------------------------------------------
3490 // A marker for JIT -> EE transition when we know we're in preemptive
3491 // gc mode.  As we leave the EE, we fix a few things:
3492 //
3493 //      - the gc state must be set back to preemptive-operative
3494 //      - the COM+ frame chain must be rewound to what it was on entry
3495 //      - ExInfo()->m_pSearchBoundary must be adjusted
3496 //        if we popped the frame that is identified as begnning the next
3497 //        crawl.
3498 //-------------------------------------------------------------------------
3499
3500 void COMPlusCooperativeTransitionHandler(Frame* pFrame)
3501 {
3502     CONTRACTL
3503     {
3504         NOTHROW;
3505         GC_TRIGGERS;
3506         MODE_ANY;
3507     }
3508     CONTRACTL_END;
3509
3510     LOG((LF_EH, LL_INFO1000, "COMPlusCooprativeTransitionHandler unwinding\n"));
3511
3512     {
3513     Thread* pThread = GetThread();
3514
3515     // Restore us to cooperative gc mode.
3516         GCX_COOP();
3517
3518     // Pop the frame chain.
3519     UnwindFrameChain(pThread, pFrame);
3520     CONSISTENCY_CHECK(pFrame == pThread->GetFrame());
3521
3522 #ifndef WIN64EXCEPTIONS
3523     // An exception is being thrown through here.  The COM+ exception
3524     // info keeps a pointer to a frame that is used by the next
3525     // COM+ Exception Handler as the starting point of its crawl.
3526     // We may have popped this marker -- in which case, we need to
3527     // update it to the current frame.
3528     //
3529     ThreadExceptionState* pExState = pThread->GetExceptionState();
3530     Frame*  pSearchBoundary = NULL;
3531
3532     if (pThread->IsExceptionInProgress())
3533     {
3534         pSearchBoundary = pExState->m_currentExInfo.m_pSearchBoundary;
3535     }
3536
3537     if (pSearchBoundary && pSearchBoundary < pFrame)
3538     {
3539         LOG((LF_EH, LL_INFO1000, "\tpExInfo->m_pSearchBoundary = %08x\n", (void*)pFrame));
3540         pExState->m_currentExInfo.m_pSearchBoundary = pFrame;
3541     }
3542 #endif // WIN64EXCEPTIONS
3543 }
3544
3545     // Restore us to preemptive gc mode.
3546     GCX_PREEMP_NO_DTOR();
3547 }
3548
3549
3550
3551 void StackTraceInfo::Init()
3552 {
3553     CONTRACTL
3554     {
3555         NOTHROW;
3556         GC_NOTRIGGER;
3557         MODE_ANY;
3558         FORBID_FAULT;
3559         SO_TOLERANT;
3560     }
3561     CONTRACTL_END;
3562
3563     LOG((LF_EH, LL_INFO10000, "StackTraceInfo::Init (%p)\n", this));
3564
3565     m_pStackTrace = NULL;
3566     m_cStackTrace = 0;
3567     m_dFrameCount = 0;
3568     m_cDynamicMethodItems = 0;
3569     m_dCurrentDynamicIndex = 0;
3570 }
3571
3572 void StackTraceInfo::FreeStackTrace()
3573 {
3574     CONTRACTL
3575     {
3576         NOTHROW;
3577         GC_NOTRIGGER;
3578         MODE_ANY;
3579         FORBID_FAULT;
3580         SO_TOLERANT;
3581     }
3582     CONTRACTL_END;
3583
3584     if (m_pStackTrace)
3585     {
3586         delete [] m_pStackTrace;
3587         m_pStackTrace = NULL;
3588         m_cStackTrace = 0;
3589         m_dFrameCount = 0;
3590         m_cDynamicMethodItems = 0;
3591         m_dCurrentDynamicIndex = 0;
3592     }
3593 }
3594
3595 BOOL StackTraceInfo::IsEmpty()
3596 {
3597     LIMITED_METHOD_CONTRACT;
3598
3599     return 0 == m_dFrameCount;
3600 }
3601
3602 void StackTraceInfo::ClearStackTrace()
3603 {
3604     LIMITED_METHOD_CONTRACT;
3605
3606     LOG((LF_EH, LL_INFO1000, "StackTraceInfo::ClearStackTrace (%p)\n", this));
3607     m_dFrameCount = 0;
3608 }
3609
3610 // allocate stack trace info. As each function is found in the stack crawl, it will be added
3611 // to this list. If the list is too small, it is reallocated.
3612 void StackTraceInfo::AllocateStackTrace()
3613 {
3614     STATIC_CONTRACT_NOTHROW;
3615     STATIC_CONTRACT_GC_NOTRIGGER;
3616     STATIC_CONTRACT_MODE_ANY;
3617     STATIC_CONTRACT_FORBID_FAULT;
3618
3619     LOG((LF_EH, LL_INFO1000, "StackTraceInfo::AllocateStackTrace (%p)\n", this));
3620
3621     if (!m_pStackTrace)
3622     {
3623 #ifdef _DEBUG
3624         unsigned int allocSize = 2;    // make small to exercise realloc
3625 #else
3626         unsigned int allocSize = 30;
3627 #endif
3628
3629         SCAN_IGNORE_FAULT; // A fault of new is okay here. The rest of the system is cool if we don't have enough
3630                            // memory to remember the stack as we run our first pass.
3631         m_pStackTrace = new (nothrow) StackTraceElement[allocSize];
3632
3633         if (m_pStackTrace != NULL)
3634         {
3635             // Remember how much we allocated.
3636             m_cStackTrace = allocSize;
3637             m_cDynamicMethodItems = allocSize;
3638         }
3639         else
3640         {
3641             m_cStackTrace = 0;
3642             m_cDynamicMethodItems = 0;
3643         }
3644     }
3645 }
3646
3647 //
3648 // Returns true if it appended the element, false otherwise.
3649 //
3650 BOOL StackTraceInfo::AppendElement(BOOL bAllowAllocMem, UINT_PTR currentIP, UINT_PTR currentSP, MethodDesc* pFunc, CrawlFrame* pCf)
3651 {
3652     CONTRACTL
3653     {
3654         GC_TRIGGERS;
3655         NOTHROW;
3656     }
3657     CONTRACTL_END
3658
3659     LOG((LF_EH, LL_INFO10000, "StackTraceInfo::AppendElement (%p), IP = %p, SP = %p, %s::%s\n", this, currentIP, currentSP, pFunc ? pFunc->m_pszDebugClassName : "", pFunc ? pFunc->m_pszDebugMethodName : "" ));
3660     BOOL bRetVal = FALSE;
3661
3662     if (pFunc != NULL && pFunc->IsILStub())
3663         return FALSE;
3664
3665     // Save this function in the stack trace array, which we only build on the first pass. We'll try to expand the
3666     // stack trace array if we don't have enough room. Note that we only try to expand if we're allowed to allocate
3667     // memory (bAllowAllocMem).
3668     if (bAllowAllocMem && (m_dFrameCount >= m_cStackTrace))
3669     {
3670         StackTraceElement* pTempElement = new (nothrow) StackTraceElement[m_cStackTrace*2];
3671
3672         if (pTempElement != NULL)
3673         {
3674             memcpy(pTempElement, m_pStackTrace, m_cStackTrace * sizeof(StackTraceElement));
3675             delete [] m_pStackTrace;
3676             m_pStackTrace = pTempElement;
3677             m_cStackTrace *= 2;
3678         }
3679     }
3680
3681     // Add the function to the stack trace array if there's room.
3682     if (m_dFrameCount < m_cStackTrace)
3683     {
3684         StackTraceElement* pStackTraceElem;
3685
3686         // If we get in here, we'd better have a stack trace array.
3687         CONSISTENCY_CHECK(m_pStackTrace != NULL);
3688
3689         pStackTraceElem = &(m_pStackTrace[m_dFrameCount]);
3690
3691         pStackTraceElem->pFunc = pFunc;
3692
3693         pStackTraceElem->ip = currentIP;
3694         pStackTraceElem->sp = currentSP;
3695
3696         // When we are building stack trace as we encounter managed frames during exception dispatch,
3697         // then none of those frames represent a stack trace from a foreign exception (as they represent
3698         // the current exception). Hence, set the corresponding flag to FALSE.
3699         pStackTraceElem->fIsLastFrameFromForeignStackTrace = FALSE;
3700
3701         // This is a workaround to fix the generation of stack traces from exception objects so that
3702         // they point to the line that actually generated the exception instead of the line
3703         // following.
3704         if (!(pCf->HasFaulted() || pCf->IsIPadjusted()) && pStackTraceElem->ip != 0)
3705         {
3706             pStackTraceElem->ip -= 1;
3707         }
3708
3709         ++m_dFrameCount;
3710         bRetVal = TRUE;
3711         COUNTER_ONLY(GetPerfCounters().m_Excep.cThrowToCatchStackDepth++);
3712     }
3713
3714 #ifndef FEATURE_PAL // Watson is supported on Windows only   
3715     Thread *pThread = GetThread();
3716     _ASSERTE(pThread);
3717
3718     if (pThread && (currentIP != 0))
3719     {
3720         // Setup the watson bucketing details for the initial throw
3721         // callback only if we dont already have them.
3722         ThreadExceptionState *pExState = pThread->GetExceptionState();
3723         if (!pExState->GetFlags()->GotWatsonBucketDetails())
3724         {
3725             // Adjust the IP if necessary.
3726             UINT_PTR adjustedIp = currentIP;
3727             // This is a workaround copied from above.
3728             if (!(pCf->HasFaulted() || pCf->IsIPadjusted()) && adjustedIp != 0)
3729             {
3730                 adjustedIp -= 1;
3731             }
3732
3733             // Setup the bucketing details for the initial throw
3734             SetupInitialThrowBucketDetails(adjustedIp);
3735         }
3736     }
3737 #endif // !FEATURE_PAL
3738
3739     return bRetVal;
3740 }
3741
3742 void StackTraceInfo::GetLeafFrameInfo(StackTraceElement* pStackTraceElement)
3743 {
3744     LIMITED_METHOD_CONTRACT;
3745
3746     if (NULL == m_pStackTrace)
3747     {
3748         return;
3749     }
3750     _ASSERTE(NULL != pStackTraceElement);
3751
3752     *pStackTraceElement = m_pStackTrace[0];
3753 }
3754
3755
3756 void UnwindFrameChain(Thread* pThread, LPVOID pvLimitSP)
3757 {
3758     CONTRACTL
3759     {
3760         NOTHROW;
3761         DISABLED(GC_TRIGGERS);  // some Frames' ExceptionUnwind methods trigger  :(
3762         MODE_ANY;
3763         SO_TOLERANT;
3764     }
3765     CONTRACTL_END;
3766
3767     // @todo - Remove this and add a hard SO probe as can't throw from here.
3768     CONTRACT_VIOLATION(SOToleranceViolation);
3769
3770     Frame* pFrame = pThread->m_pFrame;
3771     if (pFrame < pvLimitSP)
3772     {
3773         GCX_COOP_THREAD_EXISTS(pThread);
3774
3775         //
3776         // call ExceptionUnwind with the Frame chain intact
3777         //
3778         pFrame = pThread->NotifyFrameChainOfExceptionUnwind(pFrame, pvLimitSP);
3779
3780         //
3781         // now pop the frames off by trimming the Frame chain
3782         //
3783         pThread->SetFrame(pFrame);
3784     }
3785 }
3786
3787 BOOL IsExceptionOfType(RuntimeExceptionKind reKind, Exception *pException)
3788 {
3789     STATIC_CONTRACT_NOTHROW;
3790     STATIC_CONTRACT_GC_TRIGGERS;
3791     STATIC_CONTRACT_MODE_ANY;
3792     STATIC_CONTRACT_FORBID_FAULT;
3793
3794       if (pException->IsType(reKind))
3795         return TRUE;
3796
3797     if (pException->IsType(CLRException::GetType()))
3798     {
3799         // Since we're going to be holding onto the Throwable object we
3800         // need to be in COOPERATIVE.
3801         GCX_COOP();
3802
3803         OBJECTREF Throwable=((CLRException*)pException)->GetThrowable();
3804
3805         GCX_FORBID();
3806         if (IsExceptionOfType(reKind, &Throwable))
3807             return TRUE;
3808     }
3809     return FALSE;
3810 }
3811
3812 BOOL IsExceptionOfType(RuntimeExceptionKind reKind, OBJECTREF *pThrowable)
3813 {
3814     STATIC_CONTRACT_NOTHROW;
3815     STATIC_CONTRACT_GC_NOTRIGGER;
3816     STATIC_CONTRACT_MODE_COOPERATIVE;
3817     STATIC_CONTRACT_FORBID_FAULT;
3818
3819     _ASSERTE(pThrowable != NULL);
3820
3821     if (*pThrowable == NULL)
3822         return FALSE;
3823
3824     MethodTable *pThrowableMT = (*pThrowable)->GetTrueMethodTable();
3825
3826     // IsExceptionOfType is supported for mscorlib exception types only
3827     _ASSERTE(reKind <= kLastExceptionInMscorlib);
3828     return MscorlibBinder::IsException(pThrowableMT, reKind);
3829 }
3830
3831 BOOL IsAsyncThreadException(OBJECTREF *pThrowable) {
3832     STATIC_CONTRACT_NOTHROW;
3833     STATIC_CONTRACT_GC_NOTRIGGER;
3834     STATIC_CONTRACT_MODE_COOPERATIVE;
3835     STATIC_CONTRACT_FORBID_FAULT;
3836
3837     if (  (GetThread() && GetThread()->IsRudeAbort() && GetThread()->IsRudeAbortInitiated())
3838         ||IsExceptionOfType(kThreadAbortException, pThrowable)
3839         ||IsExceptionOfType(kThreadInterruptedException, pThrowable)) {
3840         return TRUE;
3841     } else {
3842         return FALSE;
3843     }
3844 }
3845
3846 BOOL IsUncatchable(OBJECTREF *pThrowable)
3847 {
3848     CONTRACTL {
3849         SO_TOLERANT;
3850         NOTHROW;
3851         GC_NOTRIGGER;
3852         MODE_COOPERATIVE;
3853         FORBID_FAULT;
3854     } CONTRACTL_END;
3855
3856     _ASSERTE(pThrowable != NULL);
3857
3858     Thread *pThread = GetThread();
3859
3860     if (pThread)
3861     {
3862         if (pThread->IsAbortInitiated())
3863             return TRUE;
3864
3865         if (OBJECTREFToObject(*pThrowable)->GetMethodTable() == g_pExecutionEngineExceptionClass)
3866             return TRUE;
3867
3868 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3869         // Corrupting exceptions are also uncatchable
3870         if (CEHelper::IsProcessCorruptedStateException(*pThrowable))
3871         {
3872             return TRUE;
3873         }
3874 #endif //FEATURE_CORRUPTING_EXCEPTIONS
3875     }
3876
3877     return FALSE;
3878 }
3879
3880 BOOL IsStackOverflowException(Thread* pThread, EXCEPTION_RECORD* pExceptionRecord)
3881 {
3882     if (IsSOExceptionCode(pExceptionRecord->ExceptionCode))
3883     {
3884         return true;
3885     }
3886
3887     if (IsComPlusException(pExceptionRecord) &&
3888          pThread->IsLastThrownObjectStackOverflowException())
3889     {
3890         return true;
3891     }
3892
3893     return false;
3894 }
3895
3896
3897 #ifdef _DEBUG
3898 BOOL IsValidClause(EE_ILEXCEPTION_CLAUSE *EHClause)
3899 {
3900     LIMITED_METHOD_CONTRACT;
3901
3902 #if 0
3903     DWORD valid = COR_ILEXCEPTION_CLAUSE_FILTER | COR_ILEXCEPTION_CLAUSE_FINALLY |
3904         COR_ILEXCEPTION_CLAUSE_FAULT | COR_ILEXCEPTION_CLAUSE_CACHED_CLASS;
3905
3906     // <TODO>@NICE: enable this when VC stops generatng a bogus 0x8000.</TODO>
3907     if (EHClause->Flags & ~valid)
3908         return FALSE;
3909 #endif
3910     if (EHClause->TryStartPC > EHClause->TryEndPC)
3911         return FALSE;
3912     return TRUE;
3913 }
3914 #endif
3915
3916
3917 #ifdef DEBUGGING_SUPPORTED
3918 LONG NotifyDebuggerLastChance(Thread *pThread,
3919                               EXCEPTION_POINTERS *pExceptionInfo,
3920                               BOOL jitAttachRequested)
3921 {
3922     STATIC_CONTRACT_NOTHROW;
3923     STATIC_CONTRACT_GC_TRIGGERS;
3924     STATIC_CONTRACT_MODE_ANY;
3925
3926     LONG retval = EXCEPTION_CONTINUE_SEARCH;
3927
3928     // Debugger does func-evals inside this call, which may take nested exceptions. We need a nested exception
3929     // handler to allow this.
3930     INSTALL_NESTED_EXCEPTION_HANDLER(pThread->GetFrame());
3931
3932     EXCEPTION_POINTERS dummy;
3933     dummy.ExceptionRecord = NULL;
3934     dummy.ContextRecord = NULL;
3935
3936     if (NULL == pExceptionInfo)
3937     {
3938         pExceptionInfo = &dummy;
3939     }
3940     else if (NULL != pExceptionInfo->ExceptionRecord && NULL == pExceptionInfo->ContextRecord)
3941     {
3942         // In a soft stack overflow, we have an exception record but not a  context record.
3943         // Debugger::LastChanceManagedException requires that both ExceptionRecord and
3944         // ContextRecord be valid or both be NULL.
3945         pExceptionInfo = &dummy;
3946     }
3947
3948     if  (g_pDebugInterface && g_pDebugInterface->LastChanceManagedException(pExceptionInfo,
3949                                                                             pThread,
3950                                                                             jitAttachRequested) == ExceptionContinueExecution)
3951     {
3952         retval = EXCEPTION_CONTINUE_EXECUTION;
3953     }
3954
3955     UNINSTALL_NESTED_EXCEPTION_HANDLER();
3956
3957 #ifdef DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED
3958     EX_TRY
3959     {
3960         // if the debugger wants to intercept the unhandled exception then we immediately unwind without returning
3961         // If there is a problem with this function unwinding here it could be separated out however
3962         // we need to be very careful. Previously we had the opposite problem in that we notified the debugger
3963         // of an unhandled exception and then either:
3964         // a) never gave the debugger a chance to intercept later, or
3965         // b) code changed more process state unaware that the debugger would be handling the exception
3966         if ((pThread->IsExceptionInProgress()) && pThread->GetExceptionState()->GetFlags()->DebuggerInterceptInfo())
3967         {
3968             // The debugger wants to intercept this exception.  It may return in a failure case, in which case we want
3969             // to continue thru this path.
3970             ClrDebuggerDoUnwindAndIntercept(X86_FIRST_ARG(EXCEPTION_CHAIN_END) pExceptionInfo->ExceptionRecord);
3971         }
3972     }
3973     EX_CATCH // if we fail to intercept just continue as is
3974     {
3975     }
3976     EX_END_CATCH(SwallowAllExceptions);
3977 #endif // DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED
3978
3979     return retval;
3980 }
3981
3982 #ifndef FEATURE_PAL
3983 //----------------------------------------------------------------------------
3984 //
3985 // DoReportFault - wrapper for ReportFault in FaultRep.dll, which also handles
3986 //                 debugger launch synchronization if the user chooses to launch
3987 //                 a debugger
3988 //
3989 // Arguments:
3990 //    pExceptionInfo - pointer to exception info
3991 //
3992 // Return Value:
3993 //    The returned EFaultRepRetVal value from ReportFault
3994 //
3995 // Note:
3996 //
3997 //----------------------------------------------------------------------------
3998 EFaultRepRetVal DoReportFault(EXCEPTION_POINTERS * pExceptionInfo)
3999 {
4000     LIMITED_METHOD_CONTRACT;
4001
4002     HINSTANCE hmod = WszLoadLibrary(W("FaultRep.dll"));
4003     EFaultRepRetVal r = frrvErr;
4004     if (hmod)
4005     {
4006         pfn_REPORTFAULT pfnReportFault = (pfn_REPORTFAULT)GetProcAddress(hmod, "ReportFault");
4007         if (pfnReportFault)
4008         {
4009             r = pfnReportFault(pExceptionInfo, 0);
4010         }
4011         FreeLibrary(hmod);
4012     }
4013
4014     if (r == frrvLaunchDebugger)
4015     {
4016         // Wait until the pending managed debugger attach is completed
4017         if (g_pDebugInterface != NULL)
4018         {
4019             g_pDebugInterface->WaitForDebuggerAttach();
4020         }
4021     }
4022     return r;
4023 }
4024
4025 //----------------------------------------------------------------------------
4026 //
4027 // DisableOSWatson - Set error mode to disable OS Watson
4028 //
4029 // Arguments:
4030 //    None
4031 //
4032 // Return Value:
4033 //    None
4034 //
4035 // Note: SetErrorMode changes the process wide error mode, which can be overridden by other threads
4036 //       in a race.  The solution is to use new Win7 per thread error mode APIs, which take precedence
4037 //       over process wide error mode. However, we shall not use per thread error mode if the runtime
4038 //       is being hosted because with per thread error mode being used the OS will ignore the process
4039 //       wide error mode set by the host.
4040 //
4041 //----------------------------------------------------------------------------
4042 void DisableOSWatson(void)
4043 {
4044     LIMITED_METHOD_CONTRACT;
4045
4046     // When a debugger is attached (or will be attaching), we need to disable the OS GPF dialog.
4047     // If we don't, an unhandled managed exception will launch the OS watson dialog even when
4048     // the debugger is attached.
4049     const UINT lastErrorMode = SetErrorMode(0);
4050     SetErrorMode(lastErrorMode | SEM_NOGPFAULTERRORBOX);
4051     LOG((LF_EH, LL_INFO100, "DisableOSWatson: SetErrorMode = 0x%x\n", lastErrorMode | SEM_NOGPFAULTERRORBOX));
4052
4053 }
4054 #endif // !FEATURE_PAL
4055
4056 //------------------------------------------------------------------------------
4057 // This function is called on an unhandled exception, via the runtime's
4058 //  Unhandled Exception Filter (Hence the name, "last chance", because this
4059 //  is the last chance to see the exception.  When running under a native
4060 //  debugger, that won't generally happen, because the OS notifies the debugger
4061 //  instead of calling the application's registered UEF; the debugger will
4062 //  show the exception as second chance.)
4063 // The function is also called sometimes for the side effects, which are
4064 //  to possibly invoke Watson and to possibly notify the managed debugger.
4065 // If running in a debugger already, either native or managed, we shouldn't
4066 //  invoke Watson.
4067 // If not running under a managed debugger, we shouldn't try to send a debugger
4068 //   notification.
4069 //------------------------------------------------------------------------------
4070 LONG WatsonLastChance(                  // EXCEPTION_CONTINUE_SEARCH, _CONTINUE_EXECUTION
4071     Thread              *pThread,       // Thread object.
4072     EXCEPTION_POINTERS  *pExceptionInfo,// Information about reported exception.
4073     TypeOfReportedError tore)           // Just what kind of error is reported?
4074 {
4075     STATIC_CONTRACT_NOTHROW;
4076     STATIC_CONTRACT_GC_TRIGGERS;
4077     STATIC_CONTRACT_MODE_ANY;
4078
4079     // If allocation fails, we may not produce watson dump.  But this is not fatal.
4080     CONTRACT_VIOLATION(AllViolation);
4081     LOG((LF_EH, LL_INFO10, "D::WLC: Enter WatsonLastChance\n"));
4082
4083 #ifndef FEATURE_PAL
4084     static DWORD fDisableWatson = -1;
4085     if (fDisableWatson == -1)
4086     {
4087         fDisableWatson = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DisableWatsonForManagedExceptions);
4088     }
4089
4090     if (fDisableWatson && (tore.GetType() == TypeOfReportedError::UnhandledException))
4091     {
4092         DisableOSWatson();
4093         LOG((LF_EH, LL_INFO10, "D::WLC: OS Watson is disabled for an managed unhandled exception\n"));
4094         return EXCEPTION_CONTINUE_SEARCH;
4095     }
4096 #endif // !FEATURE_PAL
4097
4098     // We don't want to launch Watson if a debugger is already attached to
4099     // the process.
4100     BOOL shouldNotifyDebugger = FALSE;  // Assume we won't debug.
4101
4102     // VS debugger team requested the Whidbey experience, which is no Watson when the debugger thread detects
4103     // that the debugger process is abruptly terminated, and triggers a failfast error.  In this particular
4104     // scenario CORDebuggerAttached() will be TRUE, but IsDebuggerPresent() will be FALSE because from OS
4105     // perspective the native debugger has been detached from the debuggee, but CLR has not yet marked the
4106     // managed debugger as detached.  Therefore, CORDebuggerAttached() is checked, so Watson will not pop up
4107     // when a debugger is abruptly terminated.  It also prevents a debugger from being launched on a helper
4108     // thread.
4109     BOOL alreadyDebugging     = CORDebuggerAttached() || IsDebuggerPresent();
4110
4111     BOOL jitAttachRequested   = !alreadyDebugging; // Launch debugger if not already running.
4112
4113 #ifdef _DEBUG
4114     // If BreakOnUnCaughtException is set, we may be using a native debugger to debug this stuff
4115     BOOL BreakOnUnCaughtException = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException);
4116     if(!alreadyDebugging || (!CORDebuggerAttached() && BreakOnUnCaughtException) )
4117 #else
4118     if (!alreadyDebugging)
4119 #endif
4120     {
4121         LOG((LF_EH, LL_INFO10, "WatsonLastChance: Debugger not attached at sp %p ...\n", GetCurrentSP()));
4122
4123 #ifndef FEATURE_PAL
4124         FaultReportResult result = FaultReportResultQuit;
4125
4126         BOOL fSOException = FALSE;
4127
4128         if ((pExceptionInfo != NULL) &&
4129             (pExceptionInfo->ExceptionRecord != NULL) &&
4130             (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW))
4131         {
4132             fSOException = TRUE;
4133         }
4134
4135         if (g_pDebugInterface)
4136         {
4137             // we are about to let the OS trigger jit attach, however we need to synchronize with our
4138             // own jit attach that we might be doing on another thread
4139             // PreJitAttach races this thread against any others which might be attaching and if some other
4140             // thread is doing it then we wait for its attach to complete first
4141             g_pDebugInterface->PreJitAttach(TRUE, FALSE, FALSE);
4142         }
4143
4144         // Let unhandled excpetions except stack overflow go to the OS
4145         if (tore.IsUnhandledException() && !fSOException)
4146         {
4147             return EXCEPTION_CONTINUE_SEARCH;
4148         }
4149         else if (tore.IsUserBreakpoint())
4150         {
4151             DoReportFault(pExceptionInfo);
4152         }
4153         else
4154         {
4155             BOOL fWatsonAlreadyLaunched = FALSE;
4156             if (FastInterlockCompareExchange(&g_watsonAlreadyLaunched, 1, 0) != 0)
4157             {
4158                 fWatsonAlreadyLaunched = TRUE;
4159             }
4160
4161             // Logic to avoid double prompt if more than one threads calling into WatsonLastChance
4162             if (!fWatsonAlreadyLaunched)
4163             {
4164                 // EEPolicy::HandleFatalStackOverflow pushes a FaultingExceptionFrame on the stack after SO
4165                 // exception.   Our hijack code runs in the exception context, and overwrites the stack space
4166                 // after SO excpetion, so we need to pop up this frame before invoking RaiseFailFast.
4167                 // This cumbersome code should be removed once SO synchronization is moved to be completely
4168                 // out-of-process.
4169                 if (fSOException && pThread && pThread->GetFrame() != FRAME_TOP)
4170                 {
4171                     GCX_COOP();     // Must be cooperative to modify frame chain.
4172                     pThread->GetFrame()->Pop(pThread);
4173                 }
4174
4175                 LOG((LF_EH, LL_INFO10, "D::WLC: Call RaiseFailFastExceptionOnWin7\n"));
4176
4177                 // enable preemptive mode before call into OS to allow runtime suspend to finish
4178                 GCX_PREEMP();
4179
4180                 STRESS_LOG0(LF_CORDB, LL_INFO10, "D::RFFE: About to call RaiseFailFastException\n");
4181                 RaiseFailFastException(pExceptionInfo == NULL ? NULL : pExceptionInfo->ExceptionRecord, 
4182                                         pExceptionInfo == NULL ? NULL : pExceptionInfo->ContextRecord,
4183                                         0);
4184                 STRESS_LOG0(LF_CORDB, LL_INFO10, "D::RFFE: Return from RaiseFailFastException\n");
4185             }
4186         }
4187
4188         if (g_pDebugInterface)
4189         {
4190             // if execution resumed here then we may or may not be attached
4191             // either way we need to end the attach process and unblock any other
4192             // threads which were waiting for the attach here to complete
4193             g_pDebugInterface->PostJitAttach();
4194         }
4195
4196
4197         if (IsDebuggerPresent())
4198         {
4199             result = FaultReportResultDebug;
4200             jitAttachRequested = FALSE;
4201         }
4202
4203         switch(result)
4204         {
4205             case FaultReportResultAbort:
4206             {
4207                 // We couldn't launch watson properly. First fall-back to OS error-reporting
4208                 // so that we don't break native apps.
4209                 EFaultRepRetVal r = frrvErr;
4210
4211                 if (pExceptionInfo != NULL)
4212                 {
4213                     GCX_PREEMP();
4214
4215                     if (pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_STACK_OVERFLOW)
4216                     {
4217                         r = DoReportFault(pExceptionInfo);
4218                     }
4219                     else
4220                     {
4221                         // Since the StackOverflow handler also calls us, we must keep our stack budget
4222                         // to a minimum. Thus, we will launch a thread to do the actual work.
4223                         FaultReportInfo fri;
4224                         fri.m_fDoReportFault       = TRUE;
4225                         fri.m_pExceptionInfo       = pExceptionInfo;
4226                         // DoFaultCreateThreadReportCallback will overwrite this - if it doesn't, we'll assume it failed.
4227                         fri.m_faultRepRetValResult = frrvErr;
4228
4229                         // Stack overflow case - we don't have enough stack on our own thread so let the debugger
4230                         // helper thread do the work.
4231                         if (!g_pDebugInterface || FAILED(g_pDebugInterface->RequestFavor(DoFaultReportDoFavorCallback, &fri)))
4232                         {
4233                             // If we can't initialize the debugger helper thread or we are running on the debugger helper
4234                             // thread, give it up. We don't have enough stack space.
4235                         }
4236
4237                         r = fri.m_faultRepRetValResult;
4238                     }
4239                 }
4240
4241                 if ((r == frrvErr) || (r == frrvErrNoDW) || (r == frrvErrTimeout))
4242                 {
4243                     // If we don't have an exception record, or otherwise can't use OS error
4244                     // reporting then offer the old "press OK to terminate, cancel to debug"
4245                     // dialog as a futher fallback.
4246                     if (g_pDebugInterface && g_pDebugInterface->FallbackJITAttachPrompt())
4247                     {
4248                         // User requested to launch the debugger
4249                         shouldNotifyDebugger = TRUE;
4250                     }
4251                 }
4252                 else if (r == frrvLaunchDebugger)
4253                 {
4254                     // User requested to launch the debugger
4255                     shouldNotifyDebugger = TRUE;
4256                 }
4257                 break;
4258             }
4259             case FaultReportResultQuit:
4260                 // No debugger, just exit normally
4261                 break;
4262             case FaultReportResultDebug:
4263                 // JIT attach a debugger here.
4264                 shouldNotifyDebugger = TRUE;
4265                 break;
4266             default:
4267                 UNREACHABLE_MSG("Unknown FaultReportResult");
4268                 break;
4269         }
4270     }
4271     // When the debugger thread detects that the debugger process is abruptly terminated, and triggers
4272     // a failfast error, CORDebuggerAttached() will be TRUE, but IsDebuggerPresent() will be FALSE.
4273     // If IsDebuggerPresent() is FALSE, do not try to notify the deubgger.
4274     else if (CORDebuggerAttached() && IsDebuggerPresent())
4275 #else
4276     }
4277     else if (CORDebuggerAttached())
4278 #endif // !FEATURE_PAL
4279     {
4280         // Already debugging with a managed debugger.  Should let that debugger know.
4281         LOG((LF_EH, LL_INFO100, "WatsonLastChance: Managed debugger already attached at sp %p ...\n", GetCurrentSP()));
4282
4283         // The managed EH subsystem ignores native breakpoints and single step exceptions.  These exceptions are
4284         // not considered managed, and the managed debugger should not be notified.  Moreover, we won't have
4285         // created a managed exception object at this point.
4286         if (tore.GetType() != TypeOfReportedError::NativeBreakpoint)
4287         {
4288             shouldNotifyDebugger = TRUE;
4289         }
4290     }
4291
4292 #ifndef FEATURE_PAL
4293     DisableOSWatson();
4294 #endif // !FEATURE_PAL
4295
4296     if (!shouldNotifyDebugger)
4297     {
4298         LOG((LF_EH, LL_INFO100, "WatsonLastChance: should not notify debugger.  Returning EXCEPTION_CONTINUE_SEARCH\n"));
4299         return EXCEPTION_CONTINUE_SEARCH;
4300     }
4301
4302     // If no debugger interface, we can't notify the debugger.
4303     if (g_pDebugInterface == NULL)
4304     {
4305         LOG((LF_EH, LL_INFO100, "WatsonLastChance: No debugger interface.  Returning EXCEPTION_CONTINUE_SEARCH\n"));
4306         return EXCEPTION_CONTINUE_SEARCH;
4307     }
4308
4309     LOG((LF_EH, LL_INFO10, "WatsonLastChance: Notifying debugger\n"));
4310
4311     switch (tore.GetType())
4312     {
4313         case TypeOfReportedError::FatalError:
4314             #ifdef MDA_SUPPORTED
4315             {
4316                 MdaFatalExecutionEngineError * pMDA = MDA_GET_ASSISTANT_EX(FatalExecutionEngineError);
4317
4318                 if ((pMDA != NULL) && (pExceptionInfo != NULL) && (pExceptionInfo->ExceptionRecord != NULL))
4319                 {
4320                     TADDR addr = (TADDR) pExceptionInfo->ExceptionRecord->ExceptionAddress;
4321                     HRESULT hrError = pExceptionInfo->ExceptionRecord->ExceptionCode;
4322                     pMDA->ReportFEEE(addr, hrError);
4323                 }
4324             }
4325             #endif // MDA_SUPPORTED
4326
4327             if (pThread != NULL)
4328             {
4329                 NotifyDebuggerLastChance(pThread, pExceptionInfo, jitAttachRequested);
4330
4331                 // If the registed debugger is not a managed debugger, we need to stop the debugger here.
4332                 if (!CORDebuggerAttached() && IsDebuggerPresent())
4333                 {
4334                     DebugBreak();
4335                 }
4336             }
4337             else
4338             {
4339                 g_pDebugInterface->LaunchDebuggerForUser(GetThread(), pExceptionInfo, FALSE, FALSE);
4340             }
4341
4342             return EXCEPTION_CONTINUE_SEARCH;
4343
4344         case TypeOfReportedError::UnhandledException:
4345         case TypeOfReportedError::NativeBreakpoint:
4346             // Notify the debugger only if this is a managed thread.
4347             if (pThread != NULL)
4348             {
4349                 return NotifyDebuggerLastChance(pThread, pExceptionInfo, jitAttachRequested);
4350             }
4351             else
4352             {
4353                 g_pDebugInterface->JitAttach(pThread, pExceptionInfo, FALSE, FALSE);
4354
4355                 // return EXCEPTION_CONTINUE_SEARCH, so OS's UEF will reraise the unhandled exception for debuggers
4356                 return EXCEPTION_CONTINUE_SEARCH;
4357             }
4358
4359         case TypeOfReportedError::UserBreakpoint:
4360             g_pDebugInterface->LaunchDebuggerForUser(pThread, pExceptionInfo, TRUE, FALSE);
4361
4362             return EXCEPTION_CONTINUE_EXECUTION;
4363
4364         case TypeOfReportedError::NativeThreadUnhandledException:
4365             g_pDebugInterface->JitAttach(pThread, pExceptionInfo, FALSE, FALSE);
4366
4367             // return EXCEPTION_CONTINUE_SEARCH, so OS's UEF will reraise the unhandled exception for debuggers
4368             return EXCEPTION_CONTINUE_SEARCH;
4369
4370         default:
4371             _ASSERTE(!"Unknown case in WatsonLastChance");
4372             return EXCEPTION_CONTINUE_SEARCH;
4373     }
4374
4375     UNREACHABLE();
4376 } // LONG WatsonLastChance()
4377
4378 //---------------------------------------------------------------------------------------
4379 //
4380 // This is just a simple helper to do some basic checking to see if an exception is intercepted.
4381 // It checks that we are on a managed thread and that an exception is indeed in progress.
4382 //
4383 // Return Value:
4384 //    true iff we are on a managed thread and an exception is in flight
4385 //
4386
4387 bool CheckThreadExceptionStateForInterception()
4388 {
4389     LIMITED_METHOD_CONTRACT;
4390
4391     Thread* pThread = GetThread();
4392
4393     if (pThread == NULL)
4394     {
4395         return false;
4396     }
4397
4398     if (!pThread->IsExceptionInProgress())
4399     {
4400         return false;
4401     }
4402
4403     return true;
4404 }
4405 #endif
4406
4407 //===========================================================================================
4408 //
4409 // UNHANDLED EXCEPTION HANDLING
4410 //
4411
4412 static Volatile<BOOL> fReady = 0;
4413 static SpinLock initLock;
4414
4415 void DECLSPEC_NORETURN RaiseDeadLockException()
4416 {
4417     STATIC_CONTRACT_THROWS;
4418     STATIC_CONTRACT_SO_TOLERANT;
4419
4420 // Disable the "initialization of static local vars is no thread safe" error
4421 #ifdef _MSC_VER
4422 #pragma warning(disable: 4640)
4423 #endif
4424     CHECK_LOCAL_STATIC_VAR(static SString s);
4425 #ifdef _MSC_VER
4426 #pragma warning(default : 4640)
4427 #endif
4428     if (!fReady)
4429     {
4430         WCHAR name[256];
4431         HRESULT hr = S_OK;
4432         {
4433             FAULT_NOT_FATAL();
4434             GCX_COOP();
4435             hr = UtilLoadStringRC(IDS_EE_THREAD_DEADLOCK_VICTIM, name, sizeof(name)/sizeof(WCHAR), 1);
4436             }
4437         initLock.Init(LOCK_TYPE_DEFAULT);
4438         SpinLockHolder  __spinLockHolder(&initLock);
4439         if (!fReady)
4440             {
4441                 if (SUCCEEDED(hr))
4442                 {
4443                     s.Set(name);
4444                 fReady = 1;
4445                 }
4446                 else
4447                 {
4448                     ThrowHR(hr);
4449                 }
4450             }
4451         }
4452
4453     ThrowHR(HOST_E_DEADLOCK, s);
4454 }
4455
4456 //******************************************************************************
4457 //
4458 //  ExceptionIsAlwaysSwallowed
4459 //
4460 //    Determine whether an exception is of a type that it should always
4461 //     be swallowed, even when exceptions otherwise are left to go unhandled.
4462 //     (For Whidbey, ThreadAbort, RudeThreadAbort, or AppDomainUnload exception)
4463 //
4464 //  Parameters:
4465 //    pExceptionInfo    EXCEPTION_POINTERS for current exception
4466 //
4467 //  Returns:
4468 //    true              If the exception is of a type that is always swallowed.
4469 //
4470 bool ExceptionIsAlwaysSwallowed(EXCEPTION_POINTERS *pExceptionInfo)
4471 {
4472     bool isSwallowed = false;
4473
4474     // The exception code must be ours, if it is one of our Exceptions.
4475     if (IsComPlusException(pExceptionInfo->ExceptionRecord))
4476     {
4477         // Our exception code.  Get the current exception from the thread.
4478         Thread *pThread = GetThread();
4479         if (pThread)
4480         {
4481             OBJECTREF throwable;
4482
4483             GCX_COOP();
4484             if ((throwable = pThread->GetThrowable()) == NULL)
4485             {
4486                 throwable = pThread->LastThrownObject();
4487             }
4488             //@todo: could throwable be NULL here?
4489             isSwallowed = IsExceptionOfType(kThreadAbortException, &throwable) ||
4490                           IsExceptionOfType(kAppDomainUnloadedException, &throwable);
4491         }
4492     }
4493
4494     return isSwallowed;
4495 } // BOOL ExceptionIsAlwaysSwallowed()
4496
4497 //
4498 // UserBreakpointFilter is used to ensure that we get a popup on user breakpoints (DebugBreak(), hard-coded int 3,
4499 // etc.) as soon as possible.
4500 //
4501 LONG UserBreakpointFilter(EXCEPTION_POINTERS* pEP)
4502 {
4503     CONTRACTL
4504     {
4505         NOTHROW;
4506         GC_NOTRIGGER;
4507         MODE_ANY;
4508         FORBID_FAULT;
4509         SO_TOLERANT;
4510     }
4511     CONTRACTL_END;
4512
4513 #ifdef DEBUGGING_SUPPORTED
4514     // Invoke the unhandled exception filter, bypassing any further first pass exception processing and treating
4515     // user breakpoints as if they're unhandled exceptions right away.
4516     //
4517     // @todo: The InternalUnhandledExceptionFilter can trigger.
4518     CONTRACT_VIOLATION(GCViolation | ThrowsViolation | ModeViolation | FaultViolation | FaultNotFatal);
4519
4520 #ifdef FEATURE_PAL
4521     int result = COMUnhandledExceptionFilter(pEP);
4522 #else
4523     int result = UnhandledExceptionFilter(pEP);
4524 #endif
4525
4526     if (result == EXCEPTION_CONTINUE_SEARCH)
4527     {
4528         // A debugger got attached.  Instead of allowing the exception to continue up, and hope for the
4529         // second-chance, we cause it to happen again. The debugger snags all int3's on first-chance.  NOTE: the
4530         // InternalUnhandledExceptionFilter allowed GC's to occur, but it may be the case that some managed frames
4531         // may have been unprotected. Therefore, you may have GC holes if you attempt to continue execution from
4532         // here.
4533         return EXCEPTION_CONTINUE_EXECUTION;
4534     }
4535 #endif // DEBUGGING_SUPPORTED
4536
4537     if(ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, FailFast))
4538     {
4539         // Fire an ETW FailFast event
4540         FireEtwFailFast(W("StatusBreakpoint"),
4541                        (const PVOID)((pEP && pEP->ContextRecord) ? GetIP(pEP->ContextRecord) : 0),
4542                        ((pEP && pEP->ExceptionRecord) ? pEP->ExceptionRecord->ExceptionCode : 0),
4543                        STATUS_BREAKPOINT,
4544                        GetClrInstanceId());
4545     }
4546
4547     // Otherwise, we termintate the process.
4548     TerminateProcess(GetCurrentProcess(), STATUS_BREAKPOINT);
4549
4550     // Shouldn't get here ...
4551     return EXCEPTION_CONTINUE_EXECUTION;
4552 } // LONG UserBreakpointFilter()
4553
4554 //******************************************************************************
4555 //
4556 //  DefaultCatchFilter
4557 //
4558 //    The old default except filter (v1.0/v1.1) .  For user breakpoints, call out to UserBreakpointFilter()
4559 //     but otherwise return EXCEPTION_EXECUTE_HANDLER, to swallow the exception.
4560 //
4561 //  Parameters:
4562 //    pExceptionInfo    EXCEPTION_POINTERS for current exception
4563 //    pv                A constant as an INT_PTR.  Must be COMPLUS_EXCEPTION_EXECUTE_HANDLER.
4564 //
4565 //  Returns:
4566 //    EXCEPTION_EXECUTE_HANDLER     Generally returns this to swallow the exception.
4567 //
4568 // IMPORTANT!! READ ME!!
4569 //
4570 // This filter is very similar to DefaultCatchNoSwallowFilter, except when unhandled
4571 //  exception policy/config dictate swallowing the exception.
4572 // If you make any changes to this function, look to see if the other one also needs
4573 //  the same change.
4574 //
4575 LONG DefaultCatchFilter(EXCEPTION_POINTERS *ep, PVOID pv)
4576 {
4577     CONTRACTL
4578     {
4579         NOTHROW;
4580         GC_NOTRIGGER;
4581         MODE_ANY;
4582         FORBID_FAULT;
4583         SO_TOLERANT;
4584     }
4585     CONTRACTL_END;
4586
4587     //
4588     // @TODO: this seems like a strong candidate for elimination due to duplication with
4589     //        our vectored exception handler.
4590     //
4591
4592     DefaultCatchFilterParam *pParam;
4593     pParam = (DefaultCatchFilterParam *) pv;
4594
4595     // the only valid parameter for DefaultCatchFilter so far
4596     _ASSERTE(pParam->pv == COMPLUS_EXCEPTION_EXECUTE_HANDLER);
4597
4598     PEXCEPTION_RECORD er = ep->ExceptionRecord;
4599     DWORD code = er->ExceptionCode;
4600
4601     if (code == STATUS_SINGLE_STEP || code == STATUS_BREAKPOINT)
4602     {
4603         return UserBreakpointFilter(ep);
4604     }
4605
4606     // return EXCEPTION_EXECUTE_HANDLER to swallow the exception.
4607     return EXCEPTION_EXECUTE_HANDLER;
4608 } // LONG DefaultCatchFilter()
4609
4610
4611 //******************************************************************************
4612 //
4613 //  DefaultCatchNoSwallowFilter
4614 //
4615 //    The new default except filter (v2.0).  For user breakpoints, call out to UserBreakpointFilter().
4616 //     Otherwise consults host policy and config file to return EXECUTE_HANDLER / CONTINUE_SEARCH.
4617 //
4618 //  Parameters:
4619 //    pExceptionInfo    EXCEPTION_POINTERS for current exception
4620 //    pv                A constant as an INT_PTR.  Must be COMPLUS_EXCEPTION_EXECUTE_HANDLER.
4621 //
4622 //  Returns:
4623 //    EXCEPTION_CONTINUE_SEARCH     Generally returns this to let the exception go unhandled.
4624 //    EXCEPTION_EXECUTE_HANDLER     May return this to swallow the exception.
4625 //
4626 // IMPORTANT!! READ ME!!
4627 //
4628 // This filter is very similar to DefaultCatchFilter, except when unhandled
4629 //  exception policy/config dictate swallowing the exception.
4630 // If you make any changes to this function, look to see if the other one also needs
4631 //  the same change.
4632 //
4633 LONG DefaultCatchNoSwallowFilter(EXCEPTION_POINTERS *ep, PVOID pv)
4634 {
4635     CONTRACTL
4636     {
4637         THROWS;
4638         GC_TRIGGERS;
4639         MODE_ANY;
4640     }
4641     CONTRACTL_END;
4642
4643     DefaultCatchFilterParam *pParam; pParam = (DefaultCatchFilterParam *) pv;
4644
4645     // the only valid parameter for DefaultCatchFilter so far
4646     _ASSERTE(pParam->pv == COMPLUS_EXCEPTION_EXECUTE_HANDLER);
4647
4648     PEXCEPTION_RECORD er = ep->ExceptionRecord;
4649     DWORD code = er->ExceptionCode;
4650
4651     if (code == STATUS_SINGLE_STEP || code == STATUS_BREAKPOINT)
4652     {
4653         return UserBreakpointFilter(ep);
4654     }
4655
4656     // If host policy or config file says "swallow"...
4657     if (SwallowUnhandledExceptions())
4658     {   // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception.
4659         return EXCEPTION_EXECUTE_HANDLER;
4660     }
4661
4662     // If the exception is of a type that is always swallowed (ThreadAbort, AppDomainUnload)...
4663     if (ExceptionIsAlwaysSwallowed(ep))
4664     {   // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception.
4665         return EXCEPTION_EXECUTE_HANDLER;
4666     }
4667
4668     // Otherwise, continue search. i.e. let the exception go unhandled (at least for now).
4669     return EXCEPTION_CONTINUE_SEARCH;
4670 } // LONG DefaultCatchNoSwallowFilter()
4671
4672 // Note: This is used only for CoreCLR on WLC.
4673 //
4674 // We keep a pointer to the previous unhandled exception filter.  After we install, we use
4675 // this to call the previous guy.  When we un-install, we put them back.  Putting them back
4676 // is a bug -- we have no guarantee that the DLL unload order matches the DLL load order -- we
4677 // may in fact be putting back a pointer to a DLL that has been unloaded.
4678 //
4679
4680 // initialize to -1 because NULL won't detect difference between us not having installed our handler
4681 // yet and having installed it but the original handler was NULL.
4682 static LPTOP_LEVEL_EXCEPTION_FILTER g_pOriginalUnhandledExceptionFilter = (LPTOP_LEVEL_EXCEPTION_FILTER)-1;
4683 #define FILTER_NOT_INSTALLED (LPTOP_LEVEL_EXCEPTION_FILTER) -1
4684
4685
4686 BOOL InstallUnhandledExceptionFilter() {
4687     STATIC_CONTRACT_NOTHROW;
4688     STATIC_CONTRACT_GC_NOTRIGGER;
4689     STATIC_CONTRACT_MODE_ANY;
4690     STATIC_CONTRACT_FORBID_FAULT;
4691
4692 #ifndef FEATURE_PAL   
4693     // We will be here only for CoreCLR on WLC since we dont
4694     // register UEF for SL.
4695     if (g_pOriginalUnhandledExceptionFilter == FILTER_NOT_INSTALLED) {
4696
4697         #pragma prefast(push)
4698         #pragma prefast(suppress:28725, "Calling to SetUnhandledExceptionFilter is intentional in this case.")
4699         g_pOriginalUnhandledExceptionFilter = SetUnhandledExceptionFilter(COMUnhandledExceptionFilter);
4700         #pragma prefast(pop)
4701
4702         // make sure is set (ie. is not our special value to indicate unset)
4703         LOG((LF_EH, LL_INFO10, "InstallUnhandledExceptionFilter registered UEF with OS for CoreCLR!\n"));
4704     }
4705     _ASSERTE(g_pOriginalUnhandledExceptionFilter != FILTER_NOT_INSTALLED);
4706 #endif // !FEATURE_PAL
4707
4708     // All done - successfully!
4709     return TRUE;
4710 }
4711
4712 void UninstallUnhandledExceptionFilter() {
4713     STATIC_CONTRACT_NOTHROW;
4714     STATIC_CONTRACT_GC_NOTRIGGER;
4715     STATIC_CONTRACT_MODE_ANY;
4716     STATIC_CONTRACT_FORBID_FAULT;
4717
4718 #ifndef FEATURE_PAL
4719     // We will be here only for CoreCLR on WLC or on Mac SL.
4720     if (g_pOriginalUnhandledExceptionFilter != FILTER_NOT_INSTALLED) {
4721
4722         #pragma prefast(push)
4723         #pragma prefast(suppress:28725, "Calling to SetUnhandledExceptionFilter is intentional in this case.")
4724         SetUnhandledExceptionFilter(g_pOriginalUnhandledExceptionFilter);
4725         #pragma prefast(pop)
4726
4727         g_pOriginalUnhandledExceptionFilter = FILTER_NOT_INSTALLED;
4728         LOG((LF_EH, LL_INFO10, "UninstallUnhandledExceptionFilter unregistered UEF from OS for CoreCLR!\n"));
4729     }
4730 #endif // !FEATURE_PAL
4731 }
4732
4733 //
4734 // Update the current throwable on the thread if necessary. If we're looking at one of our exceptions, and if the
4735 // current throwable on the thread is NULL, then we'll set it to something more useful based on the
4736 // LastThrownObject.
4737 //
4738 BOOL UpdateCurrentThrowable(PEXCEPTION_RECORD pExceptionRecord)
4739 {
4740     STATIC_CONTRACT_THROWS;
4741     STATIC_CONTRACT_MODE_ANY;
4742     STATIC_CONTRACT_GC_TRIGGERS;
4743
4744     BOOL useLastThrownObject = FALSE;
4745
4746     Thread* pThread = GetThread();
4747
4748     // GetThrowable needs cooperative.
4749     GCX_COOP();
4750
4751     if ((pThread->GetThrowable() == NULL) && (pThread->LastThrownObject() != NULL))
4752     {
4753         // If GetThrowable is NULL and LastThrownObject is not, use lastThrownObject.
4754         //  In current (June 05) implementation, this is only used to pass to
4755         //  NotifyAppDomainsOfUnhandledException, which needs to get a throwable
4756         //  from somewhere, with which to notify the AppDomains.
4757         useLastThrownObject = TRUE;
4758
4759         if (IsComPlusException(pExceptionRecord))
4760         {
4761 #ifndef WIN64EXCEPTIONS
4762             OBJECTREF oThrowable = pThread->LastThrownObject();
4763
4764             // @TODO: we have a problem on Win64 where we won't have any place to
4765             //        store the throwable on an unhandled exception.  Currently this
4766             //        only effects the managed debugging services as they will try
4767             //        to inspect the thread to see what the throwable is on an unhandled
4768             //        exception.. (but clearly it needs to be fixed asap)
4769             //        We have the same problem in EEPolicy::LogFatalError().
4770             LOG((LF_EH, LL_INFO100, "UpdateCurrentThrowable: setting throwable to %s\n", (oThrowable == NULL) ? "NULL" : oThrowable->GetTrueMethodTable()->GetDebugClassName()));
4771             pThread->SafeSetThrowables(oThrowable);
4772 #endif // WIN64EXCEPTIONS
4773         }
4774     }
4775
4776     return useLastThrownObject;
4777 }
4778
4779 //
4780 // COMUnhandledExceptionFilter is used to catch all unhandled exceptions.
4781 // The debugger will either handle the exception, attach a debugger, or
4782 // notify an existing attached debugger.
4783 //
4784
4785 struct SaveIPFilterParam
4786 {
4787     SLOT ExceptionEIP;
4788 };
4789
4790 LONG SaveIPFilter(EXCEPTION_POINTERS* ep, LPVOID pv)
4791 {
4792     WRAPPER_NO_CONTRACT;
4793
4794     SaveIPFilterParam *pParam = (SaveIPFilterParam *) pv;
4795     pParam->ExceptionEIP = (SLOT)GetIP(ep->ContextRecord);
4796     DefaultCatchFilterParam param(COMPLUS_EXCEPTION_EXECUTE_HANDLER);
4797     return DefaultCatchFilter(ep, &param);
4798 }
4799
4800 //------------------------------------------------------------------------------
4801 // Description
4802 //   Does not call any previous UnhandledExceptionFilter.  The assumption is that
4803 //    either it is inappropriate to call it (because we have elected to rip the
4804 //    process without transitioning completely to the base of the thread), or
4805 //    the caller has already consulted the previously installed UnhandledExceptionFilter.
4806 //
4807 //    So we know we are ripping and Watson is appropriate.
4808 //
4809 //    **** Note*****
4810 //    This is a stack-sensitive function if we have an unhandled SO.
4811 //    Do not allocate more than a few bytes on the stack or we risk taking an
4812 //    AV while trying to throw up Watson.
4813
4814 // Parameters
4815 //    pExceptionInfo -- information about the exception that caused the error.
4816 //           If the error is not the result of an exception, pass NULL for this
4817 //           parameter
4818 //
4819 // Returns
4820 //   EXCEPTION_CONTINUE_SEARCH -- we've done anything we will with the exception.
4821 //      As far as the runtime is concerned, the process is doomed.
4822 //   EXCEPTION_CONTINUE_EXECUTION -- means a debugger "caught" the exception and
4823 //      wants to continue running.
4824 //   EXCEPTION_EXECUTE_HANDLER -- CoreCLR only, and only when not running as a UEF.
4825 //      Returned only if the host has asked us to swallow unhandled exceptions on
4826 //      managed threads in an AD they (the host) creates.
4827 //------------------------------------------------------------------------------
4828 LONG InternalUnhandledExceptionFilter_Worker(
4829     EXCEPTION_POINTERS *pExceptionInfo)     // Information about the exception
4830 {
4831     STATIC_CONTRACT_THROWS;
4832     STATIC_CONTRACT_GC_TRIGGERS;
4833     STATIC_CONTRACT_MODE_ANY;
4834
4835 #ifdef _DEBUG
4836     static int fBreakOnUEF = -1;
4837     if (fBreakOnUEF==-1) fBreakOnUEF = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUEF);
4838     _ASSERTE(!fBreakOnUEF);
4839 #endif
4840
4841     STRESS_LOG2(LF_EH, LL_INFO10, "In InternalUnhandledExceptionFilter_Worker, Exception = %x, sp = %p\n",
4842                                     pExceptionInfo->ExceptionRecord->ExceptionCode, GetCurrentSP());
4843
4844     // If we can't enter the EE, done.
4845     if (g_fForbidEnterEE)
4846     {
4847         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: g_fForbidEnterEE is TRUE\n"));
4848         return EXCEPTION_CONTINUE_SEARCH;
4849     }
4850
4851
4852     if (GetEEPolicy()->GetActionOnFailure(FAIL_FatalRuntime) == eDisableRuntime)
4853     {
4854         ETaskType type = ::GetCurrentTaskType();
4855         if (type != TT_UNKNOWN && type != TT_USER)
4856         {
4857             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: calling EEPolicy::HandleFatalError\n"));
4858             EEPolicy::HandleFatalError(COR_E_EXECUTIONENGINE, (UINT_PTR)GetIP(pExceptionInfo->ContextRecord), NULL, pExceptionInfo);
4859         }
4860     }
4861
4862     // We don't do anything when this is called from an unmanaged thread.
4863     Thread *pThread = GetThread();
4864
4865 #ifdef _DEBUG
4866     static bool bBreakOnUncaught = false;
4867     static int fBreakOnUncaught = 0;
4868
4869     if (!bBreakOnUncaught)
4870     {
4871         fBreakOnUncaught = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException);
4872         bBreakOnUncaught = true;
4873     }
4874     if (fBreakOnUncaught != 0)
4875     {
4876         if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
4877         {
4878             // if we've got an uncaught SO, we don't have enough stack to pop a debug break.  So instead,
4879             // loop infinitely and we can attach a debugger at that point and break in.
4880             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Infinite loop on uncaught SO\n"));
4881             for ( ;; )
4882             {
4883             }
4884         }
4885         else
4886         {
4887             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: ASSERTING on uncaught\n"));
4888             _ASSERTE(!"BreakOnUnCaughtException");
4889         }
4890     }
4891 #endif
4892
4893 #ifdef _DEBUG_ADUNLOAD
4894     printf("%x InternalUnhandledExceptionFilter_Worker: Called for %x\n",
4895            ((pThread == NULL) ? NULL : pThread->GetThreadId()), pExceptionInfo->ExceptionRecord->ExceptionCode);
4896     fflush(stdout);
4897 #endif
4898
4899     // This shouldn't be possible, but MSVC re-installs us... for now, just bail if this happens.
4900     if (g_fNoExceptions)
4901     {
4902         return EXCEPTION_CONTINUE_SEARCH;
4903     }
4904
4905     // Are we looking at a stack overflow here?
4906     if ((pThread !=  NULL) && !pThread->DetermineIfGuardPagePresent())
4907     {
4908         g_fForbidEnterEE = true;
4909     }
4910
4911 #ifdef DEBUGGING_SUPPORTED
4912
4913     // Mark that this exception has gone unhandled. At the moment only the debugger will
4914     // ever look at this flag. This should come before any user-visible side effect of an exception
4915     // being unhandled as seen from managed code or from a debugger. These include the
4916     // managed unhandled notification callback, execution of catch/finally clauses,
4917     // receiving the managed debugger unhandled exception event,
4918     // the OS sending the debugger 2nd pass native exception notification, etc.
4919     //
4920     // This needs to be done before the check for TSNC_ProcessedUnhandledException because it is perfectly
4921     // legitimate (though rare) for the debugger to be inspecting exceptions which are nested in finally
4922     // clauses that run after an unhandled exception has already occurred on the thread
4923     if ((pThread != NULL) && pThread->IsExceptionInProgress())
4924     {
4925         LOG((LF_EH, LL_INFO1000, "InternalUnhandledExceptionFilter_Worker: Set unhandled exception flag at %p\n",
4926             pThread->GetExceptionState()->GetFlags() ));
4927         pThread->GetExceptionState()->GetFlags()->SetUnhandled();
4928     }
4929 #endif
4930
4931     // If we have already done unhandled exception processing for this thread, then
4932     // simply return back. See comment in threads.h for details for the flag
4933     // below.
4934     //
4935     if (pThread && (pThread->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException) || pThread->HasThreadStateNC(Thread::TSNC_AppDomainContainUnhandled)))
4936     {
4937         // This assert shouldnt be hit in CoreCLR since:
4938         //
4939         // 1) It has no concept of managed entry point that is invoked by the shim. You can
4940         //    only run managed code via hosting APIs that will run code in non-default domains.
4941         //
4942         // 2) Managed threads cannot be created in DefaultDomain since no user code executes
4943         //    in default domain.
4944         //
4945         // So, if this is hit, something is not right!
4946         if (pThread->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException))
4947         {
4948             _ASSERTE(!"How come a thread with TSNC_ProcessedUnhandledException state entered the UEF on CoreCLR?");
4949         }
4950
4951         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: have already processed unhandled exception for this thread.\n"));
4952         return EXCEPTION_CONTINUE_SEARCH;
4953     }
4954
4955     LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Handling\n"));
4956
4957     struct Param : SaveIPFilterParam
4958     {
4959         EXCEPTION_POINTERS *pExceptionInfo;
4960         Thread *pThread;
4961         LONG retval;
4962         BOOL fIgnore;
4963     }; Param param;
4964
4965     param.ExceptionEIP = 0;
4966     param.pExceptionInfo = pExceptionInfo;
4967     param.pThread = pThread;
4968     param.retval = EXCEPTION_CONTINUE_SEARCH;   // Result of UEF filter.
4969
4970     // Is this a particular kind of exception that we'd like to ignore?
4971     param.fIgnore = ((param.pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) ||
4972                     (param.pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP));
4973
4974     PAL_TRY(Param *, pParam, &param)
4975     {
4976         // If fIgnore, then this is some sort of breakpoint, not a "normal" unhandled exception.  But, the
4977         //  breakpoint is due to an int3 or debugger step instruction, not due to calling Debugger.Break()
4978         TypeOfReportedError tore = pParam->fIgnore ? TypeOfReportedError::NativeBreakpoint : TypeOfReportedError::UnhandledException;
4979
4980         //
4981         // If this exception is on a thread without managed code, then report this as a NativeThreadUnhandledException
4982         //
4983         // The thread object may exist if there was once managed code on the stack, but if the exception never
4984         // bubbled thru managed code, ie no managed code is on its stack, then this is a native unhandled exception
4985         //
4986         // Ignore breakpoints and single-step.
4987         if (!pParam->fIgnore)
4988         {   // Possibly interesting exception.  Is there no Thread at all?  Or, is there a Thread,
4989             //  but with no exception at all on it?
4990             if ((pParam->pThread == NULL) ||
4991                 (pParam->pThread->IsThrowableNull() && pParam->pThread->IsLastThrownObjectNull()) )
4992             {   // Whatever this exception is, we don't know about it.  Treat as Native.
4993                 tore = TypeOfReportedError::NativeThreadUnhandledException;
4994             }
4995         }
4996
4997         // If there is no throwable on the thread, go ahead and update from the last thrown exception if possible.
4998         // Note: don't do this for exceptions that we're going to ignore below anyway...
4999         BOOL useLastThrownObject = FALSE;
5000         if (!pParam->fIgnore && (pParam->pThread != NULL))
5001         {
5002             useLastThrownObject = UpdateCurrentThrowable(pParam->pExceptionInfo->ExceptionRecord);
5003         }
5004
5005 #ifdef DEBUGGING_SUPPORTED
5006
5007         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Notifying Debugger...\n"));
5008
5009         // If we are using the throwable in LastThrownObject, mark that it is now unhandled
5010         if ((pParam->pThread != NULL) && useLastThrownObject)
5011         {
5012             LOG((LF_EH, LL_INFO1000, "InternalUnhandledExceptionFilter_Worker: Set lto is unhandled\n"));
5013             pParam->pThread->MarkLastThrownObjectUnhandled();
5014         }
5015
5016         //
5017         // We don't want the managed debugger to try to "intercept" breakpoints
5018         // or singlestep exceptions.
5019         // TODO: why does the exception handling code need to set this? Shouldn't the debugger code
5020         // be able to determine what it can/should intercept?
5021         if ((pParam->pThread != NULL) && pParam->pThread->IsExceptionInProgress() && pParam->fIgnore)
5022         {
5023             pParam->pThread->GetExceptionState()->GetFlags()->SetDebuggerInterceptNotPossible();
5024         }
5025
5026
5027         if (pParam->pThread != NULL)
5028         {
5029             BOOL fIsProcessTerminating = TRUE;
5030
5031             // In CoreCLR, we can be asked to not let an exception go unhandled on managed threads in a given AppDomain.
5032             // If the exception reaches the top of the thread's stack, we simply deliver AppDomain's UnhandledException event and
5033             // return back to the filter, instead of letting the process terminate because of unhandled exception.
5034
5035             // Below is how we perform the check:
5036             //
5037             // 1) The flag is specified on the AD when it is created by the host and all managed threads created
5038             //    in such an AD will inherit the flag. For non-finalizer and non-threadpool threads, we check the flag against the thread.
5039             // 2) The finalizer thread always switches to the AD of the object that is going to be finalized. Thus,
5040             //    while it wont have the flag specified, the AD it switches to will.
5041             // 3) The threadpool thread also switches to the correct AD before executing the request. The thread wont have the
5042             //    flag specified, but the AD it switches to will.
5043
5044             // This code must only be exercised when running as a normal filter; returning
5045             // EXCEPTION_EXECUTE_HANDLER is not valid if this code is being invoked from
5046             // the UEF.
5047             // Fortunately, we should never get into this case, since the thread flag about
5048             // ignoring unhandled exceptions cannot be set on the default domain.
5049
5050             if (IsFinalizerThread() || (pParam->pThread->IsThreadPoolThread()))
5051                 fIsProcessTerminating = !(pParam->pThread->GetDomain()->IgnoreUnhandledExceptions());
5052             else
5053                 fIsProcessTerminating = !(pParam->pThread->HasThreadStateNC(Thread::TSNC_IgnoreUnhandledExceptions));
5054
5055 #ifndef FEATURE_PAL
5056             // Setup the watson bucketing details for UE processing.
5057             // do this before notifying appdomains of the UE so if an AD attempts to
5058             // retrieve the bucket params in the UE event handler it gets the correct data.
5059             SetupWatsonBucketsForUEF(useLastThrownObject);
5060 #endif // !FEATURE_PAL 
5061
5062             // Send notifications to the AppDomains.
5063             NotifyAppDomainsOfUnhandledException(pParam->pExceptionInfo, NULL, useLastThrownObject, fIsProcessTerminating /*isTerminating*/);
5064
5065             // If the process is not terminating, then return back to the filter and ask it to execute
5066             if (!fIsProcessTerminating)
5067             {
5068                 pParam->retval = EXCEPTION_EXECUTE_HANDLER;
5069                 goto lDone;
5070             }
5071         }
5072         else
5073         {
5074             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Not collecting bucket information as thread object does not exist\n"));
5075         }
5076
5077         // AppDomain.UnhandledException event could have thrown an exception that would have gone unhandled in managed code.
5078         // The runtime swallows all such exceptions. Hence, if we are not using LastThrownObject and the current LastThrownObject
5079         // is not the same as the one in active exception tracker (if available), then update the last thrown object.
5080         if ((pParam->pThread != NULL) && (!useLastThrownObject))
5081         {
5082             GCX_COOP_NO_DTOR();
5083
5084             OBJECTREF oThrowable = pParam->pThread->GetThrowable();
5085             if ((oThrowable != NULL) && (pParam->pThread->LastThrownObject() != oThrowable))
5086             {
5087                 pParam->pThread->SafeSetLastThrownObject(oThrowable);
5088                 LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Resetting the LastThrownObject as it appears to have changed.\n"));
5089             }
5090
5091             GCX_COOP_NO_DTOR_END();
5092         }
5093
5094         // Launch Watson and see if we want to debug the process
5095         //
5096         // Note that we need to do this before "ignoring" exceptions like
5097         // breakpoints and single step exceptions
5098         //
5099
5100         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Launching Watson at sp %p ...\n", GetCurrentSP()));
5101
5102         if (WatsonLastChance(pParam->pThread, pParam->pExceptionInfo, tore) == EXCEPTION_CONTINUE_EXECUTION)
5103         {
5104             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: debugger ==> EXCEPTION_CONTINUE_EXECUTION\n"));
5105             pParam->retval = EXCEPTION_CONTINUE_EXECUTION;
5106             goto lDone;
5107         }
5108
5109         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: ... returned.\n"));
5110 #endif // DEBUGGING_SUPPORTED
5111
5112
5113         //
5114         // Except for notifying debugger, ignore exception if unmanaged, or
5115         // if it's a debugger-generated exception or user breakpoint exception.
5116         //
5117         if (tore.GetType() == TypeOfReportedError::NativeThreadUnhandledException)
5118         {
5119             pParam->retval = EXCEPTION_CONTINUE_SEARCH;
5120 #if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
5121             DoReportForUnhandledNativeException(pParam->pExceptionInfo);
5122 #endif
5123             goto lDone;
5124         }
5125
5126         if (pParam->fIgnore)
5127         {
5128             LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker, ignoring the exception\n"));
5129             pParam->retval = EXCEPTION_CONTINUE_SEARCH;
5130 #if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
5131             DoReportForUnhandledNativeException(pParam->pExceptionInfo);
5132 #endif
5133             goto lDone;
5134         }
5135
5136         LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: Calling DefaultCatchHandler\n"));
5137
5138         // Call our default catch handler to do the managed unhandled exception work.
5139         DefaultCatchHandler(pParam->pExceptionInfo, NULL, useLastThrownObject,
5140             TRUE /*isTerminating*/, FALSE /*isThreadBaseFIlter*/, FALSE /*sendAppDomainEvents*/, TRUE /* sendWindowsEventLog */);
5141
5142 lDone: ;
5143     }
5144     PAL_EXCEPT_FILTER (SaveIPFilter)
5145     {
5146         // Should never get here.
5147 #ifdef _DEBUG
5148         char buffer[200];
5149         sprintf_s(buffer, 200, "\nInternal error: Uncaught exception was thrown from IP = %p in UnhandledExceptionFilter_Worker on thread 0x%08x\n",
5150                 param.ExceptionEIP, ((GetThread() == NULL) ? NULL : GetThread()->GetThreadId()));
5151         PrintToStdErrA(buffer);
5152         _ASSERTE(!"Unexpected exception in UnhandledExceptionFilter_Worker");
5153 #endif
5154         EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE)
5155     }
5156     PAL_ENDTRY;
5157
5158     //if (param.fIgnore)
5159     //{
5160         // VC's try/catch ignores breakpoint or single step exceptions.  We can not continue running.
5161     //    TerminateProcess(GetCurrentProcess(), pExceptionInfo->ExceptionRecord->ExceptionCode);
5162     //}
5163
5164     return param.retval;
5165 } // LONG InternalUnhandledExceptionFilter_Worker()
5166
5167 //------------------------------------------------------------------------------
5168 // Description
5169 //   Calls our InternalUnhandledExceptionFilter for Watson at the appropriate
5170 //   place in the chain.
5171 //
5172 //   For non-side-by-side CLR's, we call everyone else's UEF first.
5173 //
5174 //   For side-by-side CLR's, we call our own filter first. This is primary
5175 //      so Whidbey's UEF won't put up a second dialog box. In exchange,
5176 //      side-by-side CLR's won't put up UI's unless the EH really came
5177 //      from that instance's managed code.
5178 //
5179 // Parameters
5180 //    pExceptionInfo -- information about the exception that caused the error.
5181 //           If the error is not the result of an exception, pass NULL for this
5182 //           parameter
5183 //
5184 // Returns
5185 //   EXCEPTION_CONTINUE_SEARCH -- we've done anything we will with the exception.
5186 //      As far as the runtime is concerned, the process is doomed.
5187 //   EXCEPTION_CONTINUE_EXECUTION -- means a debugger "caught" the exception and
5188 //      wants to continue running.
5189 //------------------------------------------------------------------------------
5190 LONG InternalUnhandledExceptionFilter(
5191     EXCEPTION_POINTERS *pExceptionInfo)     // Information about the exception
5192 {
5193     STATIC_CONTRACT_THROWS;
5194     STATIC_CONTRACT_GC_TRIGGERS;
5195     STATIC_CONTRACT_MODE_ANY;
5196     // We don't need to be SO-robust for an unhandled exception
5197     SO_NOT_MAINLINE_FUNCTION;
5198
5199     LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter: at sp %p.\n", GetCurrentSP()));
5200
5201     // Side-by-side UEF: Calls ours first, then the rest (unless we put up a UI for
5202     // the exception.)
5203
5204     LONG    retval = InternalUnhandledExceptionFilter_Worker(pExceptionInfo);   // Result of UEF filter.
5205
5206     // Keep looking, or done?
5207     if (retval != EXCEPTION_CONTINUE_SEARCH)
5208     {   // done.
5209         return retval;
5210     }
5211
5212     BOOL fShouldOurUEFDisplayUI = ShouldOurUEFDisplayUI(pExceptionInfo);
5213
5214     // If this is a managed exception thrown by this instance of the CLR, the exception is no one's
5215     // business but ours (nudge, nudge: Whidbey). Break the UEF chain at this point.
5216     if (fShouldOurUEFDisplayUI)
5217     {
5218         return retval;
5219     }
5220
5221     // Chaining back to previous UEF handler could be a potential security risk. See
5222     // http://uninformed.org/index.cgi?v=4&a=5&p=1 for details. We are not alone in
5223     // stopping the chain - CRT (as of Orcas) is also doing that.
5224     //
5225     // The change below applies to a thread that starts in native mode and transitions to managed.
5226
5227     // Let us assume the process loaded two CoreCLRs, C1 and C2, in that order. Thus, in the UEF chain
5228     // (assuming no other entity setup their UEF), C2?s UEF will be the topmost.
5229     //
5230     // Now, assume the stack looks like the following (stack grows down):
5231     //
5232     // Native frame
5233     // Managed Frame (C1)
5234     // Managed Frame (C2)
5235     // Managed Frame (C1)
5236     // Managed Frame (C2)
5237     // Managed Frame (C1)
5238     //
5239     // Suppose an exception is thrown in C1 instance in the last managed frame and it goes unhandled. Eventually
5240     // it will reach the OS which will invoke the UEF.  Note that the topmost UEF belongs to C2 instance and it
5241     // will start processing the exception. C2?s UEF could return EXCEPTION_CONTINUE_SEARCH to indicate
5242     // that we should handoff the processing to the last installed UEF. In the example above, we would handoff
5243     // the control to the UEF of the CoreCLR instance that actually threw the exception today. In reality, it
5244     // could be some unknown code too.
5245     //
5246     // Not chaining back to the last UEF, in the case of this example, would imply that certain notifications
5247     // (e.g. Unhandled Exception Notification to the  AppDomain) specific to the instance that raised the exception
5248     // will not get fired. However, similar behavior can happen today if another UEF sits between
5249     // C1 and C2 and that may not callback to C1 or perhaps just terminate process.
5250     //
5251     // For CoreCLR, this will not be an issue. See
5252     // http://sharepoint/sites/clros/Shared%20Documents/Design%20Documents/EH/Chaining%20in%20%20UEF%20-%20One%20Pager.docx
5253     // for details.
5254     //
5255     // Note: Also see the conditional UEF registration with the OS in EEStartupHelper.
5256
5257     // We would be here only on CoreCLR for WLC since we dont register
5258     // the UEF with the OS for SL.
5259     if (g_pOriginalUnhandledExceptionFilter != FILTER_NOT_INSTALLED
5260         && g_pOriginalUnhandledExceptionFilter != NULL)
5261     {
5262         STRESS_LOG1(LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter: Not chaining back to previous UEF at address %p on CoreCLR!\n", g_pOriginalUnhandledExceptionFilter);
5263     }
5264
5265     return retval;
5266
5267 } // LONG InternalUnhandledExceptionFilter()
5268
5269 // This filter is used to trigger unhandled exception processing for the entrypoint thread
5270 // incase an exception goes unhandled from it. This makes us independent of the OS
5271 // UEF mechanism to invoke our registered UEF to trigger CLR specific unhandled exception 
5272 // processing since that can be skipped if another UEF registered over ours and not chain back.
5273 LONG EntryPointFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID _pData)
5274 {
5275     CONTRACTL
5276     {
5277         THROWS;
5278         GC_TRIGGERS;
5279         MODE_ANY;
5280         SO_TOLERANT;
5281     }
5282     CONTRACTL_END;
5283
5284     LONG ret = -1;
5285
5286     BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return EXCEPTION_CONTINUE_SEARCH;);
5287
5288     // Invoke the UEF worker to perform unhandled exception processing
5289     ret = InternalUnhandledExceptionFilter_Worker (pExceptionInfo);
5290
5291     Thread* pThread = GetThread();
5292     if (pThread)
5293     {
5294         // Set the flag that we have done unhandled exception processing for this thread
5295         // so that we dont duplicate the effort in the UEF.
5296         //
5297         // For details on this flag, refer to threads.h.
5298         LOG((LF_EH, LL_INFO100, "EntryPointFilter: setting TSNC_ProcessedUnhandledException\n"));
5299         pThread->SetThreadStateNC(Thread::TSNC_ProcessedUnhandledException);
5300     }
5301
5302
5303     END_SO_INTOLERANT_CODE;
5304     
5305     return ret;
5306 }
5307
5308 //------------------------------------------------------------------------------
5309 // Description
5310 //   The actual UEF.  Defers to InternalUnhandledExceptionFilter.
5311 //
5312 // Updated to be in its own code segment named CLR_UEF_SECTION_NAME to prevent
5313 // "VirtualProtect" calls from affecting its pages and thus, its
5314 // invocation. For details, see the comment within the implementation of
5315 // CExecutionEngine::ClrVirtualProtect.
5316 //
5317 // Parameters
5318 //   pExceptionInfo -- information about the exception
5319 //
5320 // Returns
5321 //   the result of calling InternalUnhandledExceptionFilter
5322 //------------------------------------------------------------------------------
5323 #if !defined(FEATURE_PAL)
5324 #pragma code_seg(push, uef, CLR_UEF_SECTION_NAME)
5325 #endif // !FEATURE_PAL
5326 LONG __stdcall COMUnhandledExceptionFilter(     // EXCEPTION_CONTINUE_SEARCH or EXCEPTION_CONTINUE_EXECUTION
5327     EXCEPTION_POINTERS *pExceptionInfo)         // Information about the exception.
5328 {
5329     STATIC_CONTRACT_THROWS;
5330     STATIC_CONTRACT_GC_TRIGGERS;
5331     STATIC_CONTRACT_MODE_ANY;
5332     // We don't need to be SO-robust for an unhandled exception
5333     SO_NOT_MAINLINE_FUNCTION;
5334
5335     LONG retVal = EXCEPTION_CONTINUE_SEARCH;
5336
5337     // Incase of unhandled exceptions on managed threads, we kick in our UE processing at the thread base and also invoke
5338     // UEF callbacks that various runtimes have registered with us. Once the callbacks return, we return back to the OS
5339     // to give other registered UEFs a chance to do their custom processing.
5340     //
5341     // If the topmost UEF registered with the OS belongs to mscoruef.dll (or someone chained back to its UEF callback),
5342     // it will start invoking the UEF callbacks (which is this function, COMUnhandledExceptionFiler) registered by
5343     // various runtimes again.
5344     //
5345     // Thus, check if this UEF has already been invoked in context of this thread and runtime and if so, dont invoke it again.
5346     if (GetThread() && (GetThread()->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException) ||
5347                         GetThread()->HasThreadStateNC(Thread::TSNC_AppDomainContainUnhandled)))
5348     {
5349         LOG((LF_EH, LL_INFO10, "Exiting COMUnhandledExceptionFilter since we have already done UE processing for this thread!\n"));
5350         return retVal;
5351     }
5352
5353
5354     retVal = InternalUnhandledExceptionFilter(pExceptionInfo);
5355
5356     // If thread object exists, mark that this thread has done unhandled exception processing
5357     if (GetThread())
5358     {
5359         LOG((LF_EH, LL_INFO100, "COMUnhandledExceptionFilter: setting TSNC_ProcessedUnhandledException\n"));
5360         GetThread()->SetThreadStateNC(Thread::TSNC_ProcessedUnhandledException);
5361     }
5362
5363     return retVal;
5364 } // LONG __stdcall COMUnhandledExceptionFilter()
5365 #if !defined(FEATURE_PAL)
5366 #pragma code_seg(pop, uef)
5367 #endif // !FEATURE_PAL
5368
5369 void PrintStackTraceToStdout();
5370
5371 static SString GetExceptionMessageWrapper(Thread* pThread, OBJECTREF throwable)
5372 {
5373     STATIC_CONTRACT_THROWS;
5374     STATIC_CONTRACT_MODE_COOPERATIVE;
5375     STATIC_CONTRACT_GC_TRIGGERS;
5376
5377     StackSString result;
5378
5379     INSTALL_NESTED_EXCEPTION_HANDLER(pThread->GetFrame());
5380     GetExceptionMessage(throwable, result);
5381     UNINSTALL_NESTED_EXCEPTION_HANDLER();
5382
5383     return result;
5384 }
5385
5386 void STDMETHODCALLTYPE
5387 DefaultCatchHandlerExceptionMessageWorker(Thread* pThread,
5388                                           OBJECTREF throwable,
5389                                           __inout_ecount(buf_size) WCHAR *buf,
5390                                           const int buf_size,
5391                                           BOOL sendWindowsEventLog)
5392 {
5393     GCPROTECT_BEGIN(throwable);
5394     if (throwable != NULL)
5395     {
5396         PrintToStdErrA("\n");
5397
5398         if (FAILED(UtilLoadResourceString(CCompRC::Error, IDS_EE_UNHANDLED_EXCEPTION, buf, buf_size)))
5399         {
5400             wcsncpy_s(buf, buf_size, SZ_UNHANDLED_EXCEPTION, SZ_UNHANDLED_EXCEPTION_CHARLEN);
5401         }
5402
5403         PrintToStdErrW(buf);
5404         PrintToStdErrA(" ");
5405
5406         SString message = GetExceptionMessageWrapper(pThread, throwable);
5407
5408         if (!message.IsEmpty())
5409         {
5410             NPrintToStdErrW(message, message.GetCount());
5411         }
5412
5413         PrintToStdErrA("\n");
5414
5415 #if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
5416         // Send the log to Windows Event Log
5417         if (sendWindowsEventLog && ShouldLogInEventLog())
5418         {
5419             EX_TRY
5420             {
5421                 EventReporter reporter(EventReporter::ERT_UnhandledException);
5422
5423                 if (IsException(throwable->GetMethodTable()))
5424                 {
5425                     if (!message.IsEmpty())
5426                     {
5427                         reporter.AddDescription(message);
5428                     }
5429                     reporter.Report();
5430                 }
5431                 else
5432                 {
5433                     StackSString s;
5434                     TypeString::AppendType(s, TypeHandle(throwable->GetMethodTable()), TypeString::FormatNamespace | TypeString::FormatFullInst);
5435                     reporter.AddDescription(s);
5436                     LogCallstackForEventReporter(reporter);
5437                 }
5438             }
5439             EX_CATCH
5440             {
5441             }
5442             EX_END_CATCH(SwallowAllExceptions);
5443         }
5444 #endif
5445     }
5446     GCPROTECT_END();
5447 }
5448
5449 //******************************************************************************
5450 // DefaultCatchHandler -- common processing for otherwise uncaught exceptions.
5451 //******************************************************************************
5452 void STDMETHODCALLTYPE
5453 DefaultCatchHandler(PEXCEPTION_POINTERS pExceptionPointers,
5454                     OBJECTREF *pThrowableIn,
5455                     BOOL useLastThrownObject,
5456                     BOOL isTerminating,
5457                     BOOL isThreadBaseFilter,
5458                     BOOL sendAppDomainEvents,
5459                     BOOL sendWindowsEventLog)
5460 {
5461     CONTRACTL
5462     {
5463         THROWS;
5464         GC_TRIGGERS;
5465         MODE_ANY;
5466     }
5467     CONTRACTL_END;
5468
5469     // <TODO> The strings in here should be translatable.</TODO>
5470     LOG((LF_EH, LL_INFO10, "In DefaultCatchHandler\n"));
5471
5472 #if defined(_DEBUG)
5473     static bool bHaveInitialized_BreakOnUncaught = false;
5474     enum BreakOnUncaughtAction {
5475         breakOnNone     =   0,          // Default.
5476         breakOnAll      =   1,          // Always break.
5477         breakSelective  =   2,          // Break on exceptions application can catch,
5478                                         //  but not ThreadAbort, AppdomainUnload
5479         breakOnMax      =   2
5480     };
5481     static DWORD breakOnUncaught = breakOnNone;
5482
5483     if (!bHaveInitialized_BreakOnUncaught)
5484     {
5485         breakOnUncaught = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException);
5486         if (breakOnUncaught > breakOnMax)
5487         {   // Could turn it off completely, or turn into legal value.  Since it is debug code, be accommodating.
5488             breakOnUncaught = breakOnAll;
5489         }
5490         bHaveInitialized_BreakOnUncaught = true;
5491     }
5492
5493     if (breakOnUncaught == breakOnAll)
5494     {
5495         _ASSERTE(!"BreakOnUnCaughtException");
5496     }
5497
5498     int suppressSelectiveBreak = false; // to filter for the case where breakOnUncaught == "2"
5499 #endif
5500
5501     Thread *pThread = GetThread();
5502
5503     //     The following reduces a window for a race during shutdown.
5504     if (!pThread)
5505     {
5506         _ASSERTE(g_fEEShutDown);
5507         return;
5508     }
5509
5510     _ASSERTE(pThread);
5511
5512     ThreadPreventAsyncHolder prevAsync;
5513
5514     GCX_COOP();
5515
5516     OBJECTREF throwable;
5517
5518     if (pThrowableIn != NULL)
5519     {
5520         throwable = *pThrowableIn;
5521     }
5522     else if (useLastThrownObject)
5523     {
5524         throwable = pThread->LastThrownObject();
5525     }
5526     else
5527     {
5528         throwable = pThread->GetThrowable();
5529     }
5530
5531     // If we've got no managed object, then we can't send an event or print a message, so we just return.
5532     if (throwable == NULL)
5533     {
5534 #ifdef LOGGING
5535         if (!pThread->IsRudeAbortInitiated())
5536         {
5537             LOG((LF_EH, LL_INFO10, "Unhandled exception, throwable == NULL\n"));
5538         }
5539 #endif
5540
5541         return;
5542     }
5543
5544 #ifdef _DEBUG
5545     DWORD unbreakableLockCount = 0;
5546     // Do not care about lock check for unhandled exception.
5547     while (pThread->HasUnbreakableLock())
5548     {
5549         pThread->DecUnbreakableLockCount();
5550         unbreakableLockCount ++;
5551     }
5552     BOOL fOwnsSpinLock = pThread->HasThreadStateNC(Thread::TSNC_OwnsSpinLock);
5553     if (fOwnsSpinLock)
5554     {
5555         pThread->ResetThreadStateNC(Thread::TSNC_OwnsSpinLock);
5556     }
5557 #endif
5558
5559     GCPROTECT_BEGIN(throwable);
5560     //BOOL IsStackOverflow = (throwable->GetTrueMethodTable() == g_pStackOverflowExceptionClass);
5561     BOOL IsOutOfMemory = (throwable->GetTrueMethodTable() == g_pOutOfMemoryExceptionClass);
5562
5563     // Notify the AppDomain that we have taken an unhandled exception.  Can't notify of stack overflow -- guard
5564     // page is not yet reset.
5565     BOOL SentEvent = FALSE;
5566
5567     // Send up the unhandled exception appdomain event.
5568     if (sendAppDomainEvents)
5569     {
5570         SentEvent = NotifyAppDomainsOfUnhandledException(pExceptionPointers, &throwable, useLastThrownObject, isTerminating);
5571     }
5572
5573     const int buf_size = 128;
5574     WCHAR buf[buf_size] = {0};
5575
5576     // See detailed explanation of this flag in threads.cpp.  But the basic idea is that we already
5577     // reported the exception in the AppDomain where it went unhandled, so we don't need to report
5578     // it at the process level.
5579     // Print the unhandled exception message.
5580     if (!pThread->HasThreadStateNC(Thread::TSNC_AppDomainContainUnhandled))
5581     {
5582         EX_TRY
5583         {
5584             EX_TRY
5585             {
5586                 // If this isn't ThreadAbortException, we want to print a stack trace to indicate why this thread abruptly
5587                 // terminated. Exceptions kill threads rarely enough that an uncached name check is reasonable.
5588                 BOOL        dump = TRUE;
5589
5590                 if (/*IsStackOverflow ||*/
5591                     !pThread->DetermineIfGuardPagePresent() ||
5592                     IsOutOfMemory)
5593                 {
5594                     // We have to be very careful.  If we walk off the end of the stack, the process will just
5595                     // die. e.g. IsAsyncThreadException() and Exception.ToString both consume too much stack -- and can't
5596                     // be called here.
5597                     dump = FALSE;
5598                     PrintToStdErrA("\n");
5599
5600                     if (FAILED(UtilLoadStringRC(IDS_EE_UNHANDLED_EXCEPTION, buf, buf_size)))
5601                     {
5602                         wcsncpy_s(buf, COUNTOF(buf), SZ_UNHANDLED_EXCEPTION, SZ_UNHANDLED_EXCEPTION_CHARLEN);
5603                     }
5604
5605                     PrintToStdErrW(buf);
5606
5607                     if (IsOutOfMemory)
5608                     {
5609                         PrintToStdErrA(" OutOfMemoryException.\n");
5610                     }
5611                     else
5612                     {
5613                         PrintToStdErrA(" StackOverflowException.\n");
5614                     }
5615                 }
5616                 else if (!CanRunManagedCode(LoaderLockCheck::None))
5617                 {
5618                     // Well, if we can't enter the runtime, we very well can't get the exception message.
5619                     dump = FALSE;
5620                 }
5621                 else if (SentEvent || IsAsyncThreadException(&throwable))
5622                 {
5623                     // We don't print anything on async exceptions, like ThreadAbort.
5624                     dump = FALSE;
5625                     INDEBUG(suppressSelectiveBreak=TRUE);
5626                 }
5627                 else if (isThreadBaseFilter && IsExceptionOfType(kAppDomainUnloadedException, &throwable))
5628                 {
5629                     // AppdomainUnloadedException is also a special case.
5630                     dump = FALSE;
5631                     INDEBUG(suppressSelectiveBreak=TRUE);
5632                 }
5633
5634                 // Finally, should we print the message?
5635                 if (dump)
5636                 {
5637                     // this is stack heavy because of the CQuickWSTRBase, so we break it out
5638                     // and don't have to carry the weight through our other code paths.
5639                     DefaultCatchHandlerExceptionMessageWorker(pThread, throwable, buf, buf_size, sendWindowsEventLog);
5640                 }
5641             }
5642             EX_CATCH
5643             {
5644                 LOG((LF_EH, LL_INFO10, "Exception occurred while processing uncaught exception\n"));
5645                 UtilLoadStringRC(IDS_EE_EXCEPTION_TOSTRING_FAILED, buf, buf_size);
5646                 PrintToStdErrA("\n   ");
5647                 PrintToStdErrW(buf);
5648                 PrintToStdErrA("\n");
5649             }
5650             EX_END_CATCH(SwallowAllExceptions);
5651         }
5652         EX_CATCH
5653         {   // If we got here, we can't even print the localized error message.  Print non-localized.
5654             LOG((LF_EH, LL_INFO10, "Exception occurred while logging processing uncaught exception\n"));
5655             PrintToStdErrA("\n   Error: Can't print exception string because Exception.ToString() failed.\n");
5656         }
5657         EX_END_CATCH(SwallowAllExceptions);
5658     }
5659
5660 #if defined(_DEBUG)
5661     if ((breakOnUncaught == breakSelective) && !suppressSelectiveBreak)
5662     {
5663         _ASSERTE(!"BreakOnUnCaughtException");
5664     }
5665 #endif // defined(_DEBUG)
5666
5667     FlushLogging();     // Flush any logging output
5668     GCPROTECT_END();
5669
5670 #ifdef _DEBUG
5671     // Do not care about lock check for unhandled exception.
5672     while (unbreakableLockCount)
5673     {
5674         pThread->IncUnbreakableLockCount();
5675         unbreakableLockCount --;
5676     }
5677     if (fOwnsSpinLock)
5678     {
5679         pThread->SetThreadStateNC(Thread::TSNC_OwnsSpinLock);
5680     }
5681 #endif
5682 } // DefaultCatchHandler()
5683
5684
5685 //******************************************************************************
5686 // NotifyAppDomainsOfUnhandledException -- common processing for otherwise uncaught exceptions.
5687 //******************************************************************************
5688 BOOL NotifyAppDomainsOfUnhandledException(
5689     PEXCEPTION_POINTERS pExceptionPointers,
5690     OBJECTREF   *pThrowableIn,
5691     BOOL        useLastThrownObject,
5692     BOOL        isTerminating)
5693 {
5694     CONTRACTL
5695     {
5696         THROWS;
5697         GC_TRIGGERS;
5698         MODE_ANY;
5699     }
5700     CONTRACTL_END;
5701
5702 #ifdef _DEBUG
5703     static int fBreakOnNotify = -1;
5704     if (fBreakOnNotify==-1) fBreakOnNotify = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnNotify);
5705     _ASSERTE(!fBreakOnNotify);
5706 #endif
5707
5708     BOOL SentEvent = FALSE;
5709
5710     LOG((LF_EH, LL_INFO10, "In NotifyAppDomainsOfUnhandledException\n"));
5711
5712     Thread *pThread = GetThread();
5713
5714     //     The following reduces a window for a race during shutdown.
5715     if (!pThread)
5716     {
5717         _ASSERTE(g_fEEShutDown);
5718         return FALSE;
5719     }
5720
5721     // See detailed explanation of this flag in threads.cpp.  But the basic idea is that we already
5722     // reported the exception in the AppDomain where it went unhandled, so we don't need to report
5723     // it at the process level.
5724     if (pThread->HasThreadStateNC(Thread::TSNC_AppDomainContainUnhandled))
5725         return FALSE;
5726
5727     ThreadPreventAsyncHolder prevAsync;
5728
5729     GCX_COOP();
5730
5731     OBJECTREF throwable;
5732
5733     if (pThrowableIn != NULL)
5734     {
5735         throwable = *pThrowableIn;
5736     }
5737     else if (useLastThrownObject)
5738     {
5739         throwable = pThread->LastThrownObject();
5740     }
5741     else
5742     {
5743         throwable = pThread->GetThrowable();
5744     }
5745
5746     // If we've got no managed object, then we can't send an event, so we just return.
5747     if (throwable == NULL)
5748     {
5749         return FALSE;
5750     }
5751
5752 #ifdef _DEBUG
5753     DWORD unbreakableLockCount = 0;
5754     // Do not care about lock check for unhandled exception.
5755     while (pThread->HasUnbreakableLock())
5756     {
5757         pThread->DecUnbreakableLockCount();
5758         unbreakableLockCount ++;
5759     }
5760     BOOL fOwnsSpinLock = pThread->HasThreadStateNC(Thread::TSNC_OwnsSpinLock);
5761     if (fOwnsSpinLock)
5762     {
5763         pThread->ResetThreadStateNC(Thread::TSNC_OwnsSpinLock);
5764     }
5765 #endif
5766
5767     GCPROTECT_BEGIN(throwable);
5768     //BOOL IsStackOverflow = (throwable->GetTrueMethodTable() == g_pStackOverflowExceptionClass);
5769
5770     // Notify the AppDomain that we have taken an unhandled exception.  Can't notify of stack overflow -- guard
5771     // page is not yet reset.
5772
5773     // Send up the unhandled exception appdomain event.
5774     //
5775     // If we can't run managed code, we can't deliver the event. Nor do we attempt to delieve the event in stack
5776     // overflow or OOM conditions.
5777     if (/*!IsStackOverflow &&*/
5778         pThread->DetermineIfGuardPagePresent() &&
5779         CanRunManagedCode(LoaderLockCheck::None))
5780     {
5781
5782         // x86 only
5783 #if !defined(WIN64EXCEPTIONS)
5784         // If the Thread object's exception state's exception pointers
5785         //  is null, use the passed-in pointer.
5786         BOOL bSetPointers = FALSE;
5787
5788         ThreadExceptionState* pExceptionState = pThread->GetExceptionState();
5789
5790         if (pExceptionState->GetExceptionPointers() == NULL)
5791         {
5792             bSetPointers = TRUE;
5793             pExceptionState->SetExceptionPointers(pExceptionPointers);
5794         }
5795
5796 #endif // !defined(WIN64EXCEPTIONS)
5797
5798         INSTALL_NESTED_EXCEPTION_HANDLER(pThread->GetFrame());
5799
5800         // This guy will never throw, but it will need a spot to store
5801         // any nested exceptions it might find.
5802         SentEvent = AppDomain::OnUnhandledException(&throwable, isTerminating);
5803
5804         UNINSTALL_NESTED_EXCEPTION_HANDLER();
5805
5806 #if !defined(WIN64EXCEPTIONS)
5807
5808         if (bSetPointers)
5809         {
5810             pExceptionState->SetExceptionPointers(NULL);
5811         }
5812
5813 #endif // !defined(WIN64EXCEPTIONS)
5814
5815     }
5816
5817     GCPROTECT_END();
5818
5819 #ifdef _DEBUG
5820     // Do not care about lock check for unhandled exception.
5821     while (unbreakableLockCount)
5822     {
5823         pThread->IncUnbreakableLockCount();
5824         unbreakableLockCount --;
5825     }
5826     if (fOwnsSpinLock)
5827     {
5828         pThread->SetThreadStateNC(Thread::TSNC_OwnsSpinLock);
5829     }
5830 #endif
5831
5832     return SentEvent;
5833
5834 } // NotifyAppDomainsOfUnhandledException()
5835
5836
5837 //******************************************************************************
5838 //
5839 //  ThreadBaseExceptionFilter_Worker
5840 //
5841 //    The return from the function can be EXCEPTION_CONTINUE_SEARCH to let an
5842 //     exception go unhandled.  This is the default behaviour (starting in v2.0),
5843 //     but can be overridden by hosts or by config file.
5844 //    When the behaviour is overridden, the return will be EXCEPTION_EXECUTE_HANDLER
5845 //     to swallow the exception.
5846 //    Note that some exceptions are always swallowed: ThreadAbort, and AppDomainUnload.
5847 //
5848 //  Parameters:
5849 //    pExceptionInfo    EXCEPTION_POINTERS for current exception
5850 //    _location         A constant as an INT_PTR.  Tells the context from whence called.
5851 //    swallowing        Are we swallowing unhandled exceptions based on policy?
5852 //
5853 //  Returns:
5854 //    EXCEPTION_CONTINUE_SEARCH     Generally returns this to let the exception go unhandled.
5855 //    EXCEPTION_EXECUTE_HANDLER     May return this to swallow the exception.
5856 //
5857 static LONG ThreadBaseExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo,
5858                                              PVOID pvParam,
5859                                              BOOL swallowing)
5860 {
5861     CONTRACTL
5862     {
5863         THROWS;
5864         GC_TRIGGERS;
5865         MODE_ANY;
5866     }
5867     CONTRACTL_END;
5868
5869     LOG((LF_EH, LL_INFO100, "ThreadBaseExceptionFilter_Worker: Enter\n"));
5870
5871     ThreadBaseExceptionFilterParam *pParam = (ThreadBaseExceptionFilterParam *) pvParam;
5872     UnhandledExceptionLocation location = pParam->location;
5873
5874     _ASSERTE(!g_fNoExceptions);
5875
5876     Thread* pThread = GetThread();
5877     _ASSERTE(pThread);
5878
5879 #ifdef _DEBUG
5880     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException) &&
5881         !(swallowing && (SwallowUnhandledExceptions() || ExceptionIsAlwaysSwallowed(pExceptionInfo))) &&
5882         !(location == ClassInitUnhandledException && pThread->IsRudeAbortInitiated()))
5883         _ASSERTE(!"BreakOnUnCaughtException");
5884 #endif
5885
5886     BOOL doDefault =  ((location != ClassInitUnhandledException) &&
5887                        (pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_BREAKPOINT) &&
5888                        (pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP));
5889
5890     if (swallowing)
5891     {
5892         // The default handling for versions v1.0 and v1.1 was to swallow unhandled exceptions.
5893         //  With v2.0, the default is to let them go unhandled.  Hosts & config files can modify the default
5894         //  to retain the v1.1 behaviour.
5895         // Should we swallow this exception, or let it continue up and be unhandled?
5896         if (!SwallowUnhandledExceptions())
5897         {
5898             // No, don't swallow unhandled exceptions...
5899
5900             // ...except if the exception is of a type that is always swallowed (ThreadAbort, AppDomainUnload)...
5901             if (ExceptionIsAlwaysSwallowed(pExceptionInfo))
5902             {   // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception anyway.
5903                 return EXCEPTION_EXECUTE_HANDLER;
5904             }
5905
5906             #ifdef _DEBUG
5907             if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException))
5908                 _ASSERTE(!"BreakOnUnCaughtException");
5909             #endif
5910
5911             // ...so, continue search. i.e. let the exception go unhandled.
5912             return EXCEPTION_CONTINUE_SEARCH;
5913         }
5914     }
5915
5916 #ifdef DEBUGGING_SUPPORTED
5917     // If there's a debugger (and not doing a thread abort), give the debugger a shot at the exception.
5918     // If the debugger is going to try to continue the exception, it will return ContinueException (which
5919     // we see here as EXCEPTION_CONTINUE_EXECUTION).
5920     if (!pThread->IsAbortRequested())
5921     {
5922         // TODO: do we really need this check? I don't think we do
5923         if(CORDebuggerAttached())
5924         {
5925             if (NotifyDebuggerLastChance(pThread, pExceptionInfo, FALSE) == EXCEPTION_CONTINUE_EXECUTION)
5926             {
5927                 LOG((LF_EH, LL_INFO100, "ThreadBaseExceptionFilter_Worker: EXCEPTION_CONTINUE_EXECUTION\n"));
5928                 return EXCEPTION_CONTINUE_EXECUTION;
5929             }
5930         }
5931     }
5932 #endif // DEBUGGING_SUPPORTED
5933
5934     // Do default handling, but ignore breakpoint exceptions and class init exceptions
5935     if (doDefault)
5936     {
5937         LOG((LF_EH, LL_INFO100, "ThreadBaseExceptionFilter_Worker: Calling DefaultCatchHandler\n"));
5938
5939         BOOL useLastThrownObject = UpdateCurrentThrowable(pExceptionInfo->ExceptionRecord);
5940
5941         DefaultCatchHandler(pExceptionInfo,
5942                             NULL,
5943                             useLastThrownObject,
5944                             FALSE,
5945                             location == ManagedThread || location == ThreadPoolThread || location == FinalizerThread);
5946     }
5947
5948     // Return EXCEPTION_EXECUTE_HANDLER to swallow the exception.
5949     return (swallowing
5950             ? EXCEPTION_EXECUTE_HANDLER
5951             : EXCEPTION_CONTINUE_SEARCH);
5952 } // LONG ThreadBaseExceptionFilter_Worker()
5953
5954
5955 //    This is the filter for new managed threads, for threadpool threads, and for
5956 //     running finalizer methods.
5957 LONG ThreadBaseExceptionSwallowingFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pvParam)
5958 {
5959     return ThreadBaseExceptionFilter_Worker(pExceptionInfo, pvParam, /*swallowing=*/true);
5960 }
5961
5962 //    This was the filter for new managed threads in v1.0 and v1.1.  Now used
5963 //     for delegate invoke, various things in the thread pool, and the
5964 //     class init handler.
5965 LONG ThreadBaseExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pvParam)
5966 {
5967     return ThreadBaseExceptionFilter_Worker(pExceptionInfo, pvParam, /*swallowing=*/false);
5968 }
5969
5970
5971 //    This is the filter that we install when transitioning an AppDomain at the base of a managed
5972 //     thread.  Nothing interesting will get swallowed after us.  So we never decide to continue
5973 //     the search.  Instead, we let it go unhandled and get the Watson report and debugging
5974 //     experience before the AD transition has an opportunity to catch/rethrow and lose all the
5975 //     relevant information.
5976 LONG ThreadBaseExceptionAppDomainFilter(EXCEPTION_POINTERS *pExceptionInfo, PVOID pvParam)
5977 {
5978     LONG ret = ThreadBaseExceptionSwallowingFilter(pExceptionInfo, pvParam);
5979
5980     if (ret != EXCEPTION_CONTINUE_SEARCH)
5981         return ret;
5982
5983     // Consider the exception to be unhandled
5984     return InternalUnhandledExceptionFilter_Worker(pExceptionInfo);
5985 }
5986
5987 // Filter for calls out from the 'vm' to native code, if there's a possibility of SEH exceptions
5988 // in the native code.
5989 LONG CallOutFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pv)
5990 {
5991     CallOutFilterParam *pParam = static_cast<CallOutFilterParam *>(pv);
5992
5993     _ASSERTE(pParam->OneShot && (pParam->OneShot == TRUE || pParam->OneShot == FALSE));
5994
5995     if (pParam->OneShot == TRUE)
5996     {
5997         pParam->OneShot = FALSE;
5998
5999         // Replace whatever SEH exception is in flight, with an SEHException derived from
6000         // CLRException.  But if the exception already looks like one of ours, let it
6001         // go past since LastThrownObject should already represent it.
6002         if ((!IsComPlusException(pExceptionInfo->ExceptionRecord)) &&
6003             (pExceptionInfo->ExceptionRecord->ExceptionCode != EXCEPTION_MSVC))
6004             PAL_CPP_THROW(SEHException *, new SEHException(pExceptionInfo->ExceptionRecord,
6005                                                            pExceptionInfo->ContextRecord));
6006     }
6007     return EXCEPTION_CONTINUE_SEARCH;
6008 }
6009
6010
6011 //==========================================================================
6012 // Convert the format string used by sprintf to the format used by String.Format.
6013 // Using the managed formatting routine avoids bogus access violations
6014 // that happen for long strings in Win32's FormatMessage.
6015 //
6016 // Note: This is not general purpose routine. It handles only cases found
6017 // in TypeLoadException and FileLoadException.
6018 //==========================================================================
6019 static BOOL GetManagedFormatStringForResourceID(CCompRC::ResourceCategory eCategory, UINT32 resId, SString & converted)
6020 {
6021     STANDARD_VM_CONTRACT;
6022
6023     StackSString temp;
6024     if (!temp.LoadResource(eCategory, resId))
6025         return FALSE;
6026
6027     SString::Iterator itr = temp.Begin();
6028     while (*itr)
6029     {
6030         WCHAR c = *itr++;
6031         switch (c) {
6032         case '%':
6033             {
6034                 WCHAR fmt = *itr++;
6035                 if (fmt >= '1' && fmt <= '9') {
6036                     converted.Append(W("{"));
6037                     converted.Append(fmt - 1); // the managed args start at 0
6038                     converted.Append(W("}"));
6039                 }
6040                 else
6041                 if (fmt == '%') {
6042                     converted.Append(W("%"));
6043                 }
6044                 else {
6045                     _ASSERTE(!"Unexpected formating string: %s");
6046                 }
6047             }
6048             break;
6049         case '{':
6050             converted.Append(W("{{"));
6051             break;
6052         case '}':
6053             converted.Append(W("}}"));
6054             break;
6055         default:
6056             converted.Append(c);
6057             break;
6058         }
6059     }
6060     return TRUE;
6061 }
6062
6063 //==========================================================================
6064 // Private helper for TypeLoadException.
6065 //==========================================================================
6066 void QCALLTYPE GetTypeLoadExceptionMessage(UINT32 resId, QCall::StringHandleOnStack retString)
6067 {
6068     QCALL_CONTRACT;
6069
6070     BEGIN_QCALL;
6071
6072     StackSString format;
6073     GetManagedFormatStringForResourceID(CCompRC::Error, resId ? resId : IDS_CLASSLOAD_GENERAL,  format);
6074     retString.Set(format);
6075
6076     END_QCALL;
6077 }
6078
6079
6080
6081 //==========================================================================
6082 // Private helper for FileLoadException and FileNotFoundException.
6083 //==========================================================================
6084
6085 void QCALLTYPE GetFileLoadExceptionMessage(UINT32 hr, QCall::StringHandleOnStack retString)
6086 {
6087     QCALL_CONTRACT;
6088
6089     BEGIN_QCALL;
6090
6091     StackSString format;
6092     GetManagedFormatStringForResourceID(CCompRC::Error, GetResourceIDForFileLoadExceptionHR(hr), format);
6093     retString.Set(format);
6094
6095     END_QCALL;
6096 }
6097
6098 //==========================================================================
6099 // Private helper for FileLoadException and FileNotFoundException.
6100 //==========================================================================
6101 void QCALLTYPE FileLoadException_GetMessageForHR(UINT32 hresult, QCall::StringHandleOnStack retString)
6102 {
6103     QCALL_CONTRACT;
6104
6105     BEGIN_QCALL;
6106
6107     BOOL bNoGeekStuff = FALSE;
6108     switch ((HRESULT)hresult)
6109     {
6110         // These are not usually app errors - as long
6111         // as the message is reasonably clear, we can live without the hex code stuff.
6112         case COR_E_FILENOTFOUND:
6113         case __HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND):
6114         case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND):
6115         case __HRESULT_FROM_WIN32(ERROR_INVALID_NAME):
6116         case __HRESULT_FROM_WIN32(ERROR_BAD_NET_NAME):
6117         case __HRESULT_FROM_WIN32(ERROR_BAD_NETPATH):
6118         case __HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND):
6119         case CTL_E_FILENOTFOUND:
6120         case COR_E_DLLNOTFOUND:
6121         case COR_E_PATHTOOLONG:
6122         case E_ACCESSDENIED:
6123         case COR_E_BADIMAGEFORMAT:
6124         case COR_E_NEWER_RUNTIME:
6125         case COR_E_ASSEMBLYEXPECTED:
6126             bNoGeekStuff = TRUE;
6127             break;
6128     }
6129
6130     SString s;
6131     GetHRMsg((HRESULT)hresult, s, bNoGeekStuff);
6132     retString.Set(s);
6133
6134     END_QCALL;
6135 }
6136
6137
6138 #define ValidateSigBytes(_size) do { if ((_size) > csig) COMPlusThrow(kArgumentException, W("Argument_BadSigFormat")); csig -= (_size); } while (false)
6139
6140 //==========================================================================
6141 // Unparses an individual type.
6142 //==========================================================================
6143 const BYTE *UnparseType(const BYTE *pType, DWORD& csig, StubLinker *psl)
6144 {
6145     CONTRACTL
6146     {
6147         THROWS;
6148         GC_NOTRIGGER;
6149         MODE_ANY;
6150         INJECT_FAULT(ThrowOutOfMemory();); // Emitting data to the StubLinker can throw OOM.
6151     }
6152     CONTRACTL_END;
6153
6154     LPCUTF8 pName = NULL;
6155
6156     ValidateSigBytes(sizeof(BYTE));
6157     switch ( (CorElementType) *(pType++) ) {
6158         case ELEMENT_TYPE_VOID:
6159             psl->EmitUtf8("void");
6160             break;
6161
6162         case ELEMENT_TYPE_BOOLEAN:
6163             psl->EmitUtf8("boolean");
6164             break;
6165
6166         case ELEMENT_TYPE_CHAR:
6167             psl->EmitUtf8("char");
6168             break;
6169
6170         case ELEMENT_TYPE_U1:
6171             psl->EmitUtf8("unsigned ");
6172             //fallthru
6173         case ELEMENT_TYPE_I1:
6174             psl->EmitUtf8("byte");
6175             break;
6176
6177         case ELEMENT_TYPE_U2:
6178             psl->EmitUtf8("unsigned ");
6179             //fallthru
6180         case ELEMENT_TYPE_I2:
6181             psl->EmitUtf8("short");
6182             break;
6183
6184         case ELEMENT_TYPE_U4:
6185             psl->EmitUtf8("unsigned ");
6186             //fallthru
6187         case ELEMENT_TYPE_I4:
6188             psl->EmitUtf8("int");
6189             break;
6190
6191         case ELEMENT_TYPE_I:
6192             psl->EmitUtf8("native int");
6193             break;
6194         case ELEMENT_TYPE_U:
6195             psl->EmitUtf8("native unsigned");
6196             break;
6197
6198         case ELEMENT_TYPE_U8:
6199             psl->EmitUtf8("unsigned ");
6200             //fallthru
6201         case ELEMENT_TYPE_I8:
6202             psl->EmitUtf8("long");
6203             break;
6204
6205
6206         case ELEMENT_TYPE_R4:
6207             psl->EmitUtf8("float");
6208             break;
6209
6210         case ELEMENT_TYPE_R8:
6211             psl->EmitUtf8("double");
6212             break;
6213
6214         case ELEMENT_TYPE_STRING:
6215             psl->EmitUtf8(g_StringName);
6216             break;
6217
6218         case ELEMENT_TYPE_VAR:
6219         case ELEMENT_TYPE_OBJECT:
6220             psl->EmitUtf8(g_ObjectName);
6221             break;
6222
6223         case ELEMENT_TYPE_PTR:
6224             pType = UnparseType(pType, csig, psl);
6225             psl->EmitUtf8("*");
6226             break;
6227
6228         case ELEMENT_TYPE_BYREF:
6229             pType = UnparseType(pType, csig, psl);
6230             psl->EmitUtf8("&");
6231             break;
6232
6233         case ELEMENT_TYPE_VALUETYPE:
6234         case ELEMENT_TYPE_CLASS:
6235             pName = (LPCUTF8)pType;
6236             while (true) {
6237                 ValidateSigBytes(sizeof(CHAR));
6238                 if (*(pType++) == '\0')
6239                     break;
6240             }
6241             psl->EmitUtf8(pName);
6242             break;
6243
6244         case ELEMENT_TYPE_SZARRAY:
6245             {
6246                 pType = UnparseType(pType, csig, psl);
6247                 psl->EmitUtf8("[]");
6248             }
6249             break;
6250
6251         case ELEMENT_TYPE_ARRAY:
6252             {
6253                 pType = UnparseType(pType, csig, psl);
6254                 ValidateSigBytes(sizeof(DWORD));
6255                 DWORD rank = GET_UNALIGNED_VAL32(pType);
6256                 pType += sizeof(DWORD);
6257                 if (rank)
6258                 {
6259                     ValidateSigBytes(sizeof(UINT32));
6260                     UINT32 nsizes = GET_UNALIGNED_VAL32(pType); // Get # of sizes
6261                     ValidateSigBytes(nsizes * sizeof(UINT32));
6262                     pType += 4 + nsizes*4;
6263                     ValidateSigBytes(sizeof(UINT32));
6264                     UINT32 nlbounds = GET_UNALIGNED_VAL32(pType); // Get # of lower bounds
6265                     ValidateSigBytes(nlbounds * sizeof(UINT32));
6266                     pType += 4 + nlbounds*4;
6267
6268
6269                     while (rank--) {
6270                         psl->EmitUtf8("[]");
6271                     }
6272
6273 }
6274
6275             }
6276             break;
6277
6278         case ELEMENT_TYPE_TYPEDBYREF:
6279             psl->EmitUtf8("&");
6280             break;
6281
6282         case ELEMENT_TYPE_FNPTR:
6283             psl->EmitUtf8("ftnptr");
6284             break;
6285
6286         default:
6287             psl->EmitUtf8("?");
6288             break;
6289     }
6290
6291     return pType;
6292     }
6293
6294
6295
6296 //==========================================================================
6297 // Helper for MissingMemberException.
6298 //==========================================================================
6299 static STRINGREF MissingMemberException_FormatSignature_Internal(I1ARRAYREF* ppPersistedSig)
6300 {
6301     CONTRACTL
6302     {
6303         THROWS;
6304         GC_TRIGGERS;
6305         MODE_COOPERATIVE;
6306         INJECT_FAULT(ThrowOutOfMemory(););
6307     }
6308     CONTRACTL_END;
6309
6310     STRINGREF pString = NULL;
6311
6312     DWORD csig = 0;
6313     const BYTE *psig = 0;
6314     StubLinker *psl = NULL;
6315     StubHolder<Stub> pstub;
6316
6317     if ((*ppPersistedSig) != NULL)
6318         csig = (*ppPersistedSig)->GetNumComponents();
6319
6320     if (csig == 0)
6321     {
6322         return StringObject::NewString("Unknown signature");
6323     }
6324
6325     psig = (const BYTE*)_alloca(csig);
6326     CopyMemory((BYTE*)psig,
6327                (*ppPersistedSig)->GetDirectPointerToNonObjectElements(),
6328                csig);
6329
6330     {
6331     GCX_PREEMP();
6332
6333     StubLinker sl;
6334     psl = &sl; 
6335     pstub = NULL;
6336
6337     ValidateSigBytes(sizeof(UINT32));
6338     UINT32 cconv = GET_UNALIGNED_VAL32(psig);
6339     psig += 4;
6340
6341     if (cconv == IMAGE_CEE_CS_CALLCONV_FIELD) {
6342         psig = UnparseType(psig, csig, psl);
6343     } else {
6344         ValidateSigBytes(sizeof(UINT32));
6345         UINT32 nargs = GET_UNALIGNED_VAL32(psig);
6346         psig += 4;
6347
6348         // Unparse return type
6349         psig = UnparseType(psig, csig, psl);
6350         psl->EmitUtf8("(");
6351         while (nargs--) {
6352             psig = UnparseType(psig, csig, psl);
6353             if (nargs) {
6354                 psl->EmitUtf8(", ");
6355             }
6356         }
6357         psl->EmitUtf8(")");
6358     }
6359     psl->Emit8('\0');
6360     pstub = psl->Link();
6361     }
6362
6363     pString = StringObject::NewString( (LPCUTF8)(pstub->GetEntryPoint()) );
6364     return pString;
6365 }
6366
6367 FCIMPL1(Object*, MissingMemberException_FormatSignature, I1Array* pPersistedSigUNSAFE)
6368 {
6369     FCALL_CONTRACT;
6370
6371     STRINGREF pString = NULL;
6372     I1ARRAYREF pPersistedSig = (I1ARRAYREF) pPersistedSigUNSAFE;
6373     HELPER_METHOD_FRAME_BEGIN_RET_1(pPersistedSig);
6374
6375     pString = MissingMemberException_FormatSignature_Internal(&pPersistedSig);
6376
6377     HELPER_METHOD_FRAME_END();
6378     return OBJECTREFToObject(pString);
6379     }
6380 FCIMPLEND
6381
6382 // Check if the Win32 Error code is an IO error.
6383 BOOL IsWin32IOError(SCODE scode)
6384 {
6385     LIMITED_METHOD_CONTRACT;
6386
6387     switch (scode)
6388     {
6389     case ERROR_FILE_NOT_FOUND:
6390     case ERROR_PATH_NOT_FOUND:
6391     case ERROR_TOO_MANY_OPEN_FILES:
6392     case ERROR_ACCESS_DENIED:
6393     case ERROR_INVALID_HANDLE:
6394     case ERROR_INVALID_DRIVE:
6395     case ERROR_WRITE_PROTECT:
6396     case ERROR_NOT_READY:
6397     case ERROR_WRITE_FAULT:
6398     case ERROR_SHARING_VIOLATION:
6399     case ERROR_LOCK_VIOLATION:
6400     case ERROR_SHARING_BUFFER_EXCEEDED:
6401     case ERROR_HANDLE_DISK_FULL:
6402     case ERROR_BAD_NETPATH:
6403     case ERROR_DEV_NOT_EXIST:
6404     case ERROR_FILE_EXISTS:
6405     case ERROR_CANNOT_MAKE:
6406     case ERROR_NET_WRITE_FAULT:
6407     case ERROR_DRIVE_LOCKED:
6408     case ERROR_OPEN_FAILED:
6409     case ERROR_BUFFER_OVERFLOW:
6410     case ERROR_DISK_FULL:
6411     case ERROR_INVALID_NAME:
6412     case ERROR_FILENAME_EXCED_RANGE:
6413     case ERROR_IO_DEVICE:
6414     case ERROR_DISK_OPERATION_FAILED:
6415         return TRUE;
6416
6417     default:
6418         return FALSE;
6419     }
6420 }
6421
6422
6423 // Check if there is a pending exception or the thread is already aborting. Returns 0 if yes.
6424 // Otherwise, sets the thread up for generating an abort and returns address of ThrowControlForThread
6425 // It is the caller's responsibility to set up Thread::m_OSContext prior to this call.  This is used as
6426 // the context for checking if a ThreadAbort is allowed, and also as the context for the ThreadAbortException
6427 // itself.
6428 LPVOID COMPlusCheckForAbort(UINT_PTR uTryCatchResumeAddress)
6429 {
6430     CONTRACTL
6431     {
6432         NOTHROW;
6433         GC_NOTRIGGER;
6434         MODE_ANY;
6435         SO_TOLERANT;
6436     }
6437     CONTRACTL_END;
6438
6439     // Initialize the return address
6440     LPVOID pRetAddress = 0;
6441
6442     Thread* pThread = GetThread();
6443
6444     if ((!pThread->IsAbortRequested()) ||         // if no abort has been requested
6445         (!pThread->IsRudeAbort() &&
6446         (pThread->GetThrowable() != NULL)) )  // or if there is a pending exception
6447     {
6448         goto exit;
6449     }
6450
6451     // Reverse COM interop IL stubs map all exceptions to HRESULTs and must not propagate Thread.Abort 
6452     // to their unmanaged callers.
6453     if (uTryCatchResumeAddress != NULL)
6454     {
6455         MethodDesc * pMDResumeMethod = ExecutionManager::GetCodeMethodDesc((PCODE)uTryCatchResumeAddress);
6456         if (pMDResumeMethod->IsILStub())
6457             goto exit;
6458     }
6459
6460     // else we must produce an abort
6461     if ((pThread->GetThrowable() == NULL) &&
6462         (pThread->IsAbortInitiated()))
6463     {
6464         // Oops, we just swallowed an abort, must restart the process
6465         pThread->ResetAbortInitiated();
6466     }
6467
6468     // Question: Should we also check for (pThread->m_PreventAsync == 0)
6469
6470 #if !defined(WIN64EXCEPTIONS) && defined(FEATURE_STACK_PROBE)
6471     // On Win64, this function is called by our exception handling code which has probed.
6472     // But on X86, this is called from JIT code directly.  We probe here so that
6473     // we can restore the state of the thread below.
6474     if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
6475     {
6476         // In case of SO, we will skip the managed code.
6477         CONTRACT_VIOLATION(ThrowsViolation);
6478         RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), pThread);
6479     }
6480 #endif // !WIN64EXCEPTIONS && FEATURE_STACK_PROBE
6481
6482     pThread->SetThrowControlForThread(Thread::InducedThreadRedirectAtEndOfCatch);
6483     if (!pThread->ReadyForAbort())
6484     {
6485         pThread->ResetThrowControlForThread();
6486         goto exit;
6487     }
6488     pThread->SetThrowControlForThread(Thread::InducedThreadStop);
6489
6490     pRetAddress = (LPVOID)THROW_CONTROL_FOR_THREAD_FUNCTION;
6491
6492 exit:
6493
6494 #ifndef FEATURE_PAL
6495
6496     // Only proceed if Watson is enabled - CoreCLR may have it disabled.
6497     if (IsWatsonEnabled())
6498     {
6499         BOOL fClearUEWatsonBucketTracker = TRUE;
6500         PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pThread->GetExceptionState()->GetUEWatsonBucketTracker();
6501
6502         if (pRetAddress && pThread->IsAbortRequested())
6503         {
6504             // Since we are going to reraise the thread abort exception,  we would like to assert that
6505             // the buckets present in the UE tracker are the ones which were setup TAE was first raised.
6506             //
6507             // However, these buckets could come from across AD transition as well and thus, would be
6508             // marked for "Captured at AD transition". Thus, we cannot just assert them to be only from
6509             // TAE raise.
6510             //
6511             // We try to preserve buckets incase there is another catch that may catch the exception we reraise
6512             // and it attempts to FailFast using the TA exception object. In such a case,
6513             // we should maintain the original exception point's bucket details.
6514             if (pUEWatsonBucketTracker->RetrieveWatsonBucketIp() != NULL)
6515             {
6516                 _ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort() || pUEWatsonBucketTracker->CapturedAtADTransition());
6517                 fClearUEWatsonBucketTracker = FALSE;
6518             }
6519 #ifdef _DEBUG
6520             else
6521             {
6522                 // If we are here and UE Watson bucket tracker is empty,
6523                 // then it is possible that a thread abort was signalled when the catch was executing
6524                 // and thus, hijack for TA from here is not a reraise but an initial raise.
6525                 //
6526                 // However, if we have partial details, then something is really not right.
6527                 if (!((pUEWatsonBucketTracker->RetrieveWatsonBucketIp() == NULL) &&
6528                     (pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)))
6529                 {
6530                     _ASSERTE(!"How come TA is being [re]raised and we have incomplete watson bucket details?");
6531                 }
6532             }
6533 #endif // _DEBUG
6534         }
6535
6536         if (fClearUEWatsonBucketTracker)
6537         {
6538             // Clear the UE watson bucket tracker for future use since it does not have anything
6539             // useful for us right now.
6540             pUEWatsonBucketTracker->ClearWatsonBucketDetails();
6541             LOG((LF_EH, LL_INFO100, "COMPlusCheckForAbort - Cleared UE watson bucket tracker since TAE was not being reraised.\n"));
6542         }
6543     }
6544
6545 #endif // !FEATURE_PAL
6546
6547     return pRetAddress;
6548 }
6549
6550
6551 BOOL IsThreadHijackedForThreadStop(Thread* pThread, EXCEPTION_RECORD* pExceptionRecord)
6552 {
6553     CONTRACTL
6554     {
6555         NOTHROW;
6556         GC_NOTRIGGER;
6557         MODE_ANY;
6558         FORBID_FAULT;
6559         SO_TOLERANT;
6560     }
6561     CONTRACTL_END;
6562
6563     if (IsComPlusException(pExceptionRecord))
6564     {
6565         if (pThread->ThrewControlForThread() == Thread::InducedThreadStop)
6566         {
6567             LOG((LF_EH, LL_INFO100, "Asynchronous Thread Stop or Abort\n"));
6568             return TRUE;
6569         }
6570     }
6571     else if (IsStackOverflowException(pThread, pExceptionRecord))
6572     {
6573         // SO happens before we are able to change the state to InducedThreadStop, but
6574         // we are still in our hijack routine.
6575         if (pThread->ThrewControlForThread() == Thread::InducedThreadRedirect)
6576         {
6577             LOG((LF_EH, LL_INFO100, "Asynchronous Thread Stop or Abort caused by SO\n"));
6578             return TRUE;
6579         }
6580     }
6581     return FALSE;
6582 }
6583
6584 // We sometimes move a thread's execution so it will throw an exception for us.
6585 // But then we have to treat the exception as if it came from the instruction
6586 // the thread was originally running.
6587 //
6588 // NOTE: This code depends on the fact that there are no register-based data dependencies
6589 // between a try block and a catch, fault, or finally block.  If there were, then we need
6590 // to preserve more of the register context.
6591
6592 void AdjustContextForThreadStop(Thread* pThread,
6593                                 CONTEXT* pContext)
6594 {
6595     CONTRACTL
6596     {
6597         NOTHROW;
6598         GC_NOTRIGGER;
6599         MODE_ANY;
6600         FORBID_FAULT;
6601         SO_TOLERANT;
6602     }
6603     CONTRACTL_END;
6604
6605     _ASSERTE(pThread->m_OSContext);
6606
6607 #ifndef WIN64EXCEPTIONS
6608     SetIP(pContext, GetIP(pThread->m_OSContext));
6609     SetSP(pContext, (GetSP(pThread->m_OSContext)));
6610
6611     if (GetFP(pThread->m_OSContext) != 0)  // ebp = 0 implies that we got here with the right values for ebp
6612     {
6613         SetFP(pContext, GetFP(pThread->m_OSContext));
6614     }
6615
6616     // We might have been interrupted execution at a point where the jit has roots in
6617     // registers.  We just need to store a "safe" value in here so that the collector
6618     // doesn't trap.  We're not going to use these objects after the exception.
6619     //
6620     // Only callee saved registers are going to be reported by the faulting excepiton frame.
6621 #if defined(_TARGET_X86_)
6622     // Ebx,esi,edi are important.  Eax,ecx,edx are not.
6623     pContext->Ebx = 0;
6624     pContext->Edi = 0;
6625     pContext->Esi = 0;
6626 #else
6627     PORTABILITY_ASSERT("AdjustContextForThreadStop");
6628 #endif
6629
6630 #else // !WIN64EXCEPTIONS
6631     CopyOSContext(pContext, pThread->m_OSContext);
6632 #if defined(_TARGET_ARM_) && defined(_DEBUG)
6633     // Make sure that the thumb bit is set on the IP of the original abort context we just restored.
6634     PCODE controlPC = GetIP(pContext);
6635     _ASSERTE(controlPC & THUMB_CODE);
6636 #endif // _TARGET_ARM_
6637 #endif // !WIN64EXCEPTIONS                                                    
6638
6639     pThread->ResetThrowControlForThread();
6640
6641     // Should never get here if we're already throwing an exception.
6642     _ASSERTE(!pThread->IsExceptionInProgress() || pThread->IsRudeAbort());
6643
6644     // Should never get here if we're already abort initiated.
6645     _ASSERTE(!pThread->IsAbortInitiated() || pThread->IsRudeAbort());
6646
6647     if (pThread->IsAbortRequested())
6648     {
6649         pThread->SetAbortInitiated();    // to prevent duplicate aborts
6650     }
6651 }
6652
6653 // Create a COM+ exception , stick it in the thread.
6654 OBJECTREF
6655 CreateCOMPlusExceptionObject(Thread *pThread, EXCEPTION_RECORD *pExceptionRecord, BOOL bAsynchronousThreadStop)
6656 {
6657     CONTRACTL
6658     {
6659         NOTHROW;
6660         GC_TRIGGERS;
6661         MODE_COOPERATIVE;
6662         FORBID_FAULT;
6663         SO_TOLERANT;
6664     }
6665     CONTRACTL_END;
6666
6667     _ASSERTE(GetThread() == pThread);
6668
6669     DWORD exceptionCode = pExceptionRecord->ExceptionCode;
6670
6671     OBJECTREF result = 0;
6672
6673     DWORD COMPlusExceptionCode = (bAsynchronousThreadStop
6674                                     ? kThreadAbortException
6675                                     : MapWin32FaultToCOMPlusException(pExceptionRecord));
6676
6677     if (exceptionCode == STATUS_NO_MEMORY)
6678     {
6679         result = CLRException::GetBestOutOfMemoryException();
6680     }
6681     else if (IsStackOverflowException(pThread, pExceptionRecord))
6682     {
6683         result = CLRException::GetPreallocatedStackOverflowException();
6684     }
6685     else if (bAsynchronousThreadStop && pThread->IsAbortRequested() && pThread->IsRudeAbort())
6686     {
6687         result = CLRException::GetPreallocatedRudeThreadAbortException();
6688     }
6689     else
6690     {
6691         EX_TRY
6692         {
6693             // We need to disable the backout stack validation at this point since CreateThrowable can
6694             // take arbitrarily large amounts of stack for different exception types; however we know
6695             // for a fact that we will never go through this code path if the exception is a stack
6696             // overflow exception since we already handled that case above with the pre-allocated SO exception.
6697             DISABLE_BACKOUT_STACK_VALIDATION;
6698
6699             FAULT_NOT_FATAL();
6700
6701             ThreadPreventAsyncHolder preventAsync;
6702             ResetProcessorStateHolder procState;
6703
6704             INSTALL_UNWIND_AND_CONTINUE_HANDLER;
6705
6706             GCPROTECT_BEGIN(result)
6707
6708             EEException e((RuntimeExceptionKind)COMPlusExceptionCode);
6709             result = e.CreateThrowable();
6710
6711             // EEException is "one size fits all".  But AV needs some more information.
6712             if (COMPlusExceptionCode == kAccessViolationException)
6713             {
6714                 SetExceptionAVParameters(result, pExceptionRecord);
6715             }
6716
6717             GCPROTECT_END();
6718
6719             UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
6720         }
6721         EX_CATCH
6722         {
6723             // If we get an exception trying to build the managed exception object, then go ahead and return the
6724             // thrown object as the result of this function. This is preferable to letting the exception try to
6725             // percolate up through the EH code, and it effectively replaces the thrown exception with this
6726             // exception.
6727             result = GET_THROWABLE();
6728         }
6729         EX_END_CATCH(SwallowAllExceptions);
6730     }
6731
6732     return result;
6733 }
6734
6735 LONG FilterAccessViolation(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
6736 {
6737     CONTRACTL
6738     {
6739         THROWS;
6740         GC_NOTRIGGER;
6741         MODE_ANY;
6742         FORBID_FAULT;
6743     }
6744     CONTRACTL_END;
6745
6746     if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
6747         return EXCEPTION_EXECUTE_HANDLER;
6748
6749     return EXCEPTION_CONTINUE_SEARCH;
6750 }
6751
6752 /*
6753  * IsContinuableException
6754  *
6755  * Returns whether this is an exception the EE knows how to intercept and continue from.
6756  *
6757  * Parameters:
6758  *   pThread - The thread the exception occurred on.
6759  *
6760  * Returns:
6761  *   TRUE if the exception on the thread is interceptable or not.
6762  *
6763  * Notes:
6764  *   Conditions for an interceptable exception:
6765  *   1) must be on a managed thread
6766  *   2) an exception must be in progress
6767  *   3) a managed exception object must have been created
6768  *   4) the thread must not be aborting
6769  *   5) the exception must not be a breakpoint, a single step, or a stack overflow
6770  *   6) the exception dispatch must be in the first pass
6771  *   7) the exception must not be a fatal error, as determined by the EE policy (see LogFatalError())
6772  */
6773 bool IsInterceptableException(Thread *pThread)
6774 {
6775     CONTRACTL
6776     {
6777         MODE_ANY;
6778         NOTHROW;
6779         GC_NOTRIGGER;
6780     }
6781     CONTRACTL_END;
6782
6783     return ((pThread != NULL)                       &&
6784             (!pThread->IsAbortRequested())          &&
6785             (pThread->IsExceptionInProgress())      &&
6786             (!pThread->IsThrowableNull())
6787
6788 #ifdef DEBUGGING_SUPPORTED
6789             &&
6790             pThread->GetExceptionState()->IsDebuggerInterceptable()
6791 #endif
6792
6793             );
6794 }
6795
6796 // Determines whether we hit an DO_A_GC_HERE marker in JITted code, and returns the 
6797 // appropriate exception code, or zero if the code is not a GC marker.
6798 DWORD GetGcMarkerExceptionCode(LPVOID ip)
6799 {
6800 #if defined(HAVE_GCCOVER)
6801     WRAPPER_NO_CONTRACT;
6802
6803     if (GCStress<cfg_any>::IsEnabled() && IsGcCoverageInterrupt(ip))
6804     {
6805         return STATUS_CLR_GCCOVER_CODE;
6806     }
6807 #else // defined(HAVE_GCCOVER)
6808     LIMITED_METHOD_CONTRACT;
6809 #endif // defined(HAVE_GCCOVER)
6810     return 0;
6811 }
6812
6813 // Did we hit an DO_A_GC_HERE marker in JITted code?
6814 bool IsGcMarker(DWORD exceptionCode, CONTEXT *pContext)
6815 {
6816 #ifdef HAVE_GCCOVER
6817     WRAPPER_NO_CONTRACT;
6818
6819     if (GCStress<cfg_any>::IsEnabled())
6820     {
6821 #ifdef _TARGET_X86_
6822         // on x86 we can't suspend EE to update the GC marker instruction so
6823         // we update it directly without suspending.  this can sometimes yield
6824         // a STATUS_ACCESS_VIOLATION instead of STATUS_CLR_GCCOVER_CODE.  in
6825         // this case we let the AV through and retry the instruction.  we'll
6826         // track the IP of the instruction that generated an AV so we don't
6827         // mix up a real AV with a "fake" AV.
6828         // see comments in function DoGcStress for more details on this race.
6829         // also make sure that the thread is actually in managed code since AVs
6830         // outside of of JIT code will never be potential GC markers
6831         Thread* pThread = GetThread();
6832         if (exceptionCode == STATUS_ACCESS_VIOLATION &&
6833             GCStress<cfg_instr>::IsEnabled() &&
6834             pThread->GetLastAVAddress() != (LPVOID)GetIP(pContext) &&
6835             pThread->PreemptiveGCDisabled() &&
6836             !IsIPInEE((LPVOID)GetIP(pContext)))
6837         {
6838             pThread->SetLastAVAddress((LPVOID)GetIP(pContext));
6839             return true;
6840         }
6841 #endif // _TARGET_X86_
6842
6843         if (exceptionCode == STATUS_CLR_GCCOVER_CODE)
6844         {
6845             if (OnGcCoverageInterrupt(pContext))
6846             {
6847                 return true;
6848             }
6849
6850             {
6851                 // ExecutionManager::IsManagedCode takes a spinlock.  Since this is in a debug-only
6852                 // check, we'll allow the lock.
6853                 CONTRACT_VIOLATION(TakesLockViolation);
6854
6855                 // Should never be in managed code.
6856                 CONSISTENCY_CHECK_MSG(!ExecutionManager::IsManagedCode(GetIP(pContext)), "hit privileged instruction!");
6857             }
6858         }
6859     }
6860 #else
6861     LIMITED_METHOD_CONTRACT;
6862 #endif // HAVE_GCCOVER
6863     return false;
6864 }
6865
6866 #ifndef FEATURE_PAL
6867
6868 // Return true if the access violation is well formed (has two info parameters
6869 // at the end)
6870 static inline BOOL
6871 IsWellFormedAV(EXCEPTION_RECORD *pExceptionRecord)
6872 {
6873     LIMITED_METHOD_CONTRACT;
6874
6875     #define NUM_AV_PARAMS 2
6876
6877     if (pExceptionRecord->NumberParameters == NUM_AV_PARAMS)
6878     {
6879         return TRUE;
6880     }
6881     else
6882     {
6883         return FALSE;
6884     }
6885 }
6886
6887 static inline BOOL
6888 IsDebuggerFault(EXCEPTION_RECORD *pExceptionRecord,
6889                 CONTEXT *pContext,
6890                 DWORD exceptionCode,
6891                 Thread *pThread)
6892 {
6893     LIMITED_METHOD_CONTRACT;
6894
6895 #ifdef DEBUGGING_SUPPORTED
6896     SO_NOT_MAINLINE_FUNCTION;
6897
6898 #ifdef _TARGET_ARM_
6899     // On ARM we don't have any reliable hardware support for single stepping so it is emulated in software.
6900     // The implementation will end up throwing an EXCEPTION_BREAKPOINT rather than an EXCEPTION_SINGLE_STEP
6901     // and leaves other aspects of the thread context in an invalid state. Therefore we use this opportunity
6902     // to fixup the state before any other part of the system uses it (we do it here since only the debugger
6903     // uses single step functionality).
6904
6905     // First ask the emulation itself whether this exception occurred while single stepping was enabled. If so
6906     // it will fix up the context to be consistent again and return true. If so and the exception was
6907     // EXCEPTION_BREAKPOINT then we translate it to EXCEPTION_SINGLE_STEP (otherwise we leave it be, e.g. the
6908     // instruction stepped caused an access violation).  since this is called from our VEH there might not
6909     // be a thread object so we must check pThread first.
6910     if ((pThread != NULL) && pThread->HandleSingleStep(pContext, exceptionCode) && (exceptionCode == EXCEPTION_BREAKPOINT))
6911     {
6912         exceptionCode = EXCEPTION_SINGLE_STEP;
6913         pExceptionRecord->ExceptionCode = EXCEPTION_SINGLE_STEP;
6914         pExceptionRecord->ExceptionAddress = (PVOID)pContext->Pc;
6915     }
6916 #endif // _TARGET_ARM_
6917
6918     // Is this exception really meant for the COM+ Debugger? Note: we will let the debugger have a chance if there
6919     // is a debugger attached to any part of the process. It is incorrect to consider whether or not the debugger
6920     // is attached the the thread's current app domain at this point.
6921
6922     // Even if a debugger is not attached, we must let the debugger handle the exception in case it's coming from a
6923     // patch-skipper.
6924     if ((!IsComPlusException(pExceptionRecord)) &&
6925         (GetThread() != NULL) &&
6926         (g_pDebugInterface != NULL) &&
6927         g_pDebugInterface->FirstChanceNativeException(pExceptionRecord,
6928                                                       pContext,
6929                                                       exceptionCode,
6930                                                       pThread))
6931     {
6932         LOG((LF_EH | LF_CORDB, LL_INFO1000, "IsDebuggerFault - it's the debugger's fault\n"));
6933         return true;
6934     }
6935 #endif // DEBUGGING_SUPPORTED
6936     return false;
6937 }
6938
6939 #endif // FEATURE_PAL
6940
6941 #ifdef WIN64EXCEPTIONS
6942
6943 #ifndef _TARGET_X86_
6944 EXTERN_C void JIT_MemSet_End();
6945 EXTERN_C void JIT_MemCpy_End();
6946
6947 EXTERN_C void JIT_WriteBarrier_End();
6948 EXTERN_C void JIT_CheckedWriteBarrier_End();
6949 #endif // _TARGET_X86_
6950
6951 #if defined(_TARGET_AMD64_) && defined(_DEBUG)
6952 EXTERN_C void JIT_WriteBarrier_Debug();
6953 EXTERN_C void JIT_WriteBarrier_Debug_End();
6954 #endif
6955
6956 #ifdef _TARGET_ARM_
6957 EXTERN_C void FCallMemcpy_End();
6958 #endif
6959
6960 // Check if the passed in instruction pointer is in one of the
6961 // JIT helper functions.
6962 bool IsIPInMarkedJitHelper(UINT_PTR uControlPc)
6963 {
6964     LIMITED_METHOD_CONTRACT;
6965
6966 #define CHECK_RANGE(name) \
6967     if (GetEEFuncEntryPoint(name) <= uControlPc && uControlPc < GetEEFuncEntryPoint(name##_End)) return true;
6968
6969 #ifndef _TARGET_X86_
6970     CHECK_RANGE(JIT_MemSet)
6971     CHECK_RANGE(JIT_MemCpy)
6972
6973     CHECK_RANGE(JIT_WriteBarrier)
6974     CHECK_RANGE(JIT_CheckedWriteBarrier)
6975 #else
6976 #ifdef FEATURE_PAL
6977     CHECK_RANGE(JIT_WriteBarrierGroup)
6978     CHECK_RANGE(JIT_PatchedWriteBarrierGroup)
6979 #endif // FEATURE_PAL
6980 #endif // _TARGET_X86_
6981
6982 #if defined(_TARGET_AMD64_) && defined(_DEBUG)
6983     CHECK_RANGE(JIT_WriteBarrier_Debug)
6984 #endif
6985
6986 #ifdef _TARGET_ARM_
6987     CHECK_RANGE(FCallMemcpy)
6988 #endif
6989
6990     return false;
6991 }
6992 #endif // WIN64EXCEPTIONS
6993
6994 // Returns TRUE if caller should resume execution.
6995 BOOL
6996 AdjustContextForWriteBarrier(
6997         EXCEPTION_RECORD *pExceptionRecord,
6998         CONTEXT *pContext)
6999 {
7000     WRAPPER_NO_CONTRACT;
7001
7002 #if defined(_TARGET_X86_) && !defined(PLATFORM_UNIX)
7003     void* f_IP = (void *)GetIP(pContext);
7004
7005     if (((f_IP >= (void *) JIT_WriteBarrierGroup) && (f_IP <= (void *) JIT_WriteBarrierGroup_End)) ||
7006         ((f_IP >= (void *) JIT_PatchedWriteBarrierGroup) && (f_IP <= (void *) JIT_PatchedWriteBarrierGroup_End)))
7007     {
7008         // set the exception IP to be the instruction that called the write barrier
7009         void* callsite = (void *)GetAdjustedCallAddress(*dac_cast<PTR_PCODE>(GetSP(pContext)));
7010         pExceptionRecord->ExceptionAddress = callsite;
7011         SetIP(pContext, (PCODE)callsite);
7012
7013         // put ESP back to what it was before the call.
7014         SetSP(pContext, PCODE((BYTE*)GetSP(pContext) + sizeof(void*)));
7015     }
7016     return FALSE;
7017 #elif defined(WIN64EXCEPTIONS) // _TARGET_X86_ && !PLATFORM_UNIX
7018     void* f_IP = dac_cast<PTR_VOID>(GetIP(pContext));
7019
7020     CONTEXT             tempContext;
7021     CONTEXT*            pExceptionContext = pContext;
7022
7023     BOOL fExcluded = IsIPInMarkedJitHelper((UINT_PTR)f_IP);
7024
7025     if (fExcluded)
7026     {
7027         bool fShouldHandleManagedFault = false;
7028
7029         if (pContext != &tempContext)
7030         {
7031             tempContext = *pContext;
7032             pContext = &tempContext;
7033         }
7034
7035         Thread::VirtualUnwindToFirstManagedCallFrame(pContext);
7036
7037 #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
7038         // We had an AV in the writebarrier that needs to be treated
7039         // as originating in managed code. At this point, the stack (growing
7040         // from left->right) looks like this:
7041         //
7042         // ManagedFunc -> Native_WriteBarrierInVM -> AV
7043         //
7044         // We just performed an unwind from the write-barrier
7045         // and now have the context in ManagedFunc. Since 
7046         // ManagedFunc called into the write-barrier, the return
7047         // address in the unwound context corresponds to the
7048         // instruction where the call will return.
7049         //
7050         // On ARM, just like we perform ControlPC adjustment
7051         // during exception dispatch (refer to ExceptionTracker::InitializeCrawlFrame),
7052         // we will need to perform the corresponding adjustment of IP
7053         // we got from unwind above, so as to indicate that the AV
7054         // happened "before" the call to the writebarrier and not at
7055         // the instruction at which the control will return.
7056        PCODE ControlPCPostAdjustment = GetIP(pContext) - STACKWALK_CONTROLPC_ADJUST_OFFSET;
7057        
7058        // Now we save the address back into the context so that it gets used
7059        // as the faulting address.
7060        SetIP(pContext, ControlPCPostAdjustment);
7061 #endif // _TARGET_ARM_ || _TARGET_ARM64_
7062
7063         // Unwind the frame chain - On Win64, this is required since we may handle the managed fault and to do so,
7064         // we will replace the exception context with the managed context and "continue execution" there. Thus, we do not
7065         // want any explicit frames active below the resumption SP.
7066         //
7067         // Question: Why do we unwind before determining whether we will handle the exception or not?
7068         UnwindFrameChain(GetThread(), (Frame*)GetSP(pContext));
7069         fShouldHandleManagedFault = ShouldHandleManagedFault(pExceptionRecord,pContext,
7070                                NULL, // establisher frame (x86 only)
7071                                NULL  // pThread           (x86 only)
7072                                );
7073
7074         if (fShouldHandleManagedFault)
7075         {
7076             ReplaceExceptionContextRecord(pExceptionContext, pContext);
7077             pExceptionRecord->ExceptionAddress = dac_cast<PTR_VOID>(GetIP(pContext));
7078             return TRUE;
7079         }
7080     }
7081
7082     return FALSE;
7083 #else // WIN64EXCEPTIONS
7084     PORTABILITY_ASSERT("AdjustContextForWriteBarrier");
7085     return FALSE;
7086 #endif // ELSE
7087 }
7088
7089 #if defined(USE_FEF) && !defined(FEATURE_PAL)
7090
7091 struct SavedExceptionInfo
7092 {
7093     EXCEPTION_RECORD m_ExceptionRecord;
7094     CONTEXT m_ExceptionContext;
7095     CrstStatic m_Crst;
7096
7097     void SaveExceptionRecord(EXCEPTION_RECORD *pExceptionRecord)
7098     {
7099         LIMITED_METHOD_CONTRACT;
7100         size_t erSize = offsetof(EXCEPTION_RECORD, ExceptionInformation) +
7101             pExceptionRecord->NumberParameters * sizeof(pExceptionRecord->ExceptionInformation[0]);
7102         memcpy(&m_ExceptionRecord, pExceptionRecord, erSize);
7103
7104     }
7105
7106     void SaveContext(CONTEXT *pContext)
7107     {
7108         LIMITED_METHOD_CONTRACT;
7109 #ifdef CONTEXT_EXTENDED_REGISTERS
7110
7111         size_t contextSize = offsetof(CONTEXT, ExtendedRegisters);
7112         if ((pContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
7113             contextSize += sizeof(pContext->ExtendedRegisters);
7114         memcpy(&m_ExceptionContext, pContext, contextSize);
7115
7116 #else // !CONTEXT_EXTENDED_REGISTERS
7117
7118         size_t contextSize = sizeof(CONTEXT);
7119         memcpy(&m_ExceptionContext, pContext, contextSize);
7120
7121 #endif // !CONTEXT_EXTENDED_REGISTERS
7122     }
7123
7124     DEBUG_NOINLINE void Enter()
7125     {
7126         WRAPPER_NO_CONTRACT;
7127         ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
7128         m_Crst.Enter();
7129     }
7130
7131     DEBUG_NOINLINE void Leave()
7132     {
7133         WRAPPER_NO_CONTRACT;
7134         ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
7135         m_Crst.Leave();
7136     }
7137
7138     void Init()
7139     {
7140         WRAPPER_NO_CONTRACT;
7141         m_Crst.Init(CrstSavedExceptionInfo, CRST_UNSAFE_ANYMODE);
7142     }
7143 };
7144
7145 SavedExceptionInfo g_SavedExceptionInfo;  // Globals are guaranteed zero-init;
7146
7147 void InitSavedExceptionInfo()
7148 {
7149     g_SavedExceptionInfo.Init();
7150 }
7151
7152 EXTERN_C VOID FixContextForFaultingExceptionFrame (
7153         EXCEPTION_RECORD* pExceptionRecord,
7154         CONTEXT *pContextRecord)
7155 {
7156     WRAPPER_NO_CONTRACT;
7157
7158     // don't copy parm args as have already supplied them on the throw
7159     memcpy((void*) pExceptionRecord,
7160            (void*) &g_SavedExceptionInfo.m_ExceptionRecord,
7161            offsetof(EXCEPTION_RECORD, ExceptionInformation)
7162           );
7163
7164     ReplaceExceptionContextRecord(pContextRecord, &g_SavedExceptionInfo.m_ExceptionContext);
7165
7166     g_SavedExceptionInfo.Leave();
7167
7168     GetThread()->ResetThreadStateNC(Thread::TSNC_DebuggerIsManagedException);
7169 }
7170
7171 EXTERN_C VOID __fastcall
7172 LinkFrameAndThrow(FaultingExceptionFrame* pFrame)
7173 {
7174     WRAPPER_NO_CONTRACT;
7175
7176     *(TADDR*)pFrame = FaultingExceptionFrame::GetMethodFrameVPtr();
7177     *pFrame->GetGSCookiePtr() = GetProcessGSCookie();
7178
7179     pFrame->InitAndLink(&g_SavedExceptionInfo.m_ExceptionContext);
7180
7181     GetThread()->SetThreadStateNC(Thread::TSNC_DebuggerIsManagedException);
7182
7183     ULONG       argcount = g_SavedExceptionInfo.m_ExceptionRecord.NumberParameters;
7184     ULONG       flags    = g_SavedExceptionInfo.m_ExceptionRecord.ExceptionFlags;
7185     ULONG       code     = g_SavedExceptionInfo.m_ExceptionRecord.ExceptionCode;
7186     ULONG_PTR*  args     = &g_SavedExceptionInfo.m_ExceptionRecord.ExceptionInformation[0];
7187
7188     RaiseException(code, flags, argcount, args);
7189 }
7190
7191 void SetNakedThrowHelperArgRegistersInContext(CONTEXT* pContext)
7192 {
7193 #if defined(_TARGET_AMD64_)
7194     pContext->Rcx = (UINT_PTR)GetIP(pContext);
7195 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
7196     // Save the original IP in LR
7197     pContext->Lr = (DWORD)GetIP(pContext);
7198 #else
7199     PORTABILITY_WARNING("NakedThrowHelper argument not defined");
7200 #endif
7201 }
7202
7203 EXTERN_C VOID STDCALL NakedThrowHelper(VOID);
7204
7205 void HandleManagedFault(EXCEPTION_RECORD*               pExceptionRecord,
7206                         CONTEXT*                        pContext,
7207                         EXCEPTION_REGISTRATION_RECORD*  pEstablisherFrame,
7208                         Thread*                         pThread)
7209 {
7210     WRAPPER_NO_CONTRACT;
7211
7212     // Ok.  Now we have a brand new fault in jitted code.
7213     g_SavedExceptionInfo.Enter();
7214     g_SavedExceptionInfo.SaveExceptionRecord(pExceptionRecord);
7215     g_SavedExceptionInfo.SaveContext(pContext);
7216
7217     SetNakedThrowHelperArgRegistersInContext(pContext);
7218
7219     SetIP(pContext, GetEEFuncEntryPoint(NakedThrowHelper));
7220 }
7221
7222 #else // USE_FEF && !FEATURE_PAL
7223
7224 void InitSavedExceptionInfo()
7225 {
7226 }
7227
7228 #endif // USE_FEF && !FEATURE_PAL
7229
7230 //
7231 // Init a new frame
7232 //
7233 void FaultingExceptionFrame::Init(CONTEXT *pContext)
7234 {
7235     WRAPPER_NO_CONTRACT;
7236 #ifndef WIN64EXCEPTIONS
7237 #ifdef _TARGET_X86_
7238     CalleeSavedRegisters *pRegs = GetCalleeSavedRegisters();
7239 #define CALLEE_SAVED_REGISTER(regname) pRegs->regname = pContext->regname;
7240     ENUM_CALLEE_SAVED_REGISTERS();
7241 #undef CALLEE_SAVED_REGISTER
7242     m_ReturnAddress = ::GetIP(pContext);
7243     m_Esp = (DWORD)GetSP(pContext);
7244 #else // _TARGET_X86_
7245     PORTABILITY_ASSERT("FaultingExceptionFrame::Init");
7246 #endif // _TARGET_???_ (ELSE)
7247 #else // !WIN64EXCEPTIONS
7248     m_ReturnAddress = ::GetIP(pContext);
7249     CopyOSContext(&m_ctx, pContext);
7250 #endif // !WIN64EXCEPTIONS
7251 }
7252
7253 //
7254 // Init and Link in a new frame
7255 //
7256 void FaultingExceptionFrame::InitAndLink(CONTEXT *pContext)
7257 {
7258     WRAPPER_NO_CONTRACT;
7259
7260     Init(pContext);
7261
7262     Push();
7263 }
7264
7265
7266 bool ShouldHandleManagedFault(
7267                         EXCEPTION_RECORD*               pExceptionRecord,
7268                         CONTEXT*                        pContext,
7269                         EXCEPTION_REGISTRATION_RECORD*  pEstablisherFrame,
7270                         Thread*                         pThread)
7271 {
7272     CONTRACTL
7273     {
7274         NOTHROW;
7275         GC_NOTRIGGER;
7276         SO_TOLERANT;
7277         MODE_ANY;
7278     }
7279     CONTRACTL_END;
7280
7281     // If we get a faulting instruction inside managed code, we're going to
7282     //  1. Allocate the correct exception object, store it in the thread.
7283     //  2. Save the EIP in the thread.
7284     //  3. Change the EIP to our throw helper
7285     //  4. Resume execution.
7286     //
7287     //  The helper will push a frame for us, and then throw the correct managed exception.
7288     //
7289     // Is this exception really meant for the COM+ Debugger? Note: we will let the debugger have a chance if there is a
7290     // debugger attached to any part of the process. It is incorrect to consider whether or not the debugger is attached
7291     // the the thread's current app domain at this point.
7292
7293
7294     // A managed exception never comes from managed code, and we can ignore all breakpoint
7295     // exceptions.
7296     //
7297     DWORD exceptionCode = pExceptionRecord->ExceptionCode;
7298     if (IsComPlusException(pExceptionRecord)
7299         || exceptionCode == STATUS_BREAKPOINT
7300         || exceptionCode == STATUS_SINGLE_STEP)
7301     {
7302         return false;
7303     }
7304
7305 #ifdef _DEBUG
7306     // This is a workaround, but it's debug-only as is gc stress 4.
7307     // The problem is that if we get an exception with this code that
7308     // didn't come from GCStress=4, then we won't push a FeF and will
7309     // end up with a gc hole and potential crash.
7310     if (exceptionCode == STATUS_CLR_GCCOVER_CODE)
7311         return false;
7312 #endif // _DEBUG
7313
7314 #ifndef WIN64EXCEPTIONS
7315     // If there's any frame below the ESP of the exception, then we can forget it.
7316     if (pThread->m_pFrame < dac_cast<PTR_VOID>(GetSP(pContext)))
7317         return false;
7318
7319     // If we're a subsequent handler forget it.
7320     EXCEPTION_REGISTRATION_RECORD* pBottomMostHandler = pThread->GetExceptionState()->m_currentExInfo.m_pBottomMostHandler;
7321     if (pBottomMostHandler != NULL && pEstablisherFrame > pBottomMostHandler)
7322     {
7323         return false;
7324     }
7325 #endif // WIN64EXCEPTIONS
7326
7327     {
7328         // If it's not a fault in jitted code, forget it.
7329
7330         // ExecutionManager::IsManagedCode takes a spinlock.  Since we're in the middle of throwing,
7331         // we'll allow the lock, even if a caller didn't expect it.
7332         CONTRACT_VIOLATION(TakesLockViolation);
7333
7334         if (!ExecutionManager::IsManagedCode(GetIP(pContext)))
7335             return false;
7336     }
7337
7338     // caller should call HandleManagedFault and resume execution.
7339     return true;
7340 }
7341
7342 #ifndef FEATURE_PAL
7343
7344 LONG WINAPI CLRVectoredExceptionHandlerPhase2(PEXCEPTION_POINTERS pExceptionInfo);
7345
7346 enum VEH_ACTION
7347 {
7348     VEH_NO_ACTION = 0,
7349     VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION,
7350     VEH_CONTINUE_EXECUTION,
7351     VEH_CONTINUE_SEARCH,
7352     VEH_EXECUTE_HANDLER
7353 };
7354
7355
7356 VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase3(PEXCEPTION_POINTERS pExceptionInfo);
7357
7358 LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
7359 {
7360     // It is not safe to execute code inside VM after we shutdown EE.  One example is DisablePreemptiveGC
7361     // will block forever.
7362     if (g_fForbidEnterEE)
7363     {
7364         return EXCEPTION_CONTINUE_SEARCH;
7365     }
7366
7367     //
7368     // For images ngen'd with FEATURE_LAZY_COW_PAGES, the .data section will be read-only.  Any writes to that data need to be 
7369     // preceded by a call to EnsureWritablePages.  This code is here to catch the ones we forget.
7370     //
7371 #ifdef FEATURE_LAZY_COW_PAGES
7372     if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION && 
7373         IsWellFormedAV(pExceptionInfo->ExceptionRecord) &&
7374         pExceptionInfo->ExceptionRecord->ExceptionInformation[0] == 1 /* means this was a failed write */)
7375     {
7376         void* location = (void*)pExceptionInfo->ExceptionRecord->ExceptionInformation[1];
7377
7378         if (IsInReadOnlyLazyCOWPage(location))
7379         {
7380 #ifdef _DEBUG
7381             if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DebugAssertOnMissedCOWPage))
7382                 _ASSERTE_MSG(false, "Writes to NGen'd data must be protected by EnsureWritablePages.");
7383 #endif
7384
7385 #pragma push_macro("VirtualQuery")
7386 #undef VirtualQuery
7387             MEMORY_BASIC_INFORMATION mbi;
7388             if (!::VirtualQuery(location, &mbi, sizeof(mbi)))
7389             {
7390                 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_OUTOFMEMORY);
7391             }
7392 #pragma pop_macro("VirtualQuery")
7393
7394             bool executable = (mbi.Protect == PAGE_EXECUTE_READ) || 
7395                               (mbi.Protect == PAGE_EXECUTE_READWRITE) || 
7396                               (mbi.Protect == PAGE_EXECUTE_READ) || 
7397                               (mbi.Protect == PAGE_EXECUTE_WRITECOPY);
7398
7399             if (!(executable ? EnsureWritableExecutablePagesNoThrow(location, 1) : EnsureWritablePagesNoThrow(location, 1)))
7400             {
7401                 // Note that this failfast is very rare. It will only be hit in the theoretical cases there is 
7402                 // missing EnsureWritablePages probe (there should be none when we ship), and the OS run into OOM 
7403                 // exactly at the point when we executed the code with the missing probe.
7404                 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_OUTOFMEMORY);
7405             }
7406
7407             return EXCEPTION_CONTINUE_EXECUTION;
7408         }
7409     }
7410 #endif //FEATURE_LAZY_COW_PAGES
7411
7412
7413     //
7414     // DO NOT USE CONTRACTS HERE AS THIS ROUTINE MAY NEVER RETURN.  You can use
7415     // static contracts, but currently this is all WRAPPER_NO_CONTRACT.
7416     //
7417
7418
7419     //
7420     //        READ THIS!
7421     //
7422     //
7423     // You cannot put any code in here that allocates during an out-of-memory handling.
7424     // This routine runs before *any* other handlers, including __try.  Thus, if you
7425     // allocate anything in this routine then it will throw out-of-memory and end up
7426     // right back here.
7427     //
7428     // There are various things that allocate that you may not expect to allocate.  One
7429     // instance of this is STRESS_LOG.  It allocates the log buffer if the thread does
7430     // not already have one allocated.  Thus, if we OOM during the setting up of the
7431     // thread, the log buffer will not be allocated and this will try to do so.  Thus,
7432     // all STRESS_LOGs in here need to be after you have guaranteed the allocation has
7433     // already occurred.
7434     //
7435
7436     Thread *pThread;
7437
7438     {
7439         MAYBE_FAULT_FORBID_NO_ALLOC((pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_NO_MEMORY));
7440
7441         pThread = GetThread();
7442
7443         //
7444         // Since we are in an OOM situation, we test the thread object before logging since if the
7445         // thread exists we know the log buffer has been allocated already.
7446         //
7447         if (pThread != NULL)
7448         {
7449             CantAllocHolder caHolder;
7450             STRESS_LOG4(LF_EH, LL_INFO100, "In CLRVectoredExceptionHandler, Exception = %x, Context = %p, IP = %p SP = %p\n",
7451                     pExceptionInfo->ExceptionRecord->ExceptionCode, pExceptionInfo->ContextRecord,
7452                     GetIP(pExceptionInfo->ContextRecord), GetSP(pExceptionInfo->ContextRecord));
7453         }
7454
7455     }
7456
7457     // We need to unhijack the thread here if it is not unhijacked already.  On x86 systems,
7458     // we do this in Thread::StackWalkFramesEx, but on amd64 systems we have the OS walk the
7459     // stack for us.  If we leave CLRVectoredExceptionHandler with a thread still hijacked,
7460     // the operating system will not be able to walk the stack and not find the handlers for
7461     // the exception.  It is safe to unhijack the thread in this case for two reasons:
7462     // 1.  pThread refers to *this* thread.
7463     // 2.  If another thread tries to hijack this thread, it will see we are not in managed
7464     //     code (and thus won't try to hijack us).
7465 #if defined(WIN64EXCEPTIONS) && defined(FEATURE_HIJACK)
7466     if (pThread != NULL)
7467     {
7468         pThread->UnhijackThreadNoAlloc();
7469     }
7470 #endif // defined(WIN64EXCEPTIONS) && defined(FEATURE_HIJACK)
7471
7472 #ifndef FEATURE_PAL
7473     if (IsSOExceptionCode(pExceptionInfo->ExceptionRecord->ExceptionCode))
7474     {
7475         //
7476         // Not an Out-of-memory situation, so no need for a forbid fault region here
7477         //
7478         return EXCEPTION_CONTINUE_SEARCH;
7479     }
7480
7481     LONG retVal = 0;
7482
7483 #ifdef FEATURE_STACK_PROBE
7484     // See if we've got enough stack to handle this exception
7485
7486     // There isn't much stack left to attempt to report an exception. Let's trigger a hard
7487     // SO, so we clear the guard page and give us at least another page of stack to work with.
7488
7489     if (pThread && !pThread->IsStackSpaceAvailable(ADJUST_PROBE(1)))
7490     {
7491         DontCallDirectlyForceStackOverflow();
7492     }
7493 #endif // FEATURE_STACK_PROBE
7494
7495     // We can't probe here, because we won't return from the CLRVectoredExceptionHandlerPhase2
7496     // on WIN64
7497     //
7498
7499     if (pThread)
7500     {
7501         FAULT_FORBID_NO_ALLOC();
7502         CantAllocHolder caHolder;
7503     }
7504
7505     retVal = CLRVectoredExceptionHandlerPhase2(pExceptionInfo);
7506
7507     //
7508         //END_ENTRYPOINT_VOIDRET;
7509     //
7510     return retVal;
7511 #else // !FEATURE_PAL
7512     return CLRVectoredExceptionHandlerPhase2(pExceptionInfo);
7513 #endif // !FEATURE_PAL
7514 }
7515
7516 LONG WINAPI CLRVectoredExceptionHandlerPhase2(PEXCEPTION_POINTERS pExceptionInfo)
7517 {
7518     //
7519     // DO NOT USE CONTRACTS HERE AS THIS ROUTINE MAY NEVER RETURN.  You can use
7520     // static contracts, but currently this is all WRAPPER_NO_CONTRACT.
7521     //
7522
7523     //
7524     //        READ THIS!
7525     //
7526     //
7527     // You cannot put any code in here that allocates during an out-of-memory handling.
7528     // This routine runs before *any* other handlers, including __try.  Thus, if you
7529     // allocate anything in this routine then it will throw out-of-memory and end up
7530     // right back here.
7531     //
7532     // There are various things that allocate that you may not expect to allocate.  One
7533     // instance of this is STRESS_LOG.  It allocates the log buffer if the thread does
7534     // not already have one allocated.  Thus, if we OOM during the setting up of the
7535     // thread, the log buffer will not be allocated and this will try to do so.  Thus,
7536     // all STRESS_LOGs in here need to be after you have guaranteed the allocation has
7537     // already occurred.
7538     //
7539
7540     PEXCEPTION_RECORD pExceptionRecord  = pExceptionInfo->ExceptionRecord;
7541     VEH_ACTION action;
7542
7543     {
7544         MAYBE_FAULT_FORBID_NO_ALLOC((pExceptionRecord->ExceptionCode == STATUS_NO_MEMORY));
7545         CantAllocHolder caHolder;
7546
7547         action = CLRVectoredExceptionHandlerPhase3(pExceptionInfo);
7548     }
7549
7550     if (action == VEH_CONTINUE_EXECUTION)
7551     {
7552         return EXCEPTION_CONTINUE_EXECUTION;
7553     }
7554
7555     if (action == VEH_CONTINUE_SEARCH)
7556     {
7557         return EXCEPTION_CONTINUE_SEARCH;
7558     }
7559
7560     if (action == VEH_EXECUTE_HANDLER)
7561     {
7562         return EXCEPTION_EXECUTE_HANDLER;
7563     }
7564
7565 #if defined(WIN64EXCEPTIONS)
7566
7567     if (action == VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION)
7568     {
7569         //
7570         // If the exception context was unwound by Phase3 then
7571         // we'll jump here to save the managed context and resume execution at
7572         // NakedThrowHelper.  This needs to be done outside of any holder's
7573         // scope, because HandleManagedFault may not return.
7574         //
7575         HandleManagedFault(pExceptionInfo->ExceptionRecord,
7576                            pExceptionInfo->ContextRecord,
7577                            NULL, // establisher frame (x86 only)
7578                            NULL  // pThread           (x86 only)
7579                            );
7580         return EXCEPTION_CONTINUE_EXECUTION;
7581     }
7582
7583 #endif // defined(WIN64EXCEPTIONS)
7584
7585
7586     //
7587     // In OOM situations, this call better not fault.
7588     //
7589     {
7590         MAYBE_FAULT_FORBID_NO_ALLOC((pExceptionRecord->ExceptionCode == STATUS_NO_MEMORY));
7591         CantAllocHolder caHolder;
7592
7593         // Give the debugger a chance. Note that its okay for this call to trigger a GC, since the debugger will take
7594         // special steps to make that okay.
7595         //
7596         // @TODO: I'd love a way to call into the debugger with GCX_NOTRIGGER still in scope, and force them to make
7597         // the choice to break the no-trigger region after taking all necessary precautions.
7598         if (IsDebuggerFault(pExceptionRecord, pExceptionInfo->ContextRecord, pExceptionRecord->ExceptionCode, GetThread()))
7599         {
7600             return EXCEPTION_CONTINUE_EXECUTION;
7601         }
7602     }
7603
7604     //
7605     // No reason to put a forbid fault region here as the exception code is not STATUS_NO_MEMORY.
7606     //
7607
7608     // Handle a user breakpoint. Note that its okay for the UserBreakpointFilter to trigger a GC, since we're going
7609     // to either a) terminate the process, or b) let a user attach an unmanaged debugger, and debug knowing that
7610     // managed state may be messed up.
7611     if ((pExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) ||
7612         (pExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP))
7613     {
7614         // A breakpoint outside managed code and outside the runtime will have to be handled by some
7615         //  other piece of code.
7616
7617         BOOL fExternalException = FALSE;
7618
7619         BEGIN_SO_INTOLERANT_CODE_NOPROBE;
7620
7621         {
7622             // ExecutionManager::IsManagedCode takes a spinlock.  Since we're in the middle of throwing,
7623             // we'll allow the lock, even if a caller didn't expect it.
7624             CONTRACT_VIOLATION(TakesLockViolation);
7625
7626             fExternalException = (!ExecutionManager::IsManagedCode(GetIP(pExceptionInfo->ContextRecord)) &&
7627                                   !IsIPInModule(g_pMSCorEE, GetIP(pExceptionInfo->ContextRecord)));
7628         }
7629
7630         END_SO_INTOLERANT_CODE_NOPROBE;
7631
7632         if (fExternalException)
7633         {
7634             // The breakpoint was not ours.  Someone else can handle it.  (Or if not, we'll get it again as
7635             //  an unhandled exception.)
7636             return EXCEPTION_CONTINUE_SEARCH;
7637         }
7638
7639         // The breakpoint was from managed or the runtime.  Handle it.  Or,
7640         //  this may be a Rotor build.
7641         return UserBreakpointFilter(pExceptionInfo);
7642     }
7643
7644 #if defined(WIN64EXCEPTIONS)
7645     BOOL fShouldHandleManagedFault;
7646
7647     {
7648         MAYBE_FAULT_FORBID_NO_ALLOC((pExceptionRecord->ExceptionCode == STATUS_NO_MEMORY));
7649         CantAllocHolder caHolder;
7650         fShouldHandleManagedFault = ShouldHandleManagedFault(pExceptionInfo->ExceptionRecord,
7651                                                              pExceptionInfo->ContextRecord,
7652                                                              NULL, // establisher frame (x86 only)
7653                                                              NULL  // pThread           (x86 only)
7654                                                             );
7655     }
7656
7657     if (fShouldHandleManagedFault)
7658     {
7659         //
7660         // HandleManagedFault may never return, so we cannot use a forbid fault region around it.
7661         //
7662         HandleManagedFault(pExceptionInfo->ExceptionRecord,
7663                            pExceptionInfo->ContextRecord,
7664                            NULL, // establisher frame (x86 only)
7665                            NULL  // pThread           (x86 only)
7666                            );
7667         return EXCEPTION_CONTINUE_EXECUTION;
7668 }
7669 #endif // defined(WIN64EXCEPTIONS)
7670
7671     return EXCEPTION_EXECUTE_HANDLER;
7672 }
7673
7674 /*
7675  * CLRVectoredExceptionHandlerPhase3
7676  *
7677  * This routine does some basic processing on the exception, making decisions about common
7678  * exception types and whether to continue them or not.  It has side-effects, in that it may
7679  * adjust the context in the exception.
7680  *
7681  * Parameters:
7682  *    pExceptionInfo - pointer to the exception
7683  *
7684  * Returns:
7685  *    VEH_NO_ACTION - This indicates that Phase3 has no specific action to take and that further
7686  *       processing of this exception should continue.
7687  *    VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION - This indicates that the caller should call HandleMandagedException
7688  *       immediately.
7689  *    VEH_CONTINUE_EXECUTION - Caller should return EXCEPTION_CONTINUE_EXECUTION.
7690  *    VEH_CONTINUE_SEARCH - Caller should return EXCEPTION_CONTINUE_SEARCH;
7691  *    VEH_EXECUTE_HANDLER - Caller should return EXCEPTION_EXECUTE_HANDLER.
7692  *
7693  *   Note that in all cases the context in the exception may have been adjusted.
7694  *
7695  */
7696
7697 VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase3(PEXCEPTION_POINTERS pExceptionInfo)
7698 {
7699     //
7700     // DO NOT USE CONTRACTS HERE AS THIS ROUTINE MAY NEVER RETURN.  You can use
7701     // static contracts, but currently this is all WRAPPER_NO_CONTRACT.
7702     //
7703
7704     //
7705     //        READ THIS!
7706     //
7707     //
7708     // You cannot put any code in here that allocates during an out-of-memory handling.
7709     // This routine runs before *any* other handlers, including __try.  Thus, if you
7710     // allocate anything in this routine then it will throw out-of-memory and end up
7711     // right back here.
7712     //
7713     // There are various things that allocate that you may not expect to allocate.  One
7714     // instance of this is STRESS_LOG.  It allocates the log buffer if the thread does
7715     // not already have one allocated.  Thus, if we OOM during the setting up of the
7716     // thread, the log buffer will not be allocated and this will try to do so.  Thus,
7717     // all STRESS_LOGs in here need to be after you have guaranteed the allocation has
7718     // already occurred.
7719     //
7720
7721     // Handle special cases which are common amongst all filters.
7722     PEXCEPTION_RECORD pExceptionRecord  = pExceptionInfo->ExceptionRecord;
7723     PCONTEXT          pContext          = pExceptionInfo->ContextRecord;
7724     DWORD             exceptionCode     = pExceptionRecord->ExceptionCode;
7725
7726         // Its extremely important that no one trigger a GC in here. This is called from CPFH_FirstPassHandler, in
7727         // cases where we've taken an unmanaged exception on a managed thread (AV, divide by zero, etc.) but
7728         // _before_ we've done our work to erect a FaultingExceptionFrame. Thus, the managed frames are
7729         // unprotected. We setup a GCX_NOTRIGGER holder in this scope to prevent us from messing this up. Note
7730         // that the scope of this is limited, since there are times when its okay to trigger even in this special
7731         // case. The debugger is a good example: if it gets a breakpoint in managed code, it has the smarts to
7732         // prevent the GC before enabling GC, thus its okay for it to trigger.
7733
7734     GCX_NOTRIGGER();
7735
7736 #ifdef USE_REDIRECT_FOR_GCSTRESS
7737     // NOTE: this is effectively ifdef (_TARGET_AMD64_ || _TARGET_ARM_), and does not actually trigger
7738     // a GC.  This will redirect the exception context to a stub which will
7739     // push a frame and cause GC.
7740     if (IsGcMarker(exceptionCode, pContext))
7741     {
7742         return VEH_CONTINUE_EXECUTION;;
7743     }
7744 #endif // USE_REDIRECT_FOR_GCSTRESS
7745
7746 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
7747 #ifdef _TARGET_X86_
7748     CPFH_AdjustContextForThreadSuspensionRace(pContext, GetThread());
7749 #endif // _TARGET_X86_
7750 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
7751
7752     // Some other parts of the EE use exceptions in their own nefarious ways.  We do some up-front processing
7753     // here to fix up the exception if needed.
7754     if (exceptionCode == STATUS_ACCESS_VIOLATION)
7755     {
7756         if (IsWellFormedAV(pExceptionRecord))
7757         {
7758             if (AdjustContextForWriteBarrier(pExceptionRecord, pContext))
7759             {
7760                 // On x86, AdjustContextForWriteBarrier simply backs up AV's
7761                 // in write barrier helpers into the calling frame, so that
7762                 // the subsequent logic here sees a managed fault.
7763                 //
7764                 // On 64-bit, some additional work is required..
7765 #ifdef WIN64EXCEPTIONS
7766                 return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION;
7767 #endif // defined(WIN64EXCEPTIONS) 
7768             }
7769             else if (AdjustContextForVirtualStub(pExceptionRecord, pContext))
7770             {
7771 #ifdef WIN64EXCEPTIONS
7772                 return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION;
7773 #endif
7774             }
7775
7776             // Remember the EIP for stress debugging purposes. 
7777             g_LastAccessViolationEIP = (void*) ::GetIP(pContext);
7778
7779             // Note: we have a holder, called AVInRuntimeImplOkayHolder, that tells us that its okay to have an
7780             // AV in the Runtime's implementation in certain places. So, if its okay to have an AV at this
7781             // time, then skip the check for whether or not the AV is in our impl.
7782             // AVs are ok on the Helper thread (for which there is no pThread object,
7783             // and so the AVInRuntime holder doesn't work.
7784             Thread *pThread = GetThread();
7785
7786             bool fAVisOk =
7787                 (IsDbgHelperSpecialThread() || IsETWRundownSpecialThread() || 
7788                     ((pThread != NULL) && (pThread->AVInRuntimeImplOkay())) );
7789
7790
7791             // It is unnecessary to check this on second pass as we would have torn down
7792             // the process on the first pass. Also, the context record is not reliable
7793             // on second pass and this subjects us to false positives.
7794             if ((!fAVisOk) && !(pExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING))
7795             {
7796                 PCODE ip = (PCODE)GetIP(pContext);
7797                 if (IsIPInModule(g_pMSCorEE, ip) || IsIPInModule(GCHeapUtilities::GetGCModule(), ip))
7798                 {
7799                     CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|SOToleranceViolation);
7800
7801                     //
7802                     // If you're debugging, set the debugger to catch first-chance AV's, then simply hit F5 or
7803                     // 'go' and continue after the assert. We'll recgonize that a debugger is attached, and
7804                     // return EXCEPTION_CONTINUE_EXECUTION. You'll re-execute the faulting instruction, and the
7805                     // debugger will stop at the AV. The value of EXCEPTION_CONTINUE_EXECUTION is -1, just in
7806                     // case you need to verify the return value for some reason. If you need to actually debug
7807                     // the failure path, then set your IP around the check below.
7808                     //
7809                     // You can also use Windbg's .cxr command to set the context to pContext.
7810                     //
7811 #if defined(_DEBUG) 
7812                     const char * pStack = "<stack not available>";
7813                     StackScratchBuffer buffer;
7814                     SString sStack;
7815                     if (GetStackTraceAtContext(sStack, pContext))
7816                     {
7817                         pStack = sStack.GetANSI(buffer);
7818                     }
7819
7820                     DWORD tid = GetCurrentThreadId();
7821
7822                     BOOL debuggerPresentBeforeAssert = IsDebuggerPresent();
7823
7824
7825                     CONSISTENCY_CHECK_MSGF(false, ("AV in clr at this callstack:\n------\n%s\n-----\n.AV on tid=0x%x (%d), cxr=%p, exr=%p\n",
7826                         pStack, tid, tid, pContext, pExceptionRecord));
7827
7828                     // @todo - this may not be what we want for interop-debugging...
7829                     //
7830                     // If there was no debugger before the assert, but there is one now, then go ahead and
7831                     // return EXCEPTION_CONTINUE_EXECUTION to re-execute the faulting instruction. This is
7832                     // supposed to be a nice little feature for CLR devs who attach debuggers on the "Av in
7833                     // mscorwks" assert above. Since this is only for that case, its only in debug builds.
7834                     if (!debuggerPresentBeforeAssert && IsDebuggerPresent())
7835                     {
7836                         return VEH_CONTINUE_EXECUTION;;
7837                     }
7838 #endif // defined(_DEBUG)
7839
7840                     EEPOLICY_HANDLE_FATAL_ERROR_USING_EXCEPTION_INFO(COR_E_EXECUTIONENGINE, pExceptionInfo);
7841                 }
7842             }
7843         }
7844     }
7845     else if (exceptionCode == BOOTUP_EXCEPTION_COMPLUS)
7846     {
7847         // Don't handle a boot exception
7848         return VEH_CONTINUE_SEARCH;
7849     }
7850
7851     return VEH_NO_ACTION;
7852 }
7853
7854 #endif // !FEATURE_PAL
7855
7856 BOOL IsIPInEE(void *ip)
7857 {
7858     WRAPPER_NO_CONTRACT;
7859
7860 #if defined(FEATURE_PREJIT) && !defined(FEATURE_PAL)
7861     if ((TADDR)ip > g_runtimeLoadedBaseAddress &&
7862         (TADDR)ip < g_runtimeLoadedBaseAddress + g_runtimeVirtualSize)
7863     {
7864         return TRUE;
7865     }
7866     else
7867 #endif // FEATURE_PREJIT && !FEATURE_PAL
7868     {
7869         return FALSE;
7870     }
7871 }
7872
7873 #if defined(FEATURE_HIJACK) && (!defined(_TARGET_X86_) || defined(FEATURE_PAL))
7874
7875 // This function is used to check if the specified IP is in the prolog or not.
7876 bool IsIPInProlog(EECodeInfo *pCodeInfo)
7877 {
7878     CONTRACTL
7879     {
7880         NOTHROW;
7881         GC_NOTRIGGER;
7882         MODE_ANY;
7883     }
7884     CONTRACTL_END;
7885
7886     bool fInsideProlog = true;
7887
7888     _ASSERTE(pCodeInfo->IsValid());
7889
7890 #ifdef _TARGET_AMD64_
7891
7892     // Optimized version for AMD64 that doesn't need to go through the GC info decoding
7893     PTR_RUNTIME_FUNCTION funcEntry = pCodeInfo->GetFunctionEntry();
7894
7895     // We should always get a function entry for a managed method
7896     _ASSERTE(funcEntry != NULL);
7897
7898     // Get the unwindInfo from the function entry
7899     PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(pCodeInfo->GetModuleBase() + funcEntry->UnwindData);
7900
7901     // Check if the specified IP is beyond the prolog or not.
7902     DWORD prologLen = pUnwindInfo->SizeOfProlog;
7903
7904 #else // _TARGET_AMD64_
7905
7906     GCInfoToken    gcInfoToken = pCodeInfo->GetGCInfoToken();
7907
7908 #ifdef USE_GC_INFO_DECODER
7909
7910     GcInfoDecoder gcInfoDecoder(
7911         gcInfoToken,
7912         DECODE_PROLOG_LENGTH
7913     );
7914
7915     DWORD prologLen = gcInfoDecoder.GetPrologSize();
7916
7917 #else // USE_GC_INFO_DECODER
7918
7919     size_t prologLen;
7920     pCodeInfo->GetCodeManager()->IsInPrologOrEpilog(0, gcInfoToken, &prologLen);
7921
7922 #endif // USE_GC_INFO_DECODER
7923
7924 #endif // _TARGET_AMD64_
7925
7926     if (pCodeInfo->GetRelOffset() >= prologLen)
7927     {
7928         fInsideProlog = false;
7929     }
7930
7931     return fInsideProlog;
7932 }
7933
7934 // This function is used to check if the specified IP is in the epilog or not.
7935 bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSafeToInjectThreadAbort)
7936 {
7937     CONTRACTL
7938     {
7939         NOTHROW;
7940         GC_NOTRIGGER;
7941         MODE_ANY;
7942         PRECONDITION(pContextToCheck != NULL);
7943         PRECONDITION(ExecutionManager::IsManagedCode(GetIP(pContextToCheck)));
7944         PRECONDITION(pSafeToInjectThreadAbort != NULL);
7945     }
7946     CONTRACTL_END;
7947
7948     TADDR ipToCheck = GetIP(pContextToCheck);
7949
7950     _ASSERTE(pCodeInfo->IsValid());
7951
7952     // The Codeinfo should correspond to the IP we are interested in.
7953     _ASSERTE(PCODEToPINSTR(ipToCheck) == pCodeInfo->GetCodeAddress());
7954
7955     // By default, assume its safe to inject the abort.
7956     *pSafeToInjectThreadAbort = TRUE;
7957
7958     // If we are inside a prolog, then we are obviously not in the epilog.
7959     // Its safe to inject the abort here.
7960     if (IsIPInProlog(pCodeInfo))
7961     {
7962         return false;
7963     }
7964
7965     // We are not inside the prolog. We could either be in the middle of the method body or
7966     // inside the epilog. While unwindInfo contains the prolog length, it does not contain the
7967     // epilog length.
7968     // 
7969     // Thus, to determine if we are inside the epilog, we use a property of RtlVirtualUnwind.
7970     // When invoked for an IP, it will return a NULL for personality routine in only two scenarios:
7971     //
7972     // 1) The unwindInfo does not contain any personality routine information, OR
7973     // 2) The IP is in prolog or epilog.
7974     //
7975     // For jitted code, (1) is not applicable since we *always* emit details of the managed personality routine
7976     // in the unwindInfo. Thus, since we have already determined that we are not inside the prolog, if performing
7977     // RtlVirtualUnwind against "ipToCheck" results in a NULL personality routine, it implies that we are inside
7978     // the epilog.
7979
7980     DWORD_PTR imageBase = 0;
7981     CONTEXT tempContext;
7982     PVOID HandlerData;
7983     DWORD_PTR establisherFrame = 0;
7984     PEXCEPTION_ROUTINE personalityRoutine = NULL;
7985
7986     // Lookup the function entry for the IP
7987     PTR_RUNTIME_FUNCTION funcEntry = pCodeInfo->GetFunctionEntry();
7988
7989     // We should always get a function entry for a managed method
7990     _ASSERTE(funcEntry != NULL);
7991
7992     imageBase = pCodeInfo->GetModuleBase();
7993
7994     ZeroMemory(&tempContext, sizeof(CONTEXT));
7995     CopyOSContext(&tempContext, pContextToCheck);
7996     KNONVOLATILE_CONTEXT_POINTERS ctxPtrs;
7997     ZeroMemory(&ctxPtrs, sizeof(ctxPtrs));
7998
7999     personalityRoutine = RtlVirtualUnwind(UNW_FLAG_EHANDLER,     // HandlerType
8000                      imageBase,
8001                      ipToCheck,
8002                      funcEntry,
8003                      &tempContext,
8004                      &HandlerData,
8005                      &establisherFrame,
8006                      &ctxPtrs);
8007
8008     bool fIsInEpilog = false;
8009
8010     if (personalityRoutine == NULL)
8011     {
8012         // We are in epilog. 
8013         fIsInEpilog = true;
8014
8015 #ifdef _TARGET_AMD64_
8016         // Check if context pointers has returned the address of the stack location in the hijacked function
8017         // from where RBP was restored. If the address is NULL, then it implies that RBP has been popped off.
8018         // Since JIT64 ensures that pop of RBP is the last instruction before ret/jmp, it implies its not safe
8019         // to inject an abort @ this point as EstablisherFrame (which will be based
8020         // of RBP for managed code since that is the FramePointer register, as indicated in the UnwindInfo)
8021         // will be off and can result in bad managed exception dispatch.
8022         if (ctxPtrs.Rbp == NULL)
8023 #endif
8024         {
8025             *pSafeToInjectThreadAbort = FALSE;
8026         }
8027     }
8028
8029     return fIsInEpilog;
8030 }
8031
8032 #endif // FEATURE_HIJACK && (!_TARGET_X86_ || FEATURE_PAL)
8033
8034 #define EXCEPTION_VISUALCPP_DEBUGGER        ((DWORD) (1<<30 | 0x6D<<16 | 5000))
8035
8036 #if defined(_TARGET_X86_)
8037
8038 // This holder is used to capture the FPU state, reset it to what the CLR expects
8039 // and then restore the original state that was captured.
8040 //
8041 // FPU has a set of exception masks which the CLR expects to be always set,
8042 // implying that any corresponding condition will *not* result in FPU raising
8043 // an exception.
8044 //
8045 // However, native code (e.g. high precision math libs) can change this mask.
8046 // Thus, when control enters the CLR (e.g. via exception dispatch into the VEH),
8047 // we will end up using floating point instructions that could satify the exception mask
8048 // condition and raise an exception. This could result in an infinite loop, resulting in
8049 // SO.
8050 //
8051 // We use this holder to protect applicable parts of the runtime from running into such cases.
8052 extern "C" void CaptureFPUContext(BYTE *pFPBUBuf);
8053 extern "C" void RestoreFPUContext(BYTE *pFPBUBuf);
8054
8055 // This is FPU specific and only applicable to x86 on Windows.
8056 class FPUStateHolder
8057 {
8058     // Capturing FPU state requires a 28byte buffer
8059     BYTE m_bufFPUState[28];
8060
8061 public:
8062     FPUStateHolder()
8063     {
8064         LIMITED_METHOD_CONTRACT;
8065
8066         BYTE *pFPUBuf = m_bufFPUState;
8067
8068         // Save the FPU state using the non-waiting instruction
8069         // so that FPU may not raise an exception incase the
8070         // exception masks are unset in the FPU Control Word
8071         CaptureFPUContext(pFPUBuf);
8072
8073         // Reset the FPU state
8074         ResetCurrentContext();
8075     }
8076
8077     ~FPUStateHolder()
8078     {
8079         LIMITED_METHOD_CONTRACT;
8080
8081         BYTE *pFPUBuf = m_bufFPUState;
8082
8083         // Restore the capture FPU state
8084         RestoreFPUContext(pFPUBuf);
8085     }
8086 };
8087
8088 #endif // defined(_TARGET_X86_)
8089
8090 #ifndef FEATURE_PAL
8091
8092 LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo)
8093 {
8094     //
8095     // HandleManagedFault will take a Crst that causes an unbalanced
8096     // notrigger scope, and this contract will whack the thread's
8097     // ClrDebugState to what it was on entry in the dtor, which causes
8098     // us to assert when we finally release the Crst later on.
8099     //
8100 //    CONTRACTL
8101 //    {
8102 //        NOTHROW;
8103 //        GC_NOTRIGGER;
8104 //        MODE_ANY;
8105 //    }
8106 //    CONTRACTL_END;
8107
8108     //
8109     // WARNING WARNING WARNING WARNING WARNING WARNING WARNING
8110     //
8111     // o This function should not call functions that acquire
8112     //   synchronization objects or allocate memory, because this
8113     //   can cause problems.  <-- quoteth MSDN  -- probably for
8114     //   the same reason as we cannot use LOG(); we'll recurse
8115     //   into a stack overflow.
8116     //
8117     // o You cannot use LOG() in here because that will trigger an
8118     //   exception which will cause infinite recursion with this
8119     //   function.  We work around this by ignoring all non-error
8120     //   exception codes, which serves as the base of the recursion.
8121     //   That way, we can LOG() from the rest of the function
8122     //
8123     // The same goes for any function called by this
8124     // function.
8125     //
8126     // WARNING WARNING WARNING WARNING WARNING WARNING WARNING
8127     //
8128
8129     // If exceptions (or runtime) have been disabled, then simply return.
8130     if (g_fForbidEnterEE || g_fNoExceptions)
8131     {
8132         return EXCEPTION_CONTINUE_SEARCH;
8133     }
8134
8135     // WARNING
8136     //
8137     // We must preserve this so that GCStress=4 eh processing doesnt kill last error.
8138     // Note that even GetThread below can affect the LastError.
8139     // Keep this in mind when adding code above this line!
8140     //
8141     // WARNING
8142     DWORD dwLastError = GetLastError();
8143
8144 #if defined(_TARGET_X86_)
8145     // Capture the FPU state before we do anything involving floating point instructions
8146     FPUStateHolder captureFPUState;
8147 #endif // defined(_TARGET_X86_)
8148
8149 #ifdef FEATURE_INTEROP_DEBUGGING
8150     // For interop debugging we have a fancy exception queueing stunt. When the debugger
8151     // initially gets the first chance exception notification it may not know whether to
8152     // continue it handled or unhandled, but it must continue the process to allow the
8153     // in-proc helper thread to work. What it does is continue the exception unhandled which
8154     // will let the thread immediately execute to this point. Inside this worker the thread
8155     // will block until the debugger knows how to continue the exception. If it decides the
8156     // exception was handled then we immediately resume execution as if the exeption had never
8157     // even been allowed to run into this handler. If it is unhandled then we keep processing
8158     // this handler
8159     //
8160     // WARNING: This function could potentially throw an exception, however it should only
8161     // be able to do so when an interop debugger is attached
8162     if(g_pDebugInterface != NULL)
8163     {
8164         if(g_pDebugInterface->FirstChanceSuspendHijackWorker(pExceptionInfo->ContextRecord,
8165             pExceptionInfo->ExceptionRecord) == EXCEPTION_CONTINUE_EXECUTION)
8166         return EXCEPTION_CONTINUE_EXECUTION;
8167     }
8168 #endif
8169
8170
8171     DWORD dwCode = pExceptionInfo->ExceptionRecord->ExceptionCode;
8172     if (dwCode == DBG_PRINTEXCEPTION_C || dwCode == EXCEPTION_VISUALCPP_DEBUGGER)
8173     {
8174         return EXCEPTION_CONTINUE_SEARCH;
8175     }
8176
8177 #if defined(_TARGET_X86_)
8178     if (dwCode == EXCEPTION_BREAKPOINT || dwCode == EXCEPTION_SINGLE_STEP)
8179     {
8180         // For interop debugging, debugger bashes our managed exception handler.
8181         // Interop debugging does not work with real vectored exception handler :(
8182         return EXCEPTION_CONTINUE_SEARCH;
8183     }
8184 #endif
8185
8186     bool bIsGCMarker = false;
8187
8188 #ifdef USE_REDIRECT_FOR_GCSTRESS
8189     // This is AMD64 & ARM specific as the macro above is defined for AMD64 & ARM only
8190     bIsGCMarker = IsGcMarker(dwCode, pExceptionInfo->ContextRecord);
8191 #elif defined(_TARGET_X86_) && defined(HAVE_GCCOVER)
8192     // This is the equivalent of the check done in COMPlusFrameHandler, incase the exception is
8193     // seen by VEH first on x86.
8194     bIsGCMarker = IsGcMarker(dwCode, pExceptionInfo->ContextRecord);
8195 #endif // USE_REDIRECT_FOR_GCSTRESS
8196
8197     // Do not update the TLS with exception details for exceptions pertaining to GCStress
8198     // as they are continueable in nature.
8199     if (!bIsGCMarker)
8200     {
8201         SaveCurrentExceptionInfo(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord);
8202     }
8203
8204
8205     LONG result = EXCEPTION_CONTINUE_SEARCH;
8206
8207     // If we cannot obtain a Thread object, then we have no business processing any
8208     // exceptions on this thread.  Indeed, even checking to see if the faulting
8209     // address is in JITted code is problematic if we have no Thread object, since
8210     // this thread will bypass all our locks.
8211     Thread *pThread = GetThread();
8212
8213     // Also check if the exception was in the EE or not
8214     BOOL fExceptionInEE = FALSE;
8215     if (!pThread)
8216     {
8217         // Check if the exception was in EE only if Thread object isnt available.
8218         // This will save us from unnecessary checks
8219         fExceptionInEE = IsIPInEE(pExceptionInfo->ExceptionRecord->ExceptionAddress);
8220     }
8221
8222     // We are going to process the exception only if one of the following conditions is true:
8223     //
8224     // 1) We have a valid Thread object (implies exception on managed thread)
8225     // 2) Not a valid Thread object but the IP is in the execution engine (implies native thread within EE faulted)
8226     if (pThread || fExceptionInEE)
8227     {
8228         if (!bIsGCMarker)
8229             result = CLRVectoredExceptionHandler(pExceptionInfo);
8230         else
8231             result = EXCEPTION_CONTINUE_EXECUTION;
8232
8233         if (EXCEPTION_EXECUTE_HANDLER == result)
8234         {
8235             result = EXCEPTION_CONTINUE_SEARCH;
8236         }
8237
8238 #ifdef _DEBUG
8239 #ifndef WIN64EXCEPTIONS
8240         {
8241             CantAllocHolder caHolder;
8242
8243             PEXCEPTION_REGISTRATION_RECORD pRecord = GetCurrentSEHRecord();
8244             while (pRecord != EXCEPTION_CHAIN_END)
8245             {
8246                 STRESS_LOG2(LF_EH, LL_INFO10000, "CLRVectoredExceptionHandlerShim: FS:0 %p:%p\n",
8247                             pRecord, pRecord->Handler);
8248                 pRecord = pRecord->Next;
8249             }
8250         }
8251 #endif // WIN64EXCEPTIONS
8252
8253         {
8254             // The call to "CLRVectoredExceptionHandler" above can return EXCEPTION_CONTINUE_SEARCH
8255             // for different scenarios like StackOverFlow/SOFT_SO, or if it is forbidden to enter the EE.
8256             // Thus, if we dont have a Thread object for the thread that has faulted and we came this far
8257             // because the fault was in MSCORWKS, then we work with the frame chain below only if we have
8258             // valid Thread object.
8259
8260             if (pThread)
8261             {
8262                 CantAllocHolder caHolder;
8263
8264                 TADDR* sp;
8265                 sp = (TADDR*)&sp;
8266                 DWORD count = 0;
8267                 void* stopPoint = pThread->GetCachedStackBase();
8268                 // If Frame chain is corrupted, we may get AV while accessing frames, and this function will be
8269                 // called recursively.  We use Frame chain to limit our search range.  It is not disaster if we
8270                 // can not use it.
8271                 if (!(dwCode == STATUS_ACCESS_VIOLATION &&
8272                       IsIPInEE(pExceptionInfo->ExceptionRecord->ExceptionAddress)))
8273                 {
8274                     // Find the stop point (most jitted function)
8275                     Frame* pFrame = pThread->GetFrame();
8276                     for(;;)
8277                     {
8278                         // skip GC frames
8279                         if (pFrame == 0 || pFrame == (Frame*) -1)
8280                             break;
8281
8282                         Frame::ETransitionType type = pFrame->GetTransitionType();
8283                         if (type == Frame::TT_M2U || type == Frame::TT_InternalCall)
8284                         {
8285                             stopPoint = pFrame;
8286                             break;
8287                         }
8288                         pFrame = pFrame->Next();
8289                     }
8290                 }
8291                 STRESS_LOG0(LF_EH, LL_INFO100, "CLRVectoredExceptionHandlerShim: stack");
8292                 while (count < 20 && sp < stopPoint)
8293                 {
8294                     if (IsIPInEE((BYTE*)*sp))
8295                     {
8296                         STRESS_LOG1(LF_EH, LL_INFO100, "%pK\n", *sp);
8297                         count ++;
8298                     }
8299                     sp += 1;
8300                 }
8301             }
8302         }
8303 #endif // _DEBUG
8304
8305 #ifndef WIN64EXCEPTIONS
8306         {
8307             CantAllocHolder caHolder;
8308             STRESS_LOG1(LF_EH, LL_INFO1000, "CLRVectoredExceptionHandlerShim: returning %d\n", result);
8309         }
8310 #endif // WIN64EXCEPTIONS
8311
8312     }
8313
8314     SetLastError(dwLastError);
8315
8316     return result;
8317 }
8318
8319 #endif // !FEATURE_PAL
8320
8321 // Contains the handle to the registered VEH
8322 static PVOID g_hVectoredExceptionHandler = NULL;
8323
8324 void CLRAddVectoredHandlers(void)
8325 {
8326 #ifndef FEATURE_PAL
8327
8328     // We now install a vectored exception handler on all supporting Windows architectures.
8329     g_hVectoredExceptionHandler = AddVectoredExceptionHandler(TRUE, (PVECTORED_EXCEPTION_HANDLER)CLRVectoredExceptionHandlerShim);
8330     if (g_hVectoredExceptionHandler == NULL)
8331     {
8332         LOG((LF_EH, LL_INFO100, "CLRAddVectoredHandlers: AddVectoredExceptionHandler() failed\n"));
8333         COMPlusThrowHR(E_FAIL);
8334     }
8335
8336     LOG((LF_EH, LL_INFO100, "CLRAddVectoredHandlers: AddVectoredExceptionHandler() succeeded\n"));
8337 #endif // !FEATURE_PAL
8338 }
8339
8340 // This function removes the vectored exception and continue handler registration
8341 // from the OS.
8342 void CLRRemoveVectoredHandlers(void)
8343 {
8344     CONTRACTL
8345     {
8346         NOTHROW;
8347         GC_NOTRIGGER;
8348         MODE_ANY;
8349     }
8350     CONTRACTL_END;
8351 #ifndef FEATURE_PAL
8352
8353     // Unregister the vectored exception handler if one is registered (and we can).
8354     if (g_hVectoredExceptionHandler != NULL)
8355     {
8356         // Unregister the vectored exception handler
8357         if (RemoveVectoredExceptionHandler(g_hVectoredExceptionHandler) == FALSE)
8358         {
8359             LOG((LF_EH, LL_INFO100, "CLRRemoveVectoredHandlers: RemoveVectoredExceptionHandler() failed.\n"));
8360         }
8361         else
8362         {
8363             LOG((LF_EH, LL_INFO100, "CLRRemoveVectoredHandlers: RemoveVectoredExceptionHandler() succeeded.\n"));
8364         }
8365     }
8366 #endif // !FEATURE_PAL
8367 }
8368
8369 //
8370 // This does the work of the Unwind and Continue Hanlder inside the catch clause of that handler. The stack has not
8371 // been unwound when this is called. Keep that in mind when deciding where to put new code :)
8372 //
8373 void UnwindAndContinueRethrowHelperInsideCatch(Frame* pEntryFrame, Exception* pException)
8374 {
8375     STATIC_CONTRACT_NOTHROW;
8376     STATIC_CONTRACT_GC_TRIGGERS;
8377     STATIC_CONTRACT_MODE_ANY;
8378     STATIC_CONTRACT_SO_TOLERANT;
8379
8380     Thread* pThread = GetThread();
8381
8382     GCX_COOP();
8383
8384     LOG((LF_EH, LL_INFO1000, "UNWIND_AND_CONTINUE inside catch, unwinding frame chain\n"));
8385
8386     // This SetFrame is OK because we will not have frames that require ExceptionUnwind in strictly unmanaged EE
8387     // code chunks which is all that an UnC handler can guard.
8388     //
8389     // @todo: we'd rather use UnwindFrameChain, but there is a concern: some of the ExceptionUnwind methods on some
8390     // of the Frame types do a great deal of work; load classes, throw exceptions, etc. We need to decide on some
8391     // policy here. Do we want to let such funcitons throw, etc.? Right now, we believe that there are no such
8392     // frames on the stack to be unwound, so the SetFrame is alright (see the first comment above.) At the very
8393     // least, we should add some way to assert that.
8394     pThread->SetFrame(pEntryFrame);
8395
8396 #ifdef _DEBUG
8397     if (!NingenEnabled())
8398     {
8399         CONTRACT_VIOLATION(ThrowsViolation);
8400         BEGIN_SO_INTOLERANT_CODE(pThread);
8401     // Call CLRException::GetThrowableFromException to force us to retrieve the THROWABLE
8402     // while we are still within the context of the catch block. This will help diagnose
8403     // cases where the last thrown object is NULL.
8404     OBJECTREF orThrowable = CLRException::GetThrowableFromException(pException);
8405     CONSISTENCY_CHECK(orThrowable != NULL);
8406         END_SO_INTOLERANT_CODE;
8407     }
8408 #endif
8409 }
8410
8411 //
8412 // This does the work of the Unwind and Continue Hanlder after the catch clause of that handler. The stack has been
8413 // unwound by the time this is called. Keep that in mind when deciding where to put new code :)
8414 //
8415 VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFrame, Exception* pException)
8416 {
8417     STATIC_CONTRACT_THROWS;
8418     STATIC_CONTRACT_GC_TRIGGERS;
8419     STATIC_CONTRACT_MODE_ANY;
8420     STATIC_CONTRACT_SO_TOLERANT;
8421
8422     // We really should probe before switching to cooperative mode, although there's no chance
8423     // we'll SO in doing that as we've just caught an exception.  We can't probe just
8424     // yet though, because we want to avoid reprobing on an SO exception and we need to switch
8425     // to cooperative to check the throwable for an SO as well as the pException object (as the
8426     // pException could be a LastThrownObjectException.)  Blech.
8427     CONTRACT_VIOLATION(SOToleranceViolation);
8428
8429     GCX_COOP();
8430
8431     LOG((LF_EH, LL_INFO1000, "UNWIND_AND_CONTINUE caught and will rethrow\n"));
8432
8433     OBJECTREF orThrowable = NingenEnabled() ? NULL : CLRException::GetThrowableFromException(pException);
8434     LOG((LF_EH, LL_INFO1000, "UNWIND_AND_CONTINUE got throwable %p\n",
8435         OBJECTREFToObject(orThrowable)));
8436
8437     Exception::Delete(pException);
8438
8439     if (orThrowable != NULL && g_CLRPolicyRequested)
8440     {
8441         if (orThrowable->GetMethodTable() == g_pOutOfMemoryExceptionClass)
8442         {
8443             EEPolicy::HandleOutOfMemory();
8444         }
8445         else if (orThrowable->GetMethodTable() == g_pStackOverflowExceptionClass)
8446         {
8447 #ifdef FEATURE_STACK_PROBE
8448             EEPolicy::HandleSoftStackOverflow();
8449 #else
8450             /* The parameters of the function do not matter here */
8451             EEPolicy::HandleStackOverflow(SOD_UnmanagedFrameHandler, NULL);
8452 #endif
8453         }
8454     }
8455
8456     RaiseTheExceptionInternalOnly(orThrowable, FALSE);
8457 }
8458
8459 void SaveCurrentExceptionInfo(PEXCEPTION_RECORD pRecord, PCONTEXT pContext)
8460 {
8461     CONTRACTL
8462     {
8463         NOTHROW;
8464         GC_NOTRIGGER;
8465         MODE_ANY;
8466         SO_TOLERANT;
8467     }
8468     CONTRACTL_END;
8469
8470     if ((pRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)))
8471     {
8472         // If exception is unwinding the stack, the ExceptionCode may have been changed to
8473         // STATUS_UNWIND if RtlUnwind is called with a NULL ExceptionRecord.
8474         // Since we have captured exception info in the first pass, we don't need to capture it again.
8475         return;
8476     }
8477
8478     if (CExecutionEngine::CheckThreadStateNoCreate(TlsIdx_PEXCEPTION_RECORD))
8479     {
8480         BOOL fSave = TRUE;
8481         if (!IsSOExceptionCode(pRecord->ExceptionCode))
8482         {
8483             DWORD dwLastExceptionCode = (DWORD)(SIZE_T) (ClrFlsGetValue(TlsIdx_EXCEPTION_CODE));
8484             if (IsSOExceptionCode(dwLastExceptionCode))
8485             {
8486                 PEXCEPTION_RECORD lastRecord =
8487                     static_cast<PEXCEPTION_RECORD> (ClrFlsGetValue(TlsIdx_PEXCEPTION_RECORD));
8488
8489                 // We are trying to see if C++ is attempting a rethrow of a SO exception. If so,
8490                 // we want to prevent updating the exception details in the TLS. This is a workaround,
8491                 // as explained below.
8492                 if (pRecord->ExceptionCode == EXCEPTION_MSVC)
8493                 {
8494                     // This is a workaround.
8495                     // When C++ rethrows, C++ internally gets rid of the new exception record after
8496                     // unwinding stack, and present the original exception record to the thread.
8497                     // When we get VC's support to obtain exception record in try/catch, we will replace
8498                     // this code.
8499                     if (pRecord < lastRecord)
8500                     {
8501                         // For the C++ rethrow workaround, ensure that the last exception record is still valid and as we expect it to be.
8502                         //
8503                         // Its possible that we are still below the address of last exception record
8504                         // but since the execution stack could have changed, simply comparing its address
8505                         // with the address of the current exception record may not be enough.
8506                         //
8507                         // Thus, ensure that its still valid and holds the exception code we expect it to
8508                         // have (i.e. value in dwLastExceptionCode).
8509                         if ((lastRecord != NULL) && (lastRecord->ExceptionCode == dwLastExceptionCode))
8510                         {
8511                             fSave = FALSE;
8512                         }
8513                     }
8514                 }
8515             }
8516         }
8517         if (fSave)
8518         {
8519             ClrFlsSetValue(TlsIdx_EXCEPTION_CODE, (void*)(size_t)(pRecord->ExceptionCode));
8520             ClrFlsSetValue(TlsIdx_PEXCEPTION_RECORD, pRecord);
8521             ClrFlsSetValue(TlsIdx_PCONTEXT, pContext);
8522         }
8523     }
8524 }
8525
8526 #ifndef DACCESS_COMPILE
8527 //******************************************************************************
8528 //
8529 // NotifyOfCHFFilterWrapper
8530 //
8531 // Helper function to deliver notifications of CatchHandlerFound inside a
8532 //  EX_TRY/EX_CATCH.
8533 //
8534 // Parameters:
8535 //   pExceptionInfo - the pExceptionInfo passed to a filter function.
8536 //   pCatcherStackAddr - a Frame* from the PAL_TRY/PAL_EXCEPT_FILTER site.
8537 //
8538 // Return:
8539 //   always returns EXCEPTION_CONTINUE_SEARCH.
8540 //
8541 //******************************************************************************
8542 LONG NotifyOfCHFFilterWrapper(
8543     EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
8544     PVOID               pParam)         // contains a Frame* from the PAL_TRY/PAL_EXCEPT_FILTER site.
8545 {
8546     LIMITED_METHOD_CONTRACT;
8547
8548     PVOID pCatcherStackAddr = ((NotifyOfCHFFilterWrapperParam *)pParam)->pFrame;
8549     ULONG ret = EXCEPTION_CONTINUE_SEARCH;
8550
8551     // We are here to send an event notification to the debugger and to the appdomain.  To
8552     //  determine if it is safe to send these notifications, check the following:
8553     // 1) The thread object has been set up.
8554     // 2) The thread has an exception on it.
8555     // 3) The exception is the same as the one this filter is called on.
8556     Thread *pThread = GetThread();
8557     if ( (pThread == NULL)  ||
8558          (pThread->GetExceptionState()->GetContextRecord() == NULL)  ||
8559          (GetSP(pThread->GetExceptionState()->GetContextRecord()) != GetSP(pExceptionInfo->ContextRecord) ) )
8560     {
8561         LOG((LF_EH, LL_INFO1000, "NotifyOfCHFFilterWrapper: not sending notices. pThread: %0x8", pThread));
8562         if (pThread)
8563         {
8564             LOG((LF_EH, LL_INFO1000, ", Thread SP: %0x8, Exception SP: %08x",
8565                  pThread->GetExceptionState()->GetContextRecord() ? GetSP(pThread->GetExceptionState()->GetContextRecord()) : NULL,
8566                  pExceptionInfo->ContextRecord ? GetSP(pExceptionInfo->ContextRecord) : NULL ));
8567         }
8568         LOG((LF_EH, LL_INFO1000, "\n"));
8569         return ret;
8570     }
8571
8572     if (g_pDebugInterface)
8573     {
8574         // It looks safe, so make the debugger notification.
8575         ret = g_pDebugInterface->NotifyOfCHFFilter(pExceptionInfo, pCatcherStackAddr);
8576     }
8577
8578     return ret;
8579 } // LONG NotifyOfCHFFilterWrapper()
8580
8581 // This filter will be used process exceptions escaping out of AD transition boundaries
8582 // that are not at the base of the managed thread. Those are handled in ThreadBaseRedirectingFilter.
8583 // This will be invoked when an exception is going unhandled from the called AppDomain.
8584 //
8585 // This can be used to do last moment work before the exception gets caught by the EX_CATCH setup
8586 // at the AD transition point.
8587 LONG AppDomainTransitionExceptionFilter(
8588     EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
8589     PVOID               pParam)
8590 {
8591     // Ideally, we would be NOTHROW here. However, NotifyOfCHFFilterWrapper calls into
8592     // NotifyOfCHFFilter that is THROWS. Thus, to prevent contract violation,
8593     // we abide by the rules and be THROWS.
8594     //
8595     // Same rationale for GC_TRIGGERS as well.
8596     CONTRACTL
8597     {
8598         GC_TRIGGERS;
8599         MODE_ANY;
8600         THROWS;
8601     }
8602     CONTRACTL_END;
8603
8604     ULONG ret = EXCEPTION_CONTINUE_SEARCH;
8605
8606     // First, call into NotifyOfCHFFilterWrapper
8607     ret = NotifyOfCHFFilterWrapper(pExceptionInfo, pParam);
8608
8609 #ifndef FEATURE_PAL
8610     // Setup the watson bucketing details if the escaping
8611     // exception is preallocated.
8612     if (SetupWatsonBucketsForEscapingPreallocatedExceptions())
8613     {
8614         // Set the flag that these were captured at AD Transition
8615         DEBUG_STMT(GetThread()->GetExceptionState()->GetUEWatsonBucketTracker()->SetCapturedAtADTransition());
8616     }
8617
8618     // Attempt to capture buckets for non-preallocated exceptions just before the AppDomain transition boundary
8619     {
8620         GCX_COOP();
8621         OBJECTREF oThrowable = GetThread()->GetThrowable();
8622         if ((oThrowable != NULL) && (CLRException::IsPreallocatedExceptionObject(oThrowable) == FALSE))
8623         {
8624             SetupWatsonBucketsForNonPreallocatedExceptions();
8625         }
8626     }
8627 #endif // !FEATURE_PAL
8628
8629     return ret;
8630 } // LONG AppDomainTransitionExceptionFilter()
8631
8632 // This filter will be used process exceptions escaping out of dynamic reflection invocation as
8633 // unhandled and will eventually be caught in the VM to be made as inner exception of
8634 // TargetInvocationException that will be thrown from the VM.
8635 LONG ReflectionInvocationExceptionFilter(
8636     EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
8637     PVOID               pParam)
8638 {
8639     // Ideally, we would be NOTHROW here. However, NotifyOfCHFFilterWrapper calls into
8640     // NotifyOfCHFFilter that is THROWS. Thus, to prevent contract violation,
8641     // we abide by the rules and be THROWS.
8642     //
8643     // Same rationale for GC_TRIGGERS as well.
8644     CONTRACTL
8645     {
8646         GC_TRIGGERS;
8647         MODE_ANY;
8648         THROWS;
8649     }
8650     CONTRACTL_END;
8651
8652     ULONG ret = EXCEPTION_CONTINUE_SEARCH;
8653
8654     // First, call into NotifyOfCHFFilterWrapper
8655     ret = NotifyOfCHFFilterWrapper(pExceptionInfo, pParam);
8656
8657 #ifndef FEATURE_PAL
8658     // Setup the watson bucketing details if the escaping
8659     // exception is preallocated.
8660     if (SetupWatsonBucketsForEscapingPreallocatedExceptions())
8661     {
8662         // Set the flag that these were captured during Reflection Invocation
8663         DEBUG_STMT(GetThread()->GetExceptionState()->GetUEWatsonBucketTracker()->SetCapturedAtReflectionInvocation());
8664     }
8665
8666     // Attempt to capture buckets for non-preallocated exceptions just before the ReflectionInvocation boundary
8667     {
8668         GCX_COOP();
8669         OBJECTREF oThrowable = GetThread()->GetThrowable();
8670         if ((oThrowable != NULL) && (CLRException::IsPreallocatedExceptionObject(oThrowable) == FALSE))
8671         {
8672             SetupWatsonBucketsForNonPreallocatedExceptions();
8673         }
8674     }
8675 #endif // !FEATURE_PAL
8676
8677     // If the application has opted into triggering a failfast when a CorruptedStateException enters the Reflection system,
8678     // then do the needful.
8679     if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_FailFastOnCorruptedStateException) == 1)
8680     {
8681          // Get the thread and the managed exception object - they must exist at this point
8682         Thread *pCurThread = GetThread();
8683         _ASSERTE(pCurThread != NULL);
8684
8685         // Get the thread exception state
8686         ThreadExceptionState * pCurTES = pCurThread->GetExceptionState();
8687         _ASSERTE(pCurTES != NULL);
8688
8689         // Get the exception tracker for the current exception
8690 #ifdef WIN64EXCEPTIONS
8691         PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker();
8692 #elif _TARGET_X86_
8693         PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker();
8694 #else // !(_WIN64 || _TARGET_X86_)
8695 #error Unsupported platform
8696 #endif // _WIN64
8697
8698 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
8699         if (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting)
8700         {
8701             EEPolicy::HandleFatalError(COR_E_FAILFAST, reinterpret_cast<UINT_PTR>(pExceptionInfo->ExceptionRecord->ExceptionAddress), NULL, pExceptionInfo);
8702         }
8703 #endif // FEATURE_CORRUPTING_EXCEPTIONS
8704     }
8705
8706     return ret;
8707 } // LONG ReflectionInvocationExceptionFilter()
8708
8709 #endif // !DACCESS_COMPILE
8710
8711 #ifdef _DEBUG
8712 bool DebugIsEECxxExceptionPointer(void* pv)
8713 {
8714     CONTRACTL
8715     {
8716         DISABLED(NOTHROW);
8717         GC_NOTRIGGER;
8718         MODE_ANY;
8719         DEBUG_ONLY;
8720     }
8721     CONTRACTL_END;
8722
8723     if (pv == NULL)
8724     {
8725         return false;
8726     }
8727
8728     // check whether the memory is readable in no-throw way
8729     if (!isMemoryReadable((TADDR)pv, sizeof(UINT_PTR)))
8730     {
8731         return false;
8732     }
8733
8734     bool retVal = false;
8735
8736     EX_TRY
8737     {
8738         UINT_PTR  vtbl  = *(UINT_PTR*)pv;
8739
8740         // ex.h
8741
8742         HRException             boilerplate1;
8743         COMException            boilerplate2;
8744         SEHException            boilerplate3;
8745
8746         // clrex.h
8747
8748         CLRException            boilerplate4;
8749         CLRLastThrownObjectException boilerplate5;
8750         EEException             boilerplate6;
8751         EEMessageException      boilerplate7;
8752         EEResourceException     boilerplate8;
8753
8754         // EECOMException::~EECOMException calls FreeExceptionData, which is GC_TRIGGERS,
8755         // but it won't trigger in this case because EECOMException's members remain NULL.
8756         CONTRACT_VIOLATION(GCViolation);
8757         EECOMException          boilerplate9;
8758
8759         EEFieldException        boilerplate10;
8760         EEMethodException       boilerplate11;
8761         EEArgumentException     boilerplate12;
8762         EETypeLoadException     boilerplate13;
8763         EEFileLoadException     boilerplate14;
8764         ObjrefException         boilerplate15;
8765
8766         UINT_PTR    ValidVtbls[] =
8767         {
8768             *((TADDR*)&boilerplate1),
8769             *((TADDR*)&boilerplate2),
8770             *((TADDR*)&boilerplate3),
8771             *((TADDR*)&boilerplate4),
8772             *((TADDR*)&boilerplate5),
8773             *((TADDR*)&boilerplate6),
8774             *((TADDR*)&boilerplate7),
8775             *((TADDR*)&boilerplate8),
8776             *((TADDR*)&boilerplate9),
8777             *((TADDR*)&boilerplate10),
8778             *((TADDR*)&boilerplate11),
8779             *((TADDR*)&boilerplate12),
8780             *((TADDR*)&boilerplate13),
8781             *((TADDR*)&boilerplate14),
8782             *((TADDR*)&boilerplate15)
8783         };
8784
8785         const int nVtbls = sizeof(ValidVtbls) / sizeof(ValidVtbls[0]);
8786
8787         for (int i = 0; i < nVtbls; i++)
8788         {
8789             if (vtbl == ValidVtbls[i])
8790             {
8791                 retVal = true;
8792                 break;
8793             }
8794         }
8795     }
8796     EX_CATCH
8797     {
8798         // Swallow any exception out of the exception constructors above and simply return false.
8799     }
8800     EX_END_CATCH(SwallowAllExceptions);
8801
8802     return retVal;
8803 }
8804
8805 void *DebugGetCxxException(EXCEPTION_RECORD* pExceptionRecord);
8806
8807 bool DebugIsEECxxException(EXCEPTION_RECORD* pExceptionRecord)
8808 {
8809     return DebugIsEECxxExceptionPointer(DebugGetCxxException(pExceptionRecord));
8810 }
8811
8812 //
8813 // C++ EH cracking material gleaned from the debugger:
8814 // (DO NOT USE THIS KNOWLEDGE IN NON-DEBUG CODE!!!)
8815 //
8816 // EHExceptionRecord::EHParameters
8817 //     [0] magicNumber      : uint
8818 //     [1] pExceptionObject : void*
8819 //     [2] pThrowInfo       : ThrowInfo*
8820
8821 #ifdef _WIN64
8822 #define NUM_CXX_EXCEPTION_PARAMS 4
8823 #else
8824 #define NUM_CXX_EXCEPTION_PARAMS 3
8825 #endif
8826
8827 void *DebugGetCxxException(EXCEPTION_RECORD* pExceptionRecord)
8828 {
8829     WRAPPER_NO_CONTRACT;
8830
8831     bool fExCodeIsCxx           = (EXCEPTION_MSVC == pExceptionRecord->ExceptionCode);
8832     bool fExHasCorrectNumParams = (NUM_CXX_EXCEPTION_PARAMS == pExceptionRecord->NumberParameters);
8833
8834     if (fExCodeIsCxx && fExHasCorrectNumParams)
8835     {
8836         void** ppException = (void**)pExceptionRecord->ExceptionInformation[1];
8837
8838         if (NULL == ppException)
8839         {
8840             return NULL;
8841         }
8842
8843         return *ppException;
8844
8845     }
8846
8847     CONSISTENCY_CHECK_MSG(!fExCodeIsCxx || fExHasCorrectNumParams, "We expected an EXCEPTION_MSVC exception to have 3 parameters.  Did the CRT change its exception format?");
8848
8849     return NULL;
8850 }
8851
8852 #endif // _DEBUG
8853
8854 #endif // #ifndef DACCESS_COMPILE
8855
8856 BOOL IsException(MethodTable *pMT) {
8857     CONTRACTL
8858     {
8859         NOTHROW;
8860         GC_NOTRIGGER;
8861         MODE_ANY;
8862         SO_TOLERANT;
8863         SUPPORTS_DAC;
8864     }
8865     CONTRACTL_END;
8866
8867     ASSERT(g_pExceptionClass != NULL);
8868
8869     while (pMT != NULL && pMT != g_pExceptionClass) {
8870         pMT = pMT->GetParentMethodTable();
8871     }
8872
8873     return pMT != NULL;
8874 } // BOOL IsException()
8875
8876 // Returns TRUE iff calling get_StackTrace on an exception of the given type ends up
8877 // executing some other code than just Exception.get_StackTrace.
8878 BOOL ExceptionTypeOverridesStackTraceGetter(PTR_MethodTable pMT)
8879 {
8880     CONTRACTL
8881     {
8882         THROWS;
8883         GC_NOTRIGGER;
8884         MODE_ANY;
8885         SO_TOLERANT;
8886         SUPPORTS_DAC;
8887     }
8888     CONTRACTL_END;
8889
8890     _ASSERTE(IsException(pMT));
8891
8892     if (pMT == g_pExceptionClass)
8893     {
8894         // if the type is System.Exception, it certainly doesn't override anything
8895         return FALSE;
8896     }
8897
8898     // find the slot corresponding to get_StackTrace
8899     for (DWORD slot = g_pObjectClass->GetNumVirtuals(); slot < g_pExceptionClass->GetNumVirtuals(); slot++)
8900     {
8901         MethodDesc *pMD = g_pExceptionClass->GetMethodDescForSlot(slot);
8902         LPCUTF8 name = pMD->GetName();
8903
8904         if (name != NULL && strcmp(name, "get_StackTrace") == 0)
8905         {
8906             // see if the slot is overriden by pMT
8907             MethodDesc *pDerivedMD = pMT->GetMethodDescForSlot(slot);
8908             return (pDerivedMD != pMD);
8909         }
8910     }
8911
8912     // there must be get_StackTrace on System.Exception
8913     UNREACHABLE();
8914 }
8915
8916 // Removes source file names/paths and line information from a stack trace generated
8917 // by Environment.GetStackTrace.
8918 void StripFileInfoFromStackTrace(SString &ssStackTrace)
8919 {
8920     CONTRACTL
8921     {
8922         THROWS;
8923         GC_NOTRIGGER;
8924         MODE_ANY;
8925         SUPPORTS_DAC;
8926     }
8927     CONTRACTL_END;
8928
8929     SString::Iterator i = ssStackTrace.Begin();
8930     SString::Iterator end;
8931     int countBracket = 0;
8932     int position = 0;
8933
8934     while (i < ssStackTrace.End())
8935     {
8936         if (i[0] == W('('))
8937         {
8938             countBracket ++;
8939         }
8940         else if (i[0] == W(')'))
8941         {
8942             if (countBracket == 1)
8943             {
8944                 end = i + 1;
8945                 SString::Iterator j = i + 1;
8946                 while (j < ssStackTrace.End())
8947                 {
8948                     if (j[0] == W('\r') || j[0] == W('\n'))
8949                     {
8950                         break;
8951                     }
8952                     j++;
8953                 }
8954                 if (j > end)
8955                 {
8956                     ssStackTrace.Delete(end,j-end);
8957                     i = ssStackTrace.Begin() + position;
8958                 }
8959             }
8960             countBracket --;
8961         }
8962         i ++;
8963         position ++;
8964     }
8965     ssStackTrace.Truncate(end);
8966 }
8967
8968 #ifdef _DEBUG
8969 //==============================================================================
8970 // This function will set a thread state indicating if an exception is escaping
8971 // the last CLR personality routine on the stack in a reverse pinvoke scenario.
8972 //
8973 // If the exception continues to go unhandled, it will eventually reach the OS
8974 // that will start invoking the UEFs. Since CLR registers its UEF only to handle
8975 // unhandled exceptions on such reverse pinvoke threads, we will assert this
8976 // state in our UEF to ensure it does not get called for any other reason.
8977 //
8978 // This function should be called only if the personality routine returned
8979 // EXCEPTION_CONTINUE_SEARCH.
8980 //==============================================================================
8981 void SetReversePInvokeEscapingUnhandledExceptionStatus(BOOL fIsUnwinding,
8982 #if defined(_TARGET_X86_)
8983                                                        EXCEPTION_REGISTRATION_RECORD * pEstablisherFrame
8984 #elif defined(WIN64EXCEPTIONS)
8985                                                        ULONG64 pEstablisherFrame
8986 #else
8987 #error Unsupported platform
8988 #endif
8989                                                        )
8990 {
8991 #ifndef DACCESS_COMPILE
8992
8993     LIMITED_METHOD_CONTRACT;
8994
8995     Thread *pCurThread = GetThread();
8996     _ASSERTE(pCurThread);
8997
8998     if (pCurThread->GetExceptionState()->IsExceptionInProgress())
8999     {
9000         if (!fIsUnwinding)
9001         {
9002             // Get the top-most Frame of this thread.
9003             Frame* pCurFrame = pCurThread->GetFrame();
9004             Frame* pTopMostFrame = pCurFrame;
9005             while (pCurFrame && (pCurFrame != FRAME_TOP))
9006             {
9007                 pTopMostFrame = pCurFrame;
9008                 pCurFrame = pCurFrame->PtrNextFrame();
9009             }
9010
9011             // Is the exception escaping the last CLR personality routine on the stack of a
9012             // reverse pinvoke thread?
9013             if (((pTopMostFrame == NULL) || (pTopMostFrame == FRAME_TOP)) ||
9014                 ((void *)(pEstablisherFrame) > (void *)(pTopMostFrame)))
9015             {
9016                 LOG((LF_EH, LL_INFO100, "SetReversePInvokeEscapingUnhandledExceptionStatus: setting Ex_RPInvokeEscapingException\n"));
9017                 // Set the flag on the thread indicating the exception is escaping the
9018                 // top most reverse pinvoke exception handler.
9019                 pCurThread->GetExceptionState()->GetFlags()->SetReversePInvokeEscapingException();
9020             }
9021         }
9022         else
9023         {
9024             // Since we are unwinding, simply unset the flag indicating escaping unhandled exception
9025             // if it was set.
9026             if (pCurThread->GetExceptionState()->GetFlags()->ReversePInvokeEscapingException())
9027             {
9028                 LOG((LF_EH, LL_INFO100, "SetReversePInvokeEscapingUnhandledExceptionStatus: unsetting Ex_RPInvokeEscapingException\n"));
9029                 pCurThread->GetExceptionState()->GetFlags()->ResetReversePInvokeEscapingException();
9030             }
9031         }
9032     }
9033     else
9034     {
9035         LOG((LF_EH, LL_INFO100, "SetReversePInvokeEscapingUnhandledExceptionStatus: not setting Ex_RPInvokeEscapingException since no exception is in progress.\n"));
9036     }
9037 #endif // !DACCESS_COMPILE
9038 }
9039
9040 #endif // _DEBUG
9041
9042 #ifndef FEATURE_PAL
9043
9044 // This function will capture the watson buckets for the current exception object that is:
9045 //
9046 // 1) Non-preallocated
9047 // 2) Already contains the IP for watson bucketing
9048 BOOL SetupWatsonBucketsForNonPreallocatedExceptions(OBJECTREF oThrowable /* = NULL */)
9049 {
9050 #ifndef DACCESS_COMPILE
9051
9052     // CoreCLR may have watson bucketing conditionally enabled.
9053     if (!IsWatsonEnabled())
9054     {
9055         return FALSE;
9056     }
9057
9058     CONTRACTL
9059     {
9060         GC_TRIGGERS;
9061         MODE_COOPERATIVE;
9062         NOTHROW;
9063         PRECONDITION(GetThread() != NULL);
9064     }
9065     CONTRACTL_END;
9066
9067     // By default, assume we didnt get the buckets
9068     BOOL fSetupWatsonBuckets = FALSE;
9069
9070     Thread * pThread = GetThread();
9071
9072     struct
9073     {
9074         OBJECTREF oThrowable;
9075     } gc;
9076     ZeroMemory(&gc, sizeof(gc));
9077     GCPROTECT_BEGIN(gc);
9078
9079     // Get the throwable to be used
9080     gc.oThrowable = (oThrowable != NULL) ? oThrowable : pThread->GetThrowable();
9081     if (gc.oThrowable == NULL)
9082     {
9083         // If we have no throwable, then simply return back.
9084         //
9085         // We could be here because the VM may have raised an exception,
9086         // and not managed code, for its internal usage (e.g. TA to end the
9087         // threads when unloading an AppDomain). Thus, there would be no throwable
9088         // present since the exception has not been seen by the runtime's
9089         // personality routine.
9090         //
9091         // Hence, we have no work to do here.
9092         LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForNonPreallocatedExceptions - No throwable available.\n"));
9093         goto done;
9094     }
9095
9096     // The exception object should be non-preallocated
9097     _ASSERTE(!CLRException::IsPreallocatedExceptionObject(gc.oThrowable));
9098
9099     if (((EXCEPTIONREF)gc.oThrowable)->AreWatsonBucketsPresent() == FALSE)
9100     {
9101         // Attempt to capture the watson buckets since they are not present.
9102         UINT_PTR ip = ((EXCEPTIONREF)gc.oThrowable)->GetIPForWatsonBuckets();
9103         if (ip != NULL)
9104         {
9105             // Attempt to capture the buckets
9106             PTR_VOID pBuckets = GetBucketParametersForManagedException(ip, TypeOfReportedError::UnhandledException, pThread, &gc.oThrowable);
9107             if (pBuckets != NULL)
9108             {
9109                 // Got the buckets - save them to the exception object
9110                 fSetupWatsonBuckets = FALSE;
9111                 EX_TRY
9112                 {
9113                     fSetupWatsonBuckets = CopyWatsonBucketsToThrowable(pBuckets, gc.oThrowable);
9114                 }
9115                 EX_CATCH
9116                 {
9117                     // OOM can bring us here
9118                     fSetupWatsonBuckets = FALSE;
9119                 }
9120                 EX_END_CATCH(SwallowAllExceptions);
9121
9122                 if (!fSetupWatsonBuckets)
9123                 {
9124                     LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForNonPreallocatedExceptions - Unable to copy buckets to throwable likely due to OOM.\n"));
9125                 }
9126                 else
9127                 {
9128                     // Clear the saved IP since we have captured the buckets
9129                     ((EXCEPTIONREF)gc.oThrowable)->SetIPForWatsonBuckets(NULL);
9130                     LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForNonPreallocatedExceptions - Buckets copied to throwable.\n"));
9131                 }
9132                 FreeBucketParametersForManagedException(pBuckets);
9133             }
9134             else
9135             {
9136                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForNonPreallocatedExceptions - Unable to capture buckets from IP likely due to OOM.\n"));
9137             }
9138         }
9139         else
9140         {
9141             LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForNonPreallocatedExceptions - No IP available to capture buckets from.\n"));
9142         }
9143     }
9144
9145 done:;
9146     GCPROTECT_END();
9147
9148     return fSetupWatsonBuckets;
9149 #else // DACCESS_COMPILE
9150     return FALSE;
9151 #endif // !DACCESS_COMPILE
9152 }
9153
9154 // When exceptions are escaping out of various transition boundaries,
9155 // we will need to capture bucket details for the original exception
9156 // before the exception goes across the boundary to the caller.
9157 //
9158 // Examples of such boundaries include:
9159 //
9160 // 1) AppDomain transition boundaries (these are physical transition boundaries)
9161 // 2) Dynamic method invocation in Reflection (these are logical transition boundaries).
9162 //
9163 // This function will capture the bucketing details in the UE tracker so that
9164 // they can be used once we cross over.
9165 BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions()
9166 {
9167 #ifndef DACCESS_COMPILE
9168
9169     // CoreCLR may have watson bucketing conditionally enabled.
9170     if (!IsWatsonEnabled())
9171     {
9172         return FALSE;
9173     }
9174
9175     CONTRACTL
9176     {
9177         GC_NOTRIGGER;
9178         MODE_ANY;
9179         NOTHROW;
9180         PRECONDITION(GetThread() != NULL);
9181     }
9182     CONTRACTL_END;
9183
9184     // By default, assume we didnt get the buckets
9185     BOOL fSetupWatsonBuckets = FALSE;
9186     PTR_EHWatsonBucketTracker pUEWatsonBucketTracker;
9187     
9188     Thread * pThread = GetThread();
9189
9190     // If the exception going unhandled is preallocated, then capture the Watson buckets in the UE Watson
9191     // bucket tracker provided its not already populated.
9192     //
9193     // Switch to COOP mode
9194     GCX_COOP();
9195
9196     struct
9197     {
9198         OBJECTREF oThrowable;
9199     } gc;
9200     ZeroMemory(&gc, sizeof(gc));
9201     GCPROTECT_BEGIN(gc);
9202
9203     // Get the throwable corresponding to the escaping exception
9204     gc.oThrowable = pThread->GetThrowable();
9205     if (gc.oThrowable == NULL)
9206     {
9207         // If we have no throwable, then simply return back.
9208         //
9209         // We could be here because the VM may have raised an exception,
9210         // and not managed code, for its internal usage (e.g. TA to end the
9211         // threads when unloading an AppDomain). Thus, there would be no throwable
9212         // present since the exception has not been seen by the runtime's
9213         // personality routine.
9214         //
9215         // Hence, we have no work to do here.
9216         LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForEscapingPreallocatedExceptions - No throwable available.\n"));
9217         goto done;
9218     }
9219
9220     // Is the exception preallocated? We are not going to process non-preallocated exception objects since
9221     // they already have the watson buckets in them.
9222     //
9223     // We skip thread abort as well since we track them in the UE watson bucket tracker at
9224     // throw time itself.
9225     if (!((CLRException::IsPreallocatedExceptionObject(gc.oThrowable)) &&
9226         !IsThrowableThreadAbortException(gc.oThrowable)))
9227     {
9228         // Its either not preallocated or a thread abort exception,
9229         // neither of which we need to process.
9230         goto done;
9231     }
9232
9233     // The UE watson bucket tracker could be non-empty if there were earlier transitions
9234     // on the threads stack before the exception got raised.
9235     pUEWatsonBucketTracker = pThread->GetExceptionState()->GetUEWatsonBucketTracker();
9236     _ASSERTE(pUEWatsonBucketTracker != NULL);
9237
9238     // Proceed to capture bucketing details only if the UE watson bucket tracker is empty.
9239     if((pUEWatsonBucketTracker->RetrieveWatsonBucketIp() == NULL) && (pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL))
9240     {
9241         // Get the Watson Bucket tracker for this preallocated exception
9242         PTR_EHWatsonBucketTracker pCurWatsonBucketTracker = GetWatsonBucketTrackerForPreallocatedException(gc.oThrowable, FALSE);
9243
9244         if (pCurWatsonBucketTracker != NULL)
9245         {
9246             // If the tracker exists, we must have the throw site IP
9247             _ASSERTE(pCurWatsonBucketTracker->RetrieveWatsonBucketIp() != NULL);
9248
9249             // Init the UE Watson bucket tracker
9250             pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9251
9252             // Copy the Bucket details to the UE watson bucket tracker
9253             pUEWatsonBucketTracker->CopyEHWatsonBucketTracker(*(pCurWatsonBucketTracker));
9254
9255             // If the buckets dont exist, capture them now
9256             if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
9257             {
9258                 pUEWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, &gc.oThrowable);
9259             }
9260
9261             // If the IP was in managed code, we will have the buckets.
9262             if(pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
9263             {
9264                 fSetupWatsonBuckets = TRUE;
9265                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForEscapingPreallocatedExceptions - Captured watson buckets for preallocated exception at transition.\n"));
9266             }
9267             else
9268             {
9269                 // IP was likely in native code - hence, watson helper functions couldnt get us the buckets
9270                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForEscapingPreallocatedExceptions - Watson buckets not found for IP. IP likely in native code.\n"));
9271
9272                 // Clear the UE tracker
9273                 pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9274             }
9275         }
9276         else
9277         {
9278             LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForEscapingPreallocatedExceptions - Watson bucket tracker for preallocated exception not found. Exception likely thrown in native code.\n"));
9279         }
9280     }
9281
9282 done:;
9283     GCPROTECT_END();
9284
9285     return fSetupWatsonBuckets;
9286 #else // DACCESS_COMPILE
9287     return FALSE;
9288 #endif // !DACCESS_COMPILE
9289 }
9290
9291 // This function is invoked from the UEF worker to setup the watson buckets
9292 // for the exception going unhandled, if details are available. See
9293 // implementation below for specifics.
9294 void SetupWatsonBucketsForUEF(BOOL fUseLastThrownObject)
9295 {
9296 #ifndef DACCESS_COMPILE
9297
9298     // CoreCLR may have watson bucketing conditionally enabled.
9299     if (!IsWatsonEnabled())
9300     {
9301         return;
9302     }
9303
9304     CONTRACTL
9305     {
9306         GC_TRIGGERS;
9307         MODE_ANY;
9308         NOTHROW;
9309         PRECONDITION(GetThread() != NULL);
9310     }
9311     CONTRACTL_END;
9312
9313     Thread *pThread = GetThread();
9314
9315     PTR_EHWatsonBucketTracker pCurWatsonBucketTracker = NULL;
9316     ThreadExceptionState *pExState = pThread->GetExceptionState();
9317     _ASSERTE(pExState != NULL);
9318
9319     // If the exception tracker exists, then copy the bucketing details
9320     // from it to the UE Watson Bucket tracker.
9321     //
9322     // On 64bit, the EH system allocates the EHTracker only in the case of an exception.
9323     // Thus, assume a reverse pinvoke thread transitions to managed code from native,
9324     // does some work in managed and returns back to native code.
9325     //
9326     // In the native code, it has an exception that goes unhandled and the OS
9327     // ends up invoking our UEF, and thus, we land up here.
9328     //
9329     // In such a case, on 64bit, we wont have an exception tracker since there
9330     // was no managed exception active. On 32bit, we will have a tracker
9331     // but there wont be an IP corresponding to the throw site since exception
9332     // was raised in native code.
9333     //
9334     // But if the tracker exists, simply copy the bucket details to the UE Watson Bucket
9335     // tracker for use by the "WatsonLastChance" path.
9336     BOOL fDoWeHaveWatsonBuckets = FALSE;
9337     if (pExState->GetCurrentExceptionTracker() != NULL)
9338     {
9339         // Check the exception state if we have Watson bucket details
9340         fDoWeHaveWatsonBuckets = pExState->GetFlags()->GotWatsonBucketDetails();
9341     }
9342
9343     // Switch to COOP mode before working with the throwable
9344     GCX_COOP();
9345
9346     // Get the throwable we are going to work with
9347     struct
9348     {
9349         OBJECTREF oThrowable;
9350     } gc;
9351     ZeroMemory(&gc, sizeof(gc));
9352     GCPROTECT_BEGIN(gc);
9353
9354     gc.oThrowable = fUseLastThrownObject ? pThread->LastThrownObject() : pThread->GetThrowable();
9355     BOOL fThrowableExists = (gc.oThrowable != NULL);
9356     BOOL fIsThrowablePreallocated = !fThrowableExists ? FALSE : CLRException::IsPreallocatedExceptionObject(gc.oThrowable);
9357
9358     if ((!fDoWeHaveWatsonBuckets) && fThrowableExists)
9359     {
9360         // Check the throwable if it has buckets - this could be the scenario
9361         // of native code calling into a non-default domain and thus, have an AD
9362         // transition in between that could reraise the exception but that would
9363         // never be seen by our exception handler. Thus, there wont be any tracker
9364         // or tracker state.
9365         //
9366         // Invocation of entry point on WLC via reverse pinvoke is an example.
9367         if (!fIsThrowablePreallocated)
9368         {
9369             fDoWeHaveWatsonBuckets = ((EXCEPTIONREF)gc.oThrowable)->AreWatsonBucketsPresent();
9370             if (!fDoWeHaveWatsonBuckets)
9371             {
9372                 // If buckets are not present, then we may have IP to capture the buckets from.
9373                 fDoWeHaveWatsonBuckets = ((EXCEPTIONREF)gc.oThrowable)->IsIPForWatsonBucketsPresent();
9374             }
9375         }
9376         else
9377         {
9378             // Get the watson bucket tracker for the preallocated exception
9379             PTR_EHWatsonBucketTracker pCurWBTracker = GetWatsonBucketTrackerForPreallocatedException(gc.oThrowable, FALSE);
9380
9381             // We would have buckets if we have the IP
9382             if (pCurWBTracker && (pCurWBTracker->RetrieveWatsonBucketIp() != NULL))
9383             {
9384                 fDoWeHaveWatsonBuckets = TRUE;
9385             }
9386         }
9387     }
9388
9389     if (fDoWeHaveWatsonBuckets)
9390     {
9391         // Get the UE Watson bucket tracker
9392         PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
9393
9394         // Clear any existing information
9395         pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9396
9397         if (fIsThrowablePreallocated)
9398         {
9399             // Get the watson bucket tracker for the preallocated exception
9400             PTR_EHWatsonBucketTracker pCurWBTracker = GetWatsonBucketTrackerForPreallocatedException(gc.oThrowable, FALSE);
9401
9402             if (pCurWBTracker != NULL)
9403             {
9404                 // We should be having an IP for this exception at this point
9405                 _ASSERTE(pCurWBTracker->RetrieveWatsonBucketIp() != NULL);
9406
9407                 // Copy the existing bucketing details to the UE tracker
9408                 pUEWatsonBucketTracker->CopyEHWatsonBucketTracker(*(pCurWBTracker));
9409
9410                 // Get the buckets if we dont already have them since we
9411                 // dont want to overwrite existing bucket information (e.g.
9412                 // from an AD transition)
9413                 if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
9414                 {
9415                     pUEWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, &gc.oThrowable);
9416                     if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
9417                     {
9418                         LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForUEF: Collected watson bucket information for preallocated exception\n"));
9419                     }
9420                     else
9421                     {
9422                         // If we are here, then one of the following could have happened:
9423                         //
9424                         // 1) pCurWBTracker had buckets but we couldnt copy them over to pUEWatsonBucketTracker due to OOM, or
9425                         // 2) pCurWBTracker's IP was in native code; thus pUEWatsonBucketTracker->CaptureUnhandledInfoForWatson()
9426                         //    couldnt get us the watson buckets.
9427                         LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForUEF: Unable to collect watson bucket information for preallocated exception due to OOM or IP being in native code.\n"));
9428                     }
9429                 }
9430             }
9431             else
9432             {
9433                 // We likely had an OOM earlier (while copying the bucket information) if we are here
9434                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForUEF: Watson bucket tracker for preallocated exception not found.\n"));
9435             }
9436         }
9437         else
9438         {
9439             // Throwable is not preallocated - get the bucket details from it for use by Watson
9440             _ASSERTE_MSG(((EXCEPTIONREF)gc.oThrowable)->AreWatsonBucketsPresent() ||
9441                         ((EXCEPTIONREF)gc.oThrowable)->IsIPForWatsonBucketsPresent(),
9442                         "How come we dont have watson buckets (or IP) for a non-preallocated exception in the UEF?");
9443
9444             if ((((EXCEPTIONREF)gc.oThrowable)->AreWatsonBucketsPresent() == FALSE) &&
9445                 ((EXCEPTIONREF)gc.oThrowable)->IsIPForWatsonBucketsPresent())
9446             {
9447                 // Capture the buckets using the IP we have.
9448                 SetupWatsonBucketsForNonPreallocatedExceptions(gc.oThrowable);
9449             }
9450
9451             if (((EXCEPTIONREF)gc.oThrowable)->AreWatsonBucketsPresent())
9452             {
9453                 pUEWatsonBucketTracker->CopyBucketsFromThrowable(gc.oThrowable);
9454             }
9455
9456             if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
9457             {
9458                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForUEF: Unable to copy watson buckets from regular exception throwable (%p), likely due to OOM.\n",
9459                                     OBJECTREFToObject(gc.oThrowable)));
9460             }
9461         }
9462     }
9463     else
9464     {
9465         // We dont have the watson buckets; exception was in native code that we dont care about
9466         LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForUEF: We dont have watson buckets - likely an exception in native code.\n"));
9467     }
9468
9469     GCPROTECT_END();
9470 #endif // !DACCESS_COMPILE
9471 }
9472
9473 // Given a throwable, this function will return a BOOL indicating
9474 // if it corresponds to any of the following thread abort exception
9475 // objects:
9476 //
9477 // 1) Regular allocated ThreadAbortException
9478 // 2) Preallocated ThreadAbortException
9479 // 3) Preallocated RudeThreadAbortException
9480 BOOL IsThrowableThreadAbortException(OBJECTREF oThrowable)
9481 {
9482 #ifndef DACCESS_COMPILE
9483     CONTRACTL
9484     {
9485         GC_NOTRIGGER;
9486         MODE_COOPERATIVE;
9487         NOTHROW;
9488         PRECONDITION(GetThread() != NULL);
9489         PRECONDITION(oThrowable != NULL);
9490     }
9491     CONTRACTL_END;
9492
9493     BOOL fIsTAE = FALSE;
9494
9495     struct
9496     {
9497         OBJECTREF oThrowable;
9498     } gc;
9499     ZeroMemory(&gc, sizeof(gc));
9500     GCPROTECT_BEGIN(gc);
9501
9502     gc.oThrowable = oThrowable;
9503
9504     fIsTAE = (IsExceptionOfType(kThreadAbortException,&(gc.oThrowable)) || // regular TAE
9505             ((g_pPreallocatedThreadAbortException != NULL) &&
9506             (gc.oThrowable == CLRException::GetPreallocatedThreadAbortException())) ||
9507             ((g_pPreallocatedRudeThreadAbortException != NULL) &&
9508             (gc.oThrowable == CLRException::GetPreallocatedRudeThreadAbortException())));
9509
9510     GCPROTECT_END();
9511
9512     return fIsTAE;
9513
9514 #else // DACCESS_COMPILE
9515     return FALSE;
9516 #endif // !DACCESS_COMPILE
9517 }
9518
9519 // Given a throwable, this function will walk the exception tracker
9520 // list to return the tracker, if available, corresponding to the preallocated
9521 // exception object.
9522 //
9523 // The caller can also specify the starting EHTracker to walk the list from.
9524 // If not specified, this will default to the current exception tracker active
9525 // on the thread.
9526 #if defined(WIN64EXCEPTIONS)
9527 PTR_ExceptionTracker GetEHTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable,
9528                                                           PTR_ExceptionTracker pStartingEHTracker)
9529 #elif _TARGET_X86_
9530 PTR_ExInfo GetEHTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable,
9531                                                 PTR_ExInfo pStartingEHTracker)
9532 #else
9533 #error Unsupported platform
9534 #endif
9535 {
9536     CONTRACTL
9537     {
9538         GC_NOTRIGGER;
9539         MODE_COOPERATIVE;
9540         NOTHROW;
9541         PRECONDITION(GetThread() != NULL);
9542         PRECONDITION(oPreAllocThrowable != NULL);
9543         PRECONDITION(CLRException::IsPreallocatedExceptionObject(oPreAllocThrowable));
9544         PRECONDITION(IsWatsonEnabled());
9545     }
9546     CONTRACTL_END;
9547
9548     // Get the reference to the current exception tracker
9549 #if defined(WIN64EXCEPTIONS)
9550     PTR_ExceptionTracker pEHTracker = (pStartingEHTracker != NULL) ? pStartingEHTracker : GetThread()->GetExceptionState()->GetCurrentExceptionTracker();
9551 #elif _TARGET_X86_
9552     PTR_ExInfo pEHTracker = (pStartingEHTracker != NULL) ? pStartingEHTracker : GetThread()->GetExceptionState()->GetCurrentExceptionTracker();
9553 #else // !(_WIN64 || _TARGET_X86_)
9554 #error Unsupported platform
9555 #endif // _WIN64
9556
9557     BOOL fFoundTracker = FALSE;
9558
9559     struct
9560     {
9561         OBJECTREF oPreAllocThrowable;
9562     } gc;
9563     ZeroMemory(&gc, sizeof(gc));
9564     GCPROTECT_BEGIN(gc);
9565
9566     gc.oPreAllocThrowable = oPreAllocThrowable;
9567
9568     // Start walking the list to find the tracker correponding
9569     // to the preallocated exception object.
9570     while (pEHTracker != NULL)
9571     {
9572         if (pEHTracker->GetThrowable() == gc.oPreAllocThrowable)
9573         {
9574             // found the tracker - break out.
9575             fFoundTracker = TRUE;
9576             break;
9577         }
9578
9579         // move to the previous tracker...
9580         pEHTracker = pEHTracker->GetPreviousExceptionTracker();
9581     }
9582
9583     GCPROTECT_END();
9584
9585     return fFoundTracker ? pEHTracker : NULL;
9586 }
9587
9588 // This function will return the pointer to EHWatsonBucketTracker corresponding to the
9589 // preallocated exception object. If none is found, it will return NULL.
9590 PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable,
9591                                                                          BOOL fCaptureBucketsIfNotPresent,
9592                                                                          BOOL fStartSearchFromPreviousTracker /*= FALSE*/)
9593 {
9594 #ifndef DACCESS_COMPILE
9595     CONTRACTL
9596     {
9597         GC_NOTRIGGER;
9598         MODE_COOPERATIVE;
9599         NOTHROW;
9600         PRECONDITION(GetThread() != NULL);
9601         PRECONDITION(oPreAllocThrowable != NULL);
9602         PRECONDITION(CLRException::IsPreallocatedExceptionObject(oPreAllocThrowable));
9603         PRECONDITION(IsWatsonEnabled());
9604     }
9605     CONTRACTL_END;
9606
9607     PTR_EHWatsonBucketTracker pWBTracker = NULL;
9608
9609     struct
9610     {
9611         OBJECTREF oPreAllocThrowable;
9612     } gc;
9613     ZeroMemory(&gc, sizeof(gc));
9614     GCPROTECT_BEGIN(gc);
9615
9616     gc.oPreAllocThrowable = oPreAllocThrowable;
9617
9618     // Before doing anything, check if this is a thread abort exception. If it is,
9619     // then simply return the reference to the UE watson bucket tracker since it
9620     // tracks the bucketing details for all types of TAE.
9621     if (IsThrowableThreadAbortException(gc.oPreAllocThrowable))
9622     {
9623         pWBTracker = GetThread()->GetExceptionState()->GetUEWatsonBucketTracker();
9624         LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Setting UE Watson Bucket Tracker to be returned for preallocated ThreadAbortException.\n"));
9625         goto doValidation;
9626     }
9627
9628     {
9629         // Find the reference to the exception tracker corresponding to the preallocated exception,
9630         // starting the search from the current exception tracker (2nd arg of NULL specifies that).
9631  #if defined(WIN64EXCEPTIONS)
9632         PTR_ExceptionTracker pEHTracker = NULL;
9633         PTR_ExceptionTracker pPreviousEHTracker = NULL;
9634
9635 #elif _TARGET_X86_
9636         PTR_ExInfo pEHTracker = NULL;
9637         PTR_ExInfo pPreviousEHTracker = NULL;
9638 #else // !(_WIN64 || _TARGET_X86_)
9639 #error Unsupported platform
9640 #endif // _WIN64
9641
9642         if (fStartSearchFromPreviousTracker)
9643         {
9644             // Get the exception tracker previous to the current one
9645             pPreviousEHTracker = GetThread()->GetExceptionState()->GetCurrentExceptionTracker()->GetPreviousExceptionTracker();
9646
9647             // If there is no previous tracker to start from, then simply abort the search attempt.
9648             // If we couldnt find the exception tracker, then buckets are not available
9649             if (pPreviousEHTracker == NULL)
9650             {
9651                 LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Couldnt find the previous EHTracker to start the search from.\n"));
9652                 pWBTracker = NULL;
9653                 goto done;
9654             }
9655         }
9656
9657         pEHTracker = GetEHTrackerForPreallocatedException(gc.oPreAllocThrowable, pPreviousEHTracker);
9658
9659         // If we couldnt find the exception tracker, then buckets are not available
9660         if (pEHTracker == NULL)
9661         {
9662             LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Couldnt find EHTracker for preallocated exception object.\n"));
9663             pWBTracker = NULL;
9664             goto done;
9665         }
9666
9667         // Get the Watson Bucket Tracker from the exception tracker
9668         pWBTracker = pEHTracker->GetWatsonBucketTracker();
9669     }
9670 doValidation:
9671     _ASSERTE(pWBTracker != NULL);
9672
9673     // Incase of an OOM, we may not have an IP in the Watson bucket tracker. A scenario
9674     // would be default domain calling to AD 2 that calls into AD 3.
9675     //
9676     // AD 3 has an exception that is represented by a preallocated exception object. The
9677     // exception goes unhandled and reaches AD2/AD3 transition boundary. The bucketing details
9678     // from AD3 are copied to UETracker and once the exception is reraised in AD2, we will
9679     // enter SetupInitialThrowBucketingDetails to copy the bucketing details to the active
9680     // exception tracker.
9681     //
9682     // This copy operation could fail due to OOM and the active exception tracker in AD 2,
9683     // for the preallocated exception object, will not have any bucketing details. If the
9684     // exception remains unhandled in AD 2, then just before it reaches DefDomain/AD2 boundary,
9685     // we will attempt to capture the bucketing details in AppDomainTransitionExceptionFilter,
9686     // that will bring us here.
9687     //
9688     // In such a case, the active exception tracker will not have any bucket details for the
9689     // preallocated exception. In such a case, if the IP does not exist, we will return NULL
9690     // indicating that we couldnt find the Watson bucket tracker, since returning a tracker
9691     // that does not have any bucketing details will be of no use to the caller.
9692     if (pWBTracker->RetrieveWatsonBucketIp() != NULL)
9693     {
9694         // Check if the buckets exist or not..
9695         PTR_VOID pBuckets = pWBTracker->RetrieveWatsonBuckets();
9696
9697         // If they dont exist and we have been asked to collect them,
9698         // then do so.
9699         if (pBuckets == NULL)
9700         {
9701             if (fCaptureBucketsIfNotPresent)
9702             {
9703                 pWBTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, GetThread(), &gc.oPreAllocThrowable);
9704
9705                 // Check if we have the buckets now
9706                 if (pWBTracker->RetrieveWatsonBuckets() != NULL)
9707                 {
9708                     LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Captured watson buckets for preallocated exception object.\n"));
9709                 }
9710                 else
9711                 {
9712                     LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Unable to capture watson buckets for preallocated exception object due to OOM.\n"));
9713                 }
9714             }
9715             else
9716             {
9717                 LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Found IP but no buckets for preallocated exception object.\n"));
9718             }
9719         }
9720         else
9721         {
9722             LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Buckets already exist for preallocated exception object.\n"));
9723         }
9724     }
9725     else
9726     {
9727         LOG((LF_EH, LL_INFO100, "GetWatsonBucketTrackerForPreallocatedException - Returning NULL EHWatsonBucketTracker since bucketing IP does not exist. This is likely due to an earlier OOM.\n"));
9728         pWBTracker = NULL;
9729     }
9730
9731 done:;
9732
9733     GCPROTECT_END();
9734
9735     // Return the Watson bucket tracker
9736     return pWBTracker;
9737 #else // DACCESS_COMPILE
9738     return NULL;
9739 #endif // !DACCESS_COMPILE
9740 }
9741
9742 // Given an exception object, this function will attempt to look up
9743 // the watson buckets for it and set them up against the thread
9744 // for use by FailFast mechanism.
9745 // Return TRUE when it succeeds or Waston is disabled on CoreCLR
9746 // Return FALSE when refException neither has buckets nor has inner exception
9747 BOOL SetupWatsonBucketsForFailFast(EXCEPTIONREF refException)
9748 {
9749     BOOL fResult = TRUE;
9750
9751 #ifndef DACCESS_COMPILE
9752     // On CoreCLR, Watson may not be enabled. Thus, we should
9753     // skip this.
9754     if (!IsWatsonEnabled())
9755     {
9756         return fResult;
9757     }
9758
9759     CONTRACTL
9760     {
9761         GC_TRIGGERS;
9762         MODE_ANY;
9763         NOTHROW;
9764         PRECONDITION(GetThread() != NULL);
9765         PRECONDITION(refException != NULL);
9766         PRECONDITION(IsWatsonEnabled());
9767     }
9768     CONTRACTL_END;
9769
9770     // Switch to COOP mode
9771     GCX_COOP();
9772
9773     struct
9774     {
9775         OBJECTREF refException;
9776         OBJECTREF oInnerMostExceptionThrowable;
9777     } gc;
9778     ZeroMemory(&gc, sizeof(gc));
9779     GCPROTECT_BEGIN(gc);
9780     gc.refException = refException;
9781
9782     Thread *pThread = GetThread();
9783
9784     // If we dont already have the bucketing details for the exception
9785     // being thrown, then get them.
9786     ThreadExceptionState *pExState = pThread->GetExceptionState();
9787
9788     // Check if the exception object is preallocated or not
9789     BOOL fIsPreallocatedException = CLRException::IsPreallocatedExceptionObject(gc.refException);
9790
9791     // Get the WatsonBucketTracker where bucketing details will be copied to
9792     PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
9793
9794     // Check if this is a thread abort exception of any kind.
9795     // See IsThrowableThreadAbortException implementation for details.
9796     BOOL fIsThreadAbortException = IsThrowableThreadAbortException(gc.refException);
9797
9798     if (fIsPreallocatedException)
9799     {
9800         // If the exception being used to FailFast is preallocated,
9801         // then it cannot have any inner exception. Thus, try to
9802         // find the watson bucket tracker corresponding to this exception.
9803         //
9804         // Also, capture the buckets if we dont have them already.
9805         PTR_EHWatsonBucketTracker pTargetWatsonBucketTracker = GetWatsonBucketTrackerForPreallocatedException(gc.refException, TRUE);
9806         if ((pTargetWatsonBucketTracker != NULL) && (!fIsThreadAbortException))
9807         {
9808             // Buckets are not captured proactively for preallocated exception objects. We only
9809             // save the IP in the watson bucket tracker (see SetupInitialThrowBucketingDetails for
9810             // details).
9811             //
9812             // Thus, if, say in DefDomain, a preallocated exception is thrown and we enter
9813             // the catch block and invoke the FailFast API with the reference to the preallocated
9814             // exception object, we will have the IP but not the buckets. In such a case,
9815             // capture the buckets before proceeding ahead.
9816             if (pTargetWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
9817             {
9818                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForFailFast - Collecting watson bucket details for preallocated exception.\n"));
9819                 pTargetWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, &gc.refException);
9820             }
9821
9822             // Copy the buckets to the UE tracker
9823             pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9824             pUEWatsonBucketTracker->CopyEHWatsonBucketTracker(*pTargetWatsonBucketTracker);
9825             if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
9826             {
9827                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForFailFast - Collected watson bucket details for preallocated exception in UE tracker.\n"));
9828             }
9829             else
9830             {
9831                 // If we are here, then the copy operation above had an OOM, resulting
9832                 // in no buckets for us.
9833                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForFailFast - Unable to collect watson bucket details for preallocated exception due to out of memory.\n"));
9834
9835                 // Make sure the tracker is clean.
9836                 pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9837             }
9838         }
9839         else
9840         {
9841             // For TAE, UE watson bucket tracker is the one that tracks the buckets. It *may*
9842             // not have the bucket details if FailFast is being invoked from outside the
9843             // managed EH clauses. But if invoked from within the active EH clause for the exception,
9844             // UETracker will have the bucketing details (see SetupInitialThrowBucketingDetails for details).
9845             if (fIsThreadAbortException && (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL))
9846             {
9847                 _ASSERTE(pTargetWatsonBucketTracker == pUEWatsonBucketTracker);
9848                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForFailFast - UE tracker already watson bucket details for preallocated thread abort exception.\n"));
9849             }
9850             else
9851             {
9852                 LOG((LF_EH, LL_INFO100, "SetupWatsonBucketsForFailFast - Unable to find bucket details for preallocated %s exception.\n",
9853                     fIsThreadAbortException?"rude/thread abort":""));
9854
9855                 // Make sure the tracker is clean.
9856                 pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9857             }
9858         }
9859     }
9860     else
9861     {
9862         // Since the exception object is not preallocated, start by assuming
9863         // that we dont need to check it for watson buckets
9864         BOOL fCheckThrowableForWatsonBuckets = FALSE;
9865
9866         // Get the innermost exception object (if any)
9867         gc.oInnerMostExceptionThrowable = ((EXCEPTIONREF)gc.refException)->GetBaseException();
9868         if (gc.oInnerMostExceptionThrowable != NULL)
9869         {
9870             if (CLRException::IsPreallocatedExceptionObject(gc.oInnerMostExceptionThrowable))
9871             {
9872                 // If the inner most exception being used to FailFast is preallocated,
9873                 // try to find the watson bucket tracker corresponding to it.
9874                 //
9875                 // Also, capture the buckets if we dont have them already.
9876                 PTR_EHWatsonBucketTracker pTargetWatsonBucketTracker =
9877                     GetWatsonBucketTrackerForPreallocatedException(gc.oInnerMostExceptionThrowable, TRUE);
9878
9879                 if (pTargetWatsonBucketTracker != NULL)
9880                 {
9881                     if (pTargetWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
9882                     {
9883                         LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Capturing Watson bucket details for preallocated inner exception.\n"));
9884                         pTargetWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, &gc.oInnerMostExceptionThrowable);
9885                     }
9886
9887                     // Copy the details to the UE tracker
9888                     pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9889                     pUEWatsonBucketTracker->CopyEHWatsonBucketTracker(*pTargetWatsonBucketTracker);
9890                     if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
9891                     {
9892                         LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Watson bucket details collected for preallocated inner exception.\n"));
9893                     }
9894                     else
9895                     {
9896                         // If we are here, copy operation failed likely due to OOM
9897                         LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Unable to copy watson bucket details for preallocated inner exception.\n"));
9898
9899                         // Keep the UETracker clean
9900                         pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9901                     }
9902                 }
9903                 else
9904                 {
9905                     LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Unable to find bucket details for preallocated inner exception.\n"));
9906
9907                     // Keep the UETracker clean
9908                     pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9909
9910                     // Since we couldnt find the watson bucket tracker for the the inner most exception,
9911                     // try to look for the buckets in the throwable.
9912                     fCheckThrowableForWatsonBuckets = TRUE;
9913                 }
9914             }
9915             else
9916             {
9917                 // Inner most exception is not preallocated.
9918                 //
9919                 // If it has the IP but not the buckets, then capture them now.
9920                 if ((((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent() == FALSE) &&
9921                     (((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->IsIPForWatsonBucketsPresent()))
9922                 {
9923                     SetupWatsonBucketsForNonPreallocatedExceptions(gc.oInnerMostExceptionThrowable);
9924                 }
9925
9926                 // If it has the buckets, copy them over to the current Watson bucket tracker
9927                 if (((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent())
9928                 {
9929                     pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9930                     pUEWatsonBucketTracker->CopyBucketsFromThrowable(gc.oInnerMostExceptionThrowable);
9931                     if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
9932                     {
9933                         LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Got watson buckets from regular innermost exception.\n"));
9934                     }
9935                     else
9936                     {
9937                         // Copy operation can fail due to OOM
9938                         LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Unable to copy watson buckets from regular innermost exception, likely due to OOM.\n"));
9939                     }
9940                 }
9941                 else
9942                 {
9943                     // Since the inner most exception didnt have the buckets,
9944                     // try to look for them in the throwable
9945                     fCheckThrowableForWatsonBuckets = TRUE;
9946                     LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Neither exception object nor its inner exception has watson buckets.\n"));
9947                 }
9948             }
9949         }
9950         else
9951         {
9952             // There is no innermost exception - try to look for buckets
9953             // in the throwable
9954             fCheckThrowableForWatsonBuckets = TRUE;
9955             LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Innermost exception does not exist\n"));
9956         }
9957
9958         if (fCheckThrowableForWatsonBuckets)
9959         {
9960             // Since we have not found buckets anywhere, try to look for them
9961             // in the throwable.
9962             if ((((EXCEPTIONREF)gc.refException)->AreWatsonBucketsPresent() == FALSE) &&
9963                 (((EXCEPTIONREF)gc.refException)->IsIPForWatsonBucketsPresent()))
9964             {
9965                 // Capture the buckets from the IP.
9966                 SetupWatsonBucketsForNonPreallocatedExceptions(gc.refException);
9967             }
9968
9969             if (((EXCEPTIONREF)gc.refException)->AreWatsonBucketsPresent())
9970             {
9971                 // Copy the buckets to the current watson bucket tracker
9972                 pUEWatsonBucketTracker->ClearWatsonBucketDetails();
9973                 pUEWatsonBucketTracker->CopyBucketsFromThrowable(gc.refException);
9974                 if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
9975                 {
9976                     LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Watson buckets copied from the exception object.\n"));
9977                 }
9978                 else
9979                 {
9980                     LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Unable to copy Watson buckets copied from the exception object, likely due to OOM.\n"));
9981                 }
9982             }
9983             else
9984             {
9985                 fResult = FALSE;
9986                 LOG((LF_EH, LL_INFO1000, "SetupWatsonBucketsForFailFast - Exception object neither has buckets nor has inner exception.\n"));
9987             }
9988         }
9989     }
9990
9991     GCPROTECT_END();
9992
9993 #endif // !DACCESS_COMPILE
9994
9995     return fResult;
9996 }
9997
9998 // This function will setup the bucketing details in the exception
9999 // tracker or the throwable, if they are not already setup.
10000 //
10001 // This is called when an exception is thrown (or raised):
10002 //
10003 // 1) from outside the confines of managed EH clauses, OR
10004 // 2) from within the confines of managed EH clauses but the
10005 //    exception does not have bucketing details with it, OR
10006 // 3) When an exception is reraised at AD transition boundary
10007 //    after it has been marshalled over to the returning AD.
10008 void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp)
10009 {
10010 #ifndef DACCESS_COMPILE
10011
10012     // On CoreCLR, Watson may not be enabled. Thus, we should
10013     // skip this.
10014     if (!IsWatsonEnabled())
10015     {
10016         return;
10017     }
10018
10019     CONTRACTL
10020     {
10021         GC_TRIGGERS;
10022         MODE_ANY;
10023         NOTHROW;
10024         PRECONDITION(GetThread() != NULL);
10025         PRECONDITION(!(GetThread()->GetExceptionState()->GetFlags()->GotWatsonBucketDetails()));
10026         PRECONDITION(adjustedIp != NULL);
10027         PRECONDITION(IsWatsonEnabled());
10028     }
10029     CONTRACTL_END;
10030
10031     Thread *pThread = GetThread();
10032
10033     // If we dont already have the bucketing details for the exception
10034     // being thrown, then get them.
10035     ThreadExceptionState *pExState = pThread->GetExceptionState();
10036
10037     // Ensure that the exception tracker exists
10038     _ASSERTE(pExState->GetCurrentExceptionTracker() != NULL);
10039
10040     // Switch to COOP mode
10041     GCX_COOP();
10042
10043     // Get the throwable for the exception being thrown
10044     struct
10045     {
10046         OBJECTREF oCurrentThrowable;
10047         OBJECTREF oInnerMostExceptionThrowable;
10048     } gc;
10049     ZeroMemory(&gc, sizeof(gc));
10050
10051     GCPROTECT_BEGIN(gc);
10052
10053     gc.oCurrentThrowable = pExState->GetThrowable();
10054
10055     // Check if the exception object is preallocated or not
10056     BOOL fIsPreallocatedException = CLRException::IsPreallocatedExceptionObject(gc.oCurrentThrowable);
10057
10058     // Get the WatsonBucketTracker for the current exception
10059     PTR_EHWatsonBucketTracker pWatsonBucketTracker = pExState->GetCurrentExceptionTracker()->GetWatsonBucketTracker();
10060
10061     // Get the innermost exception object (if any)
10062     gc.oInnerMostExceptionThrowable = ((EXCEPTIONREF)gc.oCurrentThrowable)->GetBaseException();
10063
10064     // By default, assume that no watson bucketing details are available and inner exception
10065     // is not preallocated
10066     BOOL fAreBucketingDetailsPresent = FALSE;
10067     BOOL fIsInnerExceptionPreallocated = FALSE;
10068
10069     // Check if this is a thread abort exception of any kind. See IsThrowableThreadAbortException implementation for details.
10070     // We shouldnt use the thread state as well to determine if it is a TAE since, in cases like throwing a cached exception
10071     // as part of type initialization failure, we could throw a TAE but the thread will not be in abort state (which is expected).
10072     BOOL fIsThreadAbortException = IsThrowableThreadAbortException(gc.oCurrentThrowable);
10073
10074     // If we are here, then this was a new exception raised
10075     // from outside the managed EH clauses (fault/finally/catch).
10076     //
10077     // The throwable *may* have the bucketing details already
10078     // if this exception was raised when it was crossing over
10079     // an AD transition boundary. Those are stored in UE watson bucket
10080     // tracker by AppDomainTransitionExceptionFilter.
10081     if (fIsPreallocatedException)
10082     {
10083         PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
10084         fAreBucketingDetailsPresent = ((pUEWatsonBucketTracker->RetrieveWatsonBucketIp() != NULL) &&
10085                                        (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL));
10086
10087         // If they are present, copy them over to the watson tracker for the exception
10088         // being processed.
10089         if (fAreBucketingDetailsPresent)
10090         {
10091 #ifdef _DEBUG
10092             // Under OOM scenarios, its possible that when we are raising a threadabort,
10093             // the throwable may get converted to preallocated OOM object when RaiseTheExceptionInternalOnly
10094             // invokes Thread::SafeSetLastThrownObject. We check if this is the current case and use it in
10095             // our validation below.
10096             BOOL fIsPreallocatedOOMExceptionForTA = FALSE;
10097             if ((!fIsThreadAbortException) && pUEWatsonBucketTracker->CapturedForThreadAbort())
10098             {
10099                 fIsPreallocatedOOMExceptionForTA = (gc.oCurrentThrowable == CLRException::GetPreallocatedOutOfMemoryException());
10100                 if (fIsPreallocatedOOMExceptionForTA)
10101                 {
10102                     LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Got preallocated OOM throwable for buckets captured for thread abort.\n"));
10103                 }
10104             }
10105 #endif // _DEBUG
10106             // These should have been captured at AD transition OR
10107             // could be bucketing details of preallocated [rude] thread abort exception.
10108             _ASSERTE(pUEWatsonBucketTracker->CapturedAtADTransition() ||
10109                      ((fIsThreadAbortException || fIsPreallocatedOOMExceptionForTA) && pUEWatsonBucketTracker->CapturedForThreadAbort()));
10110
10111             if (!fIsThreadAbortException)
10112             {
10113                 // The watson bucket tracker for the exceptiong being raised should be empty at this point
10114                 // since we are here because of a cross AD reraise of the original exception.
10115                 _ASSERTE((pWatsonBucketTracker->RetrieveWatsonBucketIp() == NULL) && (pWatsonBucketTracker->RetrieveWatsonBuckets() == NULL));
10116
10117                 // Copy the buckets over to it
10118                 pWatsonBucketTracker->CopyEHWatsonBucketTracker(*(pUEWatsonBucketTracker));
10119                 if (pWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
10120                 {
10121                     // If we dont have buckets after the copy operation, its due to us running out of
10122                     // memory.
10123                     LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Unable to copy watson buckets from cross AD rethrow, likely due to out of memory.\n"));
10124                 }
10125                 else
10126                 {
10127                     LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Copied watson buckets from cross AD rethrow.\n"));
10128                 }
10129             }
10130             else
10131             {
10132                 // Thread abort watson bucket details are already present in the
10133                 // UE watson bucket tracker.
10134                 LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Already have watson buckets for preallocated thread abort reraise.\n"));
10135             }
10136         }
10137         else if (fIsThreadAbortException)
10138         {
10139             // This is a preallocated thread abort exception.
10140             UINT_PTR ip = pUEWatsonBucketTracker->RetrieveWatsonBucketIp();
10141             if (ip != NULL)
10142             {
10143                 // Since we have the IP, assert that this was the one setup
10144                 // for ThreadAbort. This is for the reraise scenario where
10145                 // the original exception was non-preallocated TA but the
10146                 // reraise resulted in preallocated TA.
10147                 //
10148                 // In this case, we will update the ip to be used as the
10149                 // one we have. The control flow below will automatically
10150                 // endup using it.
10151                 _ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort());
10152                 adjustedIp = ip;
10153                 LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Setting an existing IP (%p) to be used for capturing buckets for preallocated thread abort.\n", ip));
10154                 goto phase1;
10155             }
10156         }
10157
10158         if (!fAreBucketingDetailsPresent || !fIsThreadAbortException)
10159         {
10160             // Clear the UE Watson bucket tracker so that its usable
10161             // in future. We dont clear this for ThreadAbort since
10162             // the UE watson bucket tracker carries bucketing details
10163             // for the same, unless the UE tracker is not containing them
10164             // already.
10165             pUEWatsonBucketTracker->ClearWatsonBucketDetails();
10166         }
10167     }
10168     else
10169     {
10170         // The exception object is not preallocated
10171         fAreBucketingDetailsPresent = ((EXCEPTIONREF)gc.oCurrentThrowable)->AreWatsonBucketsPresent();
10172         if (!fAreBucketingDetailsPresent)
10173         {
10174             // If buckets are not present, check if the bucketing IP is present.
10175             fAreBucketingDetailsPresent = ((EXCEPTIONREF)gc.oCurrentThrowable)->IsIPForWatsonBucketsPresent();
10176         }
10177
10178         // If throwable does not have buckets and this is a thread abort exception,
10179         // then this maybe a reraise of the original thread abort.
10180         //
10181         // We can also be here if an exception was caught at AppDomain transition and
10182         // in the returning domain, a non-preallocated TAE was raised. In such a case,
10183         // the UE tracker flags could indicate the exception is from AD transition.
10184         // This is similar to preallocated case above.
10185         //
10186         // Check the UE Watson bucket tracker if it has the buckets and if it does,
10187         // copy them over to the current throwable.
10188         if (!fAreBucketingDetailsPresent && fIsThreadAbortException)
10189         {
10190             PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
10191             UINT_PTR ip = pUEWatsonBucketTracker->RetrieveWatsonBucketIp();
10192             if (ip != NULL)
10193             {
10194                 // Confirm that we had the buckets captured for thread abort
10195                 _ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort() || pUEWatsonBucketTracker->CapturedAtADTransition());
10196
10197                 if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
10198                 {
10199                     // Copy the buckets to the current throwable - CopyWatsonBucketsToThrowable
10200                     // can throw in OOM. However, since the current function is called as part of
10201                     // setting up the stack trace, where we bail out incase of OOM, we will do
10202                     // no different here as well.
10203                     BOOL fCopiedBuckets = TRUE;
10204                     EX_TRY
10205                     {
10206                         CopyWatsonBucketsToThrowable(pUEWatsonBucketTracker->RetrieveWatsonBuckets());
10207                         _ASSERTE(((EXCEPTIONREF)gc.oCurrentThrowable)->AreWatsonBucketsPresent());
10208                     }
10209                     EX_CATCH
10210                     {
10211                         fCopiedBuckets = FALSE;
10212                     }
10213                     EX_END_CATCH(SwallowAllExceptions);
10214
10215                     if (fCopiedBuckets)
10216                     {
10217                         // Since the throwable has the buckets, set the flag that indicates so
10218                         fAreBucketingDetailsPresent = TRUE;
10219                         LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Setup watson buckets for thread abort reraise.\n"));
10220                     }
10221                 }
10222                 else
10223                 {
10224                     // Copy the faulting IP from the UE tracker to the exception object. This was setup in COMPlusCheckForAbort
10225                     // for non-preallocated exceptions.
10226                     ((EXCEPTIONREF)gc.oCurrentThrowable)->SetIPForWatsonBuckets(ip);
10227                     fAreBucketingDetailsPresent = TRUE;
10228                     LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Setup watson bucket IP for thread abort reraise.\n"));
10229                 }
10230             }
10231             else
10232             {
10233                 // Clear the UE Watson bucket tracker so that its usable
10234                 // in future.
10235                 pUEWatsonBucketTracker->ClearWatsonBucketDetails();
10236                 LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Didnt find watson buckets for thread abort - likely being raised.\n"));
10237             }
10238         }
10239     }
10240
10241 phase1:
10242     if (fAreBucketingDetailsPresent)
10243     {
10244         // Since we already have the buckets, simply bail out
10245         LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Already had watson ip/buckets.\n"));
10246         goto done;
10247     }
10248
10249     // Check if an inner most exception exists and if it does, examine
10250     // it for watson bucketing details.
10251     if (gc.oInnerMostExceptionThrowable != NULL)
10252     {
10253         // Preallocated exception objects do not have inner exception objects.
10254         // Thus, if we are here, then the current throwable cannot be
10255         // a preallocated exception object.
10256         _ASSERTE(!fIsPreallocatedException);
10257
10258         fIsInnerExceptionPreallocated = CLRException::IsPreallocatedExceptionObject(gc.oInnerMostExceptionThrowable);
10259
10260         // If we are here, then this was a "throw" with inner exception
10261         // outside of any managed EH clauses.
10262         //
10263         // If the inner exception object is preallocated, then we will need to create the
10264         // watson buckets since we are outside the managed EH clauses with no exception tracking
10265         // information relating to the inner exception.
10266         //
10267         // But if the inner exception object was not preallocated, create new watson buckets
10268         // only if inner exception does not have them.
10269         if (fIsInnerExceptionPreallocated)
10270         {
10271             fAreBucketingDetailsPresent = FALSE;
10272         }
10273         else
10274         {
10275             // Do we have either the IP for Watson buckets or the buckets themselves?
10276             fAreBucketingDetailsPresent = (((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent() ||
10277                                             ((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->IsIPForWatsonBucketsPresent());
10278         }
10279     }
10280
10281     if (!fAreBucketingDetailsPresent)
10282     {
10283         // Collect the bucketing details since they are not already present
10284         pWatsonBucketTracker->SaveIpForWatsonBucket(adjustedIp);
10285
10286         if (!fIsPreallocatedException || fIsThreadAbortException)
10287         {
10288             if (!fIsPreallocatedException)
10289             {
10290                 // Save the IP for Watson bucketing in the exception object for non-preallocated exception
10291                 // objects
10292                 ((EXCEPTIONREF)gc.oCurrentThrowable)->SetIPForWatsonBuckets(adjustedIp);
10293
10294                 // Save the IP in the UE tracker as well for TAE if an abort is in progress
10295                 // since when we attempt reraise, the exception object is not available. Otherwise,
10296                 // treat the exception like a regular non-preallocated exception and not do anything else.
10297                 if (fIsThreadAbortException && pThread->IsAbortInitiated())
10298                 {
10299                     PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
10300
10301                     pUEWatsonBucketTracker->ClearWatsonBucketDetails();
10302                     pUEWatsonBucketTracker->SaveIpForWatsonBucket(adjustedIp);
10303
10304                     // Set the flag that we captured the IP for Thread abort
10305                     DEBUG_STMT(pUEWatsonBucketTracker->SetCapturedForThreadAbort());
10306                     LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Saved bucket IP for initial thread abort raise.\n"));
10307                 }
10308             }
10309             else
10310             {
10311                 // Create the buckets proactively for preallocated threadabort exception
10312                 pWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, &gc.oCurrentThrowable);
10313                 PTR_VOID pUnmanagedBuckets = pWatsonBucketTracker->RetrieveWatsonBuckets();
10314                 if(pUnmanagedBuckets != NULL)
10315                 {
10316                     // Copy the details over to the UE Watson bucket tracker so that we can use them if the exception
10317                     // is "reraised" after invoking the catch block.
10318                     //
10319                     // Since we can be here for preallocated threadabort exception when UE Tracker is simply
10320                     // carrying the IP (that has been copied to pWatsonBucketTracker and buckets captured for it),
10321                     // we will need to clear UE tracker so that we can copy over the captured buckets.
10322                     PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
10323                     pUEWatsonBucketTracker->ClearWatsonBucketDetails();
10324
10325                     // Copy over the buckets from the current tracker that captured them.
10326                     pUEWatsonBucketTracker->CopyEHWatsonBucketTracker(*(pWatsonBucketTracker));
10327
10328                     // Buckets should be present now (unless the copy operation had an OOM)
10329                     if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
10330                     {
10331                         // Set the flag that we captured buckets for Thread abort
10332                         DEBUG_STMT(pUEWatsonBucketTracker->SetCapturedForThreadAbort());
10333                         LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Saved buckets for Watson Bucketing for initial thread abort raise.\n"));
10334                     }
10335                     else
10336                     {
10337                         // If we are here, then the bucket copy operation (above) failed due to OOM.
10338                         LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Unable to save buckets for Watson Bucketing for initial thread abort raise, likely due to OOM.\n"));
10339                         pUEWatsonBucketTracker->ClearWatsonBucketDetails();
10340                     }
10341                 }
10342                 else
10343                 {
10344                     // Watson helper function can bail out on us under OOM scenarios and return a NULL.
10345                     // We cannot do much in such a case.
10346                     LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - No buckets were captured and returned to us for initial thread abort raise. Likely encountered an OOM.\n"));
10347                 }
10348
10349                 // Clear the buckets since we no longer need them
10350                 pWatsonBucketTracker->ClearWatsonBucketDetails();
10351             }
10352         }
10353         else
10354         {
10355             // We have already saved the throw site IP for bucketing the non-ThreadAbort preallocated exceptions
10356             LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Saved IP (%p) for Watson Bucketing for a preallocated exception\n", adjustedIp));
10357         }
10358     }
10359     else
10360     {
10361         // The inner exception object should be having either the IP for watson bucketing or the buckets themselves.
10362         // We shall copy over, whatever is available, to the current exception object.
10363         _ASSERTE(gc.oInnerMostExceptionThrowable != NULL);
10364         _ASSERTE(((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent() ||
10365                   ((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->IsIPForWatsonBucketsPresent());
10366
10367         if (((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent())
10368         {
10369             EX_TRY
10370             {
10371                 // Copy the bucket details from innermost exception to the current exception object.
10372                 CopyWatsonBucketsFromThrowableToCurrentThrowable(gc.oInnerMostExceptionThrowable);
10373             }
10374             EX_CATCH
10375             {
10376             }
10377             EX_END_CATCH(SwallowAllExceptions);
10378
10379             LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Copied watson bucket details from the innermost exception\n"));
10380         }
10381         else
10382         {
10383             // Copy the IP to the current exception object
10384             ((EXCEPTIONREF)gc.oCurrentThrowable)->SetIPForWatsonBuckets(((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->GetIPForWatsonBuckets());
10385             LOG((LF_EH, LL_INFO100, "SetupInitialThrowBucketDetails - Copied watson bucket IP from the innermost exception\n"));
10386         }
10387     }
10388
10389 done:
10390     // Set the flag that we have got the bucketing details
10391     pExState->GetFlags()->SetGotWatsonBucketDetails();
10392
10393     GCPROTECT_END();
10394
10395 #endif // !DACCESS_COMPILE
10396 }
10397
10398 // This function is a wrapper to copy the watson bucket byte[] from the specified
10399 // throwable to the current throwable.
10400 void CopyWatsonBucketsFromThrowableToCurrentThrowable(OBJECTREF oThrowableFrom)
10401 {
10402 #ifndef DACCESS_COMPILE
10403
10404     CONTRACTL
10405     {
10406         GC_TRIGGERS;
10407         MODE_COOPERATIVE;
10408         THROWS;
10409         PRECONDITION(oThrowableFrom != NULL);
10410         PRECONDITION(!CLRException::IsPreallocatedExceptionObject(oThrowableFrom));
10411         PRECONDITION(((EXCEPTIONREF)oThrowableFrom)->AreWatsonBucketsPresent());
10412         PRECONDITION(IsWatsonEnabled());
10413     }
10414     CONTRACTL_END;
10415
10416     struct
10417     {
10418         OBJECTREF oThrowableFrom;
10419     } _gc;
10420
10421     ZeroMemory(&_gc, sizeof(_gc));
10422     GCPROTECT_BEGIN(_gc);
10423     _gc.oThrowableFrom = oThrowableFrom;
10424
10425     // Copy the watson buckets to the current throwable by NOT passing
10426     // the second argument that will default to NULL.
10427     //
10428     // CopyWatsonBucketsBetweenThrowables will pass that NULL to
10429     // CopyWatsonBucketsToThrowables that will make it copy the buckets
10430     // to the current throwable.
10431     CopyWatsonBucketsBetweenThrowables(_gc.oThrowableFrom);
10432
10433     GCPROTECT_END();
10434
10435 #endif // !DACCESS_COMPILE
10436 }
10437
10438 // This function will copy the watson bucket byte[] from the source
10439 // throwable to the destination throwable.
10440 //
10441 // If the destination throwable is NULL, it will result in the buckets
10442 // being copied to the current throwable.
10443 void CopyWatsonBucketsBetweenThrowables(OBJECTREF oThrowableFrom, OBJECTREF oThrowableTo /*=NULL*/)
10444 {
10445 #ifndef DACCESS_COMPILE
10446
10447     CONTRACTL
10448     {
10449         GC_TRIGGERS;
10450         MODE_COOPERATIVE;
10451         THROWS;
10452         PRECONDITION(oThrowableFrom != NULL);
10453         PRECONDITION(!CLRException::IsPreallocatedExceptionObject(oThrowableFrom));
10454         PRECONDITION(((EXCEPTIONREF)oThrowableFrom)->AreWatsonBucketsPresent());
10455         PRECONDITION(IsWatsonEnabled());
10456     }
10457     CONTRACTL_END;
10458
10459     BOOL fRetVal = FALSE;
10460
10461     struct
10462     {
10463         OBJECTREF oFrom;
10464         OBJECTREF oTo;
10465         OBJECTREF oWatsonBuckets;
10466     } _gc;
10467
10468     ZeroMemory(&_gc, sizeof(_gc));
10469     GCPROTECT_BEGIN(_gc);
10470
10471     _gc.oFrom = oThrowableFrom;
10472     _gc.oTo = (oThrowableTo == NULL)?GetThread()->GetThrowable():oThrowableTo;
10473     _ASSERTE(_gc.oTo != NULL);
10474
10475     // The target throwable to which Watson buckets are going to be copied
10476     // shouldnt be preallocated exception object.
10477     _ASSERTE(!CLRException::IsPreallocatedExceptionObject(_gc.oTo));
10478
10479     // Size of a watson bucket
10480     DWORD size = sizeof(GenericModeBlock);
10481
10482     // Create the managed byte[] to hold the bucket details
10483     _gc.oWatsonBuckets = AllocatePrimitiveArray(ELEMENT_TYPE_U1, size);
10484     if (_gc.oWatsonBuckets == NULL)
10485     {
10486         // return failure if failed to create bucket array
10487         fRetVal = FALSE;
10488     }
10489     else
10490     {
10491         // Get the raw array data pointer of the source array
10492         U1ARRAYREF refSourceWatsonBucketArray = ((EXCEPTIONREF)_gc.oFrom)->GetWatsonBucketReference();
10493         PTR_VOID pRawSourceWatsonBucketArray = dac_cast<PTR_VOID>(refSourceWatsonBucketArray->GetDataPtr());
10494
10495         // Get the raw array data pointer to the destination array
10496         U1ARRAYREF refDestWatsonBucketArray = (U1ARRAYREF)_gc.oWatsonBuckets;
10497         PTR_VOID pRawDestWatsonBucketArray = dac_cast<PTR_VOID>(refDestWatsonBucketArray->GetDataPtr());
10498
10499         // Deep copy the bucket information to the managed array
10500         memcpyNoGCRefs(pRawDestWatsonBucketArray, pRawSourceWatsonBucketArray, size);
10501
10502         // Setup the managed field reference to point to the byte array.
10503         //
10504         // The throwable, to which the buckets are being copied to, may be
10505         // having existing buckets (e.g. when TypeInitialization exception
10506         // maybe thrown again when attempt is made to load the originally
10507         // failed type).
10508         //
10509         // This is also possible if exception object is used as singleton
10510         // and thrown by multiple threads.
10511         if (((EXCEPTIONREF)_gc.oTo)->AreWatsonBucketsPresent())
10512         {
10513             LOG((LF_EH, LL_INFO1000, "CopyWatsonBucketsBetweenThrowables: Throwable (%p) being copied to had previous buckets.\n", OBJECTREFToObject(_gc.oTo)));
10514         }
10515
10516         ((EXCEPTIONREF)_gc.oTo)->SetWatsonBucketReference(_gc.oWatsonBuckets);
10517
10518         fRetVal = TRUE;
10519     }
10520
10521     // We shouldn't be here when fRetVal is FALSE since failure to allocate the primitive
10522     // array should throw an OOM.
10523     _ASSERTE(fRetVal);
10524
10525     GCPROTECT_END();
10526 #endif // !DACCESS_COMPILE
10527 }
10528
10529 // This function will copy the watson bucket information to the managed byte[] in
10530 // the specified managed exception object.
10531 //
10532 // If throwable is not specified, it will be copied to the current throwable.
10533 //
10534 // pUnmanagedBuckets is a pointer to native memory that cannot be affected by GC.
10535 BOOL CopyWatsonBucketsToThrowable(PTR_VOID pUnmanagedBuckets, OBJECTREF oTargetThrowable /*= NULL*/)
10536 {
10537 #ifndef DACCESS_COMPILE
10538
10539     CONTRACTL
10540     {
10541         GC_TRIGGERS;
10542         MODE_COOPERATIVE;
10543         THROWS;
10544         PRECONDITION(GetThread() != NULL);
10545         PRECONDITION(pUnmanagedBuckets != NULL);
10546         PRECONDITION(!CLRException::IsPreallocatedExceptionObject((oTargetThrowable == NULL)?GetThread()->GetThrowable():oTargetThrowable));
10547         PRECONDITION(IsWatsonEnabled());
10548     }
10549     CONTRACTL_END;
10550
10551     BOOL fRetVal = TRUE;
10552     struct
10553     {
10554         OBJECTREF oThrowable;
10555         OBJECTREF oWatsonBuckets;
10556     } _gc;
10557
10558     ZeroMemory(&_gc, sizeof(_gc));
10559     GCPROTECT_BEGIN(_gc);
10560     _gc.oThrowable = (oTargetThrowable == NULL)?GetThread()->GetThrowable():oTargetThrowable;
10561
10562     // Throwable to which buckets should be copied to, must exist.
10563     _ASSERTE(_gc.oThrowable != NULL);
10564
10565     // Size of a watson bucket
10566     DWORD size = sizeof(GenericModeBlock);
10567
10568     _gc.oWatsonBuckets = AllocatePrimitiveArray(ELEMENT_TYPE_U1, size);
10569     if (_gc.oWatsonBuckets == NULL)
10570     {
10571         // return failure if failed to create bucket array
10572         fRetVal = FALSE;
10573     }
10574     else
10575     {
10576         // Get the raw array data pointer
10577         U1ARRAYREF refWatsonBucketArray = (U1ARRAYREF)_gc.oWatsonBuckets;
10578         PTR_VOID pRawWatsonBucketArray = dac_cast<PTR_VOID>(refWatsonBucketArray->GetDataPtr());
10579
10580         // Deep copy the bucket information to the managed array
10581         memcpyNoGCRefs(pRawWatsonBucketArray, pUnmanagedBuckets, size);
10582
10583         // Setup the managed field reference to point to the byte array.
10584         //
10585         // The throwable, to which the buckets are being copied to, may be
10586         // having existing buckets (e.g. when TypeInitialization exception
10587         // maybe thrown again when attempt is made to load the originally
10588         // failed type).
10589         //
10590         // This is also possible if exception object is used as singleton
10591         // and thrown by multiple threads.
10592         if (((EXCEPTIONREF)_gc.oThrowable)->AreWatsonBucketsPresent())
10593         {
10594             LOG((LF_EH, LL_INFO1000, "CopyWatsonBucketsToThrowable: Throwable (%p) being copied to had previous buckets.\n", OBJECTREFToObject(_gc.oThrowable)));
10595         }
10596
10597         ((EXCEPTIONREF)_gc.oThrowable)->SetWatsonBucketReference(_gc.oWatsonBuckets);
10598     }
10599
10600     GCPROTECT_END();
10601
10602     return fRetVal;
10603 #else // DACCESS_COMPILE
10604     return TRUE;
10605 #endif // !DACCESS_COMPILE
10606 }
10607
10608 // This function will setup the bucketing information for nested exceptions
10609 // raised. These would be any exceptions thrown from within the confines of
10610 // managed EH clauses and include "rethrow" and "throw new ...".
10611 //
10612 // This is called from within CLR's personality routine for managed
10613 // exceptions to preemptively setup the watson buckets from the ones that may
10614 // already exist. If none exist already, we will automatically endup in the
10615 // path (SetupInitialThrowBucketDetails) that will set up buckets for the
10616 // exception being thrown.
10617 void SetStateForWatsonBucketing(BOOL fIsRethrownException, OBJECTHANDLE ohOriginalException)
10618 {
10619 #ifndef DACCESS_COMPILE
10620
10621     // On CoreCLR, Watson may not be enabled. Thus, we should
10622     // skip this.
10623     if (!IsWatsonEnabled())
10624     {
10625         return;
10626     }
10627
10628     CONTRACTL
10629     {
10630         GC_TRIGGERS;
10631         MODE_ANY;
10632         NOTHROW;
10633         PRECONDITION(GetThread() != NULL);
10634         PRECONDITION(IsWatsonEnabled());
10635     }
10636     CONTRACTL_END;
10637
10638     // Switch to COOP mode
10639     GCX_COOP();
10640
10641     struct
10642     {
10643         OBJECTREF oCurrentThrowable;
10644         OBJECTREF oInnerMostExceptionThrowable;
10645     } gc;
10646     ZeroMemory(&gc, sizeof(gc));
10647     GCPROTECT_BEGIN(gc);
10648
10649     Thread* pThread = GetThread();
10650
10651     // Get the current exception state of the thread
10652     ThreadExceptionState* pCurExState = pThread->GetExceptionState();
10653     _ASSERTE(NULL != pCurExState);
10654
10655     // Ensure that the exception tracker exists
10656     _ASSERTE(pCurExState->GetCurrentExceptionTracker() != NULL);
10657
10658     // Get the current throwable
10659     gc.oCurrentThrowable = pThread->GetThrowable();
10660     _ASSERTE(gc.oCurrentThrowable != NULL);
10661
10662     // Is the throwable a preallocated exception object?
10663     BOOL fIsPreallocatedExceptionObject = CLRException::IsPreallocatedExceptionObject(gc.oCurrentThrowable);
10664
10665     // Copy the bucketing details from the original exception tracker if the current exception is a rethrow
10666     // AND the throwable is a preallocated exception object.
10667     //
10668     // For rethrown non-preallocated exception objects, the throwable would already have the bucketing
10669     // details inside it.
10670     if (fIsRethrownException)
10671     {
10672         if (fIsPreallocatedExceptionObject)
10673         {
10674             // Get the WatsonBucket tracker for the original exception, starting search from the previous EH tracker.
10675             // This is required so that when a preallocated exception is rethrown, then the current tracker would have
10676             // the same throwable as the original exception but no bucketing details.
10677             //
10678             // To ensure GetWatsonBucketTrackerForPreallocatedException uses the EH tracker corresponding to the original
10679             // exception to get the bucketing details, we pass TRUE as the third parameter.
10680             PTR_EHWatsonBucketTracker pPreallocWatsonBucketTracker = GetWatsonBucketTrackerForPreallocatedException(gc.oCurrentThrowable, FALSE, TRUE);
10681             if (pPreallocWatsonBucketTracker != NULL)
10682             {
10683                 if (!IsThrowableThreadAbortException(gc.oCurrentThrowable))
10684                 {
10685                     // For non-thread abort preallocated exceptions, we copy the bucketing details
10686                     // from their corresponding watson bucket tracker to the one corresponding to the
10687                     // rethrow that is taking place.
10688                     //
10689                     // Bucketing details for preallocated exception may not be present if the exception came
10690                     // from across AD transition and we attempted to copy them over from the UETracker, when
10691                     // the exception was reraised in the calling AD, and the copy operation failed due to OOM.
10692                     //
10693                     // In such a case, when the reraised exception is caught and rethrown, we will not have
10694                     // any bucketing details.
10695                     if (NULL != pPreallocWatsonBucketTracker->RetrieveWatsonBucketIp())
10696                     {
10697                         // Copy the bucketing details now
10698                         pCurExState->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->CopyEHWatsonBucketTracker(*pPreallocWatsonBucketTracker);
10699                     }
10700                     else
10701                     {
10702                         LOG((LF_EH, LL_INFO1000, "SetStateForWatsonBucketing - Watson bucketing details for rethrown preallocated exception not found in the EH tracker corresponding to the original exception. This is likely due to a previous OOM.\n"));
10703                         LOG((LF_EH, LL_INFO1000, ">>>>>>>>>>>>>>>>>>>>>>>>>>   Original WatsonBucketTracker = %p\n", pPreallocWatsonBucketTracker));
10704
10705                         // Make the active tracker clear
10706                         pCurExState->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->ClearWatsonBucketDetails();
10707                     }
10708                 }
10709     #ifdef _DEBUG
10710                 else
10711                 {
10712                     // For thread abort exceptions, the returned watson bucket tracker
10713                     // would correspond to UE Watson bucket tracker and it will have
10714                     // all the details.
10715                     _ASSERTE(pPreallocWatsonBucketTracker == pCurExState->GetUEWatsonBucketTracker());
10716                 }
10717     #endif // _DEBUG
10718             }
10719             else
10720             {
10721                 // OOM can result in not having a Watson bucket tracker with valid bucketing details for a preallocated exception.
10722                 // Thus, we may end up here. For details, see implementation of GetWatsonBucketTrackerForPreallocatedException.
10723                 LOG((LF_EH, LL_INFO1000, "SetStateForWatsonBucketing - Watson bucketing tracker for rethrown preallocated exception not found. This is likely due to a previous OOM.\n"));
10724
10725                 // Make the active tracker clear
10726                 pCurExState->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->ClearWatsonBucketDetails();
10727             }
10728         }
10729         else
10730         {
10731             // We dont need to do anything here since the throwable would already have the bucketing
10732             // details inside it. Simply assert that the original exception object is the same as the current throwable.
10733             //
10734             // We cannot assert for Watson buckets since the original throwable may not have got them in
10735             // SetupInitialThrowBucketDetails due to OOM
10736             _ASSERTE((NULL != ohOriginalException) && (ObjectFromHandle(ohOriginalException) == gc.oCurrentThrowable));
10737             if ((((EXCEPTIONREF)gc.oCurrentThrowable)->AreWatsonBucketsPresent() == FALSE) &&
10738                 (((EXCEPTIONREF)gc.oCurrentThrowable)->IsIPForWatsonBucketsPresent() == FALSE))
10739             {
10740                 LOG((LF_EH, LL_INFO1000, "SetStateForWatsonBucketing - Regular rethrown exception (%p) does not have Watson buckets, likely due to OOM.\n",
10741                         OBJECTREFToObject(gc.oCurrentThrowable)));
10742             }
10743         }
10744
10745         // Set the flag that we have bucketing details for the exception
10746         pCurExState->GetFlags()->SetGotWatsonBucketDetails();
10747         LOG((LF_EH, LL_INFO1000, "SetStateForWatsonBucketing - Using original exception details for Watson bucketing for rethrown exception.\n"));
10748     }
10749     else
10750     {
10751         // If we are here, then an exception is being thrown from within the
10752         // managed EH clauses of fault, finally or catch, with an inner exception.
10753
10754         // By default, we will create buckets based upon the exception being thrown unless
10755         // thrown exception has an inner exception that has got bucketing details
10756         BOOL fCreateBucketsForExceptionBeingThrown = TRUE;
10757
10758         // Start off by assuming that inner exception object is not preallocated
10759         BOOL fIsInnerExceptionPreallocated = FALSE;
10760
10761         // Reference to the WatsonBucket tracker for the inner exception, if it is preallocated
10762         PTR_EHWatsonBucketTracker pInnerExceptionWatsonBucketTracker = NULL;
10763
10764         // Since this is a new exception being thrown, we will check if it has buckets already or not.
10765         // This is possible when Reflection throws TargetInvocationException with an inner exception
10766         // that is preallocated exception object. In such a case, we copy the inner exception details
10767         // to the TargetInvocationException object already. This is done in InvokeImpl in ReflectionInvocation.cpp.
10768         if (((EXCEPTIONREF)gc.oCurrentThrowable)->AreWatsonBucketsPresent() ||
10769             ((EXCEPTIONREF)gc.oCurrentThrowable)->IsIPForWatsonBucketsPresent())
10770         {
10771             goto done;
10772         }
10773
10774         // If no buckets are present, then we will check if it has an innermost exception or not.
10775         // If it does, then we will make the exception being thrown use the bucketing details of the
10776         // innermost exception.
10777         //
10778         // If there is no innermost exception or if one is present without bucketing details, then
10779         // we will have bucket details based upon the exception being thrown.
10780
10781         // Get the innermost exception from the exception being thrown.
10782         gc.oInnerMostExceptionThrowable = ((EXCEPTIONREF)gc.oCurrentThrowable)->GetBaseException();
10783         if (gc.oInnerMostExceptionThrowable != NULL)
10784         {
10785             fIsInnerExceptionPreallocated = CLRException::IsPreallocatedExceptionObject(gc.oInnerMostExceptionThrowable);
10786
10787             // Preallocated exception objects do not have inner exception objects.
10788             // Thus, if we are here, then the current throwable cannot be
10789             // a preallocated exception object.
10790             _ASSERTE(!fIsPreallocatedExceptionObject);
10791
10792             // Create the new buckets only if the innermost exception object
10793             // does not have them already.
10794             if (fIsInnerExceptionPreallocated)
10795             {
10796                 // If we are able to find the watson bucket tracker for the preallocated
10797                 // inner exception, then we dont need to create buckets for throw site.
10798                 pInnerExceptionWatsonBucketTracker = GetWatsonBucketTrackerForPreallocatedException(gc.oInnerMostExceptionThrowable, FALSE, TRUE);
10799                 fCreateBucketsForExceptionBeingThrown = ((pInnerExceptionWatsonBucketTracker != NULL) &&
10800                                                          (pInnerExceptionWatsonBucketTracker->RetrieveWatsonBucketIp() != NULL)) ? FALSE : TRUE;
10801             }
10802             else
10803             {
10804                 // Since the inner exception object is not preallocated, create
10805                 // watson buckets only if it does not have them.
10806                 fCreateBucketsForExceptionBeingThrown = !(((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent() ||
10807                                                           ((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->IsIPForWatsonBucketsPresent());
10808             }
10809         }
10810
10811         // If we are NOT going to create buckets for the thrown exception,
10812         // then copy them over from the inner exception object.
10813         //
10814         // If we have to create the buckets for the thrown exception,
10815         // we wont do that now - it will be done in StackTraceInfo::AppendElement
10816         // when we get the IP for bucketing.
10817         if (!fCreateBucketsForExceptionBeingThrown)
10818         {
10819             // Preallocated exception objects do not have inner exception objects.
10820             // Thus, if we are here, then the current throwable cannot be
10821             // a preallocated exception object.
10822             _ASSERTE(!fIsPreallocatedExceptionObject);
10823
10824             if (fIsInnerExceptionPreallocated)
10825             {
10826
10827                 // We should have the inner exception watson bucket tracker
10828                 _ASSERTE((pInnerExceptionWatsonBucketTracker != NULL) && (pInnerExceptionWatsonBucketTracker->RetrieveWatsonBucketIp() != NULL));
10829
10830                 // Capture the buckets for the innermost exception if they dont already exist.
10831                 // Since the current throwable cannot be preallocated (see the assert above),
10832                 // copy the buckets to the throwable.
10833                 PTR_VOID pInnerExceptionWatsonBuckets = pInnerExceptionWatsonBucketTracker->RetrieveWatsonBuckets();
10834                 if (pInnerExceptionWatsonBuckets == NULL)
10835                 {
10836                     // Capture the buckets since they dont exist
10837                     pInnerExceptionWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::UnhandledException, pThread, &gc.oInnerMostExceptionThrowable);
10838                     pInnerExceptionWatsonBuckets = pInnerExceptionWatsonBucketTracker->RetrieveWatsonBuckets();
10839                 }
10840
10841                 if (pInnerExceptionWatsonBuckets == NULL)
10842                 {
10843                     // Couldnt capture details like due to OOM
10844                     LOG((LF_EH, LL_INFO1000, "SetStateForWatsonBucketing - Preallocated inner-exception's WBTracker (%p) has no bucketing details for the thrown exception, likely due to OOM.\n", pInnerExceptionWatsonBucketTracker));
10845                 }
10846                 else
10847                 {
10848                     // Copy the buckets to the current throwable
10849                     BOOL fCopied = TRUE;
10850                     EX_TRY
10851                     {
10852                         fCopied = CopyWatsonBucketsToThrowable(pInnerExceptionWatsonBuckets);
10853                         _ASSERTE(fCopied);
10854                     }
10855                     EX_CATCH
10856                     {
10857                         // Dont do anything if we fail to copy the buckets - this is no different than
10858                         // the native watson helper functions failing under OOM
10859                         fCopied = FALSE;
10860                     }
10861                     EX_END_CATCH(SwallowAllExceptions);
10862                 }
10863             }
10864             else
10865             {
10866                 // Assert that the inner exception has the Watson buckets
10867                 _ASSERTE(gc.oInnerMostExceptionThrowable != NULL);
10868                 _ASSERTE(((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent() ||
10869                          ((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->IsIPForWatsonBucketsPresent());
10870
10871                 if (((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->AreWatsonBucketsPresent())
10872                 {
10873                     // Copy the bucket information from the inner exception object to the current throwable
10874                     EX_TRY
10875                     {
10876                         CopyWatsonBucketsFromThrowableToCurrentThrowable(gc.oInnerMostExceptionThrowable);
10877                     }
10878                     EX_CATCH
10879                     {
10880                         // Dont do anything if we fail to copy the buckets - this is no different than
10881                         // the native watson helper functions failing under OOM
10882                     }
10883                     EX_END_CATCH(SwallowAllExceptions);
10884                 }
10885                 else
10886                 {
10887                     // Copy the IP for Watson bucketing to the exception object
10888                     ((EXCEPTIONREF)gc.oCurrentThrowable)->SetIPForWatsonBuckets(((EXCEPTIONREF)gc.oInnerMostExceptionThrowable)->GetIPForWatsonBuckets());
10889                 }
10890             }
10891
10892             // Set the flag that we got bucketing details for the exception
10893             pCurExState->GetFlags()->SetGotWatsonBucketDetails();
10894             LOG((LF_EH, LL_INFO1000, "SetStateForWatsonBucketing - Using innermost exception details for Watson bucketing for thrown exception.\n"));
10895         }
10896 done:;
10897     }
10898
10899     GCPROTECT_END();
10900
10901 #endif // !DACCESS_COMPILE
10902 }
10903
10904 // Constructor that will do the initialization of the object
10905 EHWatsonBucketTracker::EHWatsonBucketTracker()
10906 {
10907     LIMITED_METHOD_CONTRACT;
10908
10909     Init();
10910 }
10911
10912 // Reset the fields to default values
10913 void EHWatsonBucketTracker::Init()
10914 {
10915     LIMITED_METHOD_CONTRACT;
10916
10917     m_WatsonUnhandledInfo.m_UnhandledIp = 0;
10918     m_WatsonUnhandledInfo.m_pUnhandledBuckets = NULL;
10919
10920     DEBUG_STMT(ResetFlags());
10921
10922     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::Init - initializing watson bucket tracker (%p)\n", this));
10923 }
10924
10925 // This method copies the bucketing details from the specified throwable
10926 // to the current Watson Bucket tracker.
10927 void EHWatsonBucketTracker::CopyBucketsFromThrowable(OBJECTREF oThrowable)
10928 {
10929 #ifndef DACCESS_COMPILE
10930     CONTRACTL
10931     {
10932         NOTHROW;
10933         GC_NOTRIGGER;
10934         MODE_ANY;
10935         PRECONDITION(oThrowable != NULL);
10936         PRECONDITION(((EXCEPTIONREF)oThrowable)->AreWatsonBucketsPresent());
10937         PRECONDITION(IsWatsonEnabled());
10938     }
10939     CONTRACTL_END;
10940
10941     GCX_COOP();
10942
10943     struct
10944     {
10945         OBJECTREF oFrom;
10946     } _gc;
10947
10948     ZeroMemory(&_gc, sizeof(_gc));
10949     GCPROTECT_BEGIN(_gc);
10950
10951     _gc.oFrom = oThrowable;
10952
10953     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CopyEHWatsonBucketTracker - Copying bucketing details from throwable (%p) to tracker (%p)\n",
10954                             OBJECTREFToObject(_gc.oFrom), this));
10955
10956     // Watson bucket is a "GenericModeBlock" type. Set up an empty GenericModeBlock
10957     // to hold the bucket parameters.
10958     GenericModeBlock *pgmb = new (nothrow) GenericModeBlock;
10959     if (pgmb == NULL)
10960     {
10961         // If we are unable to allocate memory to hold the WatsonBucket, then
10962         // reset the IP and bucket pointer to NULL and bail out
10963         SaveIpForWatsonBucket(NULL);
10964         m_WatsonUnhandledInfo.m_pUnhandledBuckets = NULL;
10965     }
10966     else
10967     {
10968         // Get the raw array data pointer
10969         U1ARRAYREF refWatsonBucketArray = ((EXCEPTIONREF)_gc.oFrom)->GetWatsonBucketReference();
10970         PTR_VOID pRawWatsonBucketArray = dac_cast<PTR_VOID>(refWatsonBucketArray->GetDataPtr());
10971
10972         // Copy over the details to our new allocation
10973         memcpyNoGCRefs(pgmb, pRawWatsonBucketArray, sizeof(GenericModeBlock));
10974
10975         // and save the address where the buckets were copied
10976         _ASSERTE(m_WatsonUnhandledInfo.m_pUnhandledBuckets == NULL);
10977         m_WatsonUnhandledInfo.m_pUnhandledBuckets = pgmb;
10978     }
10979
10980     GCPROTECT_END();
10981
10982     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CopyEHWatsonBucketTracker - Copied Watson Buckets from throwable to (%p)\n",
10983                             m_WatsonUnhandledInfo.m_pUnhandledBuckets));
10984 #endif // !DACCESS_COMPILE
10985 }
10986
10987 // This method copies the bucketing details from the specified Watson Bucket tracker
10988 // to the current one.
10989 void EHWatsonBucketTracker::CopyEHWatsonBucketTracker(const EHWatsonBucketTracker& srcTracker)
10990 {
10991 #ifndef DACCESS_COMPILE
10992     CONTRACTL
10993     {
10994         NOTHROW;
10995         GC_NOTRIGGER;
10996         MODE_ANY;
10997         PRECONDITION(m_WatsonUnhandledInfo.m_UnhandledIp == 0);
10998         PRECONDITION(m_WatsonUnhandledInfo.m_pUnhandledBuckets == NULL);
10999         PRECONDITION(IsWatsonEnabled());
11000     }
11001     CONTRACTL_END;
11002
11003     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CopyEHWatsonBucketTracker - Copying bucketing details from %p to %p\n", &srcTracker, this));
11004
11005     // Copy the tracking details over from the specified tracker
11006     SaveIpForWatsonBucket(srcTracker.m_WatsonUnhandledInfo.m_UnhandledIp);
11007
11008     if (srcTracker.m_WatsonUnhandledInfo.m_pUnhandledBuckets != NULL)
11009     {
11010         // To save the bucket information, we will need to memcpy.
11011         // This is to ensure that if the original watson bucket tracker
11012         // (for original exception) is released and its memory deallocated,
11013         // the new watson bucket tracker (for rethrown exception, for e.g.)
11014         // would still have all the bucket details.
11015
11016         // Watson bucket is a "GenericModeBlock" type. Set up an empty GenericModeBlock
11017         // to hold the bucket parameters.
11018         GenericModeBlock *pgmb = new (nothrow) GenericModeBlock;
11019         if (pgmb == NULL)
11020         {
11021             // If we are unable to allocate memory to hold the WatsonBucket, then
11022             // reset the IP and bucket pointer to NULL and bail out
11023             SaveIpForWatsonBucket(NULL);
11024             m_WatsonUnhandledInfo.m_pUnhandledBuckets = NULL;
11025
11026             LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CopyEHWatsonBucketTracker - Not copying buckets due to out of memory.\n"));
11027         }
11028         else
11029         {
11030             // Copy over the details to our new allocation
11031             memcpyNoGCRefs(pgmb, srcTracker.m_WatsonUnhandledInfo.m_pUnhandledBuckets, sizeof(GenericModeBlock));
11032
11033             // and save the address where the buckets were copied
11034             m_WatsonUnhandledInfo.m_pUnhandledBuckets = pgmb;
11035         }
11036     }
11037
11038     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CopyEHWatsonBucketTracker - Copied Watson Bucket to (%p)\n", m_WatsonUnhandledInfo.m_pUnhandledBuckets));
11039 #endif // !DACCESS_COMPILE
11040 }
11041
11042 void EHWatsonBucketTracker::SaveIpForWatsonBucket(
11043     UINT_PTR    ip)                     // The new IP.
11044 {
11045 #ifndef DACCESS_COMPILE
11046     CONTRACTL
11047     {
11048         NOTHROW;
11049         GC_NOTRIGGER;
11050         MODE_ANY;
11051         SO_TOLERANT;
11052         PRECONDITION(IsWatsonEnabled());
11053     }
11054     CONTRACTL_END;
11055
11056     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::SaveIpForUnhandledInfo  - this = %p, IP = %p\n", this, ip));
11057
11058     // Since we are setting a new IP for tracking buckets,
11059     // clear any existing details we may hold
11060     ClearWatsonBucketDetails();
11061
11062     // Save the new IP for bucketing
11063     m_WatsonUnhandledInfo.m_UnhandledIp = ip;
11064 #endif // !DACCESS_COMPILE
11065 }
11066
11067 UINT_PTR EHWatsonBucketTracker::RetrieveWatsonBucketIp()
11068 {
11069     LIMITED_METHOD_CONTRACT;
11070
11071     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::RetrieveWatsonBucketIp - this = %p, IP = %p\n", this, m_WatsonUnhandledInfo.m_UnhandledIp));
11072
11073     return m_WatsonUnhandledInfo.m_UnhandledIp;
11074 }
11075
11076 // This function returns the reference to the Watson buckets tracked by the
11077 // instance of WatsonBucket tracker.
11078 //
11079 // This is *also* invoked from the DAC when buckets are requested.
11080 PTR_VOID EHWatsonBucketTracker::RetrieveWatsonBuckets()
11081 {
11082 #if !defined(DACCESS_COMPILE)
11083     if (!IsWatsonEnabled())
11084     {
11085         return NULL;
11086     }
11087 #endif //!defined(DACCESS_COMPILE)
11088
11089     CONTRACTL
11090     {
11091         NOTHROW;
11092         GC_NOTRIGGER;
11093         MODE_ANY;
11094         SO_TOLERANT;
11095         PRECONDITION(IsWatsonEnabled());
11096     }
11097     CONTRACTL_END;
11098
11099     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::RetrieveWatsonBuckets - this = %p, bucket address = %p\n", this, m_WatsonUnhandledInfo.m_pUnhandledBuckets));
11100
11101     return m_WatsonUnhandledInfo.m_pUnhandledBuckets;
11102 }
11103
11104 void EHWatsonBucketTracker::ClearWatsonBucketDetails()
11105 {
11106 #ifndef DACCESS_COMPILE
11107
11108     if (!IsWatsonEnabled())
11109     {
11110         return;
11111     }
11112
11113     CONTRACTL
11114     {
11115         NOTHROW;
11116         GC_NOTRIGGER;
11117         MODE_ANY;
11118         SO_TOLERANT;
11119         PRECONDITION(IsWatsonEnabled());
11120     }
11121     CONTRACTL_END;
11122
11123
11124     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::ClearWatsonBucketDetails for tracker (%p)\n", this));
11125
11126     if (m_WatsonUnhandledInfo.m_pUnhandledBuckets != NULL)
11127     {
11128         FreeBucketParametersForManagedException(m_WatsonUnhandledInfo.m_pUnhandledBuckets);
11129     }
11130
11131     Init();
11132 #endif // !DACCESS_COMPILE
11133 }
11134
11135 void EHWatsonBucketTracker::CaptureUnhandledInfoForWatson(TypeOfReportedError tore, Thread * pThread, OBJECTREF * pThrowable)
11136 {
11137 #ifndef DACCESS_COMPILE
11138     CONTRACTL
11139     {
11140         NOTHROW;
11141         GC_NOTRIGGER;
11142         MODE_ANY;
11143         PRECONDITION(IsWatsonEnabled());
11144     }
11145     CONTRACTL_END;
11146
11147     LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CaptureUnhandledInfoForWatson capturing watson bucket details for (%p)\n", this));
11148
11149     // Only capture the bucket information if there is an IP AND we dont already have collected them.
11150     // We could have collected them from a previous AD transition and wouldnt want to overwrite them.
11151     if (m_WatsonUnhandledInfo.m_UnhandledIp != 0)
11152     {
11153         if (m_WatsonUnhandledInfo.m_pUnhandledBuckets == NULL)
11154         {
11155             // Get the bucket details since we dont have them
11156             m_WatsonUnhandledInfo.m_pUnhandledBuckets = GetBucketParametersForManagedException(m_WatsonUnhandledInfo.m_UnhandledIp, tore, pThread, pThrowable);
11157             LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CaptureUnhandledInfoForWatson captured the following watson bucket details: (this = %p, bucket addr = %p)\n",
11158                 this, m_WatsonUnhandledInfo.m_pUnhandledBuckets));
11159         }
11160         else
11161         {
11162             // We already have the bucket details - so no need to capture them again
11163             LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CaptureUnhandledInfoForWatson already have the watson bucket details: (this = %p, bucket addr = %p)\n",
11164                 this, m_WatsonUnhandledInfo.m_pUnhandledBuckets));
11165         }
11166     }
11167     else
11168     {
11169         LOG((LF_EH, LL_INFO1000, "EHWatsonBucketTracker::CaptureUnhandledInfoForWatson didnt have an IP to use for capturing watson buckets\n"));
11170     }
11171 #endif // !DACCESS_COMPILE
11172 }
11173 #endif // !FEATURE_PAL
11174
11175 // Given a throwable, this function will attempt to find an active EH tracker corresponding to it.
11176 // If none found, it will return NULL
11177 #ifdef WIN64EXCEPTIONS
11178 PTR_ExceptionTracker GetEHTrackerForException(OBJECTREF oThrowable, PTR_ExceptionTracker pStartingEHTracker)
11179 #elif _TARGET_X86_
11180 PTR_ExInfo GetEHTrackerForException(OBJECTREF oThrowable, PTR_ExInfo pStartingEHTracker)
11181 #else
11182 #error Unsupported platform
11183 #endif
11184 {
11185     CONTRACTL
11186     {
11187         GC_NOTRIGGER;
11188         MODE_COOPERATIVE;
11189         NOTHROW;
11190         SO_TOLERANT;
11191         PRECONDITION(GetThread() != NULL);
11192         PRECONDITION(oThrowable != NULL);
11193     }
11194     CONTRACTL_END;
11195
11196     // Get the reference to the exception tracker to start with. If one has been provided to us,
11197     // then use it. Otherwise, start from the current one.
11198 #ifdef WIN64EXCEPTIONS
11199     PTR_ExceptionTracker pEHTracker = (pStartingEHTracker != NULL) ? pStartingEHTracker : GetThread()->GetExceptionState()->GetCurrentExceptionTracker();
11200 #elif _TARGET_X86_
11201     PTR_ExInfo pEHTracker = (pStartingEHTracker != NULL) ? pStartingEHTracker : GetThread()->GetExceptionState()->GetCurrentExceptionTracker();
11202 #else
11203 #error Unsupported platform
11204 #endif
11205
11206     BOOL fFoundTracker = FALSE;
11207
11208     // Start walking the list to find the tracker correponding
11209     // to the exception object.
11210     while (pEHTracker != NULL)
11211     {
11212         if (pEHTracker->GetThrowable() == oThrowable)
11213         {
11214             // found the tracker - break out.
11215             fFoundTracker = TRUE;
11216             break;
11217         }
11218
11219         // move to the previous tracker...
11220         pEHTracker = pEHTracker->GetPreviousExceptionTracker();
11221     }
11222
11223     return fFoundTracker ? pEHTracker : NULL;
11224 }
11225
11226 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
11227 // -----------------------------------------------------------------------
11228 // Support for CorruptedState Exceptions
11229 // -----------------------------------------------------------------------
11230
11231 // Given an exception code, this method returns a BOOL to indicate if the
11232 // code belongs to a corrupting exception or not.
11233 /* static */
11234 BOOL CEHelper::IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*= TRUE*/)
11235 {
11236     CONTRACTL
11237     {
11238         NOTHROW;
11239         GC_NOTRIGGER;
11240         MODE_ANY;
11241         SO_TOLERANT;
11242     }
11243     CONTRACTL_END;
11244
11245     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11246     {
11247         return FALSE;
11248     }
11249
11250     // Call into the utilcode helper function to check if this
11251     // is a CE or not.
11252     return (::IsProcessCorruptedStateException(dwExceptionCode, fCheckForSO));
11253 }
11254
11255 // This is used in the VM folder version of "SET_CE_RETHROW_FLAG_FOR_EX_CATCH" (in clrex.h)
11256 // to check if the managed exception caught by EX_END_CATCH is CSE or not.
11257 //
11258 // If you are using it from rethrow boundaries (e.g. SET_CE_RETHROW_FLAG_FOR_EX_CATCH
11259 // macro that is used to automatically rethrow corrupting exceptions), then you may
11260 // want to set the "fMarkForReuseIfCorrupting" to TRUE to enable propagation of the
11261 // corruption severity when the reraised exception is seen by managed code again.
11262 /* static */
11263 BOOL CEHelper::IsLastActiveExceptionCorrupting(BOOL fMarkForReuseIfCorrupting /* = FALSE */)
11264 {
11265     CONTRACTL
11266     {
11267         NOTHROW;
11268         GC_NOTRIGGER;
11269         MODE_ANY;
11270         PRECONDITION(GetThread() != NULL);
11271     }
11272     CONTRACTL_END;
11273
11274     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11275     {
11276         return FALSE;
11277     }
11278
11279     BOOL fIsCorrupting = FALSE;
11280     ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
11281
11282     // Check the corruption severity
11283     CorruptionSeverity severity = pCurTES->GetLastActiveExceptionCorruptionSeverity();
11284     fIsCorrupting = (severity == ProcessCorrupting);
11285     if (fIsCorrupting && fMarkForReuseIfCorrupting)
11286     {
11287         // Mark the corruption severity for reuse
11288         CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse();
11289     }
11290
11291     LOG((LF_EH, LL_INFO100, "CEHelper::IsLastActiveExceptionCorrupting - Using corruption severity from TES.\n"));
11292
11293     return fIsCorrupting;
11294 }
11295
11296 // Given a MethodDesc, this method will return a BOOL to indicate if
11297 // the containing assembly was built for PreV4 runtime or not.
11298 /* static */
11299 BOOL CEHelper::IsMethodInPreV4Assembly(PTR_MethodDesc pMethodDesc)
11300 {
11301     CONTRACTL
11302     {
11303         NOTHROW;
11304         GC_NOTRIGGER;
11305         MODE_ANY;
11306         PRECONDITION(pMethodDesc != NULL);
11307     }
11308     CONTRACTL_END;
11309
11310     // By default, assume that the containing assembly was not
11311     // built for PreV4 runtimes.
11312     BOOL fBuiltForPreV4Runtime = FALSE;
11313
11314     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11315     {
11316         return TRUE;
11317     }
11318
11319     LPCSTR pszVersion = NULL;
11320
11321     // Retrieve the manifest metadata reference since that contains
11322     // the "built-for" runtime details
11323     IMDInternalImport *pImport = pMethodDesc->GetAssembly()->GetManifestImport();
11324     if (pImport && SUCCEEDED(pImport->GetVersionString(&pszVersion)))
11325     {
11326         if (pszVersion != NULL)
11327         {
11328             // If version begins with "v1.*" or "v2.*", it was built for preV4 runtime
11329             if ((pszVersion[0] == 'v' || pszVersion[0] == 'V') &&
11330                 IS_DIGIT(pszVersion[1]) &&
11331                 (pszVersion[2] == '.') )
11332             {
11333                 // Looks like a version.  Is it lesser than v4.0 major version where we start using new behavior?
11334                 fBuiltForPreV4Runtime = ((DIGIT_TO_INT(pszVersion[1]) != 0) &&
11335                                         (DIGIT_TO_INT(pszVersion[1]) <= HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME));
11336             }
11337         }
11338     }
11339
11340     return fBuiltForPreV4Runtime;
11341 }
11342
11343 // Given a MethodDesc and CorruptionSeverity, this method will return a
11344 // BOOL indicating if the method can handle those kinds of CEs or not.
11345 /* static */
11346 BOOL CEHelper::CanMethodHandleCE(PTR_MethodDesc pMethodDesc, CorruptionSeverity severity, BOOL fCalculateSecurityInfo /*= TRUE*/)
11347 {
11348     BOOL fCanMethodHandleSeverity = FALSE;
11349
11350 #ifndef DACCESS_COMPILE
11351     CONTRACTL
11352     {
11353         if (fCalculateSecurityInfo)
11354         {
11355             GC_TRIGGERS; // CEHelper::CanMethodHandleCE will invoke Security::IsMethodCritical that could endup invoking MethodTable::LoadEnclosingMethodTable that is GC_TRIGGERS
11356         }
11357         else
11358         {
11359             // See comment in COMPlusUnwindCallback for details.
11360             GC_NOTRIGGER;
11361         }
11362         // First pass requires THROWS and in 2nd we need to be due to the AppX check below where GetFusionAssemblyName can throw.
11363         THROWS;
11364         MODE_ANY;
11365         PRECONDITION(pMethodDesc != NULL);
11366     }
11367     CONTRACTL_END;
11368
11369
11370     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11371     {
11372         return TRUE;
11373     }
11374
11375     // Since the method is Security Critical, now check if it is
11376     // attributed to handle the CE or not.
11377     IMDInternalImport *pImport = pMethodDesc->GetMDImport();
11378     if (pImport != NULL)
11379     {
11380         mdMethodDef methodDef = pMethodDesc->GetMemberDef();
11381         switch(severity)
11382         {
11383             case ProcessCorrupting:
11384                     fCanMethodHandleSeverity = (S_OK == pImport->GetCustomAttributeByName(
11385                                                 methodDef,
11386                                                 HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE,
11387                                                 NULL,
11388                                                 NULL));
11389                 break;
11390             default:
11391                 _ASSERTE(!"Unknown Exception Corruption Severity!");
11392                 break;
11393         }
11394     }
11395 #endif // !DACCESS_COMPILE
11396
11397     return fCanMethodHandleSeverity;
11398 }
11399
11400 // Given a MethodDesc, this method will return a BOOL to indicate if the method should be examined for exception
11401 // handlers for the specified exception.
11402 //
11403 // This method accounts for both corrupting and non-corrupting exceptions.
11404 /* static */
11405 BOOL CEHelper::CanMethodHandleException(CorruptionSeverity severity, PTR_MethodDesc pMethodDesc, BOOL fCalculateSecurityInfo /*= TRUE*/)
11406 {
11407     CONTRACTL
11408     {
11409         // CEHelper::CanMethodHandleCE will invoke Security::IsMethodCritical that could endup invoking MethodTable::LoadEnclosingMethodTable that is GC_TRIGGERS/THROWS
11410         if (fCalculateSecurityInfo)
11411         {
11412             GC_TRIGGERS;
11413         }
11414         else
11415         {
11416             // See comment in COMPlusUnwindCallback for details.
11417             GC_NOTRIGGER;
11418         }
11419         THROWS;
11420         MODE_ANY;
11421         PRECONDITION(pMethodDesc != NULL);
11422     }
11423     CONTRACTL_END;
11424
11425     // By default, assume that the runtime shouldn't look for exception handlers
11426     // in the method pointed by the MethodDesc
11427     BOOL fLookForExceptionHandlersInMethod = FALSE;
11428
11429     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11430     {
11431         return TRUE;
11432     }
11433
11434     // If we have been asked to use the last active corruption severity (e.g. in cases of Reflection
11435     // or COM interop), then retrieve it.
11436     if (severity == UseLast)
11437     {
11438         LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Using LastActiveExceptionCorruptionSeverity.\n"));
11439         severity = GetThread()->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity();
11440     }
11441
11442     LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Processing CorruptionSeverity: %d.\n", severity));
11443
11444     if (severity > NotCorrupting)
11445     {
11446         // If the method lies in an assembly built for pre-V4 runtime, allow the runtime
11447         // to look for exception handler for the CE.
11448         BOOL fIsMethodInPreV4Assembly = FALSE;
11449         fIsMethodInPreV4Assembly = CEHelper::IsMethodInPreV4Assembly(pMethodDesc);
11450
11451         if (!fIsMethodInPreV4Assembly)
11452         {
11453             // Method lies in an assembly built for V4 or later runtime.
11454             LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Method is in an assembly built for V4 or later runtime.\n"));
11455
11456             // Depending upon the corruption severity of the exception, see if the
11457             // method supports handling that.
11458             LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Exception is corrupting.\n"));
11459
11460             // Check if the method can handle the severity specified in the exception object.
11461             fLookForExceptionHandlersInMethod = CEHelper::CanMethodHandleCE(pMethodDesc, severity, fCalculateSecurityInfo);
11462         }
11463         else
11464         {
11465             // Method is in a Pre-V4 assembly - allow it to be examined for processing the CE
11466             fLookForExceptionHandlersInMethod = TRUE;
11467         }
11468     }
11469     else
11470     {
11471         // Non-corrupting exceptions can continue to be delivered
11472         fLookForExceptionHandlersInMethod = TRUE;
11473     }
11474
11475     return fLookForExceptionHandlersInMethod;
11476 }
11477
11478 // Given a managed exception object, this method will return a BOOL
11479 // indicating if it corresponds to a ProcessCorruptedState exception
11480 // or not.
11481 /* static */
11482 BOOL CEHelper::IsProcessCorruptedStateException(OBJECTREF oThrowable)
11483 {
11484     CONTRACTL
11485     {
11486         NOTHROW;
11487         GC_NOTRIGGER;
11488         MODE_COOPERATIVE;
11489         SO_TOLERANT;
11490         PRECONDITION(oThrowable != NULL);
11491     }
11492     CONTRACTL_END;
11493
11494     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11495     {
11496         return FALSE;
11497     }
11498
11499 #ifndef DACCESS_COMPILE
11500     // If the throwable represents preallocated SO, then indicate it as a CSE
11501     if (CLRException::GetPreallocatedStackOverflowException() == oThrowable)
11502     {
11503         return TRUE;
11504     }
11505 #endif // !DACCESS_COMPILE
11506
11507     // Check if we have an exception tracker for this exception
11508     // and if so, if it represents corrupting exception or not.
11509     // Get the exception tracker for the current exception
11510 #ifdef WIN64EXCEPTIONS
11511     PTR_ExceptionTracker pEHTracker = GetEHTrackerForException(oThrowable, NULL);
11512 #elif _TARGET_X86_
11513     PTR_ExInfo pEHTracker = GetEHTrackerForException(oThrowable, NULL);
11514 #else
11515 #error Unsupported platform
11516 #endif
11517
11518     if (pEHTracker != NULL)
11519     {
11520         // Found the tracker for exception object - check if its CSE or not.
11521         return (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting);
11522     }
11523
11524     return FALSE;
11525 }
11526
11527 #ifdef WIN64EXCEPTIONS
11528 void CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass(Thread *pCurThread, PTR_ExceptionTracker pEHTracker, BOOL fIsFirstPass,
11529                                     DWORD dwExceptionCode)
11530 {
11531 #ifndef DACCESS_COMPILE
11532     CONTRACTL
11533     {
11534         NOTHROW;
11535         GC_NOTRIGGER;
11536         MODE_ANY;
11537         SO_TOLERANT;
11538         PRECONDITION(!fIsFirstPass); // This method should only be called during an unwind
11539         PRECONDITION(pCurThread != NULL);
11540     }
11541     CONTRACTL_END;
11542
11543     // <WIN64>
11544     //
11545     // Typically, exception tracker is created for an exception when the OS is in the first pass.
11546     // However, it may be created during the 2nd pass under specific cases. Managed C++ provides
11547     // such a scenario. In the following, stack grows left to right:
11548     //
11549     // CallDescrWorker -> ILStub1 -> <Native Main> -> UMThunkStub -> IL_Stub2 -> <Managed Main>
11550     //
11551     // If a CSE exception goes unhandled from managed main, it will reach the OS. The [CRT in?] OS triggers
11552     // unwind that results in invoking the personality routine of UMThunkStub, called UMThunkStubUnwindFrameChainHandler,
11553     // that releases all exception trackers below it. Thus, the tracker for the CSE, which went unhandled, is also
11554     // released. This detail is 64bit specific and the crux of this issue.
11555     //
11556     // Now, it is expected that by the time we are in the unwind pass, the corruption severity would have already been setup in the
11557     // exception tracker and thread exception state (TES) as part of the first pass, and thus, are identical.
11558     //
11559     // However, for the scenario above, when the unwind continues and reaches ILStub1, its personality routine (which is ProcessCLRException)
11560     // is invoked. It attempts to get the exception tracker corresponding to the exception. Since none exists, it creates a brand new one,
11561     // which has the exception corruption severity as NotSet.
11562     //
11563     // During the stack walk, we know (from TES) that the active exception was a CSE, and thus, ILStub1 cannot handle the exception. Prior
11564     // to bailing out, we assert that our data structures are intact by comparing the exception severity in TES with the one in the current
11565     // exception tracker. Since the tracker was recreated, it had the severity as NotSet and this does not match the severity in TES.
11566     // Thus, the assert fires. [This check is performed in ProcessManagedCallFrame.]
11567     //
11568     // To address such a case, if we have created a new exception tracker in the unwind (2nd) pass, then set its
11569     // exception corruption severity to what the TES holds currently. This will maintain the same semantic as the case
11570     // where new tracker is not created (for e.g. the exception was caught in Managed main).
11571     //
11572     // The exception is the scenario of code that uses longjmp to jump to a different context. Longjmp results in a raise
11573     // of a new exception with the longjmp exception code (0x80000026) but with ExceptionFlags set indicating unwind. When this is
11574     // seen by ProcessCLRException (64bit personality routine), it will create a new tracker in the 2nd pass.
11575     //
11576     // Longjmp outside an exceptional path does not interest us, but the one in the exceptional
11577     // path would only happen when a method attributed to handle CSE invokes it. Thus, if the longjmp happened during the 2nd pass of a CSE,
11578     // we want it to proceed (and thus, jump) as expected and not apply the CSE severity to the tracker - this is equivalent to
11579     // a catch block that handles a CSE and then does a "throw new Exception();". The new exception raised is
11580     // non-CSE in nature as well.
11581     //
11582     // http://www.nynaeve.net/?p=105 has a brief description of how exception-safe setjmp/longjmp works.
11583     //
11584     // </WIN64>
11585     if (pEHTracker->GetCorruptionSeverity() == NotSet)
11586     {
11587         // Get the thread exception state
11588         ThreadExceptionState *pCurTES = pCurThread->GetExceptionState();
11589
11590         // Set the tracker to have the same corruption severity as the last active severity unless we are dealing
11591         // with LONGJMP
11592         if (dwExceptionCode == STATUS_LONGJUMP)
11593         {
11594             pCurTES->SetLastActiveExceptionCorruptionSeverity(NotCorrupting);
11595         }
11596
11597         pEHTracker->SetCorruptionSeverity(pCurTES->GetLastActiveExceptionCorruptionSeverity());
11598         LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass - Setup the corruption severity in the second pass.\n"));
11599     }
11600 #endif // !DACCESS_COMPILE
11601 }
11602 #endif // WIN64EXCEPTIONS
11603
11604 // This method is invoked from the personality routine for managed code and is used to setup the
11605 // corruption severity for the active exception on the thread exception state and the
11606 // exception tracker corresponding to the exception.
11607 /* static */
11608 void CEHelper::SetupCorruptionSeverityForActiveException(BOOL fIsRethrownException, BOOL fIsNestedException, BOOL fShouldTreatExceptionAsNonCorrupting /* = FALSE */)
11609 {
11610 #ifndef DACCESS_COMPILE
11611     CONTRACTL
11612     {
11613         NOTHROW;
11614         GC_NOTRIGGER;
11615         MODE_COOPERATIVE;
11616     }
11617     CONTRACTL_END;
11618
11619     // Get the thread and the managed exception object - they must exist at this point
11620     Thread *pCurThread = GetThread();
11621     _ASSERTE(pCurThread != NULL);
11622
11623     OBJECTREF oThrowable = pCurThread->GetThrowable();
11624     _ASSERTE(oThrowable != NULL);
11625
11626     // Get the thread exception state
11627     ThreadExceptionState * pCurTES = pCurThread->GetExceptionState();
11628     _ASSERTE(pCurTES != NULL);
11629
11630     // Get the exception tracker for the current exception
11631 #ifdef WIN64EXCEPTIONS
11632     PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker();
11633 #elif _TARGET_X86_
11634     PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker();
11635 #else // !(_WIN64 || _TARGET_X86_)
11636 #error Unsupported platform
11637 #endif // _WIN64
11638
11639     _ASSERTE(pEHTracker != NULL);
11640
11641     // Get the current exception code from the tracker.
11642     PEXCEPTION_RECORD pEHRecord = pCurTES->GetExceptionRecord();
11643     _ASSERTE(pEHRecord != NULL);
11644     DWORD dwActiveExceptionCode = pEHRecord->ExceptionCode;
11645
11646     if (pEHTracker->GetCorruptionSeverity() != NotSet)
11647     {
11648         // Since the exception tracker already has the corruption severity set,
11649         // we dont have much to do. Just confirm that our assumptions are correct.
11650         _ASSERTE(pEHTracker->GetCorruptionSeverity() == pCurTES->GetLastActiveExceptionCorruptionSeverity());
11651
11652         LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Current tracker already has the corruption severity set.\n"));
11653         return;
11654     }
11655
11656     // If the exception in question is to be treated as non-corrupting,
11657     // then flag it and exit.
11658     if (fShouldTreatExceptionAsNonCorrupting || g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11659     {
11660         pEHTracker->SetCorruptionSeverity(NotCorrupting);
11661         LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Exception treated as non-corrupting.\n"));
11662         goto done;
11663     }
11664
11665     if (!fIsRethrownException && !fIsNestedException)
11666     {
11667         // There should be no previously active exception for this case
11668         _ASSERTE(pEHTracker->GetPreviousExceptionTracker() == NULL);
11669
11670         CorruptionSeverity severityTES = NotSet;
11671
11672         if (pCurTES->ShouldLastActiveExceptionCorruptionSeverityBeReused())
11673         {
11674             // Get the corruption severity from the ThreadExceptionState (TES) for the last active exception
11675             severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity();
11676
11677             // Incase of scenarios like AD transition or Reflection invocation,
11678             // TES would hold corruption severity of the last active exception. To propagate it
11679             // to the current exception, we will apply it to current tracker and only if the applied
11680             // severity is "NotSet", will we proceed to check the current exception for corruption
11681             // severity.
11682             pEHTracker->SetCorruptionSeverity(severityTES);
11683         }
11684
11685         // Reset TES Corruption Severity
11686         pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet);
11687
11688         if (severityTES == NotSet)
11689         {
11690             // Since the last active exception's severity was "NotSet", we will look up the
11691             // exception code and the exception object to see if the exception should be marked
11692             // corrupting.
11693             //
11694             // Since this exception was neither rethrown nor is nested, it implies that we are
11695             // outside an active exception. Thus, even if it contains inner exceptions, we wont have
11696             // corruption severity for them since that information is tracked in EH tracker and
11697             // we wont have an EH tracker for the inner most exception.
11698
11699             if (CEHelper::IsProcessCorruptedStateException(dwActiveExceptionCode) ||
11700                 CEHelper::IsProcessCorruptedStateException(oThrowable))
11701             {
11702                 pEHTracker->SetCorruptionSeverity(ProcessCorrupting);
11703                 LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked non-rethrow/non-nested exception as ProcessCorrupting.\n"));
11704             }
11705             else
11706             {
11707                 pEHTracker->SetCorruptionSeverity(NotCorrupting);
11708                 LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked non-rethrow/non-nested exception as NotCorrupting.\n"));
11709             }
11710         }
11711         else
11712         {
11713             LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity to tracker from ThreadExceptionState for non-rethrow/non-nested exception.\n"));
11714         }
11715     }
11716     else
11717     {
11718         // Its either a rethrow or nested exception
11719
11720 #ifdef WIN64EXCEPTIONS
11721     PTR_ExceptionTracker pOrigEHTracker = NULL;
11722 #elif _TARGET_X86_
11723     PTR_ExInfo pOrigEHTracker = NULL;
11724 #else
11725 #error Unsupported platform
11726 #endif
11727
11728         BOOL fDoWeHaveCorruptionSeverity = FALSE;
11729
11730         if (fIsRethrownException)
11731         {
11732             // Rethrown exceptions are nested by nature (of our implementation). The
11733             // original EHTracker will exist for the exception - infact, it will be
11734             // the tracker previous to the current one. We will simply copy
11735             // its severity to the current EH tracker representing the rethrow.
11736             pOrigEHTracker = pEHTracker->GetPreviousExceptionTracker();
11737             _ASSERTE(pOrigEHTracker != NULL);
11738
11739             // Ideally, we would like have the assert below enabled. But, as may happen under OOM
11740             // stress, this can be false. Here's how it will happen:
11741             //
11742             // An exception is thrown, which is later caught and rethrown in the catch block. Rethrow
11743             // results in calling IL_Rethrow that will call RaiseTheExceptionInternalOnly to actually
11744             // raise the exception. Prior to the raise, we update the last thrown object on the thread
11745             // by calling Thread::SafeSetLastThrownObject which, internally, could have an OOM, resulting
11746             // in "changing" the throwable used to raise the exception to be preallocated OOM object.
11747             //
11748             // When the rethrow happens and CLR's exception handler for managed code sees the exception,
11749             // the exception tracker created for the rethrown exception will contain the reference to
11750             // the last thrown object, which will be the preallocated OOM object.
11751             //
11752             // Thus, though, we came here because of a rethrow, and logically, the throwable should remain
11753             // the same, it neednt be. Simply put, rethrow can result in working with a completely different
11754             // exception object than what was originally thrown.
11755             //
11756             // Hence, the assert cannot be enabled.
11757             //
11758             // Thus, we will use the EH tracker corresponding to the original exception, to get the
11759             // rethrown exception's corruption severity, only when the rethrown throwable is the same
11760             // as the original throwable. Otherwise, we will pretend that we didnt get the original tracker
11761             // and will automatically enter the path below to set the corruption severity based upon the
11762             // rethrown throwable.
11763
11764             // _ASSERTE(pOrigEHTracker->GetThrowable() == oThrowable);
11765             if (pOrigEHTracker->GetThrowable() != oThrowable)
11766             {
11767                 pOrigEHTracker = NULL;
11768                 LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Rethrown throwable does not match the original throwable. Corruption severity will be set based upon rethrown throwable.\n"));
11769             }
11770         }
11771         else
11772         {
11773             // Get the corruption severity from the ThreadExceptionState (TES) for the last active exception
11774             CorruptionSeverity severityTES = NotSet;
11775
11776             if (pCurTES->ShouldLastActiveExceptionCorruptionSeverityBeReused())
11777             {
11778                 severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity();
11779
11780                 // Incase of scenarios like AD transition or Reflection invocation,
11781                 // TES would hold corruption severity of the last active exception. To propagate it
11782                 // to the current exception, we will apply it to current tracker and only if the applied
11783                 // severity is "NotSet", will we proceed to check the current exception for corruption
11784                 // severity.
11785                 pEHTracker->SetCorruptionSeverity(severityTES);
11786             }
11787
11788             // Reset TES Corruption Severity
11789             pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet);
11790
11791             // If the last exception didnt have any corruption severity, proceed to look for it.
11792             if (severityTES == NotSet)
11793             {
11794                 // This is a nested exception - check if it has an inner exception(s). If it does,
11795                 // find the EH tracker corresponding to the innermost exception and we will copy the
11796                 // corruption severity from the original tracker to the current one.
11797                 OBJECTREF oInnermostThrowable = ((EXCEPTIONREF)oThrowable)->GetBaseException();
11798                 if (oInnermostThrowable != NULL)
11799                 {
11800                     // Find the tracker corresponding to the inner most exception, starting from
11801                     // the tracker previous to the current one. An EH tracker may not be found if
11802                     // the code did the following inside a catch clause:
11803                     //
11804                     // Exception ex = new Exception("inner exception");
11805                     // throw new Exception("message", ex);
11806                     //
11807                     // Or, an exception like AV happened in the catch clause.
11808                     pOrigEHTracker = GetEHTrackerForException(oInnermostThrowable, pEHTracker->GetPreviousExceptionTracker());
11809                 }
11810             }
11811             else
11812             {
11813                 // We have the corruption severity from the TES. Set the flag indicating so.
11814                 fDoWeHaveCorruptionSeverity = TRUE;
11815                 LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity to tracker from ThreadExceptionState for nested exception.\n"));
11816             }
11817         }
11818
11819         if (!fDoWeHaveCorruptionSeverity)
11820         {
11821             if (pOrigEHTracker != NULL)
11822             {
11823                 // Copy the severity from the original EH tracker to the current one
11824                 CorruptionSeverity origCorruptionSeverity = pOrigEHTracker->GetCorruptionSeverity();
11825                 _ASSERTE(origCorruptionSeverity != NotSet);
11826                 pEHTracker->SetCorruptionSeverity(origCorruptionSeverity);
11827
11828                 LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity (%d) from the original EH tracker for rethrown exception.\n", origCorruptionSeverity));
11829             }
11830             else
11831             {
11832                 if (CEHelper::IsProcessCorruptedStateException(dwActiveExceptionCode) ||
11833                     CEHelper::IsProcessCorruptedStateException(oThrowable))
11834                 {
11835                     pEHTracker->SetCorruptionSeverity(ProcessCorrupting);
11836                     LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked nested exception as ProcessCorrupting.\n"));
11837                 }
11838                 else
11839                 {
11840                     pEHTracker->SetCorruptionSeverity(NotCorrupting);
11841                     LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked nested exception as NotCorrupting.\n"));
11842                 }
11843             }
11844         }
11845     }
11846
11847 done:
11848     // Save the current exception's corruption severity in the ThreadExceptionState (TES)
11849     // for cases when we catch the managed exception in the runtime using EX_CATCH.
11850     // At such a time, all exception trackers get released (due to unwind triggered
11851     // by EX_END_CATCH) and yet we need the corruption severity information for
11852     // scenarios like AD Transition, Reflection invocation, etc.
11853     CorruptionSeverity currentSeverity = pEHTracker->GetCorruptionSeverity();
11854
11855     // We should be having a valid corruption severity at this point
11856     _ASSERTE(currentSeverity != NotSet);
11857
11858     // Save it in the TES
11859     pCurTES->SetLastActiveExceptionCorruptionSeverity(currentSeverity);
11860     LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity (%d) to ThreadExceptionState.\n", currentSeverity));
11861
11862 #endif // !DACCESS_COMPILE
11863 }
11864
11865 // CE can be caught in the VM and later reraised again. Examples of such scenarios
11866 // include AD transition, COM interop, Reflection invocation, to name a few.
11867 // In such cases, we want to mark the corruption severity for reuse upon reraise,
11868 // implying that when the VM does a reraise of such an exception, we should use
11869 // the original corruption severity for the new raised exception, instead of creating
11870 // a new one for it.
11871 /* static */
11872 void CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse()
11873 {
11874     CONTRACTL
11875     {
11876         NOTHROW;
11877         GC_NOTRIGGER;
11878         MODE_ANY;
11879         SO_TOLERANT;
11880         PRECONDITION(GetThread() != NULL);
11881     }
11882     CONTRACTL_END;
11883
11884     // If the last active exception's corruption severity is anything but
11885     // "NotSet", mark it for ReraiseReuse
11886     ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
11887     _ASSERTE(pCurTES != NULL);
11888
11889     CorruptionSeverity severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity();
11890     if (severityTES != NotSet)
11891     {
11892         pCurTES->SetLastActiveExceptionCorruptionSeverity((CorruptionSeverity)(severityTES | ReuseForReraise));
11893     }
11894 }
11895
11896 // This method will return a BOOL to indicate if the current exception is to be treated as
11897 // non-corrupting. Currently, this returns true for NullReferenceException only.
11898 /* static */
11899 BOOL CEHelper::ShouldTreatActiveExceptionAsNonCorrupting()
11900 {
11901     BOOL fShouldTreatAsNonCorrupting = FALSE;
11902
11903 #ifndef DACCESS_COMPILE
11904     CONTRACTL
11905     {
11906         THROWS;
11907         GC_TRIGGERS;
11908         MODE_COOPERATIVE;
11909         PRECONDITION(GetThread() != NULL);
11910     }
11911     CONTRACTL_END;
11912
11913     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
11914     {
11915         return TRUE;
11916     }
11917
11918     DWORD dwActiveExceptionCode = GetThread()->GetExceptionState()->GetExceptionRecord()->ExceptionCode;
11919     if (dwActiveExceptionCode == STATUS_ACCESS_VIOLATION)
11920     {
11921         // NullReference has the same exception code as AV
11922         OBJECTREF oThrowable = NULL;
11923         GCPROTECT_BEGIN(oThrowable);
11924
11925         // Get the throwable and check if it represents null reference exception
11926         oThrowable = GetThread()->GetThrowable();
11927         _ASSERTE(oThrowable != NULL);
11928         if (MscorlibBinder::GetException(kNullReferenceException) == oThrowable->GetMethodTable())
11929         {
11930             fShouldTreatAsNonCorrupting = TRUE;
11931         }
11932         GCPROTECT_END();
11933     }
11934 #endif // !DACCESS_COMPILE
11935
11936     return fShouldTreatAsNonCorrupting;
11937 }
11938
11939 // If we were working in a nested exception scenario, reset the corruption severity to the last
11940 // exception we were processing, based upon its EH tracker.
11941 //
11942 // If none was present, reset it to NotSet.
11943 //
11944 // Note: This method must be called once the exception trackers have been adjusted post catch-block execution.
11945 /* static */
11946 void CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler(Thread *pThread)
11947 {
11948     CONTRACTL
11949     {
11950         NOTHROW;
11951         GC_NOTRIGGER;
11952         MODE_ANY;
11953         PRECONDITION(pThread != NULL);
11954     }
11955     CONTRACTL_END;
11956
11957     ThreadExceptionState *pCurTES = pThread->GetExceptionState();
11958
11959     // By this time, we would have set the correct exception tracker for the active exception domain,
11960     // if applicable. An example is throwing and catching an exception within a catch block. We will update
11961     // the LastActiveCorruptionSeverity based upon the active exception domain. If we are not in one, we will
11962     // set it to "NotSet".
11963 #ifdef WIN64EXCEPTIONS
11964     PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker();
11965 #elif _TARGET_X86_
11966     PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker();
11967 #else
11968 #error Unsupported platform
11969 #endif
11970
11971     if (pEHTracker)
11972     {
11973         pCurTES->SetLastActiveExceptionCorruptionSeverity(pEHTracker->GetCorruptionSeverity());
11974     }
11975     else
11976     {
11977         pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet);
11978     }
11979
11980     LOG((LF_EH, LL_INFO100, "CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler - Reset LastActiveException corruption severity to %d.\n",
11981         pCurTES->GetLastActiveExceptionCorruptionSeverity()));
11982 }
11983
11984 // This method will return a BOOL indicating if the target of IDispatch can handle the specified exception or not.
11985 /* static */
11986 BOOL CEHelper::CanIDispatchTargetHandleException()
11987 {
11988     CONTRACTL
11989     {
11990         NOTHROW;
11991         GC_NOTRIGGER;
11992         MODE_ANY;
11993         PRECONDITION(GetThread() != NULL);
11994     }
11995     CONTRACTL_END;
11996
11997     // By default, assume that the target of IDispatch cannot handle the exception.
11998     BOOL fCanMethodHandleException = FALSE;
11999
12000     if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
12001     {
12002         return TRUE;
12003     }
12004
12005     // IDispatch implementation in COM interop works by invoking the actual target via reflection.
12006     // Thus, a COM client could use the V4 runtime to invoke a V2 method. In such a case, a CSE
12007     // could come unhandled at the actual target invoked via reflection.
12008     //
12009     // Reflection invocation would have set a flag for us, indicating if the actual target was
12010     // enabled to handle the CE or not. If it is, then we should allow the COM client to get the
12011     // hresult from the call and not let the exception continue up the stack.
12012     ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
12013     fCanMethodHandleException = pCurTES->CanReflectionTargetHandleException();
12014
12015     // Reset the flag so that subsequent invocations work as expected.
12016     pCurTES->SetCanReflectionTargetHandleException(FALSE);
12017
12018     return fCanMethodHandleException;
12019 }
12020
12021 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12022
12023 #ifndef DACCESS_COMPILE
12024 // When a managed thread starts in non-default domain, its callstack looks like below:
12025 //
12026 // <ManagedThreadBase_DispatchOuter>
12027 // <ManagedThreadBase_DispatchMiddle>
12028 // <ManagedThreadBase_DispatchInner>
12029 //
12030 // -- AD transition is here --        ==> Pushes ContextTransitionFrame and has EX_CATCH
12031 //
12032 // <ManagedThreadBase_DispatchOuter>
12033 // <ManagedThreadBase_DispatchMiddle>
12034 // <ManagedThreadBase_DispatchInner>
12035 //
12036 // In CoreCLR, all managed threads spawned will have a stack like this since they all
12037 // run in non-DefaultDomain. The upper three frames are in default domain and the lower
12038 // three are in the non-default domain in which the thread was created. Any exception
12039 // that is unhandled in non-default domain will be caught at AD transition boundary.
12040 // The transition boundary does the following tasks:
12041 //
12042 // 1) Catch any incoming unhandled exception from the non-default domain using EX_CATCH.
12043 // 2) Marshal the exception object to the return context (i.e. DefaultDomain)
12044 // 3) Return to the context of DefaultDomain and throw the marshalled exception object there.
12045 //
12046 // All this depends upon the EX_CATCH (which is based upon C++ exception handling) being
12047 // able to catch the exception.
12048 //
12049 // However, if a breakpoint exception ia raised and a debugger is not available to handle it,
12050 // C++'s catch(...) will not be able to catch it, even when compiled with /EHa. For the curious,
12051 // refer to "FindHandlerForForeignException" function's implementation in the CRT. One of the first
12052 // things it does is check for breakpoint exception and if it is, it will simply bail out of the
12053 // process of finding a handler. Thus, EX_CATCH will not be able to catch this exception and we
12054 // will not be able to transition to the previous AD context.
12055 //
12056 // Imagine a thread in non-default domain suffers breakpoint exception. Assuming it will go unhandled,
12057 // it will reach the OS, which will trigger an unwind. The execution of termination handlers in lower
12058 // three frames (above) is fine since they are in the same AD as the thread. But when termination
12059 // handlers in the upper three frames execute, its a case of bad mixup since the thread is in a different
12060 // AD context than what the frames are expected to be in.
12061 //
12062 // Hence, we need a mechanism to transition to the expected AppDomain in case of breakpoint exception.
12063 // This function supports this mechanism in a generic fashion, i.e., one can use it to transition to
12064 // any AppDomain, though only up the stack.
12065
12066 BOOL ReturnToPreviousAppDomain()
12067 {
12068     STATIC_CONTRACT_GC_NOTRIGGER;
12069     STATIC_CONTRACT_NOTHROW;
12070     STATIC_CONTRACT_MODE_COOPERATIVE;
12071     STATIC_CONTRACT_SO_TOLERANT;
12072
12073     Thread *pCurThread = GetThread();
12074     _ASSERTE(pCurThread != NULL);
12075
12076     BOOL fTransitioned = FALSE;
12077
12078     BEGIN_SO_INTOLERANT_CODE_NOTHROW(pCurThread, return FALSE);
12079
12080     // Get the thread's current domain
12081     AppDomain *pCurDomain = pCurThread->GetDomain();
12082     _ASSERTE(pCurDomain != NULL);
12083
12084     // Lookup the ContextTransitionFrame for the transition into the current AppDomain.
12085     Frame *pCtxTransitionFrame = pCurThread->GetFirstTransitionInto(pCurDomain, NULL);
12086     if (pCtxTransitionFrame == NULL)
12087     {
12088         // Since we couldnt find the context transition frame, check if its the default domain.
12089         // If so, we will set fTransitioned to TRUE since there is no context transition frame
12090         // setup for the initial entry into the default domain. For all other transitions to it
12091         // from non-default domains, we will have a context transition frame. We will do a
12092         // debug-only check to assert this invariant.
12093         BOOL fIsDefDomain = pCurDomain->IsDefaultDomain();
12094 #ifdef _DEBUG
12095         if (fIsDefDomain)
12096         {
12097             // Start with the topmost frame and look for a CTX frame until we reach the top of the frame chain.
12098             // We better not find one since we couldnt find a transition frame to the DefaultDomain.
12099             Frame *pStartFrame = pCurThread->GetFrame();
12100             BOOL fFoundCTXFrame = FALSE;
12101             while ((pStartFrame != NULL) && (pStartFrame != (Frame *)FRAME_TOP))
12102             {
12103                  if (pStartFrame->GetVTablePtr() == ContextTransitionFrame::GetMethodFrameVPtr())
12104                  {
12105                     fFoundCTXFrame = TRUE;
12106                     break;
12107                  }
12108
12109                 // Get the next frame in the chain
12110                 pStartFrame = pStartFrame->PtrNextFrame();
12111             }
12112
12113             _ASSERTE_MSG(!fFoundCTXFrame, "How come we didnt find the transition frame to DefDomain but found another CTX frame on the frame chain?");
12114         }
12115 #endif // _DEBUG
12116         fTransitioned = fIsDefDomain;
12117         LOG((LF_EH, LL_INFO100, "ReturnToPreviousAppDomain: Unable to find the transition into the current domain (IsDefaultDomain: %d).\n", fIsDefDomain));
12118
12119         goto done;
12120     }
12121
12122     // Confirm its the correct type of frame
12123     _ASSERTE_MSG(pCtxTransitionFrame->GetVTablePtr() == ContextTransitionFrame::GetMethodFrameVPtr(),
12124                     "How come we didn't find context transition frame for this AD transition?");
12125
12126     // Get the topmost Frame
12127     Frame *pCurFrame;
12128     pCurFrame = pCurThread->GetFrame();
12129
12130     // <ASSUMPTION>
12131     //
12132     // The loop below assumes we are called during an exception unwind since it
12133     // unwinds the Frames and pops them off the thread.
12134     //
12135     // </ASSUMPTION>
12136     //
12137     // Clear all the frames until we are at the frame of our interest. If there was a
12138     // CTX frame between the topmost frame and the AD transition, then we should be able to
12139     // catch it here as well.
12140     while((pCurFrame != NULL) && (pCurFrame < pCtxTransitionFrame) &&
12141           (pCurFrame->GetVTablePtr() != ContextTransitionFrame::GetMethodFrameVPtr()))
12142     {
12143         // Invoke exception unwind and pop the frame off
12144         pCurFrame->ExceptionUnwind();
12145         pCurFrame->Pop();
12146         pCurFrame = pCurThread->GetFrame();
12147     }
12148
12149     // Confirm that we are at the expected Frame.
12150     _ASSERTE_MSG(((pCurFrame != NULL) &&
12151                   (pCurFrame->GetVTablePtr() == ContextTransitionFrame::GetMethodFrameVPtr()) &&
12152                   (pCurFrame == pCtxTransitionFrame)),
12153                     "How come we are not at the exact context transition frame?");
12154
12155     // Log our context return
12156     LOG((LF_EH, LL_INFO100, "ReturnToPreviousAppDomain: Returning from AD %d to AD %d\n",
12157         GetAppDomain()->GetId().m_dwId, pCtxTransitionFrame->GetReturnDomain()->GetId().m_dwId));
12158
12159     // Return to the previous AD context
12160     pCurThread->ReturnToContext((ContextTransitionFrame *)pCtxTransitionFrame);
12161
12162 #ifdef _DEBUG
12163     // At this point, the context transition frame would have been popped off by
12164     // ReturnToContext above.
12165     pCurFrame = pCurThread->GetFrame();
12166     _ASSERTE_MSG(pCurFrame != pCtxTransitionFrame, "How come the CTX frame of AD transition is still on the frame chain?");
12167 #endif // _DEBUG
12168
12169     // Set the flag that we transitioned correctly.
12170     fTransitioned = TRUE;
12171
12172 done:;
12173     END_SO_INTOLERANT_CODE;
12174
12175     return fTransitioned;
12176 }
12177
12178 // This class defines a holder that can be used to return to previous AppDomain incase an exception
12179 // goes across an AD transition boundary without reverting the active context.
12180 //
12181 // Use this holder *after* you have transitioned to the target AD.
12182 void ReturnToPreviousAppDomainHolder::Init()
12183 {
12184     CONTRACTL
12185     {
12186         NOTHROW;
12187         GC_NOTRIGGER;
12188         MODE_ANY;
12189         SO_TOLERANT;
12190     }
12191     CONTRACTL_END;
12192
12193     m_fShouldReturnToPreviousAppDomain = TRUE;
12194     m_pThread = GetThread();
12195     _ASSERTE(m_pThread != NULL);
12196
12197 #ifdef _DEBUG
12198     m_pTransitionedToAD = m_pThread->GetDomain();
12199 #endif // _DEBUG
12200 }
12201
12202 ReturnToPreviousAppDomainHolder::ReturnToPreviousAppDomainHolder()
12203 {
12204     CONTRACTL
12205     {
12206         NOTHROW;
12207         GC_NOTRIGGER;
12208         MODE_ANY;
12209         SO_TOLERANT;
12210     }
12211     CONTRACTL_END;
12212
12213     Init();
12214 }
12215
12216 void ReturnToPreviousAppDomainHolder::ReturnToPreviousAppDomain()
12217 {
12218     CONTRACTL
12219     {
12220         NOTHROW;
12221         GC_NOTRIGGER;
12222         MODE_ANY;
12223         SO_TOLERANT;
12224         // Test your sanity - we should still be in the transitioned-to AD.
12225         PRECONDITION(m_pThread->GetDomain() == m_pTransitionedToAD);
12226     }
12227     CONTRACTL_END;
12228
12229     {
12230         GCX_COOP();
12231         ::ReturnToPreviousAppDomain();
12232     }
12233
12234     // Set the LastThrownObject as NULL since we have returned to a different
12235     // AD. Maintaining the reference to an object in the "returned-from" AD
12236     // will prevent the AD from getting unloaded.
12237     //
12238     // Setting to NULL does not require us to be in COOP mode.
12239     m_pThread->SafeSetLastThrownObject(NULL);
12240 }
12241
12242 ReturnToPreviousAppDomainHolder::~ReturnToPreviousAppDomainHolder()
12243 {
12244     CONTRACTL
12245     {
12246         NOTHROW;
12247         GC_NOTRIGGER;
12248         MODE_ANY;
12249         SO_TOLERANT;
12250     }
12251     CONTRACTL_END;
12252
12253     if (m_fShouldReturnToPreviousAppDomain)
12254     {
12255         ReturnToPreviousAppDomain();
12256     }
12257 }
12258
12259 // Reset the flag to indicate that reverting to previous AD is not required anymore.
12260 // This should be invoked when the call has successfully returned from the target execution context.
12261 //
12262 // By default, this flag is TRUE (see the contructor above) to enable automatic context
12263 // revert incase an exception goes past the transition.
12264 //
12265 // END_DOMAIN_TRANSITION_NO_EH_AT_TRANSITION macro uses it. See its implementation in threads.h
12266 // for usage.
12267 void ReturnToPreviousAppDomainHolder::SuppressRelease()
12268 {
12269     LIMITED_METHOD_CONTRACT;
12270
12271     m_fShouldReturnToPreviousAppDomain = FALSE;
12272 }
12273
12274 #endif // !DACCESS_COMPILE
12275
12276 #ifndef DACCESS_COMPILE
12277 // This method will deliver the actual exception notification. Its assumed that the caller has done the necessary checks, including
12278 // checking whether the delegate can be invoked for the exception's corruption severity.
12279 void ExceptionNotifications::DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate,
12280         OBJECTREF *pAppDomain, OBJECTREF *pEventArgs)
12281 {
12282     CONTRACTL
12283     {
12284         THROWS;
12285         GC_TRIGGERS;
12286         MODE_COOPERATIVE;
12287         PRECONDITION(pDelegate  != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL));
12288         PRECONDITION(pEventArgs != NULL && IsProtectedByGCFrame(pEventArgs));
12289         PRECONDITION(pAppDomain != NULL && IsProtectedByGCFrame(pAppDomain));
12290     }
12291     CONTRACTL_END;
12292
12293     PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(DELEGATEREF(*pDelegate)->GetMethodPtr());
12294
12295     DECLARE_ARGHOLDER_ARRAY(args, 3);
12296
12297     args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(DELEGATEREF(*pDelegate)->GetTarget());
12298     args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*pAppDomain);
12299     args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(*pEventArgs);
12300
12301     CALL_MANAGED_METHOD_NORET(args);
12302 }
12303
12304 // To include definition of COMDelegate::GetMethodDesc
12305 #include "comdelegate.h"
12306
12307 // This method constructs the arguments to be passed to the exception notification event callback
12308 void ExceptionNotifications::GetEventArgsForNotification(ExceptionNotificationHandlerType notificationType,
12309                                                          OBJECTREF *pOutEventArgs, OBJECTREF *pThrowable)
12310 {
12311     CONTRACTL
12312     {
12313         THROWS;
12314         GC_TRIGGERS;
12315         MODE_COOPERATIVE;
12316         PRECONDITION(notificationType != UnhandledExceptionHandler);
12317         PRECONDITION((pOutEventArgs != NULL) && IsProtectedByGCFrame(pOutEventArgs));
12318         PRECONDITION(*pOutEventArgs == NULL);
12319         PRECONDITION((pThrowable != NULL) && (*pThrowable != NULL) && IsProtectedByGCFrame(pThrowable));
12320         PRECONDITION(IsException((*pThrowable)->GetMethodTable())); // We expect a valid exception object
12321     }
12322     CONTRACTL_END;
12323
12324     MethodTable *pMTEventArgs = NULL;
12325     BinderMethodID idEventArgsCtor = METHOD__FIRSTCHANCE_EVENTARGS__CTOR;
12326
12327     EX_TRY
12328     {
12329         switch(notificationType)
12330         {
12331             case FirstChanceExceptionHandler:
12332                 pMTEventArgs = MscorlibBinder::GetClass(CLASS__FIRSTCHANCE_EVENTARGS);
12333                 idEventArgsCtor = METHOD__FIRSTCHANCE_EVENTARGS__CTOR;
12334                 break;
12335             default:
12336                 _ASSERTE(!"Invalid Exception Notification Handler!");
12337                 break;
12338         }
12339
12340         // Allocate the instance of the eventargs corresponding to the notification
12341         *pOutEventArgs = AllocateObject(pMTEventArgs);
12342
12343         // Prepare to invoke the .ctor
12344         MethodDescCallSite ctor(idEventArgsCtor, pOutEventArgs);
12345
12346         // Setup the arguments to be passed to the notification specific EventArgs .ctor
12347         if (notificationType == FirstChanceExceptionHandler)
12348         {
12349             // FirstChance notification takes only a single argument: the exception object.
12350             ARG_SLOT args[] =
12351             {
12352                 ObjToArgSlot(*pOutEventArgs),
12353                 ObjToArgSlot(*pThrowable),
12354             };
12355
12356             ctor.Call(args);
12357         }
12358         else
12359         {
12360             // Since we have already asserted above, just set the args to NULL.
12361             *pOutEventArgs = NULL;
12362         }
12363     }
12364     EX_CATCH
12365     {
12366         // Set event args to be NULL incase of any error (e.g. OOM)
12367         *pOutEventArgs = NULL;
12368         LOG((LF_EH, LL_INFO100, "ExceptionNotifications::GetEventArgsForNotification: Setting event args to NULL due to an exception.\n"));
12369     }
12370     EX_END_CATCH(RethrowCorruptingExceptions); // Dont swallow any CSE that may come in from the .ctor.
12371 }
12372
12373 // This SEH filter will be invoked when an exception escapes out of the exception notification
12374 // callback and enters the runtime. In such a case, we ill simply failfast.
12375 static LONG ExceptionNotificationFilter(PEXCEPTION_POINTERS pExceptionInfo, LPVOID pParam)
12376 {
12377     EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
12378 }
12379
12380 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12381 // This method will return a BOOL indicating if the delegate should be invoked for the exception
12382 // of the specified corruption severity.
12383 BOOL ExceptionNotifications::CanDelegateBeInvokedForException(OBJECTREF *pDelegate, CorruptionSeverity severity)
12384 {
12385     CONTRACTL
12386     {
12387         THROWS;
12388         GC_TRIGGERS;
12389         MODE_COOPERATIVE;
12390         PRECONDITION(pDelegate  != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL));
12391         PRECONDITION(severity > NotSet);
12392     }
12393     CONTRACTL_END;
12394
12395     // Notifications for CSE are only delivered if the delegate target follows CSE rules.
12396     BOOL fCanMethodHandleException = g_pConfig->LegacyCorruptedStateExceptionsPolicy() ? TRUE:(severity == NotCorrupting);
12397     if (!fCanMethodHandleException)
12398     {
12399         EX_TRY
12400         {
12401             // Get the MethodDesc of the delegate to be invoked
12402             MethodDesc *pMDDelegate = COMDelegate::GetMethodDesc(*pDelegate);
12403             _ASSERTE(pMDDelegate != NULL);
12404
12405             // Check the callback target and see if it is following CSE rules or not.
12406             fCanMethodHandleException = CEHelper::CanMethodHandleException(severity, pMDDelegate);
12407         }
12408         EX_CATCH
12409         {
12410             // Incase of any exceptions, pretend we cannot handle the exception
12411             fCanMethodHandleException = FALSE;
12412             LOG((LF_EH, LL_INFO100, "ExceptionNotifications::CanDelegateBeInvokedForException: Exception while trying to determine if exception notification can be invoked or not.\n"));
12413         }
12414         EX_END_CATCH(RethrowCorruptingExceptions); // Dont swallow any CSEs.
12415     }
12416
12417     return fCanMethodHandleException;
12418 }
12419 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12420
12421 // This method will make the actual delegate invocation for the exception notification to be delivered. If an
12422 // exception escapes out of the notification, our filter in ExceptionNotifications::DeliverNotification will
12423 // address it.
12424 void ExceptionNotifications::InvokeNotificationDelegate(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs,
12425                                                         OBJECTREF *pAppDomain
12426 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12427                                                         , CorruptionSeverity severity
12428 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12429                                                         )
12430 {
12431     CONTRACTL
12432     {
12433         THROWS;
12434         GC_TRIGGERS;
12435         MODE_COOPERATIVE;
12436         PRECONDITION(pDelegate  != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL));
12437         PRECONDITION(pEventArgs != NULL && IsProtectedByGCFrame(pEventArgs));
12438         PRECONDITION(pAppDomain != NULL && IsProtectedByGCFrame(pAppDomain));
12439 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12440         PRECONDITION(severity > NotSet);
12441 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12442         // Unhandled Exception Notification is delivered via Unhandled Exception Processing
12443         // mechanism.
12444         PRECONDITION(notificationType != UnhandledExceptionHandler);
12445     }
12446     CONTRACTL_END;
12447
12448 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12449     // Notifications are delivered based upon corruption severity of the exception
12450     if (!ExceptionNotifications::CanDelegateBeInvokedForException(pDelegate, severity))
12451     {
12452         LOG((LF_EH, LL_INFO100, "ExceptionNotifications::InvokeNotificationDelegate: Delegate cannot be invoked for corruption severity %d\n",
12453         severity));
12454         return;
12455     }
12456 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12457
12458     // We've already exercised the prestub on this delegate's COMDelegate::GetMethodDesc,
12459     // as part of wiring up a reliable event sink in the BCL. Deliver the notification.
12460     ExceptionNotifications::DeliverExceptionNotification(notificationType, pDelegate, pAppDomain, pEventArgs);
12461 }
12462
12463 // This method returns a BOOL to indicate if the AppDomain is ready to receive exception notifications or not.
12464 BOOL ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType)
12465 {
12466     CONTRACTL
12467     {
12468         NOTHROW;
12469         GC_NOTRIGGER;
12470         MODE_COOPERATIVE;
12471         SO_TOLERANT;
12472         PRECONDITION(GetThread() != NULL);
12473         PRECONDITION(notificationType  != UnhandledExceptionHandler);
12474     }
12475     CONTRACTL_END;
12476
12477     Thread *pCurThread = GetThread();
12478
12479     // Get the current AppDomain
12480     OBJECTREF oCurAppDomain = pCurThread->GetDomain()->GetRawExposedObject();
12481     if (oCurAppDomain == NULL)
12482     {
12483         // Managed object for the current domain does not exist. Hence, no one
12484         // can wireup to exception notifications, let alone receive them.
12485         return FALSE;
12486     }
12487
12488     // Do we have handler(s) of the specific type wired up?
12489     if (notificationType == FirstChanceExceptionHandler)
12490     {
12491         return (((APPDOMAINREF)oCurAppDomain)->GetFirstChanceExceptionNotificationHandler() != NULL);
12492     }
12493     else
12494     {
12495         _ASSERTE(!"Invalid exception notification handler specified!");
12496         return FALSE;
12497     }
12498 }
12499
12500 // This method wraps the call to the actual 'DeliverNotificationInternal' method in an SEH filter
12501 // so that if an exception escapes out of the notification callback, we will trigger failfast from
12502 // our filter.
12503 void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerType notificationType,
12504                                                  OBJECTREF *pThrowable
12505 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12506         , CorruptionSeverity severity
12507 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12508         )
12509 {
12510     STATIC_CONTRACT_GC_TRIGGERS;
12511     STATIC_CONTRACT_NOTHROW; // NOTHROW because incase of an exception, we will FailFast.
12512     STATIC_CONTRACT_MODE_COOPERATIVE;
12513
12514     struct TryArgs
12515     {
12516         ExceptionNotificationHandlerType notificationType;
12517         OBJECTREF *pThrowable;
12518 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12519         CorruptionSeverity severity;
12520 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12521     } args;
12522
12523     args.notificationType = notificationType;
12524     args.pThrowable = pThrowable;
12525 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12526     args.severity = severity;
12527 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12528
12529     PAL_TRY(TryArgs *, pArgs, &args)
12530     {
12531         // Make the call to the actual method that will invoke the callbacks
12532         ExceptionNotifications::DeliverNotificationInternal(pArgs->notificationType,
12533             pArgs->pThrowable
12534 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12535             , pArgs->severity
12536 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12537             );
12538     }
12539     PAL_EXCEPT_FILTER(ExceptionNotificationFilter)
12540     {
12541         // We should never be entering this handler since there should be
12542         // no exception escaping out of a callback. If we are here,
12543         // failfast.
12544         EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
12545     }
12546     PAL_ENDTRY;
12547 }
12548
12549 // This method will deliver the exception notification to the current AppDomain.
12550 void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHandlerType notificationType,
12551                                                  OBJECTREF *pThrowable
12552 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12553         , CorruptionSeverity severity
12554 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12555         )
12556 {
12557     CONTRACTL
12558     {
12559         THROWS;
12560         GC_TRIGGERS;
12561         MODE_COOPERATIVE;
12562
12563         // Unhandled Exception Notification is delivered via Unhandled Exception Processing
12564         // mechanism.
12565         PRECONDITION(notificationType != UnhandledExceptionHandler);
12566         PRECONDITION((pThrowable != NULL) && (*pThrowable != NULL));
12567         PRECONDITION(ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(notificationType));
12568 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12569         PRECONDITION(severity > NotSet); // Exception corruption severity must be valid at this point.
12570 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12571     }
12572     CONTRACTL_END;
12573
12574     Thread *pCurThread = GetThread();
12575     _ASSERTE(pCurThread != NULL);
12576
12577     // Get the current AppDomain
12578     AppDomain *pCurDomain = GetAppDomain();
12579     _ASSERTE(pCurDomain != NULL);
12580
12581     struct
12582     {
12583         OBJECTREF oNotificationDelegate;
12584         PTRARRAYREF arrDelegates;
12585         OBJECTREF   oInnerDelegate;
12586         OBJECTREF   oEventArgs;
12587         OBJECTREF   oCurrentThrowable;
12588         OBJECTREF   oCurAppDomain;
12589     } gc;
12590     ZeroMemory(&gc, sizeof(gc));
12591
12592     // This will hold the MethodDesc of the callback that will be invoked.
12593     MethodDesc *pMDDelegate = NULL;
12594
12595     GCPROTECT_BEGIN(gc);
12596
12597     // Protect the throwable to be passed to the delegate callback
12598     gc.oCurrentThrowable = *pThrowable;
12599
12600     // We expect a valid exception object
12601     _ASSERTE(IsException(gc.oCurrentThrowable->GetMethodTable()));
12602
12603     // Save the reference to the current AppDomain. If the user code has
12604     // wired upto this event, then the managed AppDomain object will exist.
12605     gc.oCurAppDomain = pCurDomain->GetRawExposedObject();
12606     _ASSERTE(gc.oCurAppDomain);
12607
12608     // Get the reference to the delegate based upon the type of notification
12609     if (notificationType == FirstChanceExceptionHandler)
12610     {
12611         gc.oNotificationDelegate = ((APPDOMAINREF)gc.oCurAppDomain)->GetFirstChanceExceptionNotificationHandler();
12612     }
12613     else
12614     {
12615         gc.oNotificationDelegate = NULL;
12616         _ASSERTE(!"Invalid Exception Notification Handler specified!");
12617     }
12618
12619     if (gc.oNotificationDelegate != NULL)
12620     {
12621         // Prevent any async exceptions from this moment on this thread
12622         ThreadPreventAsyncHolder prevAsync;
12623
12624         gc.oEventArgs = NULL;
12625
12626         // Get the arguments to be passed to the delegate callback. Incase of any
12627         // problem while allocating the event args, we will return a NULL.
12628         ExceptionNotifications::GetEventArgsForNotification(notificationType, &gc.oEventArgs,
12629             &gc.oCurrentThrowable);
12630
12631         // Check if there are multiple callbacks registered? If there are, we will
12632         // loop through them, invoking each one at a time. Before invoking the target,
12633         // we will check if the target can be invoked based upon the corruption severity
12634         // for the active exception that was passed to us.
12635         gc.arrDelegates = (PTRARRAYREF) ((DELEGATEREF)(gc.oNotificationDelegate))->GetInvocationList();
12636         if (gc.arrDelegates == NULL || !gc.arrDelegates->GetMethodTable()->IsArray())
12637         {
12638             ExceptionNotifications::InvokeNotificationDelegate(notificationType, &gc.oNotificationDelegate, &gc.oEventArgs,
12639                 &gc.oCurAppDomain
12640 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12641                 , severity
12642 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12643                 );
12644         }
12645         else
12646         {
12647             // The _invocationCount could be less than the array size, if we are sharing
12648             // immutable arrays cleverly.
12649             UINT_PTR      cnt = ((DELEGATEREF)(gc.oNotificationDelegate))->GetInvocationCount();
12650             _ASSERTE(cnt <= gc.arrDelegates->GetNumComponents());
12651
12652             for (UINT_PTR i=0; i<cnt; i++)
12653             {
12654                 gc.oInnerDelegate = gc.arrDelegates->m_Array[i];
12655                 ExceptionNotifications::InvokeNotificationDelegate(notificationType, &gc.oInnerDelegate, &gc.oEventArgs,
12656                     &gc.oCurAppDomain
12657 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12658                     , severity
12659 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12660                     );
12661             }
12662         }
12663     }
12664
12665     GCPROTECT_END();
12666 }
12667
12668 void ExceptionNotifications::DeliverFirstChanceNotification()
12669 {
12670     CONTRACTL
12671     {
12672         THROWS;
12673         GC_TRIGGERS;
12674         MODE_ANY;
12675     }
12676     CONTRACTL_END;
12677
12678     // We check for FirstChance notification delivery after setting up the corruption severity
12679     // so that we can determine if the callback delegate can handle CSE (or not).
12680     //
12681     // Deliver it only if not already done and someone has wiredup to receive it.
12682     //
12683     // We do this provided this is the first frame of a new exception
12684     // that was thrown or a rethrown exception. We dont want to do this
12685     // processing for subsequent frames on the stack since FirstChance notification
12686     // will be delivered only when the exception is first thrown/rethrown.
12687     ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
12688     _ASSERTE(pCurTES->GetCurrentExceptionTracker());
12689     _ASSERTE(!(pCurTES->GetCurrentExceptionTracker()->DeliveredFirstChanceNotification()));
12690     {
12691         GCX_COOP();
12692         if (ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(FirstChanceExceptionHandler))
12693         {
12694             OBJECTREF oThrowable = NULL;
12695             GCPROTECT_BEGIN(oThrowable);
12696
12697             oThrowable = pCurTES->GetThrowable();
12698             _ASSERTE(oThrowable != NULL);
12699
12700             ExceptionNotifications::DeliverNotification(FirstChanceExceptionHandler, &oThrowable
12701 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
12702              , pCurTES->GetCurrentExceptionTracker()->GetCorruptionSeverity()
12703 #endif // FEATURE_CORRUPTING_EXCEPTIONS
12704              );
12705             GCPROTECT_END();
12706
12707         }
12708
12709         // Mark the exception tracker as having delivered the first chance notification
12710         pCurTES->GetCurrentExceptionTracker()->SetFirstChanceNotificationStatus(TRUE);
12711     }
12712 }
12713
12714
12715 #ifdef WIN64EXCEPTIONS
12716 struct TAResetStateCallbackData
12717 {
12718     // Do we have more managed code up the stack?
12719     BOOL fDoWeHaveMoreManagedCodeOnStack;
12720
12721     // StackFrame representing the crawlFrame above which
12722     // we are searching for presence of managed code.
12723     StackFrame sfSeedCrawlFrame;
12724 };
12725
12726 // This callback helps the 64bit EH attempt to determine if there is more managed code
12727 // up the stack (or not). Currently, it is used to conditionally reset the thread abort state
12728 // as the unwind passes by.
12729 StackWalkAction TAResetStateCallback(CrawlFrame* pCf, void* data)
12730 {
12731     CONTRACTL {
12732         NOTHROW;
12733         GC_NOTRIGGER;
12734     }
12735     CONTRACTL_END;
12736
12737     TAResetStateCallbackData *pTAResetStateCallbackData = static_cast<TAResetStateCallbackData *>(data);
12738     StackWalkAction retStatus = SWA_CONTINUE;
12739
12740     if(pCf->IsFrameless())
12741     {
12742         IJitManager* pJitManager = pCf->GetJitManager();
12743         _ASSERTE(pJitManager);
12744         if (pJitManager && (!pTAResetStateCallbackData->fDoWeHaveMoreManagedCodeOnStack))
12745         {
12746             // The stackwalker can give us a callback for the seeding CrawlFrame (or other crawlframes)
12747             // depending upon which is closer to the leaf: the seeding crawlframe or the explicit frame
12748             // specified when starting the stackwalk.
12749             //
12750             // Since we are interested in checking if there is more managed code up the stack from
12751             // the seeding crawlframe, we check if the current crawlframe is above it or not. If it is,
12752             // then we have found managed code up the stack and should stop the stack walk. Otherwise,
12753             // continue searching.
12754             StackFrame sfCurrentFrame = StackFrame::FromRegDisplay(pCf->GetRegisterSet());
12755             if (pTAResetStateCallbackData->sfSeedCrawlFrame < sfCurrentFrame)
12756             {
12757                 // We have found managed code on the stack. Flag it and stop the stackwalk.
12758                 pTAResetStateCallbackData->fDoWeHaveMoreManagedCodeOnStack = TRUE;
12759                 retStatus = SWA_ABORT;
12760             }
12761         }
12762     }
12763
12764     return retStatus;
12765 }
12766 #endif // WIN64EXCEPTIONS
12767
12768 // This function will reset the thread abort state agains the specified thread if it is determined that
12769 // there is no more managed code on the stack.
12770 //
12771 // Note: This function should be invoked ONLY during unwind.
12772 #ifndef WIN64EXCEPTIONS
12773 void ResetThreadAbortState(PTR_Thread pThread, void *pEstablisherFrame)
12774 #else
12775 void ResetThreadAbortState(PTR_Thread pThread, CrawlFrame *pCf, StackFrame sfCurrentStackFrame)
12776 #endif
12777 {
12778     CONTRACTL
12779     {
12780         NOTHROW;
12781         GC_NOTRIGGER;
12782         MODE_ANY;
12783         PRECONDITION(pThread != NULL);
12784 #ifndef WIN64EXCEPTIONS
12785         PRECONDITION(pEstablisherFrame != NULL);
12786 #else
12787         PRECONDITION(pCf != NULL);
12788         PRECONDITION(!sfCurrentStackFrame.IsNull());
12789 #endif
12790     }
12791     CONTRACTL_END;
12792
12793     BOOL fResetThreadAbortState = FALSE;
12794
12795     if (pThread->IsAbortRequested())
12796     {
12797 #ifndef WIN64EXCEPTIONS
12798         if (GetNextCOMPlusSEHRecord(static_cast<EXCEPTION_REGISTRATION_RECORD *>(pEstablisherFrame)) == EXCEPTION_CHAIN_END)
12799         {
12800             // Topmost handler and abort requested.
12801             fResetThreadAbortState = TRUE;
12802             LOG((LF_EH, LL_INFO100, "ResetThreadAbortState: Topmost handler resets abort as no more managed code beyond %p.\n", pEstablisherFrame));
12803         }
12804 #else // !WIN64EXCEPTIONS
12805         // Get the active exception tracker
12806         PTR_ExceptionTracker pCurEHTracker = pThread->GetExceptionState()->GetCurrentExceptionTracker();
12807         _ASSERTE(pCurEHTracker != NULL);
12808
12809         // We will check if thread abort state needs to be reset only for the case of exception caught in
12810         // native code. This will happen when:
12811         //
12812         // 1) an unwind is triggered and
12813         // 2) current frame is the topmost frame we saw in the first pass and
12814         // 3) a thread abort is requested and
12815         // 4) we dont have address of the exception handler to be invoked.
12816         //
12817         // (1), (2) and (4) above are checked for in ExceptionTracker::ProcessOSExceptionNotification from where we call this
12818         // function.
12819
12820         // Current frame should be the topmost frame we saw in the first pass
12821         _ASSERTE(pCurEHTracker->GetTopmostStackFrameFromFirstPass() == sfCurrentStackFrame);
12822
12823         // If the exception has been caught in native code, then alongwith not having address of the handler to be
12824         // invoked, we also wont have the IL clause for the catch block and resume stack frame will be NULL as well.
12825         _ASSERTE((pCurEHTracker->GetCatchToCallPC() == NULL) &&
12826             (pCurEHTracker->GetCatchHandlerExceptionClauseToken() == NULL) &&
12827                  (pCurEHTracker->GetResumeStackFrame().IsNull()));
12828
12829         // Walk the frame chain to see if there is any more managed code on the stack. If not, then this is the last managed frame
12830         // on the stack and we can reset the thread abort state.
12831         //
12832         // Get the frame from which to start the stack walk from
12833         Frame*  pFrame = pCurEHTracker->GetLimitFrame();
12834
12835         // At this point, we are at the topmost frame we saw during the first pass
12836         // before the unwind began. Walk the stack using the specified crawlframe and the topmost
12837         // explicit frame to determine if we have more managed code up the stack. If none is found,
12838         // we can reset the thread abort state.
12839
12840         // Setup the data structure to be passed to the callback
12841         TAResetStateCallbackData dataCallback;
12842         dataCallback.fDoWeHaveMoreManagedCodeOnStack = FALSE;
12843
12844         // At this point, the StackFrame in CrawlFrame should represent the current frame we have been called for.
12845         // _ASSERTE(sfCurrentStackFrame == StackFrame::FromRegDisplay(pCf->GetRegisterSet()));
12846
12847         // Reference to the StackFrame beyond which we are looking for managed code.
12848         dataCallback.sfSeedCrawlFrame = sfCurrentStackFrame;
12849
12850         pThread->StackWalkFramesEx(pCf->GetRegisterSet(), TAResetStateCallback, &dataCallback, QUICKUNWIND, pFrame);
12851
12852         if (!dataCallback.fDoWeHaveMoreManagedCodeOnStack)
12853         {
12854             // There is no more managed code on the stack, so reset the thread abort state.
12855             fResetThreadAbortState = TRUE;
12856             LOG((LF_EH, LL_INFO100, "ResetThreadAbortState: Resetting thread abort state since there is no more managed code beyond stack frames:\n"));
12857             LOG((LF_EH, LL_INFO100, "sf.SP = %p   ", dataCallback.sfSeedCrawlFrame.SP));
12858         }
12859 #endif // !WIN64EXCEPTIONS
12860     }
12861
12862     if (fResetThreadAbortState)
12863     {
12864         pThread->EEResetAbort(Thread::TAR_Thread);
12865     }
12866 }
12867 #endif // !DACCESS_COMPILE
12868
12869 #endif // !CROSSGEN_COMPILE
12870
12871 //---------------------------------------------------------------------------------
12872 //
12873 //
12874 // EXCEPTION THROWING HELPERS
12875 //
12876 //
12877 //---------------------------------------------------------------------------------
12878
12879 //---------------------------------------------------------------------------------
12880 // Funnel-worker for THROW_BAD_FORMAT and friends.
12881 //
12882 // Note: The "cond" argument is there to tide us over during the transition from
12883 //  BAD_FORMAT_ASSERT to THROW_BAD_FORMAT. It will go away soon.
12884 //---------------------------------------------------------------------------------
12885 VOID ThrowBadFormatWorker(UINT resID, LPCWSTR imageName DEBUGARG(__in_z const char *cond))
12886 {
12887     CONTRACTL
12888     {
12889         THROWS;
12890         GC_TRIGGERS;
12891         INJECT_FAULT(COMPlusThrowOM(););
12892         SUPPORTS_DAC;
12893     }
12894     CONTRACTL_END
12895
12896 #ifndef DACCESS_COMPILE
12897     SString msgStr;
12898
12899     if ((imageName != NULL) && (imageName[0] != 0))
12900     {
12901         msgStr += W("[");
12902         msgStr += imageName;
12903         msgStr += W("] ");
12904     }
12905
12906     SString resStr;
12907     if (resID == 0 || !resStr.LoadResource(CCompRC::Optional, resID))
12908     {
12909         resStr.LoadResource(CCompRC::Error, MSG_FOR_URT_HR(COR_E_BADIMAGEFORMAT));
12910     }
12911     msgStr += resStr;
12912
12913 #ifdef _DEBUG
12914     if (0 != strcmp(cond, "FALSE"))
12915     {
12916         msgStr += W(" (Failed condition: "); // this is in DEBUG only - not going to localize it.
12917         SString condStr(SString::Ascii, cond);
12918         msgStr += condStr;
12919         msgStr += W(")");
12920     }
12921 #endif
12922
12923     ThrowHR(COR_E_BADIMAGEFORMAT, msgStr);
12924 #endif // #ifndef DACCESS_COMPILE
12925 }
12926
12927 UINT GetResourceIDForFileLoadExceptionHR(HRESULT hr)
12928 {
12929     switch (hr) {
12930
12931     case CTL_E_FILENOTFOUND:
12932         hr = IDS_EE_FILE_NOT_FOUND;
12933         break;
12934
12935     case (HRESULT)IDS_EE_PROC_NOT_FOUND:
12936     case (HRESULT)IDS_EE_PATH_TOO_LONG:
12937     case INET_E_OBJECT_NOT_FOUND:
12938     case INET_E_DATA_NOT_AVAILABLE:
12939     case INET_E_DOWNLOAD_FAILURE:
12940     case INET_E_UNKNOWN_PROTOCOL:
12941     case (HRESULT)IDS_INET_E_SECURITY_PROBLEM:
12942     case (HRESULT)IDS_EE_BAD_USER_PROFILE:
12943     case (HRESULT)IDS_EE_ALREADY_EXISTS:
12944     case IDS_EE_REFLECTIONONLY_LOADFAILURE:
12945     case IDS_CLASSLOAD_32BITCLRLOADING64BITASSEMBLY:
12946        break;
12947
12948     case MK_E_SYNTAX:
12949         hr = FUSION_E_INVALID_NAME;
12950         break;
12951
12952     case INET_E_CONNECTION_TIMEOUT:
12953         hr = IDS_INET_E_CONNECTION_TIMEOUT;
12954         break;
12955
12956     case INET_E_CANNOT_CONNECT:
12957         hr = IDS_INET_E_CANNOT_CONNECT;
12958         break;
12959
12960     case INET_E_RESOURCE_NOT_FOUND:
12961         hr = IDS_INET_E_RESOURCE_NOT_FOUND;
12962         break;
12963
12964     case NTE_BAD_HASH:
12965     case NTE_BAD_LEN:
12966     case NTE_BAD_KEY:
12967     case NTE_BAD_DATA:
12968     case NTE_BAD_ALGID:
12969     case NTE_BAD_FLAGS:
12970     case NTE_BAD_HASH_STATE:
12971     case NTE_BAD_UID:
12972     case NTE_FAIL:
12973     case NTE_BAD_TYPE:
12974     case NTE_BAD_VER:
12975     case NTE_BAD_SIGNATURE:
12976     case NTE_SIGNATURE_FILE_BAD:
12977     case CRYPT_E_HASH_VALUE:
12978         hr = IDS_EE_HASH_VAL_FAILED;
12979         break;
12980
12981     default:
12982         hr = IDS_EE_FILELOAD_ERROR_GENERIC;
12983         break;
12984
12985     }
12986
12987     return (UINT) hr;
12988 }
12989
12990 #ifndef DACCESS_COMPILE
12991
12992 //==========================================================================
12993 // Throw a runtime exception based on the last Win32 error (GetLastError())
12994 //==========================================================================
12995 VOID DECLSPEC_NORETURN RealCOMPlusThrowWin32()
12996 {
12997
12998 // before we do anything else...
12999     DWORD   err = ::GetLastError();
13000
13001     CONTRACTL
13002     {
13003         THROWS;
13004         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13005         MODE_ANY;
13006     }
13007     CONTRACTL_END;
13008
13009     RealCOMPlusThrowWin32(HRESULT_FROM_WIN32(err));
13010 } // VOID DECLSPEC_NORETURN RealCOMPlusThrowWin32()
13011
13012 //==========================================================================
13013 // Throw a runtime exception based on the last Win32 error (GetLastError())
13014 //==========================================================================
13015 VOID DECLSPEC_NORETURN RealCOMPlusThrowWin32(HRESULT hr)
13016 {
13017     CONTRACTL
13018     {
13019         THROWS;
13020         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13021         MODE_ANY;
13022 }
13023     CONTRACTL_END;
13024
13025     // Force to ApplicationException for compatibility with previous versions.  We would
13026     //  prefer a "Win32Exception" here.
13027     EX_THROW(EEMessageException, (kApplicationException, hr, 0 /* resid*/,
13028                                  NULL /* szArg1 */, NULL /* szArg2 */, NULL /* szArg3 */, NULL /* szArg4 */, 
13029                                  NULL /* szArg5 */, NULL /* szArg6 */));
13030 } // VOID DECLSPEC_NORETURN RealCOMPlusThrowWin32()
13031
13032
13033 //==========================================================================
13034 // Throw an OutOfMemoryError
13035 //==========================================================================
13036 VOID DECLSPEC_NORETURN RealCOMPlusThrowOM()
13037 {
13038     CONTRACTL
13039     {
13040         THROWS;
13041         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13042         CANNOT_TAKE_LOCK;
13043         MODE_ANY;
13044         SO_TOLERANT;
13045         SUPPORTS_DAC;
13046     }
13047     CONTRACTL_END;
13048
13049     ThrowOutOfMemory();
13050 }
13051
13052 //==========================================================================
13053 // Throw an undecorated runtime exception.
13054 //==========================================================================
13055 VOID DECLSPEC_NORETURN RealCOMPlusThrow(RuntimeExceptionKind reKind)
13056 {
13057     CONTRACTL
13058     {
13059         THROWS;
13060         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13061         MODE_ANY;
13062     }
13063     CONTRACTL_END;
13064
13065     _ASSERTE((reKind != kExecutionEngineException) ||
13066              !"ExecutionEngineException shouldn't be thrown. Use EEPolicy to failfast or a better exception. The caller of this function should modify their code.");
13067
13068     EX_THROW(EEException, (reKind));
13069 }
13070
13071 //==========================================================================
13072 // Throw a decorated runtime exception.
13073 // Try using RealCOMPlusThrow(reKind, wszResourceName) instead.
13074 //==========================================================================
13075 VOID DECLSPEC_NORETURN RealCOMPlusThrowNonLocalized(RuntimeExceptionKind reKind, LPCWSTR wszTag)
13076 {
13077     CONTRACTL
13078     {
13079         THROWS;
13080         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13081         MODE_ANY;
13082     }
13083     CONTRACTL_END;
13084
13085     _ASSERTE((reKind != kExecutionEngineException) ||
13086              !"ExecutionEngineException shouldn't be thrown. Use EEPolicy to failfast or a better exception. The caller of this function should modify their code.");
13087
13088     EX_THROW(EEMessageException, (reKind, IDS_EE_GENERIC, wszTag));
13089 }
13090
13091 //==========================================================================
13092 // Throw a runtime exception based on an HResult
13093 //==========================================================================
13094 VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, IErrorInfo* pErrInfo, Exception * pInnerException)
13095 {
13096     CONTRACTL
13097     {
13098         THROWS;
13099         GC_TRIGGERS;        // because of IErrorInfo
13100         MODE_ANY;
13101     }
13102     CONTRACTL_END;
13103
13104     _ASSERTE (FAILED(hr));
13105
13106     // Though we would like to assert this, it can happen in the following scenario:
13107     //
13108     // MgdCode --RCW-> COM --CCW-> MgdCode2
13109     //
13110     // If MgdCode2 throws EEE, when it reaches the RCW, it will invoking MarshalNative::ThrowExceptionForHr and thus,
13111     // reach here. Hence, we will need to keep the assert off, until user code is stopped for creating an EEE.
13112
13113     //_ASSERTE((hr != COR_E_EXECUTIONENGINE) ||
13114     //         !"ExecutionEngineException shouldn't be thrown. Use EEPolicy to failfast or a better exception. The caller of this function should modify their code.");
13115
13116 #ifndef CROSSGEN_COMPILE
13117 #ifdef FEATURE_COMINTEROP
13118     // check for complus created IErrorInfo pointers
13119     if (pErrInfo != NULL)
13120     {
13121         GCX_COOP();
13122         {
13123             OBJECTREF oRetVal = NULL;
13124             GCPROTECT_BEGIN(oRetVal);
13125             GetExceptionForHR(hr, pErrInfo, &oRetVal);
13126             _ASSERTE(oRetVal != NULL);
13127             RealCOMPlusThrow(oRetVal);
13128             GCPROTECT_END ();
13129         }
13130     }
13131 #endif // FEATURE_COMINTEROP
13132
13133     if (pErrInfo != NULL)
13134     {
13135         if (pInnerException == NULL)
13136         {
13137             EX_THROW(EECOMException, (hr, pErrInfo, true, NULL, FALSE));
13138         }
13139         else
13140         {
13141             EX_THROW_WITH_INNER(EECOMException, (hr, pErrInfo, true, NULL, FALSE), pInnerException);
13142         }
13143     }
13144     else
13145 #endif // CROSSGEN_COMPILE
13146     {
13147         if (pInnerException == NULL)
13148         {
13149             EX_THROW(EEMessageException, (hr));
13150         }
13151         else
13152         {
13153             EX_THROW_WITH_INNER(EEMessageException, (hr), pInnerException);
13154         }
13155     }
13156 }
13157
13158 VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr)
13159 {
13160     CONTRACTL
13161     {
13162         THROWS;
13163         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13164         MODE_ANY;
13165     }
13166     CONTRACTL_END;
13167
13168
13169     // ! COMPlusThrowHR(hr) no longer snags the IErrorInfo off the TLS (Too many places
13170     // ! call this routine where no IErrorInfo was set by the prior call.)
13171     // !
13172     // ! If you actually want to pull IErrorInfo off the TLS, call
13173     // !
13174     // ! COMPlusThrowHR(hr, kGetErrorInfo)
13175
13176     RealCOMPlusThrowHR(hr, (IErrorInfo*)NULL);
13177 }
13178
13179
13180 VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, tagGetErrorInfo)
13181 {
13182     CONTRACTL
13183     {
13184         THROWS;
13185         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13186         MODE_ANY;
13187     }
13188     CONTRACTL_END;
13189
13190     // Get an IErrorInfo if one is available.
13191     IErrorInfo *pErrInfo = NULL;
13192
13193 #ifndef CROSSGEN_COMPILE
13194     if (SafeGetErrorInfo(&pErrInfo) != S_OK)
13195         pErrInfo = NULL;
13196 #endif
13197
13198     // Throw the exception.
13199     RealCOMPlusThrowHR(hr, pErrInfo);
13200 }
13201
13202
13203
13204 VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, UINT resID, LPCWSTR wszArg1,
13205                                           LPCWSTR wszArg2, LPCWSTR wszArg3, LPCWSTR wszArg4,
13206                                           LPCWSTR wszArg5, LPCWSTR wszArg6)
13207 {
13208     CONTRACTL
13209     {
13210         THROWS;
13211         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13212         MODE_ANY;
13213     }
13214     CONTRACTL_END;
13215
13216     _ASSERTE (FAILED(hr));
13217
13218     // Though we would like to assert this, it can happen in the following scenario:
13219     //
13220     // MgdCode --RCW-> COM --CCW-> MgdCode2
13221     //
13222     // If MgdCode2 throws EEE, when it reaches the RCW, it will invoking MarshalNative::ThrowExceptionForHr and thus,
13223     // reach here. Hence, we will need to keep the assert off, until user code is stopped for creating an EEE.
13224
13225     //_ASSERTE((hr != COR_E_EXECUTIONENGINE) ||
13226     //         !"ExecutionEngineException shouldn't be thrown. Use EEPolicy to failfast or a better exception. The caller of this function should modify their code.");
13227
13228     EX_THROW(EEMessageException,
13229         (hr, resID, wszArg1, wszArg2, wszArg3, wszArg4, wszArg5, wszArg6));
13230 }
13231
13232 //==========================================================================
13233 // Throw a decorated runtime exception with a localized message.
13234 // Queries the ResourceManager for a corresponding resource value.
13235 //==========================================================================
13236 VOID DECLSPEC_NORETURN RealCOMPlusThrow(RuntimeExceptionKind reKind, LPCWSTR wszResourceName, Exception * pInnerException)
13237 {
13238     CONTRACTL
13239     {
13240         THROWS;
13241         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13242         MODE_ANY;
13243         PRECONDITION(CheckPointer(wszResourceName));
13244     }
13245     CONTRACTL_END;
13246
13247     _ASSERTE((reKind != kExecutionEngineException) ||
13248              !"ExecutionEngineException shouldn't be thrown. Use EEPolicy to failfast or a better exception. The caller of this function should modify their code.");
13249     //
13250     // For some reason, the compiler complains about unreachable code if
13251     // we don't split the new from the throw.  So we're left with this
13252     // unnecessarily verbose syntax.
13253     //
13254
13255     if (pInnerException == NULL)
13256     {
13257         EX_THROW(EEResourceException, (reKind, wszResourceName));
13258     }
13259     else
13260     {
13261         EX_THROW_WITH_INNER(EEResourceException, (reKind, wszResourceName), pInnerException);
13262     }
13263 }
13264
13265 //==========================================================================
13266 // Used by the classloader to record a managed exception object to explain
13267 // why a classload got botched.
13268 //
13269 // - Can be called with gc enabled or disabled.
13270 //   This allows a catch-all error path to post a generic catchall error
13271 //   message w/out bonking more specific error messages posted by inner functions.
13272 //==========================================================================
13273 VOID DECLSPEC_NORETURN ThrowTypeLoadException(LPCWSTR pFullTypeName,
13274                                               LPCWSTR pAssemblyName,
13275                                               LPCUTF8 pMessageArg,
13276                                               UINT resIDWhy)
13277 {
13278     CONTRACTL
13279     {
13280         THROWS;
13281         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13282         MODE_ANY;
13283     }
13284     CONTRACTL_END;
13285
13286     EX_THROW(EETypeLoadException, (pFullTypeName, pAssemblyName, pMessageArg, resIDWhy));
13287 }
13288
13289
13290 //==========================================================================
13291 // Used by the classloader to post illegal layout
13292 //==========================================================================
13293 VOID DECLSPEC_NORETURN ThrowFieldLayoutError(mdTypeDef cl,                // cl of the NStruct being loaded
13294                            Module* pModule,             // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
13295                            DWORD   dwOffset,            // Offset of field
13296                            DWORD   dwID)                // Message id
13297 {
13298     CONTRACTL
13299     {
13300         THROWS;
13301         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13302         MODE_ANY;
13303     }
13304     CONTRACTL_END;
13305
13306     IMDInternalImport *pInternalImport = pModule->GetMDImport();    // Internal interface for the NStruct being loaded.
13307
13308     LPCUTF8 pszName, pszNamespace;
13309     if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &pszName, &pszNamespace)))
13310     {
13311         pszName = pszNamespace = "Invalid TypeDef record";
13312     }
13313
13314     CHAR offsetBuf[16];
13315     sprintf_s(offsetBuf, COUNTOF(offsetBuf), "%d", dwOffset);
13316     offsetBuf[COUNTOF(offsetBuf) - 1] = '\0';
13317
13318     pModule->GetAssembly()->ThrowTypeLoadException(pszNamespace,
13319                                                    pszName,
13320                                                    offsetBuf,
13321                                                    dwID);
13322 }
13323
13324 //==========================================================================
13325 // Throw an ArithmeticException
13326 //==========================================================================
13327 VOID DECLSPEC_NORETURN RealCOMPlusThrowArithmetic()
13328 {
13329     CONTRACTL
13330     {
13331         THROWS;
13332         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13333         MODE_ANY;
13334     }
13335     CONTRACTL_END;
13336
13337     RealCOMPlusThrow(kArithmeticException);
13338 }
13339
13340 //==========================================================================
13341 // Throw an ArgumentNullException
13342 //==========================================================================
13343 VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentNull(LPCWSTR argName, LPCWSTR wszResourceName)
13344 {
13345     CONTRACTL
13346     {
13347         THROWS;
13348         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13349         MODE_ANY;
13350         PRECONDITION(CheckPointer(wszResourceName));
13351     }
13352     CONTRACTL_END;
13353
13354     EX_THROW(EEArgumentException, (kArgumentNullException, argName, wszResourceName));
13355 }
13356
13357
13358 VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentNull(LPCWSTR argName)
13359 {
13360     CONTRACTL
13361     {
13362         THROWS;
13363         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13364         MODE_ANY;
13365     }
13366     CONTRACTL_END;
13367
13368     EX_THROW(EEArgumentException, (kArgumentNullException, argName, W("ArgumentNull_Generic")));
13369 }
13370
13371
13372 //==========================================================================
13373 // Throw an ArgumentOutOfRangeException
13374 //==========================================================================
13375 VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentOutOfRange(LPCWSTR argName, LPCWSTR wszResourceName)
13376 {
13377     CONTRACTL
13378     {
13379         THROWS;
13380         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13381         MODE_ANY;
13382     }
13383     CONTRACTL_END;
13384
13385     EX_THROW(EEArgumentException, (kArgumentOutOfRangeException, argName, wszResourceName));
13386 }
13387
13388 //==========================================================================
13389 // Throw an ArgumentException
13390 //==========================================================================
13391 VOID DECLSPEC_NORETURN RealCOMPlusThrowArgumentException(LPCWSTR argName, LPCWSTR wszResourceName)
13392 {
13393     CONTRACTL
13394     {
13395         THROWS;
13396         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13397         MODE_ANY;
13398     }
13399     CONTRACTL_END;
13400
13401     EX_THROW(EEArgumentException, (kArgumentException, argName, wszResourceName));
13402 }
13403
13404 //=========================================================================
13405 // Used by the classloader to record a managed exception object to explain
13406 // why a classload got botched.
13407 //
13408 // - Can be called with gc enabled or disabled.
13409 //   This allows a catch-all error path to post a generic catchall error
13410 //   message w/out bonking more specific error messages posted by inner functions.
13411 //==========================================================================
13412 VOID DECLSPEC_NORETURN ThrowTypeLoadException(LPCUTF8 pszNameSpace,
13413                                               LPCUTF8 pTypeName,
13414                                               LPCWSTR pAssemblyName,
13415                                               LPCUTF8 pMessageArg,
13416                                               UINT resIDWhy)
13417 {
13418     CONTRACTL
13419     {
13420         THROWS;
13421         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13422         MODE_ANY;
13423     }
13424     CONTRACTL_END;
13425
13426     EX_THROW(EETypeLoadException, (pszNameSpace, pTypeName, pAssemblyName, pMessageArg, resIDWhy));
13427 }
13428
13429 //==========================================================================
13430 // Throw a decorated runtime exception.
13431 //==========================================================================
13432 VOID DECLSPEC_NORETURN RealCOMPlusThrow(RuntimeExceptionKind  reKind, UINT resID, 
13433                                         LPCWSTR wszArg1, LPCWSTR wszArg2, LPCWSTR wszArg3, 
13434                                         LPCWSTR wszArg4, LPCWSTR wszArg5, LPCWSTR wszArg6)
13435 {
13436     CONTRACTL
13437     {
13438         THROWS;
13439         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13440         MODE_ANY;
13441     }
13442     CONTRACTL_END;
13443
13444     EX_THROW(EEMessageException,
13445         (reKind, resID, wszArg1, wszArg2, wszArg3, wszArg4, wszArg5, wszArg6));
13446 }
13447
13448 #ifdef FEATURE_COMINTEROP
13449 #ifndef CROSSGEN_COMPILE
13450 //==========================================================================
13451 // Throw a runtime exception based on an HResult, check for error info
13452 //==========================================================================
13453 VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr, IUnknown *iface, REFIID riid)
13454 {
13455     CONTRACTL
13456     {
13457         THROWS;
13458         GC_TRIGGERS;         // because of IErrorInfo
13459         MODE_ANY;
13460     }
13461     CONTRACTL_END;
13462
13463     IErrorInfo *info = NULL;
13464     {
13465         GCX_PREEMP();
13466         info = GetSupportedErrorInfo(iface, riid);
13467     }
13468     RealCOMPlusThrowHR(hr, info);
13469 }
13470
13471 //==========================================================================
13472 // Throw a runtime exception based on an EXCEPINFO. This function will free
13473 // the strings in the EXCEPINFO that is passed in.
13474 //==========================================================================
13475 VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(EXCEPINFO *pExcepInfo)
13476 {
13477     CONTRACTL
13478     {
13479         THROWS;
13480         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13481         MODE_ANY;
13482     }
13483     CONTRACTL_END;
13484
13485     EX_THROW(EECOMException, (pExcepInfo));
13486 }
13487 #endif //CROSSGEN_COMPILE
13488
13489 #endif // FEATURE_COMINTEROP
13490
13491
13492 #ifdef FEATURE_STACK_PROBE
13493 //==========================================================================
13494 // Throw a StackOverflowError
13495 //==========================================================================
13496 VOID DECLSPEC_NORETURN RealCOMPlusThrowSO()
13497 {
13498     CONTRACTL
13499     {
13500         // This should be throws... But it isn't because a SO doesn't technically
13501         // fall into the same THROW/NOTHROW conventions as the rest of the contract
13502         // infrastructure.
13503         NOTHROW;
13504
13505         DISABLED(GC_NOTRIGGER);  // Must sanitize first pass handling to enable this
13506         SO_TOLERANT;
13507         MODE_ANY;
13508     }
13509     CONTRACTL_END;
13510
13511     // We only use BreakOnSO if we are in debug mode, so we'll only checking if the
13512     // _DEBUG flag is set.
13513 #ifdef _DEBUG
13514     static int breakOnSO = -1;
13515
13516     if (breakOnSO == -1)
13517         breakOnSO = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BreakOnSO);
13518
13519     if (breakOnSO != 0)
13520     {
13521         _ASSERTE(!"SO occurred");
13522     }
13523 #endif
13524
13525     ThrowStackOverflow();
13526 }
13527 #endif
13528
13529 //==========================================================================
13530 // Throw an InvalidCastException
13531 //==========================================================================
13532
13533
13534 VOID GetAssemblyDetailInfo(SString    &sType,
13535                            SString    &sAssemblyDisplayName,
13536                            PEAssembly *pPEAssembly,
13537                            SString    &sAssemblyDetailInfo)
13538 {
13539     WRAPPER_NO_CONTRACT;
13540
13541     InlineSString<MAX_LONGPATH> sFormat;
13542     const WCHAR *pwzLoadContext = W("Default");
13543
13544     if (pPEAssembly->GetPath().IsEmpty())
13545     {
13546         sFormat.LoadResource(CCompRC::Debugging, IDS_EE_CANNOTCAST_HELPER_BYTE);
13547
13548         sAssemblyDetailInfo.Printf(sFormat.GetUnicode(),
13549                                    sType.GetUnicode(),
13550                                    sAssemblyDisplayName.GetUnicode(),
13551                                    pwzLoadContext);
13552     }
13553     else
13554     {
13555         sFormat.LoadResource(CCompRC::Debugging, IDS_EE_CANNOTCAST_HELPER_PATH);
13556
13557         sAssemblyDetailInfo.Printf(sFormat.GetUnicode(),
13558                                    sType.GetUnicode(),
13559                                    sAssemblyDisplayName.GetUnicode(),
13560                                    pwzLoadContext,
13561                                    pPEAssembly->GetPath().GetUnicode());
13562     }
13563 }
13564
13565 VOID CheckAndThrowSameTypeAndAssemblyInvalidCastException(TypeHandle thCastFrom,
13566                                                           TypeHandle thCastTo)
13567 {
13568      CONTRACTL {
13569         THROWS;
13570         GC_TRIGGERS;
13571         MODE_COOPERATIVE;
13572         SO_INTOLERANT;
13573     } CONTRACTL_END;
13574
13575      Module *pModuleTypeFrom = thCastFrom.GetModule();
13576      Module *pModuleTypeTo = thCastTo.GetModule();
13577
13578      if ((pModuleTypeFrom != NULL) && (pModuleTypeTo != NULL))
13579      {
13580          Assembly *pAssemblyTypeFrom = pModuleTypeFrom->GetAssembly();
13581          Assembly *pAssemblyTypeTo = pModuleTypeTo->GetAssembly();
13582
13583          _ASSERTE(pAssemblyTypeFrom != NULL);
13584          _ASSERTE(pAssemblyTypeTo != NULL);
13585
13586          PEAssembly *pPEAssemblyTypeFrom = pAssemblyTypeFrom->GetManifestFile();
13587          PEAssembly *pPEAssemblyTypeTo = pAssemblyTypeTo->GetManifestFile();
13588
13589          _ASSERTE(pPEAssemblyTypeFrom != NULL);
13590          _ASSERTE(pPEAssemblyTypeTo != NULL);
13591
13592          InlineSString<MAX_LONGPATH> sAssemblyFromDisplayName;
13593          InlineSString<MAX_LONGPATH> sAssemblyToDisplayName;
13594
13595          pPEAssemblyTypeFrom->GetDisplayName(sAssemblyFromDisplayName);
13596          pPEAssemblyTypeTo->GetDisplayName(sAssemblyToDisplayName);
13597
13598          // Found the culprit case. Now format the new exception text.
13599          InlineSString<MAX_CLASSNAME_LENGTH + 1> strCastFromName;
13600          InlineSString<MAX_CLASSNAME_LENGTH + 1> strCastToName;
13601          InlineSString<MAX_LONGPATH> sAssemblyDetailInfoFrom;
13602          InlineSString<MAX_LONGPATH> sAssemblyDetailInfoTo;
13603
13604          thCastFrom.GetName(strCastFromName);
13605          thCastTo.GetName(strCastToName);
13606
13607          SString typeA = SL(W("A"));
13608          GetAssemblyDetailInfo(typeA,
13609                                sAssemblyFromDisplayName,
13610                                pPEAssemblyTypeFrom,
13611                                sAssemblyDetailInfoFrom);
13612          SString typeB = SL(W("B"));
13613          GetAssemblyDetailInfo(typeB,
13614                                sAssemblyToDisplayName,
13615                                pPEAssemblyTypeTo,
13616                                sAssemblyDetailInfoTo);
13617
13618          COMPlusThrow(kInvalidCastException,
13619                       IDS_EE_CANNOTCASTSAME,
13620                       strCastFromName.GetUnicode(),
13621                       strCastToName.GetUnicode(),
13622                       sAssemblyDetailInfoFrom.GetUnicode(),
13623                       sAssemblyDetailInfoTo.GetUnicode());
13624      }
13625 }
13626
13627 VOID RealCOMPlusThrowInvalidCastException(TypeHandle thCastFrom, TypeHandle thCastTo)
13628 {
13629      CONTRACTL {
13630         THROWS;
13631         GC_TRIGGERS;
13632         MODE_COOPERATIVE;
13633     } CONTRACTL_END;
13634
13635     // Use an InlineSString with a size of MAX_CLASSNAME_LENGTH + 1 to prevent
13636     // TypeHandle::GetName from having to allocate a new block of memory. This
13637     // significantly improves the performance of throwing an InvalidCastException.
13638     InlineSString<MAX_CLASSNAME_LENGTH + 1> strCastFromName;
13639     InlineSString<MAX_CLASSNAME_LENGTH + 1> strCastToName;
13640
13641     thCastTo.GetName(strCastToName);
13642     {
13643         thCastFrom.GetName(strCastFromName);
13644         // Attempt to catch the A.T != A.T case that causes so much user confusion.
13645         if (strCastFromName.Equals(strCastToName))
13646         {
13647             CheckAndThrowSameTypeAndAssemblyInvalidCastException(thCastFrom, thCastTo);
13648         }
13649          COMPlusThrow(kInvalidCastException, IDS_EE_CANNOTCAST, strCastFromName.GetUnicode(), strCastToName.GetUnicode());
13650     }
13651 }
13652
13653 #ifndef CROSSGEN_COMPILE
13654 VOID RealCOMPlusThrowInvalidCastException(OBJECTREF *pObj, TypeHandle thCastTo)
13655 {
13656      CONTRACTL {
13657         THROWS;
13658         GC_TRIGGERS;
13659         MODE_COOPERATIVE;
13660         PRECONDITION(IsProtectedByGCFrame (pObj));
13661     } CONTRACTL_END;
13662
13663     TypeHandle thCastFrom = (*pObj)->GetTypeHandle();
13664 #ifdef FEATURE_COMINTEROP
13665     if (thCastFrom.GetMethodTable()->IsComObjectType())
13666     {
13667         // Special case casting RCWs so we can give better error information when the
13668         // cast fails. 
13669         ComObject::ThrowInvalidCastException(pObj, thCastTo.GetMethodTable());
13670     }
13671 #endif
13672     COMPlusThrowInvalidCastException(thCastFrom, thCastTo);
13673 }
13674 #endif // CROSSGEN_COMPILE
13675
13676 #endif // DACCESS_COMPILE
13677
13678 #ifndef CROSSGEN_COMPILE // ???
13679 #ifdef FEATURE_COMINTEROP
13680 #include "comtoclrcall.h"
13681 #endif // FEATURE_COMINTEROP
13682
13683 // Reverse COM interop IL stubs need to catch all exceptions and translate them into HRESULTs.
13684 // But we allow for CSEs to be rethrown.  Our corrupting state policy gets applied to the 
13685 // original user-visible method that triggered the IL stub to be generated.  So we must be able
13686 // to map back from a given IL stub to the user-visible method.  Here, we do that only when we
13687 // see a 'matching' ComMethodFrame further up the stack.
13688 MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDesc * pILStubMD, Frame ** ppFrameOut)
13689 {
13690     CONTRACTL
13691     {
13692         NOTHROW;
13693         GC_NOTRIGGER;
13694         MODE_ANY;
13695         PRECONDITION(pILStubMD->IsILStub());
13696     }
13697     CONTRACTL_END;
13698
13699     MethodDesc * pUserMD = pILStubMD;
13700 #ifdef FEATURE_COMINTEROP
13701     DynamicMethodDesc * pDMD = pILStubMD->AsDynamicMethodDesc();
13702     if (pDMD->IsCOMToCLRStub())
13703     {
13704         // There are some differences across architectures for "which" SP is passed in.
13705         // On ARM, the SP is the SP on entry to the IL stub, on the other arches, it's
13706         // a post-prolog SP.  But this doesn't matter here because the COM->CLR path 
13707         // always pushes the Frame in a caller's stack frame.
13708
13709         Frame * pCurFrame = pThread->GetFrame();
13710         while ((UINT_PTR)pCurFrame < uStubSP)
13711         {
13712             pCurFrame = pCurFrame->PtrNextFrame();
13713         }
13714
13715         // The construction of the COM->CLR path ensures that our corresponding ComMethodFrame
13716         // should be present further up the stack. Normally, the ComMethodFrame in question is
13717         // simply the next stack frame; however, there are situations where there may be other
13718         // stack frames present (such as an optional ContextTransitionFrame if we switched
13719         // AppDomains, or an inlined stack frame from a QCall in the IL stub).
13720         while (pCurFrame->GetVTablePtr() != ComMethodFrame::GetMethodFrameVPtr())
13721         {
13722             pCurFrame = pCurFrame->PtrNextFrame();
13723         }
13724
13725         ComMethodFrame * pComFrame = (ComMethodFrame *)pCurFrame;
13726         _ASSERTE((UINT_PTR)pComFrame > uStubSP);
13727
13728         CONSISTENCY_CHECK_MSG(pComFrame->GetVTablePtr() == ComMethodFrame::GetMethodFrameVPtr(),
13729                               "Expected to find a ComMethodFrame.");
13730
13731         ComCallMethodDesc * pCMD = pComFrame->GetComCallMethodDesc();
13732
13733         CONSISTENCY_CHECK_MSG(pILStubMD == ExecutionManager::GetCodeMethodDesc(pCMD->GetILStub()), 
13734                               "The ComMethodFrame that we found doesn't match the IL stub passed in.");
13735
13736         pUserMD = pCMD->GetMethodDesc();
13737         *ppFrameOut = pComFrame;
13738     }
13739 #endif // FEATURE_COMINTEROP
13740     return pUserMD;
13741 }
13742 #endif //CROSSGEN_COMPILE