Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / vm / i386 / excepx86.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 #include "common.h"
12
13 #include "frames.h"
14 #include "excep.h"
15 #include "object.h"
16 #include "field.h"
17 #include "dbginterface.h"
18 #include "cgensys.h"
19 #include "comutilnative.h"
20 #include "sigformat.h"
21 #include "siginfo.hpp"
22 #include "gcheaputilities.h"
23 #include "eedbginterfaceimpl.h" //so we can clearexception in COMPlusThrow
24 #include "perfcounters.h"
25 #include "eventtrace.h"
26 #include "eetoprofinterfacewrapper.inl"
27 #include "eedbginterfaceimpl.inl"
28 #include "dllimportcallback.h"
29 #include "threads.h"
30 #ifdef FEATURE_REMOTING
31 #include "appdomainhelper.h"
32 #endif
33 #include "eeconfig.h"
34 #include "vars.hpp"
35 #include "generics.h"
36
37 #include "asmconstants.h"
38 #include "virtualcallstub.h"
39
40 #ifndef WIN64EXCEPTIONS
41 MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDesc * pILStubMD, Frame ** ppFrameOut);
42
43 #if !defined(DACCESS_COMPILE)
44
45 #define FORMAT_MESSAGE_BUFFER_LENGTH 1024
46
47 BOOL ComPlusFrameSEH(EXCEPTION_REGISTRATION_RECORD*);
48 PEXCEPTION_REGISTRATION_RECORD GetPrevSEHRecord(EXCEPTION_REGISTRATION_RECORD*);
49
50 extern "C" {
51 // in asmhelpers.asm:
52 VOID STDCALL ResumeAtJitEHHelper(EHContext *pContext);
53 int STDCALL CallJitEHFilterHelper(size_t *pShadowSP, EHContext *pContext);
54 VOID STDCALL CallJitEHFinallyHelper(size_t *pShadowSP, EHContext *pContext);
55
56 typedef void (*RtlUnwindCallbackType)(void);
57
58 BOOL CallRtlUnwind(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
59            RtlUnwindCallbackType callback,
60            EXCEPTION_RECORD *pExceptionRecord,
61            void *retval);
62
63 BOOL CallRtlUnwindSafe(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
64            RtlUnwindCallbackType callback,
65            EXCEPTION_RECORD *pExceptionRecord,
66            void *retval);
67 }
68
69 static inline BOOL
70 CPFH_ShouldUnwindStack(const EXCEPTION_RECORD * pCER) {
71
72     LIMITED_METHOD_CONTRACT;
73
74     _ASSERTE(pCER != NULL);
75
76     // We can only unwind those exceptions whose context/record we don't need for a
77     // rethrow.  This is complus, and stack overflow.  For all the others, we
78     // need to keep the context around for a rethrow, which means they can't
79     // be unwound.
80     if (IsComPlusException(pCER) || pCER->ExceptionCode == STATUS_STACK_OVERFLOW)
81         return TRUE;
82     else
83         return FALSE;
84 }
85
86 static inline BOOL IsComPlusNestedExceptionRecord(EXCEPTION_REGISTRATION_RECORD* pEHR)
87 {
88     LIMITED_METHOD_CONTRACT;
89     if (pEHR->Handler == (PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler)
90         return TRUE;
91     return FALSE;
92 }
93
94 EXCEPTION_REGISTRATION_RECORD *TryFindNestedEstablisherFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame)
95 {
96     LIMITED_METHOD_CONTRACT;
97     while (pEstablisherFrame->Handler != (PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler) {
98         pEstablisherFrame = pEstablisherFrame->Next;
99         if (pEstablisherFrame == EXCEPTION_CHAIN_END) return 0;
100     }
101     return pEstablisherFrame;
102 }
103
104 #ifdef _DEBUG
105 // stores last handler we went to in case we didn't get an endcatch and stack is
106 // corrupted we can figure out who did it.
107 static MethodDesc *gLastResumedExceptionFunc = NULL;
108 static DWORD gLastResumedExceptionHandler = 0;
109 #endif
110
111 //---------------------------------------------------------------------
112 //  void RtlUnwindCallback()
113 // call back function after global unwind, rtlunwind calls this function
114 //---------------------------------------------------------------------
115 static void RtlUnwindCallback()
116 {
117     LIMITED_METHOD_CONTRACT;
118     _ASSERTE(!"Should never get here");
119 }
120
121 BOOL NExportSEH(EXCEPTION_REGISTRATION_RECORD* pEHR)
122 {
123     LIMITED_METHOD_CONTRACT;
124
125     if ((LPVOID)pEHR->Handler == (LPVOID)UMThunkPrestubHandler)
126     {
127         return TRUE;
128     }
129     return FALSE;
130 }
131
132 BOOL FastNExportSEH(EXCEPTION_REGISTRATION_RECORD* pEHR)
133 {
134     LIMITED_METHOD_CONTRACT;
135
136     if ((LPVOID)pEHR->Handler == (LPVOID)FastNExportExceptHandler)
137         return TRUE;
138     return FALSE;
139 }
140
141 BOOL ReverseCOMSEH(EXCEPTION_REGISTRATION_RECORD* pEHR)
142 {
143     LIMITED_METHOD_CONTRACT;
144
145 #ifdef FEATURE_COMINTEROP
146     if ((LPVOID)pEHR->Handler == (LPVOID)COMPlusFrameHandlerRevCom)
147         return TRUE;
148 #endif // FEATURE_COMINTEROP
149     return FALSE;
150 }
151
152
153 //
154 // Returns true if the given SEH handler is one of our SEH handlers that is responsible for managing exceptions in
155 // regions of managed code.
156 //
157 BOOL IsUnmanagedToManagedSEHHandler(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame)
158 {
159     WRAPPER_NO_CONTRACT;
160
161     //
162     // ComPlusFrameSEH() is for COMPlusFrameHandler & COMPlusNestedExceptionHandler.
163     // FastNExportSEH() is for FastNExportExceptHandler.
164     // NExportSEH() is for UMThunkPrestubHandler.
165     //
166     return (ComPlusFrameSEH(pEstablisherFrame) || FastNExportSEH(pEstablisherFrame) || NExportSEH(pEstablisherFrame) || ReverseCOMSEH(pEstablisherFrame));
167 }
168
169 Frame *GetCurrFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame)
170 {
171     Frame *pFrame;
172     WRAPPER_NO_CONTRACT;
173     _ASSERTE(IsUnmanagedToManagedSEHHandler(pEstablisherFrame));
174     if (NExportSEH(pEstablisherFrame))
175         pFrame = ((ComToManagedExRecord *)pEstablisherFrame)->GetCurrFrame();
176     else
177         pFrame = ((FrameHandlerExRecord *)pEstablisherFrame)->GetCurrFrame();
178
179     _ASSERTE(GetThread() == NULL || GetThread()->GetFrame() <= pFrame);
180
181     return pFrame;
182 }
183
184 EXCEPTION_REGISTRATION_RECORD* GetNextCOMPlusSEHRecord(EXCEPTION_REGISTRATION_RECORD* pRec) {
185     WRAPPER_NO_CONTRACT;
186     if (pRec == EXCEPTION_CHAIN_END)
187         return EXCEPTION_CHAIN_END;
188
189     do {
190         _ASSERTE(pRec != 0);
191         pRec = pRec->Next;
192     } while (pRec != EXCEPTION_CHAIN_END && !IsUnmanagedToManagedSEHHandler(pRec));
193
194     _ASSERTE(pRec == EXCEPTION_CHAIN_END || IsUnmanagedToManagedSEHHandler(pRec));
195     return pRec;
196 }
197
198
199 /*
200  * GetClrSEHRecordServicingStackPointer
201  *
202  * This function searchs all the Frame SEH records, and finds the one that is
203  * currently signed up to do all exception handling for the given stack pointer
204  * on the given thread.
205  *
206  * Parameters:
207  *   pThread - The thread to search on.
208  *   pStackPointer - The stack location that we are finding the Frame SEH Record for.
209  *
210  * Returns
211  *   A pointer to the SEH record, or EXCEPTION_CHAIN_END if none was found.
212  *
213  */
214
215 PEXCEPTION_REGISTRATION_RECORD
216 GetClrSEHRecordServicingStackPointer(Thread *pThread,
217                                      void *pStackPointer)
218 {
219     ThreadExceptionState* pExState = pThread->GetExceptionState();
220
221     //
222     // We can only do this if there is a context in the pExInfo. There are cases (most notably the
223     // EEPolicy::HandleFatalError case) where we don't have that.  In these cases we will return
224     // no enclosing handler since we cannot accurately determine the FS:0 entry which services
225     // this stack address.
226     //
227     // The side effect of this is that for these cases, the debugger cannot intercept
228     // the exception
229     //
230     CONTEXT* pContextRecord = pExState->GetContextRecord();
231     if (pContextRecord == NULL)
232     {
233         return EXCEPTION_CHAIN_END;
234     }
235
236     void *exceptionSP = dac_cast<PTR_VOID>(GetSP(pContextRecord));
237
238
239     //
240     // Now set the establishing frame.  What this means in English is that we need to find
241     // the fs:0 entry that handles exceptions for the place on the stack given in stackPointer.
242     //
243     PEXCEPTION_REGISTRATION_RECORD pSEHRecord = GetFirstCOMPlusSEHRecord(pThread);
244
245     while (pSEHRecord != EXCEPTION_CHAIN_END)
246     {
247
248         //
249         // Skip any SEHRecord which is not a CLR record or was pushed after the exception
250         // on this thread occurred.
251         //
252         if (IsUnmanagedToManagedSEHHandler(pSEHRecord) && (exceptionSP <= (void *)pSEHRecord))
253         {
254             Frame *pFrame = GetCurrFrame(pSEHRecord);
255             //
256             // Arcane knowledge here.  All Frame records are stored on the stack by the runtime
257             // in ever decreasing address space.  So, we merely have to search back until
258             // we find the first frame record with a higher stack value to find the
259             // establishing frame for the given stack address.
260             //
261             if (((void *)pFrame) >= pStackPointer)
262             {
263                 break;
264             }
265
266         }
267
268         pSEHRecord = GetNextCOMPlusSEHRecord(pSEHRecord);
269     }
270
271     return pSEHRecord;
272 }
273
274 #ifdef _DEBUG
275 // We've deteremined during a stack walk that managed code is transitioning to unamanaged (EE) code. Check that the
276 // state of the EH chain is correct.
277 //
278 // For x86, check that we do INSTALL_COMPLUS_EXCEPTION_HANDLER before calling managed code.  This check should be
279 // done for all managed code sites, not just transistions. But this will catch most problem cases.
280 void VerifyValidTransitionFromManagedCode(Thread *pThread, CrawlFrame *pCF)
281 {
282     WRAPPER_NO_CONTRACT;
283
284     _ASSERTE(ExecutionManager::IsManagedCode(GetControlPC(pCF->GetRegisterSet())));
285
286     // Cannot get to the TEB of other threads. So ignore them.
287     if (pThread != GetThread())
288     {
289         return;
290     }
291
292     // Find the EH record guarding the current region of managed code, based on the CrawlFrame passed in.
293     PEXCEPTION_REGISTRATION_RECORD pEHR = GetCurrentSEHRecord();
294
295     while ((pEHR != EXCEPTION_CHAIN_END) && ((ULONG_PTR)pEHR < GetRegdisplaySP(pCF->GetRegisterSet())))
296     {
297         pEHR = pEHR->Next;
298     }
299
300     // VerifyValidTransitionFromManagedCode can be called before the CrawlFrame's MethodDesc is initialized.
301     // Fix that if necessary for the consistency check.
302     MethodDesc * pFunction = pCF->GetFunction();
303     if ((!IsUnmanagedToManagedSEHHandler(pEHR)) && // Will the assert fire?  If not, don't waste our time.
304         (pFunction == NULL))
305     {
306         _ASSERTE(pCF->GetRegisterSet());
307         PCODE ip = GetControlPC(pCF->GetRegisterSet());
308         pFunction = ExecutionManager::GetCodeMethodDesc(ip);
309         _ASSERTE(pFunction);
310     }
311
312     // Great, we've got the EH record that's next up the stack from the current SP (which is in managed code). That
313     // had better be a record for one of our handlers responsible for handling exceptions in managed code. If its
314     // not, then someone made it into managed code without setting up one of our EH handlers, and that's really
315     // bad.
316     CONSISTENCY_CHECK_MSGF(IsUnmanagedToManagedSEHHandler(pEHR),
317                            ("Invalid transition into managed code!\n\n"
318                             "We're walking this thread's stack and we've reached a managed frame at Esp=0x%p. "
319                             "(The method is %s::%s) "
320                             "The very next FS:0 record (0x%p) up from this point on the stack should be one of "
321                             "our 'unmanaged to managed SEH handlers', but its not... its something else, and "
322                             "that's very bad. It indicates that someone managed to call into managed code without "
323                             "setting up the proper exception handling.\n\n"
324                             "Get a good unmanaged stack trace for this thread. All FS:0 records are on the stack, "
325                             "so you can see who installed the last handler. Somewhere between that function and "
326                             "where the thread is now is where the bad transition occurred.\n\n"
327                             "A little extra info: FS:0 = 0x%p, pEHR->Handler = 0x%p\n",
328                             GetRegdisplaySP(pCF->GetRegisterSet()),
329                             pFunction ->m_pszDebugClassName,
330                             pFunction ->m_pszDebugMethodName,
331                             pEHR,
332                             GetCurrentSEHRecord(),
333                             pEHR->Handler));
334 }
335
336 #endif
337
338 //================================================================================
339
340 // There are some things that should never be true when handling an
341 // exception.  This function checks for them.  Will assert or trap
342 // if it finds an error.
343 static inline void
344 CPFH_VerifyThreadIsInValidState(Thread* pThread, DWORD exceptionCode, EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame) {
345     WRAPPER_NO_CONTRACT;
346
347     if (   exceptionCode == STATUS_BREAKPOINT
348         || exceptionCode == STATUS_SINGLE_STEP) {
349         return;
350     }
351
352 #ifdef _DEBUG
353     // check for overwriting of stack
354     CheckStackBarrier(pEstablisherFrame);
355     // trigger check for bad fs:0 chain
356     GetCurrentSEHRecord();
357 #endif
358
359     if (!g_fEEShutDown) {
360         // An exception on the GC thread, or while holding the thread store lock, will likely lock out the entire process.
361         if (::IsGCThread() || ThreadStore::HoldingThreadStore())
362         {
363             _ASSERTE(!"Exception during garbage collection or while holding thread store");
364             EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
365         }
366     }
367 }
368
369
370 #ifdef FEATURE_HIJACK
371 void
372 CPFH_AdjustContextForThreadSuspensionRace(CONTEXT *pContext, Thread *pThread)
373 {
374     WRAPPER_NO_CONTRACT;
375
376 #ifndef FEATURE_PAL
377     PCODE f_IP = GetIP(pContext);
378     if (Thread::IsAddrOfRedirectFunc((PVOID)f_IP)) {
379
380         // This is a very rare case where we tried to redirect a thread that was
381         // just about to dispatch an exception, and our update of EIP took, but
382         // the thread continued dispatching the exception.
383         //
384         // If this should happen (very rare) then we fix it up here.
385         //
386         _ASSERTE(pThread->GetSavedRedirectContext());
387         SetIP(pContext, GetIP(pThread->GetSavedRedirectContext()));
388         STRESS_LOG1(LF_EH, LL_INFO100, "CPFH_AdjustContextForThreadSuspensionRace: Case 1 setting IP = %x\n", pContext->Eip);
389     }
390
391     if (f_IP == GetEEFuncEntryPoint(THROW_CONTROL_FOR_THREAD_FUNCTION)) {
392
393         // This is a very rare case where we tried to redirect a thread that was
394         // just about to dispatch an exception, and our update of EIP took, but
395         // the thread continued dispatching the exception.
396         //
397         // If this should happen (very rare) then we fix it up here.
398         //
399         SetIP(pContext, GetIP(pThread->m_OSContext));
400         STRESS_LOG1(LF_EH, LL_INFO100, "CPFH_AdjustContextForThreadSuspensionRace: Case 2 setting IP = %x\n", pContext->Eip);
401     }
402
403 // We have another even rarer race condition:
404 // - A) On thread A, Debugger puts an int 3 in the code stream at address X
405 // - A) We hit it and the begin an exception. The eip will be X + 1 (int3 is special)
406 // - B) Meanwhile, thread B redirects A's eip to Y. (Although A is really somewhere
407 // in the kernel, it looks like it's still in user code, so it can fall under the
408 // HandledJitCase and can be redirected)
409 // - A) The OS, trying to be nice, expects we have a breakpoint exception at X+1,
410 // but does -1 on the address since it knows int3 will leave the eip +1.
411 // So the context structure it will pass to the Handler is ideally (X+1)-1 = X
412 //
413 // ** Here's the race: Since thread B redirected A, the eip is actually Y (not X+1),
414 // but the kernel still touches it up to Y-1. So there's a window between when we hit a
415 // bp and when the handler gets called that this can happen.
416 // This causes an unhandled BP (since the debugger doesn't recognize the bp at Y-1)
417 //
418 // So what to do: If we land at Y-1 (ie, if f_IP+1 is the addr of a Redirected Func),
419 // then restore the EIP back to X. This will skip the redirection.
420 // Fortunately, this only occurs in cases where it's ok
421 // to skip. The debugger will recognize the patch and handle it.
422
423     if (Thread::IsAddrOfRedirectFunc((PVOID)(f_IP + 1))) {
424         _ASSERTE(pThread->GetSavedRedirectContext());
425         SetIP(pContext, GetIP(pThread->GetSavedRedirectContext()) - 1);
426         STRESS_LOG1(LF_EH, LL_INFO100, "CPFH_AdjustContextForThreadSuspensionRace: Case 3 setting IP = %x\n", pContext->Eip);
427     }
428
429     if (f_IP + 1 == GetEEFuncEntryPoint(THROW_CONTROL_FOR_THREAD_FUNCTION)) {
430         SetIP(pContext, GetIP(pThread->m_OSContext) - 1);
431         STRESS_LOG1(LF_EH, LL_INFO100, "CPFH_AdjustContextForThreadSuspensionRace: Case 4 setting IP = %x\n", pContext->Eip);
432     }
433 #else
434     PORTABILITY_ASSERT("CPFH_AdjustContextForThreadSuspensionRace");
435 #endif
436 }
437 #endif // FEATURE_HIJACK
438
439
440
441 static inline void
442 CPFH_UpdatePerformanceCounters() {
443     WRAPPER_NO_CONTRACT;
444     COUNTER_ONLY(GetPerfCounters().m_Excep.cThrown++);
445 }
446
447
448 //******************************************************************************
449 EXCEPTION_DISPOSITION COMPlusAfterUnwind(
450         EXCEPTION_RECORD *pExceptionRecord,
451         EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
452         ThrowCallbackType& tct)
453 {
454     WRAPPER_NO_CONTRACT;
455
456     // Note: we've completed the unwind pass up to the establisher frame, and we're headed off to finish our
457     // cleanup and end up back in jitted code. Any more FS0 handlers pushed from this point on out will _not_ be
458     // unwound. We go ahead and assert right here that indeed there are no handlers below the establisher frame
459     // before we go any further.
460     _ASSERTE(pEstablisherFrame == GetCurrentSEHRecord());
461
462     Thread* pThread = GetThread();
463
464     _ASSERTE(tct.pCurrentExceptionRecord == pEstablisherFrame);
465
466     NestedHandlerExRecord nestedHandlerExRecord;
467     nestedHandlerExRecord.Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, GetCurrFrame(pEstablisherFrame));
468
469     // ... and now, put the nested record back on.
470     INSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg));
471
472     // We entered COMPlusAfterUnwind in PREEMP, but we need to be in COOP from here on out
473     GCX_COOP_NO_DTOR();
474
475     tct.bIsUnwind = TRUE;
476     tct.pProfilerNotify = NULL;
477
478     LOG((LF_EH, LL_INFO100, "COMPlusFrameHandler: unwinding\n"));
479
480     tct.bUnwindStack = CPFH_ShouldUnwindStack(pExceptionRecord);
481
482     LOG((LF_EH, LL_INFO1000, "COMPlusAfterUnwind: going to: pFunc:%#X, pStack:%#X\n",
483         tct.pFunc, tct.pStack));
484
485     // TODO: UnwindFrames ends up calling into StackWalkFrames which is SO_INTOLERANT
486     //                 as is UnwindFrames, etc... Should we make COMPlusAfterUnwind SO_INTOLERANT???
487     ANNOTATION_VIOLATION(SOToleranceViolation);
488
489     UnwindFrames(pThread, &tct);
490
491 #ifdef DEBUGGING_SUPPORTED
492     ExInfo* pExInfo = pThread->GetExceptionState()->GetCurrentExceptionTracker();
493     if (pExInfo->m_ValidInterceptionContext)
494     {
495         // By now we should have all unknown FS:[0] handlers unwinded along with the managed Frames until
496         // the interception point. We can now pop nested exception handlers and resume at interception context.
497         EHContext context = pExInfo->m_InterceptionContext;
498         pExInfo->m_InterceptionContext.Init();
499         pExInfo->m_ValidInterceptionContext = FALSE;
500
501         UnwindExceptionTrackerAndResumeInInterceptionFrame(pExInfo, &context);
502     }
503 #endif // DEBUGGING_SUPPORTED
504
505     _ASSERTE(!"Should not get here");
506     return ExceptionContinueSearch;
507 } // EXCEPTION_DISPOSITION COMPlusAfterUnwind()
508
509 #ifdef DEBUGGING_SUPPORTED
510
511 //---------------------------------------------------------------------------------------
512 //
513 // This function is called to intercept an exception and start an unwind.
514 //
515 // Arguments:
516 //    pCurrentEstablisherFrame  - the exception registration record covering the stack range 
517 //                                containing the interception point
518 //    pExceptionRecord          - EXCEPTION_RECORD of the exception being intercepted
519 //
520 // Return Value:
521 //    ExceptionContinueSearch if the exception cannot be intercepted
522 //
523 // Notes:
524 //    If the exception is intercepted, this function never returns.
525 //
526
527 EXCEPTION_DISPOSITION ClrDebuggerDoUnwindAndIntercept(EXCEPTION_REGISTRATION_RECORD *pCurrentEstablisherFrame,
528                                                       EXCEPTION_RECORD *pExceptionRecord)
529 {
530     WRAPPER_NO_CONTRACT;
531
532     if (!CheckThreadExceptionStateForInterception())
533     {
534         return ExceptionContinueSearch;
535     }
536
537     Thread*               pThread  = GetThread();
538     ThreadExceptionState* pExState = pThread->GetExceptionState();
539
540     EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame;
541     ThrowCallbackType tct;
542     tct.Init();
543
544     pExState->GetDebuggerState()->GetDebuggerInterceptInfo(&pEstablisherFrame,
545                                       &(tct.pFunc),
546                                       &(tct.dHandler),
547                                       &(tct.pStack),
548                                       NULL,
549                                       &(tct.pBottomFrame)
550                                      );
551
552     //
553     // If the handler that we've selected as the handler for the target frame of the unwind is in fact above the
554     // handler that we're currently executing in, then use the current handler instead. Why? Our handlers for
555     // nested exceptions actually process managed frames that live above them, up to the COMPlusFrameHanlder that
556     // pushed the nested handler. If the user selectes a frame above the nested handler, then we will have selected
557     // the COMPlusFrameHandler above the current nested handler. But we don't want to ask RtlUnwind to unwind past
558     // the nested handler that we're currently executing in.
559     //
560     if (pEstablisherFrame > pCurrentEstablisherFrame)
561     {
562         // This should only happen if we're in a COMPlusNestedExceptionHandler.
563         _ASSERTE(IsComPlusNestedExceptionRecord(pCurrentEstablisherFrame));
564
565         pEstablisherFrame = pCurrentEstablisherFrame;
566     }
567
568 #ifdef _DEBUG
569     tct.pCurrentExceptionRecord = pEstablisherFrame;
570 #endif
571
572     LOG((LF_EH|LF_CORDB, LL_INFO100, "ClrDebuggerDoUnwindAndIntercept: Intercepting at %s\n", tct.pFunc->m_pszDebugMethodName));
573     LOG((LF_EH|LF_CORDB, LL_INFO100, "\t\t: pFunc is 0x%X\n", tct.pFunc));
574     LOG((LF_EH|LF_CORDB, LL_INFO100, "\t\t: pStack is 0x%X\n", tct.pStack));
575
576     CallRtlUnwindSafe(pEstablisherFrame, RtlUnwindCallback, pExceptionRecord, 0);
577
578     ExInfo* pExInfo = pThread->GetExceptionState()->GetCurrentExceptionTracker();
579     if (pExInfo->m_ValidInterceptionContext)
580     {
581         // By now we should have all unknown FS:[0] handlers unwinded along with the managed Frames until
582         // the interception point. We can now pop nested exception handlers and resume at interception context.
583         GCX_COOP();
584         EHContext context = pExInfo->m_InterceptionContext;
585         pExInfo->m_InterceptionContext.Init();
586         pExInfo->m_ValidInterceptionContext = FALSE;
587
588         UnwindExceptionTrackerAndResumeInInterceptionFrame(pExInfo, &context);
589     }
590
591     // on x86 at least, RtlUnwind always returns
592
593     // Note: we've completed the unwind pass up to the establisher frame, and we're headed off to finish our
594     // cleanup and end up back in jitted code. Any more FS0 handlers pushed from this point on out will _not_ be
595     // unwound.
596     return COMPlusAfterUnwind(pExState->GetExceptionRecord(), pEstablisherFrame, tct);
597 } // EXCEPTION_DISPOSITION ClrDebuggerDoUnwindAndIntercept()
598
599 #endif // DEBUGGING_SUPPORTED
600
601 // This is a wrapper around the assembly routine that invokes RtlUnwind in the OS.
602 // When we invoke RtlUnwind, the OS will modify the ExceptionFlags field in the 
603 // exception record to reflect unwind. Since we call RtlUnwind in the first pass
604 // with a valid exception record when we find an exception handler AND because RtlUnwind 
605 // returns on x86, the OS would have flagged the exception record for unwind.
606 //
607 // Incase the exception is rethrown from the catch/filter-handler AND it's a non-COMPLUS
608 // exception, the runtime will use the reference to the saved exception record to reraise 
609 // the exception, as part of rethrow fixup. Since the OS would have modified the exception record
610 // to reflect unwind, this wrapper will "reset" the ExceptionFlags field when RtlUnwind returns.
611 // Otherwise, the rethrow will result in second pass, as opposed to first, since the ExceptionFlags
612 // would indicate an unwind.
613 // 
614 // This rethrow issue does not affect COMPLUS exceptions since we always create a brand new exception
615 // record for them in RaiseTheExceptionInternalOnly.
616 BOOL CallRtlUnwindSafe(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
617            RtlUnwindCallbackType callback,
618            EXCEPTION_RECORD *pExceptionRecord,
619            void *retval)
620 {
621     LIMITED_METHOD_CONTRACT;
622
623     // Save the ExceptionFlags value before invoking RtlUnwind.
624     DWORD dwExceptionFlags = pExceptionRecord->ExceptionFlags;
625
626     BOOL fRetVal = CallRtlUnwind(pEstablisherFrame, callback, pExceptionRecord, retval);
627
628     // Reset ExceptionFlags field, if applicable
629     if (pExceptionRecord->ExceptionFlags != dwExceptionFlags)
630     {
631         // We would expect the 32bit OS to have set the unwind flag at this point.
632         _ASSERTE(pExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING);
633         LOG((LF_EH, LL_INFO100, "CallRtlUnwindSafe: Resetting ExceptionFlags from %lu to %lu\n", pExceptionRecord->ExceptionFlags, dwExceptionFlags));
634         pExceptionRecord->ExceptionFlags = dwExceptionFlags;
635     }
636
637     return fRetVal;
638 }
639
640 //******************************************************************************
641 // The essence of the first pass handler (after we've decided to actually do
642 //  the first pass handling).
643 //******************************************************************************
644 inline EXCEPTION_DISPOSITION __cdecl
645 CPFH_RealFirstPassHandler(                  // ExceptionContinueSearch, etc.
646     EXCEPTION_RECORD *pExceptionRecord,     // The exception record, with exception type.
647     EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,   // Exception frame on whose behalf this is called.
648     CONTEXT     *pContext,                  // Context from the exception.
649     void        *pDispatcherContext,        // @todo
650     BOOL        bAsynchronousThreadStop,    // @todo
651     BOOL        fPGCDisabledOnEntry)        // @todo
652 {
653     // We don't want to use a runtime contract here since this codepath is used during
654     // the processing of a hard SO. Contracts use a significant amount of stack
655     // which we can't afford for those cases.
656     STATIC_CONTRACT_THROWS;
657     STATIC_CONTRACT_GC_TRIGGERS;
658     STATIC_CONTRACT_MODE_COOPERATIVE;
659     STATIC_CONTRACT_SO_TOLERANT;
660
661 #ifdef _DEBUG
662     static int breakOnFirstPass = -1;
663
664     if (breakOnFirstPass == -1)
665         breakOnFirstPass = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnFirstPass);
666
667     if (breakOnFirstPass != 0)
668     {
669         _ASSERTE(!"First pass exception handler");
670     }
671 #endif
672
673     EXCEPTION_DISPOSITION retval;
674     DWORD exceptionCode = pExceptionRecord->ExceptionCode;
675     Thread *pThread = GetThread();
676
677 #ifdef _DEBUG
678     static int breakOnSO = -1;
679
680     if (breakOnSO == -1)
681         breakOnSO = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BreakOnSO);
682
683     if (breakOnSO != 0 && exceptionCode == STATUS_STACK_OVERFLOW)
684     {
685         DebugBreak();   // ASSERTing will overwrite the guard region
686     }
687 #endif
688
689     // We always want to be in co-operative mode when we run this function and whenever we return
690     // from it, want to go to pre-emptive mode because are returning to OS.
691     _ASSERTE(pThread->PreemptiveGCDisabled());
692
693     BOOL bPopNestedHandlerExRecord = FALSE;
694     LFH found = LFH_NOT_FOUND;          // Result of calling LookForHandler.
695     BOOL bRethrownException = FALSE;
696     BOOL bNestedException = FALSE;
697
698 #if defined(USE_FEF)
699     BOOL bPopFaultingExceptionFrame = FALSE;
700     FrameWithCookie<FaultingExceptionFrame> faultingExceptionFrame;
701 #endif // USE_FEF
702     ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
703
704     ThrowCallbackType tct;
705     tct.Init();
706
707     tct.pTopFrame = GetCurrFrame(pEstablisherFrame); // highest frame to search to
708
709 #ifdef _DEBUG
710     tct.pCurrentExceptionRecord = pEstablisherFrame;
711     tct.pPrevExceptionRecord    = GetPrevSEHRecord(pEstablisherFrame);
712 #endif // _DEBUG
713
714     BOOL fIsManagedCode = pContext ? ExecutionManager::IsManagedCode(GetIP(pContext)) : FALSE;
715
716
717     // this establishes a marker so can determine if are processing a nested exception
718     // don't want to use the current frame to limit search as it could have been unwound by
719     // the time get to nested handler (ie if find an exception, unwind to the call point and
720     // then resume in the catch and then get another exception) so make the nested handler
721     // have the same boundary as this one. If nested handler can't find a handler, we won't
722     // end up searching this frame list twice because the nested handler will set the search
723     // boundary in the thread and so if get back to this handler it will have a range that starts
724     // and ends at the same place.
725
726     NestedHandlerExRecord nestedHandlerExRecord;
727     nestedHandlerExRecord.Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, GetCurrFrame(pEstablisherFrame));
728
729     INSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg));
730     bPopNestedHandlerExRecord = TRUE;
731
732 #if defined(USE_FEF)
733     // Note: don't attempt to push a FEF for an exception in managed code if we weren't in cooperative mode when
734     // the exception was received. If preemptive GC was enabled when we received the exception, then it means the
735     // exception was rethrown from unmangaed code (including EE impl), and we shouldn't push a FEF.
736     if (fIsManagedCode &&
737         fPGCDisabledOnEntry &&
738         (pThread->m_pFrame == FRAME_TOP ||
739          pThread->m_pFrame->GetVTablePtr() != FaultingExceptionFrame::GetMethodFrameVPtr() ||
740          (size_t)pThread->m_pFrame > (size_t)pEstablisherFrame))
741     {
742         // setup interrupted frame so that GC during calls to init won't collect the frames
743         // only need it for non COM+ exceptions in managed code when haven't already
744         // got one on the stack (will have one already if we have called rtlunwind because
745         // the instantiation that called unwind would have installed one)
746         faultingExceptionFrame.InitAndLink(pContext);
747         bPopFaultingExceptionFrame = TRUE;
748     }
749 #endif // USE_FEF
750
751     OBJECTREF e;
752     e = pThread->LastThrownObject();
753
754     STRESS_LOG7(LF_EH, LL_INFO10, "CPFH_RealFirstPassHandler: code:%X, LastThrownObject:%p, MT:%pT"
755         ", IP:%p, SP:%p, pContext:%p, pEstablisherFrame:%p\n",
756         exceptionCode, OBJECTREFToObject(e), (e!=0)?e->GetMethodTable():0,
757         pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0, 
758         pContext, pEstablisherFrame);
759
760 #ifdef LOGGING
761     // If it is a complus exception, and there is a thrown object, get its name, for better logging.
762     if (IsComPlusException(pExceptionRecord))
763     {
764         const char * eClsName = "!EXCEPTION_COMPLUS";
765         if (e != 0)
766         {
767             eClsName = e->GetTrueMethodTable()->GetDebugClassName();
768     }
769         LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: exception: 0x%08X, class: '%s', IP: 0x%p\n",
770              exceptionCode, eClsName, pContext ? GetIP(pContext) : NULL));
771     }
772 #endif
773
774     EXCEPTION_POINTERS exceptionPointers = {pExceptionRecord, pContext};
775
776     STRESS_LOG4(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: setting boundaries: Exinfo: 0x%p, BottomMostHandler:0x%p, SearchBoundary:0x%p, TopFrame:0x%p\n",
777          pExInfo, pExInfo->m_pBottomMostHandler, pExInfo->m_pSearchBoundary, tct.pTopFrame);
778
779     // Here we are trying to decide if we are coming in as:
780     // 1) first handler in a brand new exception
781     // 2) a subsequent handler in an exception
782     // 3) a nested exception
783     // m_pBottomMostHandler is the registration structure (establisher frame) for the most recent (ie lowest in
784     // memory) non-nested handler that was installed  and pEstablisher frame is what the current handler
785     // was registered with.
786     // The OS calls each registered handler in the chain, passing its establisher frame to it.
787     if (pExInfo->m_pBottomMostHandler != NULL && pEstablisherFrame > pExInfo->m_pBottomMostHandler)
788     {
789         STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: detected subsequent handler.  ExInfo:0x%p, BottomMost:0x%p SearchBoundary:0x%p\n", 
790                     pExInfo, pExInfo->m_pBottomMostHandler, pExInfo->m_pSearchBoundary);
791         
792         // If the establisher frame of this handler is greater than the bottommost then it must have been
793         // installed earlier and therefore we are case 2
794         if (pThread->GetThrowable() == NULL)
795         {
796             // Bottommost didn't setup a throwable, so not exception not for us
797             retval = ExceptionContinueSearch;
798             goto exit;
799         }
800
801         // setup search start point
802         tct.pBottomFrame = pExInfo->m_pSearchBoundary;
803
804         if (tct.pTopFrame == tct.pBottomFrame)
805         {
806             // this will happen if our nested handler already searched for us so we don't want
807             // to search again
808             retval = ExceptionContinueSearch;
809             goto exit;
810         }
811     }
812     else
813     {   // we are either case 1 or case 3
814 #if defined(_DEBUG_IMPL)
815         //@todo: merge frames, context, handlers
816         if (pThread->GetFrame() != FRAME_TOP)
817             pThread->GetFrame()->LogFrameChain(LF_EH, LL_INFO1000);
818 #endif // _DEBUG_IMPL
819
820         // If the exception was rethrown, we'll create a new ExInfo, which will represent the rethrown exception.
821         //  The original exception is not the rethrown one.
822         if (pExInfo->m_ExceptionFlags.IsRethrown() && pThread->LastThrownObject() != NULL)
823         {
824             pExInfo->m_ExceptionFlags.ResetIsRethrown();
825             bRethrownException = TRUE;
826
827 #if defined(USE_FEF)
828             if (bPopFaultingExceptionFrame)
829             {
830                 // if we added a FEF, it will refer to the frame at the point of the original exception which is
831                 // already unwound so don't want it.
832                 // If we rethrew the exception we have already added a helper frame for the rethrow, so don't
833                 // need this one. If we didn't rethrow it, (ie rethrow from native) then there the topmost frame will
834                 // be a transition to native frame in which case we don't need it either
835                 faultingExceptionFrame.Pop();
836                 bPopFaultingExceptionFrame = FALSE;
837             }
838 #endif
839         }
840
841         // If the establisher frame is less than the bottommost handler, then this is nested because the
842         // establisher frame was installed after the bottommost.
843         if (pEstablisherFrame < pExInfo->m_pBottomMostHandler
844             /* || IsComPlusNestedExceptionRecord(pEstablisherFrame) */ )
845         {
846             bNestedException = TRUE;
847
848             // case 3: this is a nested exception. Need to save and restore the thread info
849             STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: ExInfo:0x%p detected nested exception 0x%p < 0x%p\n",
850                         pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler);
851
852             EXCEPTION_REGISTRATION_RECORD* pNestedER = TryFindNestedEstablisherFrame(pEstablisherFrame);
853             ExInfo *pNestedExInfo;
854
855             if (!pNestedER || pNestedER >= pExInfo->m_pBottomMostHandler )
856             {
857                 // RARE CASE.  We've re-entered the EE from an unmanaged filter.
858                 // 
859                 // OR
860                 //
861                 // We can be here if we dont find a nested exception handler. This is exemplified using 
862                 // call chain of scenario 2 explained further below.
863                 //
864                 // Assuming __try of NativeB throws an exception E1 and it gets caught in ManagedA2, then
865                 // bottom-most handler (BMH) is going to be CPFH_A. The catch will trigger an unwind
866                 // and invoke __finally in NativeB. Let the __finally throw a new exception E2.
867                 //
868                 // Assuming ManagedB2 has a catch block to catch E2, when we enter CPFH_B looking for a 
869                 // handler for E2, our establisher frame will be that of CPFH_B, which will be lower
870                 // in stack than current BMH (which is CPFH_A). Thus, we will come here, determining
871                 // E2 to be nested exception correctly but not find a nested exception handler.
872                 void *limit = (void *) GetPrevSEHRecord(pExInfo->m_pBottomMostHandler);
873
874                 pNestedExInfo = new (nothrow) ExInfo();     // Very rare failure here; need robust allocator.
875                 if (pNestedExInfo == NULL)
876                 {   // if we can't allocate memory, we can't correctly continue.
877                     #if defined(_DEBUG)
878                     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NestedEhOom))
879                         _ASSERTE(!"OOM in callback from unmanaged filter.");
880                     #endif // _DEBUG
881                     
882                     EEPOLICY_HANDLE_FATAL_ERROR(COR_E_OUTOFMEMORY);
883                 }
884
885                 
886                 pNestedExInfo->m_StackAddress = limit;      // Note: this is also the flag that tells us this
887                                                             // ExInfo was stack allocated.
888             }
889             else
890             {
891                 pNestedExInfo = &((NestedHandlerExRecord*)pNestedER)->m_handlerInfo;
892             }
893
894             LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: PushExInfo() current: 0x%p previous: 0x%p\n", 
895                  pExInfo->m_StackAddress, pNestedExInfo->m_StackAddress));
896
897             _ASSERTE(pNestedExInfo);
898             pNestedExInfo->m_hThrowable = NULL; // pNestedExInfo may be stack allocated, and as such full of
899                                                 // garbage. m_hThrowable must be sane, so set it to NULL. (We could
900                                                 // zero the entire record, but this is cheaper.)
901
902             pNestedExInfo->CopyAndClearSource(pExInfo);
903
904             pExInfo->m_pPrevNestedInfo = pNestedExInfo;     // Save at head of nested info chain
905
906 #if 0
907 /* the following code was introduced in Whidbey as part of the Faulting Exception Frame removal (12/03).
908    However it isn't correct.  If any nested exceptions occur while processing a rethrow, we would
909    incorrectly consider the nested exception to be a rethrow.  See VSWhidbey 349379 for an example.
910
911    Therefore I am disabling this code until we see a failure that explains why it was added in the first
912    place.  cwb 9/04.
913 */
914             // If we're here as a result of a rethrown exception, set the rethrown flag on the new ExInfo.
915             if (bRethrownException)
916             {
917                 pExInfo->m_ExceptionFlags.SetIsRethrown();
918             }
919 #endif
920         }
921         else
922         {
923             // At this point, either:
924             //
925             // 1) the bottom-most handler is NULL, implying this is a new exception for which we are getting ready, OR
926             // 2) the bottom-most handler is not-NULL, implying that a there is already an existing exception in progress.
927             //
928             // Scenario 1 is that of a new throw and is easy to understand. Scenario 2 is the interesting one.
929             //
930             // ManagedA1 -> ManagedA2 -> ManagedA3 -> NativeCodeA -> ManagedB1 -> ManagedB2 -> ManagedB3 -> NativeCodeB
931             //
932             // On x86, each block of managed code is protected by one COMPlusFrameHandler [CPFH] (CLR's exception handler
933             // for managed code), unlike 64bit where each frame has a personality routine attached to it. Thus,
934             // for the example above, assume CPFH_A protects ManagedA* blocks and is setup just before the call to
935             // ManagedA1. Likewise, CPFH_B protects ManagedB* blocks and is setup just before the call to ManagedB1.
936             // 
937             // When ManagedB3 throws an exception, CPFH_B is invoked to look for a handler in all of the ManagedB* blocks.
938             // At this point, it is setup as the "bottom-most-handler" (BMH). If no handler is found and exception reaches
939             // ManagedA* blocks, CPFH_A is invoked to look for a handler and thus, becomes BMH. 
940             //
941             // Thus, in the first pass on x86 for a given exception, a particular CPFH will be invoked only once when looking 
942             // for a handler and thus, registered as BMH only once. Either the exception goes unhandled and the process will
943             // terminate or a handler will be found and second pass will commence.
944             //
945             // However, assume NativeCodeB had a __try/__finally and raised an exception [E1] within the __try. Let's assume
946             // it gets caught in ManagedB1 and thus, unwind is triggered. At this point, the active exception tracker
947             // has context about the exception thrown out of __try and CPFH_B is registered as BMH. 
948             //
949             // If the __finally throws a new exception [E2], CPFH_B will be invoked again for first pass while looking for 
950             // a handler for the thrown exception. Since BMH is already non-NULL, we will come here since EstablisherFrame will be
951             // the same as BMH (because EstablisherFrame will be that of CPFH_B). We will proceed to overwrite the "required" parts
952             // of the existing exception tracker with the details of E2 (see setting of exception record and context below), erasing 
953             // any artifact of E1. 
954             //
955             // This is unlike Scenario 1 when exception tracker is completely initialized to default values. This is also
956             // unlike 64bit which will detect that E1 and E2 are different exceptions and hence, will setup a new tracker
957             // to track E2, effectively behaving like Scenario 1 above. X86 cannot do this since there is no nested exception
958             // tracker setup that gets to see the new exception. 
959             //
960             // Thus, if E1 was a CSE and E2 isn't, we will come here and treat E2 as a CSE as well since corruption severity
961             // is initialized as part of exception tracker initialization. Thus, E2 will start to be treated as CSE, which is 
962             // incorrect. Similar argument applies to delivery of First chance exception notification delivery.
963             //
964             // <QUIP> Another example why we should unify EH systems :) </QUIP>
965             //
966             // To address this issue, we will need to reset exception tracker here, just like the overwriting of "required"
967             // parts of exception tracker.
968
969             // If the current establisher frame is the same as the bottom-most-handler and we are here
970             // in the first pass, assert that current exception and the one tracked by active exception tracker
971             // are indeed different exceptions. In such a case, we must reset the exception tracker so that it can be
972             // setup correctly further down when CEHelper::SetupCorruptionSeverityForActiveException is invoked.
973             
974             if ((pExInfo->m_pBottomMostHandler != NULL) &&
975                 (pEstablisherFrame == pExInfo->m_pBottomMostHandler))
976             {
977                 // Current exception should be different from the one exception tracker is already tracking.
978                 _ASSERTE(pExceptionRecord != pExInfo->m_pExceptionRecord);
979
980                 // This cannot be nested exceptions - they are handled earlier (see above).
981                 _ASSERTE(!bNestedException);
982                 
983                 LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: Bottom-most handler (0x%p) is the same as EstablisherFrame.\n", 
984                  pExInfo->m_pBottomMostHandler));
985                 LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: Exception record in exception tracker is 0x%p, while that of new exception is 0x%p.\n", 
986                  pExInfo->m_pExceptionRecord, pExceptionRecord));
987                 LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: Resetting exception tracker (0x%p).\n", pExInfo));
988                 
989                 // This will reset the exception tracker state, including the corruption severity.
990                 pExInfo->Init();
991             }
992         }
993
994         // If we are handling a fault from managed code, we need to set the Thread->ExInfo->pContext to
995         //  the current fault context, which is used in the stack walk to get back into the managed
996         //  stack with the correct registers.  (Previously, this was done by linking in a FaultingExceptionFrame
997         //  record.)
998         // We are about to create the managed exception object, which may trigger a GC, so set this up now.
999
1000         pExInfo->m_pExceptionRecord = pExceptionRecord;
1001         pExInfo->m_pContext = pContext;
1002         if (pContext && ShouldHandleManagedFault(pExceptionRecord, pContext, pEstablisherFrame, pThread))
1003         {   // If this was a fault in managed code, rather than create a Frame for stackwalking,
1004             //  we can use this exinfo (after all, it has all the register info.)
1005             pExInfo->m_ExceptionFlags.SetUseExInfoForStackwalk();
1006         }
1007
1008         // It should now be safe for a GC to happen.
1009
1010         // case 1 & 3: this is the first time through of a new, nested, or rethrown exception, so see if we can
1011         // find a handler.  Only setup throwable if are bottommost handler
1012         if (IsComPlusException(pExceptionRecord) && (!bAsynchronousThreadStop))
1013         {
1014
1015             // Update the throwable from the last thrown object. Note: this may cause OOM, in which case we replace
1016             // both throwables with the preallocated OOM exception.
1017             pThread->SafeSetThrowables(pThread->LastThrownObject());
1018
1019             // now we've got a COM+ exception, fall through to so see if we handle it
1020
1021             STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: fall through ExInfo:0x%p setting m_pBottomMostHandler to 0x%p from 0x%p\n",
1022                         pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler);
1023             pExInfo->m_pBottomMostHandler = pEstablisherFrame;
1024         }
1025         else if (bRethrownException)
1026         {
1027             // If it was rethrown and not COM+, will still be the last one thrown. Either we threw it last and
1028             // stashed it here or someone else caught it and rethrew it, in which case it will still have been
1029             // originally stashed here.
1030
1031             // Update the throwable from the last thrown object. Note: this may cause OOM, in which case we replace
1032             // both throwables with the preallocated OOM exception.
1033             pThread->SafeSetThrowables(pThread->LastThrownObject());
1034             STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: rethrow non-COM+ ExInfo:0x%p setting m_pBottomMostHandler to 0x%p from 0x%p\n",
1035                         pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler);
1036             pExInfo->m_pBottomMostHandler = pEstablisherFrame;
1037         }
1038         else
1039         {
1040             if (!fIsManagedCode)
1041             {
1042                 tct.bDontCatch = false;
1043             }
1044
1045             if (exceptionCode == STATUS_BREAKPOINT)
1046             {
1047                 // don't catch int 3
1048                 retval = ExceptionContinueSearch;
1049                 goto exit;
1050             }
1051
1052             // We need to set m_pBottomMostHandler here, Thread::IsExceptionInProgress returns 1.
1053             // This is a necessary part of suppressing thread abort exceptions in the constructor
1054             // of any exception object we might create.
1055             STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_RealFirstPassHandler: setting ExInfo:0x%p m_pBottomMostHandler for IsExceptionInProgress to 0x%p from 0x%p\n",
1056                         pExInfo, pEstablisherFrame, pExInfo->m_pBottomMostHandler);
1057             pExInfo->m_pBottomMostHandler = pEstablisherFrame;
1058
1059             // Create the managed exception object.
1060             OBJECTREF throwable = CreateCOMPlusExceptionObject(pThread, pExceptionRecord, bAsynchronousThreadStop);
1061
1062             // Set the throwables on the thread to the newly created object. If this fails, it will return a
1063             // preallocated exception object instead. This also updates the last thrown exception, for rethrows.
1064             throwable = pThread->SafeSetThrowables(throwable);
1065
1066             // Set the exception code and pointers. We set these after setting the throwables on the thread,
1067             // because if the proper exception is replaced by an OOM exception, we still want the exception code
1068             // and pointers set in the OOM exception.
1069             EXCEPTIONREF exceptionRef = (EXCEPTIONREF)throwable;
1070             exceptionRef->SetXCode(pExceptionRecord->ExceptionCode);
1071             exceptionRef->SetXPtrs(&exceptionPointers);
1072         }
1073
1074         tct.pBottomFrame = NULL;
1075
1076         EEToProfilerExceptionInterfaceWrapper::ExceptionThrown(pThread);
1077         
1078         CPFH_UpdatePerformanceCounters();
1079     } // End of case-1-or-3
1080
1081     {
1082         // Allocate storage for the stack trace.
1083         OBJECTREF throwable = NULL;
1084         GCPROTECT_BEGIN(throwable);
1085         throwable = pThread->GetThrowable();
1086
1087 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
1088         {
1089             BEGIN_SO_INTOLERANT_CODE(GetThread());
1090             // Setup the state in current exception tracker indicating the corruption severity
1091             // of the active exception.
1092             CEHelper::SetupCorruptionSeverityForActiveException(bRethrownException, bNestedException, 
1093                 CEHelper::ShouldTreatActiveExceptionAsNonCorrupting());
1094             END_SO_INTOLERANT_CODE;
1095         }
1096 #endif // FEATURE_CORRUPTING_EXCEPTIONS
1097
1098         // Check if we are dealing with AV or not and if we are,
1099         // ensure that this is a real AV and not managed AV exception
1100         BOOL fIsThrownExceptionAV = FALSE;
1101         if ((pExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) &&
1102             (MscorlibBinder::GetException(kAccessViolationException) == throwable->GetMethodTable()))
1103         {
1104             // Its an AV - set the flag
1105             fIsThrownExceptionAV = TRUE;
1106         }
1107         
1108         // Did we get an AV?
1109         if (fIsThrownExceptionAV == TRUE)
1110         {
1111             // Get the escalation policy action for handling AV
1112             EPolicyAction actionAV = GetEEPolicy()->GetActionOnFailure(FAIL_AccessViolation);
1113             
1114             // Valid actions are: eNoAction (default behviour) or eRudeExitProcess
1115             _ASSERTE(((actionAV == eNoAction) || (actionAV == eRudeExitProcess)));
1116             if (actionAV == eRudeExitProcess)
1117             {
1118                 LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: AccessViolation handler found and doing RudeExitProcess due to escalation policy (eRudeExitProcess)\n"));
1119                 
1120                 // EEPolicy::HandleFatalError will help us RudeExit the process.
1121                 // RudeExitProcess due to AV is to prevent a security risk - we are ripping
1122                 // at the boundary, without looking for the handlers.
1123                 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_SECURITY);
1124             }
1125         }
1126
1127         // If we're out of memory, then we figure there's probably not memory to maintain a stack trace, so we skip it.
1128         // If we've got a stack overflow, then we figure the stack will be so huge as to make tracking the stack trace
1129         // impracticle, so we skip it.
1130         if ((throwable == CLRException::GetPreallocatedOutOfMemoryException()) ||
1131             (throwable == CLRException::GetPreallocatedStackOverflowException()))
1132         {
1133             tct.bAllowAllocMem = FALSE;
1134         }
1135         else
1136         {
1137             pExInfo->m_StackTraceInfo.AllocateStackTrace();
1138         }
1139         
1140         GCPROTECT_END();
1141     }
1142
1143     // Set up information for GetExceptionPointers()/GetExceptionCode() callback.
1144     pExInfo->SetExceptionCode(pExceptionRecord);
1145
1146     pExInfo->m_pExceptionPointers = &exceptionPointers;
1147
1148 #ifndef FEATURE_PAL
1149     if (bRethrownException || bNestedException)
1150     {
1151         _ASSERTE(pExInfo->m_pPrevNestedInfo != NULL);
1152         
1153         BEGIN_SO_INTOLERANT_CODE(GetThread());
1154         SetStateForWatsonBucketing(bRethrownException, pExInfo->GetPreviousExceptionTracker()->GetThrowableAsHandle());
1155         END_SO_INTOLERANT_CODE;
1156     }
1157 #endif
1158
1159 #ifdef DEBUGGING_SUPPORTED
1160     //
1161     // At this point the exception is still fresh to us, so assert that
1162     // there should be nothing from the debugger on it.
1163     //
1164     _ASSERTE(!pExInfo->m_ExceptionFlags.DebuggerInterceptInfo());
1165 #endif
1166
1167     if (pThread->IsRudeAbort())
1168     {
1169         OBJECTREF rudeAbortThrowable = CLRException::GetPreallocatedRudeThreadAbortException();
1170
1171         if (pThread->GetThrowable() != rudeAbortThrowable)
1172         {
1173             // Neither of these sets will throw because the throwable that we're setting is a preallocated
1174             // exception. This also updates the last thrown exception, for rethrows.
1175             pThread->SafeSetThrowables(rudeAbortThrowable);
1176         }
1177
1178         if (!pThread->IsRudeAbortInitiated())
1179         {
1180             pThread->PreWorkForThreadAbort();
1181         }
1182     }
1183
1184     LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: looking for handler bottom %x, top %x\n",
1185          tct.pBottomFrame, tct.pTopFrame));
1186     tct.bReplaceStack = pExInfo->m_pBottomMostHandler == pEstablisherFrame && !bRethrownException;
1187     tct.bSkipLastElement = bRethrownException && bNestedException;
1188     found = LookForHandler(&exceptionPointers,
1189                                 pThread,
1190                                 &tct);
1191
1192     // We have searched this far.
1193     pExInfo->m_pSearchBoundary = tct.pTopFrame;
1194     LOG((LF_EH, LL_INFO1000, "CPFH_RealFirstPassHandler: set pSearchBoundary to 0x%p\n", pExInfo->m_pSearchBoundary));
1195
1196     if ((found == LFH_NOT_FOUND)
1197 #ifdef DEBUGGING_SUPPORTED
1198         && !pExInfo->m_ExceptionFlags.DebuggerInterceptInfo()
1199 #endif
1200         )
1201     {
1202         LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: NOT_FOUND\n"));
1203
1204         if (tct.pTopFrame == FRAME_TOP)
1205         {
1206             LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: NOT_FOUND at FRAME_TOP\n"));
1207         }
1208
1209         retval = ExceptionContinueSearch;
1210         goto exit;
1211     }
1212     else
1213     {
1214     // so we are going to handle the exception
1215
1216     // Remove the nested exception record -- before calling RtlUnwind.
1217     // The second-pass callback for a NestedExceptionRecord assumes that if it's
1218     // being unwound, it should pop one exception from the pExInfo chain.  This is
1219     // true for any older NestedRecords that might be unwound -- but not for the
1220     // new one we're about to add.  To avoid this, we remove the new record
1221     // before calling Unwind.
1222     //
1223     // <TODO>@NICE: This can probably be a little cleaner -- the nested record currently
1224     // is also used to guard the running of the filter code.  When we clean up the
1225     // behaviour of exceptions within filters, we should be able to get rid of this
1226     // PUSH/POP/PUSH behaviour.</TODO>
1227     _ASSERTE(bPopNestedHandlerExRecord);
1228
1229     UNINSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg));
1230
1231     // Since we are going to handle the exception we switch into preemptive mode
1232     GCX_PREEMP_NO_DTOR();
1233
1234 #ifdef DEBUGGING_SUPPORTED
1235     //
1236     // Check if the debugger wants to intercept this frame at a different point than where we are.
1237     //
1238     if (pExInfo->m_ExceptionFlags.DebuggerInterceptInfo())
1239     {
1240         ClrDebuggerDoUnwindAndIntercept(pEstablisherFrame, pExceptionRecord);
1241
1242         //
1243         // If this returns, then the debugger couldn't do it's stuff and we default to the found handler.
1244         //
1245         if (found == LFH_NOT_FOUND)
1246         {
1247             retval = ExceptionContinueSearch;
1248                 // we need to be sure to switch back into Cooperative mode since we are going to 
1249                 // jump to the exit: label and follow the normal return path (it is expected that
1250                 // CPFH_RealFirstPassHandler returns in COOP.
1251                 GCX_PREEMP_NO_DTOR_END();
1252             goto exit;
1253         }
1254     }
1255 #endif
1256
1257     LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: handler found: %s\n", tct.pFunc->m_pszDebugMethodName));
1258
1259     CallRtlUnwindSafe(pEstablisherFrame, RtlUnwindCallback, pExceptionRecord, 0);
1260     // on x86 at least, RtlUnwind always returns
1261
1262     // Note: we've completed the unwind pass up to the establisher frame, and we're headed off to finish our
1263     // cleanup and end up back in jitted code. Any more FS0 handlers pushed from this point on out will _not_ be
1264     // unwound.
1265         // Note: we are still in Preemptive mode here and that is correct, COMPlusAfterUnwind will switch us back
1266         // into Cooperative mode.
1267     return COMPlusAfterUnwind(pExceptionRecord, pEstablisherFrame, tct);
1268     }
1269
1270 exit:
1271     {
1272         // We need to be in COOP if we get here
1273         GCX_ASSERT_COOP();
1274     }
1275
1276     // If we got as far as saving pExInfo, save the context pointer so it's available for the unwind.
1277     if (pExInfo)
1278     {
1279         pExInfo->m_pContext = pContext;
1280         // pExInfo->m_pExceptionPointers points to a local structure, which is now going out of scope.
1281         pExInfo->m_pExceptionPointers = NULL;
1282     }
1283
1284 #if defined(USE_FEF)
1285     if (bPopFaultingExceptionFrame)
1286     {
1287         faultingExceptionFrame.Pop();
1288     }
1289 #endif // USE_FEF
1290
1291     if (bPopNestedHandlerExRecord)
1292     {
1293         UNINSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg));
1294     }
1295     return retval;
1296 } // CPFH_RealFirstPassHandler()
1297
1298
1299 //******************************************************************************
1300 //
1301 void InitializeExceptionHandling()
1302 {
1303     WRAPPER_NO_CONTRACT;
1304
1305     InitSavedExceptionInfo();
1306
1307     CLRAddVectoredHandlers();
1308
1309     // Initialize the lock used for synchronizing access to the stacktrace in the exception object
1310     g_StackTraceArrayLock.Init(LOCK_TYPE_DEFAULT, TRUE);
1311 }
1312
1313 //******************************************************************************
1314 static inline EXCEPTION_DISPOSITION __cdecl
1315 CPFH_FirstPassHandler(EXCEPTION_RECORD *pExceptionRecord,
1316                       EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
1317                       CONTEXT *pContext,
1318                       DISPATCHER_CONTEXT *pDispatcherContext)
1319 {
1320     WRAPPER_NO_CONTRACT;
1321     EXCEPTION_DISPOSITION retval;
1322
1323     _ASSERTE (!(pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)));
1324
1325     DWORD exceptionCode = pExceptionRecord->ExceptionCode;
1326
1327     Thread *pThread = GetThread();
1328
1329     STRESS_LOG4(LF_EH, LL_INFO100,
1330                 "CPFH_FirstPassHandler: pEstablisherFrame = %x EH code = %x  EIP = %x with ESP = %x\n",
1331                                 pEstablisherFrame, exceptionCode, pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0);
1332
1333     EXCEPTION_POINTERS ptrs = { pExceptionRecord, pContext };
1334
1335     // Call to the vectored handler to give other parts of the Runtime a chance to jump in and take over an
1336     // exception before we do too much with it. The most important point in the vectored handler is not to toggle
1337     // the GC mode.
1338     DWORD filter = CLRVectoredExceptionHandler(&ptrs);
1339
1340     if (filter == (DWORD) EXCEPTION_CONTINUE_EXECUTION)
1341     {
1342         return ExceptionContinueExecution;
1343     }
1344     else if (filter == EXCEPTION_CONTINUE_SEARCH)
1345     {
1346         return ExceptionContinueSearch;
1347     }
1348
1349 #if defined(STRESS_HEAP)
1350     //
1351     // Check to see if this exception is due to GCStress. Since the GCStress mechanism only injects these faults
1352     // into managed code, we only need to check for them in CPFH_FirstPassHandler.
1353     //
1354     if (IsGcMarker(exceptionCode, pContext))
1355     {
1356         return ExceptionContinueExecution;
1357     }
1358 #endif // STRESS_HEAP
1359
1360     // We always want to be in co-operative mode when we run this function and whenever we return
1361     // from it, want to go to pre-emptive mode because are returning to OS.
1362     BOOL disabled = pThread->PreemptiveGCDisabled();
1363     GCX_COOP_NO_DTOR();
1364
1365     BOOL bAsynchronousThreadStop = IsThreadHijackedForThreadStop(pThread, pExceptionRecord);
1366
1367     if (bAsynchronousThreadStop)
1368     {
1369         // If we ever get here in preemptive mode, we're in trouble.  We've
1370         // changed the thread's IP to point at a little function that throws ... if
1371         // the thread were to be in preemptive mode and a GC occurred, the stack
1372         // crawl would have been all messed up (becuase we have no frame that points
1373         // us back to the right place in managed code).
1374         _ASSERTE(disabled);
1375
1376         AdjustContextForThreadStop(pThread, pContext);
1377         LOG((LF_EH, LL_INFO100, "CPFH_FirstPassHandler is Asynchronous Thread Stop or Abort\n"));
1378     }
1379
1380     pThread->ResetThrowControlForThread();
1381
1382     CPFH_VerifyThreadIsInValidState(pThread, exceptionCode, pEstablisherFrame);
1383
1384     // If we were in cooperative mode when we came in here, then its okay to see if we should do HandleManagedFault
1385     // and push a FaultingExceptionFrame. If we weren't in coop mode coming in here, then it means that there's no
1386     // way the exception could really be from managed code. I might look like it was from managed code, but in
1387     // reality its a rethrow from unmanaged code, either unmanaged user code, or unmanaged EE implementation.
1388     if (disabled && ShouldHandleManagedFault(pExceptionRecord, pContext, pEstablisherFrame, pThread))
1389     {
1390 #if defined(USE_FEF)
1391         HandleManagedFault(pExceptionRecord, pContext, pEstablisherFrame, pThread);
1392         retval = ExceptionContinueExecution;
1393         goto exit;
1394 #else // USE_FEF
1395         // Save the context pointer in the Thread's EXInfo, so that a stack crawl can recover the
1396         //  register values from the fault.
1397
1398         //@todo: I haven't yet found any case where we need to do anything here.  If there are none, eliminate
1399         //  this entire if () {} block.
1400 #endif // USE_FEF
1401     }
1402
1403     // OK. We're finally ready to start the real work. Nobody else grabbed the exception in front of us. Now we can
1404     // get started.
1405     retval = CPFH_RealFirstPassHandler(pExceptionRecord,
1406                                        pEstablisherFrame,
1407                                        pContext,
1408                                        pDispatcherContext,
1409                                        bAsynchronousThreadStop,
1410                                        disabled);
1411
1412 #if defined(USE_FEF) // This label is only used in the HandleManagedFault() case above.
1413 exit:
1414 #endif
1415     if (retval != ExceptionContinueExecution || !disabled)
1416     {
1417         GCX_PREEMP_NO_DTOR();
1418     }
1419
1420     STRESS_LOG1(LF_EH, LL_INFO100, "CPFH_FirstPassHandler: exiting with retval %d\n", retval);
1421     return retval;
1422 } // CPFH_FirstPassHandler()
1423
1424 //******************************************************************************
1425 inline void
1426 CPFH_UnwindFrames1(Thread* pThread, EXCEPTION_REGISTRATION_RECORD* pEstablisherFrame, DWORD exceptionCode)
1427 {
1428     WRAPPER_NO_CONTRACT;
1429
1430     ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
1431
1432     // Ready to unwind the stack...
1433     ThrowCallbackType tct;
1434     tct.Init();
1435     tct.bIsUnwind = TRUE;
1436     tct.pTopFrame = GetCurrFrame(pEstablisherFrame); // highest frame to search to
1437     tct.pBottomFrame = NULL;
1438     
1439     // Set the flag indicating if the current exception represents a longjmp.
1440     // See comment in COMPlusUnwindCallback for details.
1441     CORRUPTING_EXCEPTIONS_ONLY(tct.m_fIsLongJump = (exceptionCode == STATUS_LONGJUMP);)
1442
1443     #ifdef _DEBUG
1444     tct.pCurrentExceptionRecord = pEstablisherFrame;
1445     tct.pPrevExceptionRecord = GetPrevSEHRecord(pEstablisherFrame);
1446     #endif
1447
1448     #ifdef DEBUGGING_SUPPORTED
1449         EXCEPTION_REGISTRATION_RECORD *pInterceptEstablisherFrame = NULL;
1450     
1451         // If the exception is intercepted, use information stored in the DebuggerExState to unwind the stack.
1452         if (pExInfo->m_ExceptionFlags.DebuggerInterceptInfo())
1453         {
1454             pExInfo->m_DebuggerExState.GetDebuggerInterceptInfo(&pInterceptEstablisherFrame,
1455                                               NULL,     // MethodDesc **ppFunc,                              
1456                                               NULL,     // int *pdHandler,                                   
1457                                               NULL,     // BYTE **ppStack                                    
1458                                               NULL,     // ULONG_PTR *pNativeOffset,                        
1459                                               NULL      // Frame **ppFrame)                                 
1460                                              );
1461             LOG((LF_EH, LL_INFO1000, "CPFH_UnwindFrames1: frames are Est 0x%X, Intercept 0x%X\n",
1462                  pEstablisherFrame, pInterceptEstablisherFrame));
1463     
1464             //
1465             // When we set up for the interception we store off the CPFH or CPNEH that we
1466             // *know* will handle unwinding the destination of the intercept.
1467             //
1468             // However, a CPNEH with the same limiting Capital-F-rame could do the work
1469             // and unwind us, so...
1470             //
1471             // If this is the exact frame handler we are supposed to search for, or
1472             // if this frame handler services the same Capital-F-rame as the frame handler
1473             // we are looking for (i.e. this frame handler may do the work that we would
1474             // expect our frame handler to do),
1475             // then
1476             //   we need to pass the interception destination during this unwind.
1477             //
1478             _ASSERTE(IsUnmanagedToManagedSEHHandler(pEstablisherFrame));
1479     
1480             if ((pEstablisherFrame == pInterceptEstablisherFrame) ||
1481                 (GetCurrFrame(pEstablisherFrame) == GetCurrFrame(pInterceptEstablisherFrame)))
1482             {
1483                 pExInfo->m_DebuggerExState.GetDebuggerInterceptInfo(NULL,
1484                                               &(tct.pFunc),
1485                                               &(tct.dHandler),
1486                                               &(tct.pStack),
1487                                               NULL,
1488                                               &(tct.pBottomFrame)
1489                                              );
1490     
1491                 LOG((LF_EH, LL_INFO1000, "CPFH_UnwindFrames1: going to: pFunc:%#X, pStack:%#X\n",
1492                     tct.pFunc, tct.pStack));
1493     
1494             }
1495     
1496         }
1497     #endif
1498     
1499     UnwindFrames(pThread, &tct);
1500
1501     LOG((LF_EH, LL_INFO1000, "CPFH_UnwindFrames1: after unwind ec:%#x, tct.pTopFrame:0x%p, pSearchBndry:0x%p\n"
1502                              "                    pEstFrame:0x%p, IsC+NestExRec:%d, !Nest||Active:%d\n", 
1503          exceptionCode, tct.pTopFrame, pExInfo->m_pSearchBoundary, pEstablisherFrame,  
1504          IsComPlusNestedExceptionRecord(pEstablisherFrame), 
1505          (!IsComPlusNestedExceptionRecord(pEstablisherFrame) || reinterpret_cast<NestedHandlerExRecord*>(pEstablisherFrame)->m_ActiveForUnwind)));
1506
1507     if (tct.pTopFrame >= pExInfo->m_pSearchBoundary &&
1508          (!IsComPlusNestedExceptionRecord(pEstablisherFrame) ||
1509           reinterpret_cast<NestedHandlerExRecord*>(pEstablisherFrame)->m_ActiveForUnwind) )
1510     {
1511         // If this is the search boundary, and we're not a nested handler, then
1512         // this is the last time we'll see this exception.  Time to unwind our
1513         // exinfo.
1514         STRESS_LOG0(LF_EH, LL_INFO100, "CPFH_UnwindFrames1: Exception unwind -- unmanaged catcher detected\n");
1515         pExInfo->UnwindExInfo((VOID*)pEstablisherFrame);
1516     }
1517 } // CPFH_UnwindFrames1()
1518
1519 //******************************************************************************
1520 inline EXCEPTION_DISPOSITION __cdecl
1521 CPFH_UnwindHandler(EXCEPTION_RECORD *pExceptionRecord,
1522                    EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
1523                    CONTEXT *pContext,
1524                    void *pDispatcherContext)
1525 {
1526     WRAPPER_NO_CONTRACT;
1527     _ASSERTE (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND));
1528
1529     #ifdef _DEBUG
1530     // Note: you might be inclined to write "static int breakOnSecondPass = CLRConfig::GetConfigValue(...);", but
1531     // you can't do that here. That causes C++ EH to be generated under the covers for this function, and this
1532     // function isn't allowed to have any C++ EH in it because its never going to return.
1533     static int breakOnSecondPass; // = 0
1534     static BOOL breakOnSecondPassSetup; // = FALSE
1535     if (!breakOnSecondPassSetup)
1536     {
1537         breakOnSecondPass = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnSecondPass);
1538         breakOnSecondPassSetup = TRUE;
1539     }
1540     if (breakOnSecondPass != 0)
1541     {
1542         _ASSERTE(!"Unwind handler");
1543     }
1544     #endif
1545
1546     DWORD exceptionCode = pExceptionRecord->ExceptionCode;
1547     Thread *pThread = GetThread();
1548
1549     ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
1550
1551     STRESS_LOG4(LF_EH, LL_INFO100, "In CPFH_UnwindHandler EHCode = %x EIP = %x with ESP = %x, pEstablisherFrame = 0x%p\n", exceptionCode,
1552         pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0, pEstablisherFrame);
1553
1554     // We always want to be in co-operative mode when we run this function.  Whenever we return
1555     // from it, want to go to pre-emptive mode because are returning to OS.
1556
1557     {
1558         // needs to be in its own scope to avoid polluting the namespace, since
1559         // we don't do a _END then we don't revert the state
1560         GCX_COOP_NO_DTOR();
1561     }
1562
1563     CPFH_VerifyThreadIsInValidState(pThread, exceptionCode, pEstablisherFrame);
1564
1565     if (IsComPlusNestedExceptionRecord(pEstablisherFrame))
1566     {
1567         NestedHandlerExRecord *pHandler = reinterpret_cast<NestedHandlerExRecord*>(pEstablisherFrame);
1568         if (pHandler->m_pCurrentExInfo != NULL)
1569         {
1570             // See the comment at the end of COMPlusNestedExceptionHandler about nested exception.
1571             // OS is going to skip the EstablisherFrame before our NestedHandler.
1572             if (pHandler->m_pCurrentExInfo->m_pBottomMostHandler <= pHandler->m_pCurrentHandler)
1573             {
1574                 // We're unwinding -- the bottom most handler is potentially off top-of-stack now.  If
1575                 // it is, change it to the next COM+ frame.  (This one is not good, as it's about to
1576                 // disappear.)
1577                 EXCEPTION_REGISTRATION_RECORD *pNextBottomMost = GetNextCOMPlusSEHRecord(pHandler->m_pCurrentHandler);
1578
1579                 STRESS_LOG3(LF_EH, LL_INFO10000, "COMPlusNestedExceptionHandler: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", 
1580                     pHandler->m_pCurrentExInfo, pHandler->m_pCurrentExInfo->m_pBottomMostHandler, pNextBottomMost);
1581
1582                 pHandler->m_pCurrentExInfo->m_pBottomMostHandler = pNextBottomMost;
1583             }
1584         }
1585     }
1586
1587     // this establishes a marker so can determine if are processing a nested exception
1588     // don't want to use the current frame to limit search as it could have been unwound by
1589     // the time get to nested handler (ie if find an exception, unwind to the call point and
1590     // then resume in the catch and then get another exception) so make the nested handler
1591     // have the same boundary as this one. If nested handler can't find a handler, we won't
1592     // end up searching this frame list twice because the nested handler will set the search
1593     // boundary in the thread and so if get back to this handler it will have a range that starts
1594     // and ends at the same place.
1595     NestedHandlerExRecord nestedHandlerExRecord;
1596     nestedHandlerExRecord.Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, GetCurrFrame(pEstablisherFrame));
1597
1598     nestedHandlerExRecord.m_ActiveForUnwind = TRUE;
1599         nestedHandlerExRecord.m_pCurrentExInfo = pExInfo;
1600         nestedHandlerExRecord.m_pCurrentHandler = pEstablisherFrame;
1601
1602     INSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg));
1603
1604     // Unwind the stack.  The establisher frame sets the boundary.
1605     CPFH_UnwindFrames1(pThread, pEstablisherFrame, exceptionCode);
1606
1607     // We're unwinding -- the bottom most handler is potentially off top-of-stack now.  If
1608     // it is, change it to the next COM+ frame.  (This one is not good, as it's about to
1609     // disappear.)
1610     if (pExInfo->m_pBottomMostHandler &&
1611         pExInfo->m_pBottomMostHandler <= pEstablisherFrame) 
1612     {
1613         EXCEPTION_REGISTRATION_RECORD *pNextBottomMost = GetNextCOMPlusSEHRecord(pEstablisherFrame);
1614
1615         // If there is no previous COM+ SEH handler, GetNextCOMPlusSEHRecord() will return -1.  Much later, we will dereference that and AV.
1616         _ASSERTE (pNextBottomMost != EXCEPTION_CHAIN_END);
1617         
1618         STRESS_LOG3(LF_EH, LL_INFO10000, "CPFH_UnwindHandler: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", 
1619             pExInfo, pExInfo->m_pBottomMostHandler, pNextBottomMost);
1620         
1621         pExInfo->m_pBottomMostHandler = pNextBottomMost;
1622     }
1623
1624     {
1625         // needs to be in its own scope to avoid polluting the namespace, since
1626         // we don't do a _END then we don't revert the state
1627         GCX_PREEMP_NO_DTOR();
1628     }
1629     UNINSTALL_EXCEPTION_HANDLING_RECORD(&(nestedHandlerExRecord.m_ExReg));
1630
1631     // If we are here, then exception was not caught in managed code protected by this
1632     // ComplusFrameHandler. Hence, reset thread abort state if this is the last personality routine,
1633     // for managed code, on the stack.
1634     ResetThreadAbortState(pThread, pEstablisherFrame);
1635
1636     STRESS_LOG0(LF_EH, LL_INFO100, "CPFH_UnwindHandler: Leaving with ExceptionContinueSearch\n");
1637     return ExceptionContinueSearch;
1638 } // CPFH_UnwindHandler()
1639
1640 //******************************************************************************
1641 // This is the first handler that is called in the context of managed code
1642 // It is the first level of defense and tries to find a handler in the user
1643 // code to handle the exception
1644 //-------------------------------------------------------------------------
1645 // EXCEPTION_DISPOSITION __cdecl COMPlusFrameHandler(
1646 //     EXCEPTION_RECORD *pExceptionRecord,
1647 //     _EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
1648 //     CONTEXT *pContext,
1649 //     DISPATCHER_CONTEXT *pDispatcherContext)
1650 // 
1651 // See http://www.microsoft.com/msj/0197/exception/exception.aspx for a background piece on Windows
1652 // unmanaged structured exception handling.  
1653 EXCEPTION_HANDLER_IMPL(COMPlusFrameHandler)
1654 {
1655     WRAPPER_NO_CONTRACT;
1656     _ASSERTE(!DebugIsEECxxException(pExceptionRecord) && "EE C++ Exception leaked into managed code!");
1657
1658     STRESS_LOG5(LF_EH, LL_INFO100, "In COMPlusFrameHander EH code = %x  flag = %x EIP = %x with ESP = %x, pEstablisherFrame = 0x%p\n",
1659         pExceptionRecord->ExceptionCode, pExceptionRecord->ExceptionFlags, 
1660         pContext ? GetIP(pContext) : 0, pContext ? GetSP(pContext) : 0, pEstablisherFrame);
1661
1662     _ASSERTE((pContext == NULL) || ((pContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL));
1663     
1664     if (g_fNoExceptions)
1665         return ExceptionContinueSearch; // No EH during EE shutdown.
1666
1667     // Check if the exception represents a GCStress Marker. If it does,
1668     // we shouldnt record its entry in the TLS as such exceptions are
1669     // continuable and can confuse the VM to treat them as CSE, 
1670     // as they are implemented using illegal instruction exception.
1671
1672     bool fIsGCMarker = false;
1673
1674 #ifdef HAVE_GCCOVER // This is a debug only macro
1675     if (GCStress<cfg_instr_jit>::IsEnabled())
1676     {
1677         // UnsafeTlsGetValue trashes last error. When Complus_GCStress=4, GC is invoked
1678         // on every allowable JITed instruction by means of our exception handling machanism
1679         // it is very easy to trash the last error. For example, a p/invoke called a native method
1680         // which sets last error. Before we getting the last error in the IL stub, it is trashed here
1681         DWORD dwLastError = GetLastError();
1682         fIsGCMarker = IsGcMarker(pExceptionRecord->ExceptionCode, pContext);
1683         if (!fIsGCMarker)
1684         {
1685             SaveCurrentExceptionInfo(pExceptionRecord, pContext);
1686         }
1687         SetLastError(dwLastError);
1688     }
1689     else
1690 #endif
1691     {
1692         // GCStress does not exist on retail builds (see IsGcMarker implementation for details).
1693         SaveCurrentExceptionInfo(pExceptionRecord, pContext);
1694     }
1695
1696     if (fIsGCMarker)
1697     {
1698         // If this was a GCStress marker exception, then return
1699         // ExceptionContinueExecution to the OS.
1700         return ExceptionContinueExecution;
1701     }
1702     
1703     EXCEPTION_DISPOSITION retVal = ExceptionContinueSearch;
1704
1705     Thread *pThread = GetThread();
1706     if ((pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) == 0)
1707     {
1708         if (IsSOExceptionCode(pExceptionRecord->ExceptionCode))
1709         {
1710             EEPolicy::HandleStackOverflow(SOD_ManagedFrameHandler, (void*)pEstablisherFrame);
1711
1712             // VC's unhandled exception filter plays with stack.  It VirtualAlloc's a new stack, and
1713             // then launch Watson from the new stack.  When Watson asks CLR to save required data, we
1714             // are not able to walk the stack.
1715             // Setting Context in ExInfo so that our Watson dump routine knows how to walk this stack.
1716             ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
1717             pExInfo->m_pContext = pContext;
1718
1719             // Save the reference to the topmost handler we see during first pass when an SO goes past us. 
1720             // When an unwind gets triggered for the exception, we will reset the frame chain when we reach
1721             // the topmost handler we saw during the first pass.
1722             //
1723             // This unifies, behaviour-wise, 32bit with 64bit.
1724             if ((pExInfo->m_pTopMostHandlerDuringSO == NULL) ||
1725                 (pEstablisherFrame > pExInfo->m_pTopMostHandlerDuringSO))
1726             {
1727                 pExInfo->m_pTopMostHandlerDuringSO = pEstablisherFrame;
1728             }
1729
1730             // Switch to preemp mode since we are returning back to the OS.
1731             // We will do the quick switch since we are short of stack
1732             FastInterlockAnd (&pThread->m_fPreemptiveGCDisabled, 0);
1733
1734             return ExceptionContinueSearch;
1735         }
1736         else
1737         {
1738 #ifdef FEATURE_STACK_PROBE
1739             if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
1740             {
1741                 RetailStackProbe(static_cast<unsigned int>(ADJUST_PROBE(BACKOUT_CODE_STACK_LIMIT)), pThread);
1742             }
1743 #endif
1744         }
1745     }
1746     else
1747     {
1748         DWORD exceptionCode = pExceptionRecord->ExceptionCode;
1749
1750         if (exceptionCode == STATUS_UNWIND)
1751         {
1752             // If exceptionCode is STATUS_UNWIND, RtlUnwind is called with a NULL ExceptionRecord,
1753             // therefore OS uses a faked ExceptionRecord with STATUS_UNWIND code.  Then we need to
1754             // look at our saved exception code.
1755             exceptionCode = GetCurrentExceptionCode();
1756         }
1757
1758         if (IsSOExceptionCode(exceptionCode))
1759         {
1760             // We saved the context during the first pass in case the stack overflow exception is
1761             // unhandled and Watson dump code needs it.  Now we are in the second pass, therefore
1762             // either the exception is handled by user code, or we have finished unhandled exception 
1763             // filter process, and the OS is unwinding the stack.  Either way, we don't need the 
1764             // context any more.  It is very important to reset the context so that our code does not
1765             // accidentally walk the frame using the dangling context in ExInfoWalker::WalkToPosition.
1766             ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
1767             pExInfo->m_pContext = NULL;
1768
1769             // We should have the reference to the topmost handler seen during the first pass of SO
1770             _ASSERTE(pExInfo->m_pTopMostHandlerDuringSO != NULL);
1771
1772             // Reset frame chain till we reach the topmost establisher frame we saw in the first pass.
1773             // This will ensure that if any intermediary frame calls back into managed (e.g. native frame
1774             // containing a __finally that reverse pinvokes into managed), then we have the correct
1775             // explicit frame on the stack. Resetting the frame chain only when we reach the topmost
1776             // personality routine seen in the first pass may not result in expected behaviour,
1777             // specially during stack walks when crawl frame needs to be initialized from
1778             // explicit frame.
1779             if (pEstablisherFrame <= pExInfo->m_pTopMostHandlerDuringSO)
1780             {
1781                 GCX_COOP_NO_DTOR();
1782
1783                 if (pThread->GetFrame() < GetCurrFrame(pEstablisherFrame))
1784                 {
1785                     // We are very short of stack.  We avoid calling UnwindFrame which may
1786                     // run unknown code here.
1787                     pThread->SetFrame(GetCurrFrame(pEstablisherFrame));
1788                 }
1789             }
1790
1791             // Switch to preemp mode since we are returning back to the OS.
1792             // We will do the quick switch since we are short of stack
1793             FastInterlockAnd(&pThread->m_fPreemptiveGCDisabled, 0);
1794
1795             return ExceptionContinueSearch;
1796         }
1797     }
1798
1799     // <TODO> .  We need to probe here, but can't introduce destructors etc. </TODO>
1800     BEGIN_CONTRACT_VIOLATION(SOToleranceViolation);
1801
1802     if (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
1803     {
1804         retVal =  CPFH_UnwindHandler(pExceptionRecord,
1805                                      pEstablisherFrame,
1806                                      pContext,
1807                                      pDispatcherContext);
1808     }
1809     else
1810     {
1811
1812         /* Make no assumptions about the current machine state.
1813            <TODO>@PERF: Only needs to be called by the very first handler invoked by SEH </TODO>*/
1814         ResetCurrentContext();
1815
1816         retVal = CPFH_FirstPassHandler(pExceptionRecord,
1817                                        pEstablisherFrame,
1818                                        pContext,
1819                                        pDispatcherContext);
1820
1821     }
1822
1823     END_CONTRACT_VIOLATION;
1824
1825     return retVal;
1826 } // COMPlusFrameHandler()
1827
1828
1829 //-------------------------------------------------------------------------
1830 // This is called by the EE to restore the stack pointer if necessary.
1831 //-------------------------------------------------------------------------
1832
1833 // This can't be inlined into the caller to avoid introducing EH frame
1834 NOINLINE LPVOID COMPlusEndCatchWorker(Thread * pThread)
1835 {
1836     STATIC_CONTRACT_THROWS;
1837     STATIC_CONTRACT_GC_TRIGGERS;
1838     STATIC_CONTRACT_MODE_COOPERATIVE;
1839     STATIC_CONTRACT_SO_INTOLERANT;
1840
1841     LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch:called with "
1842         "pThread:0x%x\n",pThread));
1843
1844     // indicate that we are out of the managed clause as early as possible
1845     ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
1846     pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE);
1847
1848     void* esp = NULL;
1849
1850     // @todo .  We need to probe in the EH code, but can't introduce destructors etc.
1851     BEGIN_CONTRACT_VIOLATION(SOToleranceViolation);
1852
1853     // Notify the profiler that the catcher has finished running
1854     // IL stubs don't contain catch blocks so inability to perform this check does not matter.
1855     // if (!pFunc->IsILStub())
1856     EEToProfilerExceptionInterfaceWrapper::ExceptionCatcherLeave();
1857
1858     // no need to set pExInfo->m_ClauseType = (DWORD)COR_PRF_CLAUSE_NONE now that the
1859     // notification is done because because the ExInfo record is about to be popped off anyway
1860
1861     LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch:pThread:0x%x\n",pThread));
1862     
1863 #ifdef _DEBUG
1864     gLastResumedExceptionFunc = NULL;
1865     gLastResumedExceptionHandler = 0;
1866 #endif
1867     // Set the thrown object to NULL as no longer needed. This also sets the last thrown object to NULL.
1868     pThread->SafeSetThrowables(NULL);
1869
1870     // reset the stashed exception info
1871     pExInfo->m_pExceptionRecord = NULL;
1872     pExInfo->m_pContext = NULL;
1873     pExInfo->m_pExceptionPointers = NULL;
1874
1875     if  (pExInfo->m_pShadowSP)
1876     {
1877         *pExInfo->m_pShadowSP = 0;  // Reset the shadow SP
1878     }
1879
1880     // pExInfo->m_dEsp was set in ResumeAtJITEH(). It is the Esp of the
1881     // handler nesting level which catches the exception.
1882     esp = (void*)(size_t)pExInfo->m_dEsp;
1883
1884     pExInfo->UnwindExInfo(esp);
1885     
1886     // Prepare to sync managed exception state
1887     //
1888     // In a case when we're nested inside another catch block, the domain in which we're executing may not be the
1889     // same as the one the domain of the throwable that was just made the current throwable above. Therefore, we
1890     // make a special effort to preserve the domain of the throwable as we update the the last thrown object.
1891     //
1892     // This function (COMPlusEndCatch) can also be called by the in-proc debugger helper thread on x86 when
1893     // an attempt to SetIP takes place to set IP outside the catch clause. In such a case, managed thread object
1894     // will not be available. Thus, we should reset the severity only if its not such a thread.
1895     //
1896     // This behaviour (of debugger doing SetIP) is not allowed on 64bit since the catch clauses are implemented
1897     // as a seperate funclet and it's just not allowed to set the IP across EH scopes, such as from inside a catch 
1898     // clause to outside of the catch clause.
1899     bool fIsDebuggerHelperThread = (g_pDebugInterface == NULL) ? false : g_pDebugInterface->ThisIsHelperThread();
1900
1901     // Sync managed exception state, for the managed thread, based upon any active exception tracker
1902     pThread->SyncManagedExceptionState(fIsDebuggerHelperThread);
1903
1904     LOG((LF_EH, LL_INFO1000, "COMPlusPEndCatch: esp=%p\n", esp));
1905    
1906     END_CONTRACT_VIOLATION;
1907
1908     return esp;
1909 }
1910
1911 //
1912 // This function works in conjunction with JIT_EndCatch.  On input, the parameters are set as follows:
1913 //    ebp, ebx, edi, esi: the values of these registers at the end of the catch block
1914 //    *pRetAddress: the next instruction after the call to JIT_EndCatch
1915 //
1916 // On output, *pRetAddress is the instruction at which to resume execution.  This may be user code,
1917 // or it may be ThrowControlForThread (which will re-raise a pending ThreadAbortException).
1918 //
1919 // Returns the esp to set before resuming at *pRetAddress.
1920 //
1921 LPVOID STDCALL COMPlusEndCatch(LPVOID ebp, DWORD ebx, DWORD edi, DWORD esi, LPVOID* pRetAddress)
1922 {
1923     //
1924     // PopNestedExceptionRecords directly manipulates fs:[0] chain. This method can't have any EH!
1925     //
1926     STATIC_CONTRACT_THROWS;
1927     STATIC_CONTRACT_GC_TRIGGERS;
1928     STATIC_CONTRACT_MODE_COOPERATIVE;
1929     STATIC_CONTRACT_SO_INTOLERANT;
1930
1931     ETW::ExceptionLog::ExceptionCatchEnd();
1932     ETW::ExceptionLog::ExceptionThrownEnd();
1933
1934     void* esp = COMPlusEndCatchWorker(GetThread());
1935
1936     // We are going to resume at a handler nesting level whose esp is dEsp. Pop off any SEH records below it. This
1937     // would be the COMPlusNestedExceptionHandler we had inserted.
1938     PopNestedExceptionRecords(esp);
1939
1940     //
1941     // Set up m_OSContext for the call to COMPlusCheckForAbort
1942     //
1943     Thread* pThread = GetThread();
1944     _ASSERTE(pThread != NULL);
1945
1946     SetIP(pThread->m_OSContext, (PCODE)*pRetAddress);
1947     SetSP(pThread->m_OSContext, (TADDR)esp);
1948     SetFP(pThread->m_OSContext, (TADDR)ebp);
1949     pThread->m_OSContext->Ebx = ebx;
1950     pThread->m_OSContext->Edi = edi;
1951     pThread->m_OSContext->Esi = esi;
1952
1953     LPVOID throwControl = COMPlusCheckForAbort((UINT_PTR)*pRetAddress);
1954     if (throwControl)
1955         *pRetAddress = throwControl;
1956
1957     return esp;
1958 }
1959
1960 #endif // !DACCESS_COMPILE
1961
1962 PTR_CONTEXT GetCONTEXTFromRedirectedStubStackFrame(CONTEXT * pContext)
1963 {
1964     LIMITED_METHOD_DAC_CONTRACT;
1965     
1966     UINT_PTR stackSlot = pContext->Ebp + REDIRECTSTUB_EBP_OFFSET_CONTEXT;
1967     PTR_PTR_CONTEXT ppContext = dac_cast<PTR_PTR_CONTEXT>((TADDR)stackSlot);
1968     return *ppContext;
1969 }
1970
1971 #if !defined(DACCESS_COMPILE)
1972 #ifdef FEATURE_PAL
1973 static PEXCEPTION_REGISTRATION_RECORD CurrentSEHRecord = EXCEPTION_CHAIN_END;
1974 #endif
1975
1976 PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord()
1977 {
1978     WRAPPER_NO_CONTRACT;
1979
1980 #ifdef FEATURE_PAL
1981     LPVOID fs0 = CurrentSEHRecord;
1982 #else  // FEATURE_PAL
1983     LPVOID fs0 = (LPVOID)__readfsdword(0);
1984
1985 #if 0  // This walk is too expensive considering we hit it every time we a CONTRACT(NOTHROW)
1986 #ifdef _DEBUG
1987     EXCEPTION_REGISTRATION_RECORD *pEHR = (EXCEPTION_REGISTRATION_RECORD *)fs0;
1988     LPVOID spVal;
1989     __asm {
1990         mov spVal, esp
1991     }
1992
1993     // check that all the eh frames are all greater than the current stack value. If not, the
1994     // stack has been updated somehow w/o unwinding the SEH chain.
1995
1996     // LOG((LF_EH, LL_INFO1000000, "ER Chain:\n"));
1997     while (pEHR != NULL && pEHR != EXCEPTION_CHAIN_END) {
1998         // LOG((LF_EH, LL_INFO1000000, "\tp: prev:p handler:%x\n", pEHR, pEHR->Next, pEHR->Handler));
1999         if (pEHR < spVal) {
2000             if (gLastResumedExceptionFunc != 0)
2001                 _ASSERTE(!"Stack is greater than start of SEH chain - possible missing leave in handler. See gLastResumedExceptionHandler & gLastResumedExceptionFunc for info");
2002             else
2003                 _ASSERTE(!"Stack is greater than start of SEH chain (FS:0)");
2004         }
2005         if (pEHR->Handler == (void *)-1)
2006             _ASSERTE(!"Handler value has been corrupted");
2007
2008             _ASSERTE(pEHR < pEHR->Next);
2009
2010         pEHR = pEHR->Next;
2011     }
2012 #endif
2013 #endif // 0
2014 #endif // FEATURE_PAL
2015
2016     return (EXCEPTION_REGISTRATION_RECORD*) fs0;
2017 }
2018
2019 PEXCEPTION_REGISTRATION_RECORD GetFirstCOMPlusSEHRecord(Thread *pThread) {
2020     WRAPPER_NO_CONTRACT;
2021 #ifndef FEATURE_PAL
2022     EXCEPTION_REGISTRATION_RECORD *pEHR = *(pThread->GetExceptionListPtr());
2023     if (pEHR == EXCEPTION_CHAIN_END || IsUnmanagedToManagedSEHHandler(pEHR)) {
2024         return pEHR;
2025     } else {
2026         return GetNextCOMPlusSEHRecord(pEHR);
2027     }
2028 #else   // FEATURE_PAL
2029     PORTABILITY_ASSERT("GetFirstCOMPlusSEHRecord");
2030     return NULL;
2031 #endif  // FEATURE_PAL
2032 }
2033
2034
2035 PEXCEPTION_REGISTRATION_RECORD GetPrevSEHRecord(EXCEPTION_REGISTRATION_RECORD *next)
2036 {
2037     WRAPPER_NO_CONTRACT;
2038     _ASSERTE(IsUnmanagedToManagedSEHHandler(next));
2039
2040     EXCEPTION_REGISTRATION_RECORD *pEHR = GetCurrentSEHRecord();
2041     _ASSERTE(pEHR != 0 && pEHR != EXCEPTION_CHAIN_END);
2042
2043     EXCEPTION_REGISTRATION_RECORD *pBest = 0;
2044     while (pEHR != next) {
2045         if (IsUnmanagedToManagedSEHHandler(pEHR))
2046             pBest = pEHR;
2047         pEHR = pEHR->Next;
2048         _ASSERTE(pEHR != 0 && pEHR != EXCEPTION_CHAIN_END);
2049     }
2050
2051     return pBest;
2052 }
2053
2054 VOID SetCurrentSEHRecord(EXCEPTION_REGISTRATION_RECORD *pSEH)
2055 {
2056     WRAPPER_NO_CONTRACT;
2057 #ifndef FEATURE_PAL
2058     *GetThread()->GetExceptionListPtr() = pSEH;
2059 #else  // FEATURE_PAL
2060     _ASSERTE("NYI");
2061 #endif // FEATURE_PAL
2062 }
2063
2064
2065 //
2066 // Unwind pExinfo, pops FS:[0] handlers until the interception context SP, and
2067 // resumes at interception context.
2068 //
2069 VOID UnwindExceptionTrackerAndResumeInInterceptionFrame(ExInfo* pExInfo, EHContext* context)
2070 {
2071     STATIC_CONTRACT_NOTHROW;
2072     STATIC_CONTRACT_GC_NOTRIGGER;
2073     STATIC_CONTRACT_MODE_COOPERATIVE;
2074     STATIC_CONTRACT_SO_TOLERANT;
2075
2076     _ASSERTE(pExInfo && context);
2077
2078     pExInfo->UnwindExInfo((LPVOID)(size_t)context->Esp);
2079     PopNestedExceptionRecords((LPVOID)(size_t)context->Esp);
2080
2081     STRESS_LOG3(LF_EH|LF_CORDB, LL_INFO100, "UnwindExceptionTrackerAndResumeInInterceptionFrame: completing intercept at EIP = %p  ESP = %p EBP = %p\n", context->Eip, context->Esp, context->Ebp);
2082
2083     ResumeAtJitEHHelper(context);
2084     UNREACHABLE_MSG("Should never return from ResumeAtJitEHHelper!");
2085 }
2086
2087 //
2088 // Pop SEH records below the given target ESP. This is only used to pop nested exception records.
2089 // If bCheckForUnknownHandlers is set, it only checks for unknown FS:[0] handlers.
2090 //
2091 BOOL PopNestedExceptionRecords(LPVOID pTargetSP, BOOL bCheckForUnknownHandlers)
2092 {
2093     // No CONTRACT here, because we can't run the risk of it pushing any SEH into the current method.
2094     STATIC_CONTRACT_NOTHROW;
2095     STATIC_CONTRACT_GC_NOTRIGGER;
2096     STATIC_CONTRACT_SO_TOLERANT;
2097
2098 #ifndef FEATURE_PAL
2099     PEXCEPTION_REGISTRATION_RECORD pEHR = GetCurrentSEHRecord();
2100
2101     while ((LPVOID)pEHR < pTargetSP)
2102     {
2103         //
2104         // The only handler type we're allowed to have below the limit on the FS:0 chain in these cases is a nested
2105         // exception record, so we verify that here.
2106         //
2107         // There is a special case, of course: for an unhandled exception, when the default handler does the exit
2108         // unwind, we may have an exception that escapes a finally clause, thus replacing the original unhandled
2109         // exception. If we find a catcher for that new exception, then we'll go ahead and do our own unwind, then
2110         // jump to the catch. When we are called here, just before jumpping to the catch, we'll pop off our nested
2111         // handlers, then we'll pop off one more handler: the handler that ntdll!ExecuteHandler2 pushed before
2112         // calling our nested handler. We go ahead and pop off that handler, too. Its okay, its only there to catch
2113         // exceptions from handlers and turn them into collided unwind status codes... there's no cleanup in the
2114         // handler that we're removing, and that's the important point. The handler that ExecuteHandler2 pushes
2115         // isn't a public export from ntdll, but its named "UnwindHandler" and is physically shortly after
2116         // ExecuteHandler2 in ntdll.
2117         //
2118         static HINSTANCE ExecuteHandler2Module = 0;
2119         static BOOL ExecuteHandler2ModuleInited = FALSE;
2120
2121         // Cache the handle to the dll with the handler pushed by ExecuteHandler2.
2122         if (!ExecuteHandler2ModuleInited)
2123         {
2124             ExecuteHandler2Module = WszGetModuleHandle(W("ntdll.dll"));
2125             ExecuteHandler2ModuleInited = TRUE;
2126         }
2127
2128         if (bCheckForUnknownHandlers)
2129         {
2130             if (!IsComPlusNestedExceptionRecord(pEHR) || 
2131                 !((ExecuteHandler2Module != NULL) && IsIPInModule(ExecuteHandler2Module, (PCODE)pEHR->Handler)))
2132             {
2133                 return TRUE;
2134             }
2135         }
2136 #ifdef _DEBUG
2137         else
2138         {
2139             // Note: if we can't find the module containing ExecuteHandler2, we'll just be really strict and require
2140             // that we're only popping nested handlers.
2141             _ASSERTE(IsComPlusNestedExceptionRecord(pEHR) ||
2142                      ((ExecuteHandler2Module != NULL) && IsIPInModule(ExecuteHandler2Module, (PCODE)pEHR->Handler)));
2143         }
2144 #endif // _DEBUG
2145
2146         pEHR = pEHR->Next;
2147     }
2148
2149     if (!bCheckForUnknownHandlers)
2150     {
2151         SetCurrentSEHRecord(pEHR);
2152     }
2153     return FALSE;
2154 #else   // FEATURE_PAL
2155     PORTABILITY_ASSERT("PopNestedExceptionRecords");
2156     return FALSE;
2157 #endif  // FEATURE_PAL
2158 }
2159
2160 //
2161 // This is implemented differently from the PopNestedExceptionRecords above because it's called in the context of
2162 // the DebuggerRCThread to operate on the stack of another thread.
2163 //
2164 VOID PopNestedExceptionRecords(LPVOID pTargetSP, CONTEXT *pCtx, void *pSEH)
2165 {
2166     // No CONTRACT here, because we can't run the risk of it pushing any SEH into the current method.
2167     STATIC_CONTRACT_NOTHROW;
2168     STATIC_CONTRACT_GC_NOTRIGGER;
2169
2170 #ifdef _DEBUG
2171     LOG((LF_CORDB,LL_INFO1000, "\nPrintSEHRecords:\n"));
2172
2173     EXCEPTION_REGISTRATION_RECORD *pEHR = (EXCEPTION_REGISTRATION_RECORD *)(size_t)*(DWORD *)pSEH;
2174
2175     // check that all the eh frames are all greater than the current stack value. If not, the
2176     // stack has been updated somehow w/o unwinding the SEH chain.
2177     while (pEHR != NULL && pEHR != EXCEPTION_CHAIN_END)
2178     {
2179         LOG((LF_EH, LL_INFO1000000, "\t%08x: next:%08x handler:%x\n", pEHR, pEHR->Next, pEHR->Handler));
2180         pEHR = pEHR->Next;
2181     }
2182 #endif
2183
2184     DWORD dwCur = *(DWORD*)pSEH; // 'EAX' in the original routine
2185     DWORD dwPrev = (DWORD)(size_t)pSEH;
2186
2187     while (dwCur < (DWORD)(size_t)pTargetSP)
2188     {
2189         // Watch for the OS handler
2190         // for nested exceptions, or any C++ handlers for destructors in our call
2191         // stack, or anything else.
2192         if (dwCur < (DWORD)GetSP(pCtx))
2193             dwPrev = dwCur;
2194
2195         dwCur = *(DWORD *)(size_t)dwCur;
2196
2197         LOG((LF_CORDB,LL_INFO10000, "dwCur: 0x%x dwPrev:0x%x pTargetSP:0x%x\n",
2198             dwCur, dwPrev, pTargetSP));
2199     }
2200
2201     *(DWORD *)(size_t)dwPrev = dwCur;
2202
2203 #ifdef _DEBUG
2204     pEHR = (EXCEPTION_REGISTRATION_RECORD *)(size_t)*(DWORD *)pSEH;
2205     // check that all the eh frames are all greater than the current stack value. If not, the
2206     // stack has been updated somehow w/o unwinding the SEH chain.
2207
2208     LOG((LF_CORDB,LL_INFO1000, "\nPopSEHRecords:\n"));
2209     while (pEHR != NULL && pEHR != (void *)-1)
2210     {
2211         LOG((LF_EH, LL_INFO1000000, "\t%08x: next:%08x handler:%x\n", pEHR, pEHR->Next, pEHR->Handler));
2212         pEHR = pEHR->Next;
2213     }
2214 #endif
2215 }
2216
2217 //==========================================================================
2218 // COMPlusThrowCallback
2219 //
2220 //==========================================================================
2221
2222 /*
2223  *
2224  * COMPlusThrowCallbackHelper
2225  *
2226  * This function is a simple helper function for COMPlusThrowCallback.  It is needed
2227  * because of the EX_TRY macro.  This macro does an alloca(), which allocates space
2228  * off the stack, not free'ing it.  Thus, doing a EX_TRY in a loop can easily result
2229  * in a stack overflow error.  By factoring out the EX_TRY into a separate function,
2230  * we recover that stack space.
2231  *
2232  * Parameters:
2233  *   pJitManager - The JIT manager that will filter the EH.
2234  *   pCf - The frame to crawl.
2235  *   EHClausePtr
2236  *   nestingLevel
2237  *   pThread - Used to determine if the thread is throwable or not.
2238  *
2239  * Return:
2240  *   Exception status.
2241  *
2242  */
2243 int COMPlusThrowCallbackHelper(IJitManager *pJitManager,
2244                                CrawlFrame *pCf,
2245                                ThrowCallbackType* pData,
2246                                EE_ILEXCEPTION_CLAUSE  *EHClausePtr,
2247                                DWORD nestingLevel,
2248                                OBJECTREF throwable,
2249                                Thread *pThread
2250                               )
2251 {
2252     CONTRACTL
2253     {
2254         NOTHROW;
2255         GC_TRIGGERS;
2256         MODE_COOPERATIVE;
2257     }
2258     CONTRACTL_END;
2259
2260     int iFilt = 0;
2261
2262 #ifndef FEATURE_PAL
2263     EX_TRY
2264     {
2265         GCPROTECT_BEGIN (throwable);
2266
2267         // We want to call filters even if the thread is aborting, so suppress abort
2268         // checks while the filter runs.
2269         ThreadPreventAsyncHolder preventAbort;
2270
2271         BYTE* startAddress = (BYTE*)pCf->GetCodeInfo()->GetStartAddress();
2272         iFilt = ::CallJitEHFilter(pCf, startAddress, EHClausePtr, nestingLevel, throwable);
2273
2274         GCPROTECT_END();
2275     }
2276     EX_CATCH
2277     {
2278         // We had an exception in filter invocation that remained unhandled.
2279         // Sync managed exception state, for the managed thread, based upon the active exception tracker.
2280         pThread->SyncManagedExceptionState(false);
2281         
2282         //
2283         // Swallow exception.  Treat as exception continue search.
2284         //
2285         iFilt = EXCEPTION_CONTINUE_SEARCH;
2286
2287     }
2288     EX_END_CATCH(SwallowAllExceptions)
2289
2290     return iFilt;
2291 #else   // FEATURE_PAL
2292     PORTABILITY_ASSERT("COMPlusThrowCallbackHelper");
2293     return EXCEPTION_CONTINUE_SEARCH;
2294 #endif  // FEATURE_PAL
2295 }
2296
2297 //******************************************************************************
2298 // The stack walk callback for exception handling on x86.
2299 // Returns one of:
2300 //    SWA_CONTINUE    = 0,    // continue walking
2301 //    SWA_ABORT       = 1,    // stop walking, early out in "failure case"
2302 //    SWA_FAILED      = 2     // couldn't walk stack
2303 StackWalkAction COMPlusThrowCallback(       // SWA value
2304     CrawlFrame  *pCf,                       // Data from StackWalkFramesEx
2305     ThrowCallbackType *pData)               // Context data passed through from CPFH
2306 {
2307     // We don't want to use a runtime contract here since this codepath is used during
2308     // the processing of a hard SO. Contracts use a significant amount of stack
2309     // which we can't afford for those cases.
2310     STATIC_CONTRACT_THROWS;
2311     STATIC_CONTRACT_GC_TRIGGERS;
2312     STATIC_CONTRACT_MODE_COOPERATIVE;
2313
2314     Frame *pFrame = pCf->GetFrame();
2315     MethodDesc *pFunc = pCf->GetFunction();
2316
2317     #if defined(_DEBUG)
2318     #define METHODNAME(pFunc) (pFunc?pFunc->m_pszDebugMethodName:"<n/a>")
2319     #else
2320     #define METHODNAME(pFunc) "<n/a>"
2321     #endif
2322     STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusThrowCallback: STACKCRAWL method:%pM ('%s'), Frame:%p, FrameVtable = %pV\n",
2323         pFunc, METHODNAME(pFunc), pFrame, pCf->IsFrameless()?0:(*(void**)pFrame));
2324     #undef METHODNAME
2325
2326     Thread *pThread = GetThread();
2327
2328     if (pFrame && pData->pTopFrame == pFrame)
2329         /* Don't look past limiting frame if there is one */
2330         return SWA_ABORT;
2331
2332     if (!pFunc)
2333         return SWA_CONTINUE;
2334
2335     if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pCf))
2336     {
2337         return SWA_CONTINUE;
2338     }
2339
2340     ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
2341
2342     _ASSERTE(!pData->bIsUnwind);
2343 #ifdef _DEBUG
2344     // It SHOULD be the case that any frames we consider live between this exception
2345     // record and the previous one.
2346     if (!pExInfo->m_pPrevNestedInfo) {
2347         if (pData->pCurrentExceptionRecord) {
2348             if (pFrame) _ASSERTE(pData->pCurrentExceptionRecord > pFrame);
2349             if (pCf->IsFrameless()) _ASSERTE((ULONG_PTR)pData->pCurrentExceptionRecord >= GetRegdisplaySP(pCf->GetRegisterSet()));
2350         }
2351         if (pData->pPrevExceptionRecord) {
2352             // FCALLS have an extra SEH record in debug because of the desctructor
2353             // associated with ForbidGC checking.  This is benign, so just ignore it.
2354             if (pFrame) _ASSERTE(pData->pPrevExceptionRecord < pFrame || pFrame->GetVTablePtr() == HelperMethodFrame::GetMethodFrameVPtr());
2355             if (pCf->IsFrameless()) _ASSERTE((ULONG_PTR)pData->pPrevExceptionRecord <= GetRegdisplaySP(pCf->GetRegisterSet()));
2356         }
2357     }
2358 #endif
2359
2360     UINT_PTR currentIP = 0;
2361     UINT_PTR currentSP = 0;
2362
2363     if (pCf->IsFrameless())
2364     {
2365         currentIP = (UINT_PTR)GetControlPC(pCf->GetRegisterSet());
2366         currentSP = (UINT_PTR)GetRegdisplaySP(pCf->GetRegisterSet());
2367     }
2368     else if (InlinedCallFrame::FrameHasActiveCall(pFrame))
2369     {
2370         // don't have the IP, SP for native code
2371         currentIP = 0;
2372         currentSP = 0;
2373     }
2374     else
2375     {
2376         currentIP = (UINT_PTR)(pCf->GetFrame()->GetIP());
2377         currentSP = 0; //Don't have an SP to get.
2378     }
2379     
2380     if (!pFunc->IsILStub())
2381     {
2382         // Append the current frame to the stack trace and save the save trace to the managed Exception object.
2383         pExInfo->m_StackTraceInfo.AppendElement(pData->bAllowAllocMem, currentIP, currentSP, pFunc, pCf);
2384
2385         pExInfo->m_StackTraceInfo.SaveStackTrace(pData->bAllowAllocMem,
2386                                                  pThread->GetThrowableAsHandle(),
2387                                                  pData->bReplaceStack,
2388                                                  pData->bSkipLastElement);
2389     }
2390     else
2391     {
2392         LOG((LF_EH, LL_INFO1000, "COMPlusThrowCallback: Skipping AppendElement/SaveStackTrace for IL stub MD %p\n", pFunc));
2393     }
2394
2395     // Fire an exception thrown ETW event when an exception occurs
2396     ETW::ExceptionLog::ExceptionThrown(pCf, pData->bSkipLastElement, pData->bReplaceStack);
2397
2398     // Reset the flags.  These flags are set only once before each stack walk done by LookForHandler(), and
2399     // they apply only to the first frame we append to the stack trace.  Subsequent frames are always appended.
2400     if (pData->bReplaceStack)
2401     {
2402         pData->bReplaceStack = FALSE;
2403     }
2404     if (pData->bSkipLastElement)
2405     {
2406         pData->bSkipLastElement = FALSE;
2407     }
2408
2409     // now we've got the stack trace, if we aren't allowed to catch this and we're first pass, return
2410     if (pData->bDontCatch)
2411         return SWA_CONTINUE;
2412
2413     if (!pCf->IsFrameless())
2414     {
2415         // @todo - remove this once SIS is fully enabled.
2416         extern bool g_EnableSIS;
2417         if (g_EnableSIS)
2418         {
2419             // For debugger, we may want to notify 1st chance exceptions if they're coming out of a stub.
2420             // We recognize stubs as Frames with a M2U transition type. The debugger's stackwalker also
2421             // recognizes these frames and publishes ICorDebugInternalFrames in the stackwalk. It's
2422             // important to use pFrame as the stack address so that the Exception callback matches up
2423             // w/ the ICorDebugInternlFrame stack range.
2424             if (CORDebuggerAttached())
2425             {
2426                 Frame * pFrameStub = pCf->GetFrame();
2427                 Frame::ETransitionType t = pFrameStub->GetTransitionType();
2428                 if (t == Frame::TT_M2U)
2429                 {
2430                     // Use address of the frame as the stack address.
2431                     currentSP = (SIZE_T) ((void*) pFrameStub);
2432                     currentIP = 0; // no IP.
2433                     EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedException(pThread, (SIZE_T)currentIP, (SIZE_T)currentSP);
2434 #ifdef FEATURE_EXCEPTION_NOTIFICATIONS
2435                     // Deliver the FirstChanceNotification after the debugger, if not already delivered.
2436                     if (!pExInfo->DeliveredFirstChanceNotification())
2437                     {
2438                         ExceptionNotifications::DeliverFirstChanceNotification();
2439                     }
2440 #endif // FEATURE_EXCEPTION_NOTIFICATIONS
2441                 }
2442             }
2443         }
2444         return SWA_CONTINUE;
2445     }
2446
2447     bool fIsILStub = pFunc->IsILStub();
2448     bool fGiveDebuggerAndProfilerNotification = !fIsILStub;
2449     BOOL fMethodCanHandleException = TRUE;
2450
2451     MethodDesc * pUserMDForILStub = NULL;
2452     Frame * pILStubFrame = NULL;
2453     if (fIsILStub)
2454         pUserMDForILStub = GetUserMethodForILStub(pThread, currentSP, pFunc, &pILStubFrame);
2455
2456 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2457     CorruptionSeverity currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity();
2458     {
2459         // We must defer to the MethodDesc of the user method instead of the IL stub
2460         // itself because the user can specify the policy on a per-method basis and 
2461         // that won't be reflected via the IL stub's MethodDesc.
2462         MethodDesc * pMDWithCEAttribute = fIsILStub ? pUserMDForILStub : pFunc;
2463
2464         // Check if the exception can be delivered to the method? It will check if the exception
2465         // is a CE or not. If it is, it will check if the method can process it or not.
2466         fMethodCanHandleException = CEHelper::CanMethodHandleException(currentSeverity, pMDWithCEAttribute);
2467     }
2468 #endif // FEATURE_CORRUPTING_EXCEPTIONS
2469
2470     // Let the profiler know that we are searching for a handler within this function instance
2471     if (fGiveDebuggerAndProfilerNotification)
2472         EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pFunc);
2473
2474     // The following debugger notification and AppDomain::FirstChanceNotification should be scoped together
2475     // since the AD notification *must* follow immediately after the debugger's notification.
2476     {
2477 #ifdef DEBUGGING_SUPPORTED
2478         //
2479         // Go ahead and notify any debugger of this exception.
2480         //
2481         EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedException(pThread, (SIZE_T)currentIP, (SIZE_T)currentSP);
2482
2483         if (CORDebuggerAttached() && pExInfo->m_ExceptionFlags.DebuggerInterceptInfo())
2484         {
2485             return SWA_ABORT;
2486         }
2487 #endif // DEBUGGING_SUPPORTED
2488
2489 #ifdef FEATURE_EXCEPTION_NOTIFICATIONS
2490         // Attempt to deliver the first chance notification to the AD only *AFTER* the debugger
2491         // has done that, provided we have not already done that.
2492         if (!pExInfo->DeliveredFirstChanceNotification())
2493         {
2494             ExceptionNotifications::DeliverFirstChanceNotification();
2495         }
2496 #endif // FEATURE_EXCEPTION_NOTIFICATIONS
2497     }
2498     IJitManager* pJitManager = pCf->GetJitManager();
2499     _ASSERTE(pJitManager);
2500     EH_CLAUSE_ENUMERATOR pEnumState;
2501     unsigned EHCount = 0;
2502
2503 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2504     // If exception cannot be handled, then just bail out. We shouldnt examine the EH clauses
2505     // in such a method.
2506     if (!fMethodCanHandleException)
2507     {
2508         LOG((LF_EH, LL_INFO100, "COMPlusThrowCallback - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pFunc));
2509
2510         // Set the flag to skip this frame since the CE cannot be delivered
2511         _ASSERTE(currentSeverity == ProcessCorrupting);
2512
2513         // Ensure EHClause count is zero
2514         EHCount = 0;
2515     }
2516     else
2517 #endif // FEATURE_CORRUPTING_EXCEPTIONS
2518     {
2519         EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
2520     }
2521
2522     if (EHCount == 0)
2523     {
2524         // Inform the profiler that we're leaving, and what pass we're on
2525         if (fGiveDebuggerAndProfilerNotification)
2526             EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc);
2527         return SWA_CONTINUE;
2528     }
2529
2530     TypeHandle thrownType = TypeHandle();
2531     // if we are being called on an unwind for an exception that we did not try to catch, eg.
2532     // an internal EE exception, then pThread->GetThrowable will be null
2533     {
2534         OBJECTREF  throwable = pThread->GetThrowable();
2535         if (throwable != NULL)
2536         {
2537             throwable = PossiblyUnwrapThrowable(throwable, pCf->GetAssembly());
2538             thrownType = TypeHandle(throwable->GetTrueMethodTable());
2539         }
2540     }
2541
2542     PREGDISPLAY regs = pCf->GetRegisterSet();
2543     BYTE *pStack = (BYTE *) GetRegdisplaySP(regs);
2544 #ifdef DEBUGGING_SUPPORTED
2545     BYTE *pHandlerEBP   = (BYTE *) GetRegdisplayFP(regs);
2546 #endif
2547
2548     DWORD offs = (DWORD)pCf->GetRelOffset();  //= (BYTE*) (*regs->pPC) - (BYTE*) pCf->GetStartAddress();
2549     STRESS_LOG1(LF_EH, LL_INFO10000, "COMPlusThrowCallback: offset is %d\n", offs);
2550
2551     EE_ILEXCEPTION_CLAUSE EHClause;
2552     unsigned start_adjust, end_adjust;
2553
2554     start_adjust = !(pCf->HasFaulted() || pCf->IsIPadjusted());
2555     end_adjust = pCf->IsActiveFunc();
2556
2557     for(ULONG i=0; i < EHCount; i++)
2558     {
2559         pJitManager->GetNextEHClause(&pEnumState, &EHClause);
2560         _ASSERTE(IsValidClause(&EHClause));
2561
2562         STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusThrowCallback: considering '%s' clause [%d,%d], ofs:%d\n",
2563             (IsFault(&EHClause) ? "fault" : (
2564             IsFinally(&EHClause) ? "finally" : (
2565             IsFilterHandler(&EHClause) ? "filter" : (
2566             IsTypedHandler(&EHClause) ? "typed" : "unknown")))),
2567             EHClause.TryStartPC,
2568             EHClause.TryEndPC,
2569             offs
2570             );
2571
2572         // Checking the exception range is a bit tricky because
2573         // on CPU faults (null pointer access, div 0, ..., the IP points
2574         // to the faulting instruction, but on calls, the IP points
2575         // to the next instruction.
2576         // This means that we should not include the start point on calls
2577         // as this would be a call just preceding the try block.
2578         // Also, we should include the end point on calls, but not faults.
2579
2580         // If we're in the FILTER part of a filter clause, then we
2581         // want to stop crawling.  It's going to be caught in a
2582         // EX_CATCH just above us.  If not, the exception
2583         if (   IsFilterHandler(&EHClause)
2584             && (   offs > EHClause.FilterOffset
2585                 || (offs == EHClause.FilterOffset && !start_adjust) )
2586             && (   offs < EHClause.HandlerStartPC
2587                 || (offs == EHClause.HandlerStartPC && !end_adjust) )) {
2588
2589             STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusThrowCallback: Fault inside filter [%d,%d] startAdj %d endAdj %d\n",
2590                         EHClause.FilterOffset, EHClause.HandlerStartPC, start_adjust, end_adjust);
2591             
2592             if (fGiveDebuggerAndProfilerNotification)
2593                 EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc);
2594             return SWA_ABORT;
2595         }
2596
2597         if ( (offs < EHClause.TryStartPC) ||
2598              (offs > EHClause.TryEndPC) ||
2599              (offs == EHClause.TryStartPC && start_adjust) ||
2600              (offs == EHClause.TryEndPC && end_adjust))
2601             continue;
2602
2603         BOOL typeMatch = FALSE;
2604         BOOL isTypedHandler = IsTypedHandler(&EHClause);
2605
2606         if (isTypedHandler && !thrownType.IsNull())
2607         {
2608             if (EHClause.TypeHandle == (void*)(size_t)mdTypeRefNil)
2609             {
2610                 // this is a catch(...)
2611                 typeMatch = TRUE;
2612             }
2613             else
2614             {
2615                 TypeHandle exnType = pJitManager->ResolveEHClause(&EHClause,pCf);
2616
2617                 // if doesn't have cached class then class wasn't loaded so couldn't have been thrown
2618                 typeMatch = !exnType.IsNull() && ExceptionIsOfRightType(exnType, thrownType);
2619             }
2620         }
2621
2622         // <TODO>@PERF: Is this too expensive? Consider storing the nesting level
2623         // instead of the HandlerEndPC.</TODO>
2624
2625         // Determine the nesting level of EHClause. Just walk the table
2626         // again, and find out how many handlers enclose it
2627         DWORD nestingLevel = 0;
2628
2629         if (IsFaultOrFinally(&EHClause))
2630             continue;
2631         if (isTypedHandler)
2632         {
2633             LOG((LF_EH, LL_INFO100, "COMPlusThrowCallback: %s match for typed handler.\n", typeMatch?"Found":"Did not find"));
2634             if (!typeMatch)
2635             {
2636                 continue;
2637             }
2638         }
2639         else
2640         {
2641             // Must be an exception filter (__except() part of __try{}__except(){}).
2642             nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager,
2643                                                                pCf->GetMethodToken(),
2644                                                                EHClause.HandlerStartPC);
2645
2646             // We just need *any* address within the method. This will let the debugger
2647             // resolve the EnC version of the method.
2648             PCODE pMethodAddr = GetControlPC(regs);            
2649             if (fGiveDebuggerAndProfilerNotification)
2650                 EEToDebuggerExceptionInterfaceWrapper::ExceptionFilter(pFunc, pMethodAddr, EHClause.FilterOffset, pHandlerEBP);
2651
2652             UINT_PTR uStartAddress = (UINT_PTR)pCf->GetCodeInfo()->GetStartAddress();
2653
2654             // save clause information in the exinfo
2655             pExInfo->m_EHClauseInfo.SetInfo(COR_PRF_CLAUSE_FILTER, 
2656                                             uStartAddress + EHClause.FilterOffset, 
2657                                             StackFrame((UINT_PTR)pHandlerEBP));
2658            
2659             // Let the profiler know we are entering a filter
2660             if (fGiveDebuggerAndProfilerNotification)
2661                 EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFilterEnter(pFunc);
2662
2663             COUNTER_ONLY(GetPerfCounters().m_Excep.cFiltersExecuted++);
2664
2665             STRESS_LOG3(LF_EH, LL_INFO10, "COMPlusThrowCallback: calling filter code, EHClausePtr:%08x, Start:%08x, End:%08x\n",
2666                 &EHClause, EHClause.HandlerStartPC, EHClause.HandlerEndPC);
2667
2668             OBJECTREF throwable = PossiblyUnwrapThrowable(pThread->GetThrowable(), pCf->GetAssembly());
2669
2670             pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE);
2671
2672             int iFilt = COMPlusThrowCallbackHelper(pJitManager,
2673                                                    pCf,
2674                                                    pData,
2675                                                    &EHClause,
2676                                                    nestingLevel,
2677                                                    throwable,
2678                                                    pThread);
2679
2680             pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE);
2681
2682             // Let the profiler know we are leaving a filter
2683             if (fGiveDebuggerAndProfilerNotification)
2684                 EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFilterLeave();
2685
2686             pExInfo->m_EHClauseInfo.ResetInfo();
2687
2688             if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pCf))
2689             {
2690                 if (fGiveDebuggerAndProfilerNotification)
2691                     EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc);
2692                 return SWA_CONTINUE;
2693             }
2694
2695             // If this filter didn't want the exception, keep looking.
2696             if (EXCEPTION_EXECUTE_HANDLER != iFilt)
2697                 continue;
2698         }
2699
2700         // Record this location, to stop the unwind phase, later.
2701         pData->pFunc = pFunc;
2702         pData->dHandler = i;
2703         pData->pStack = pStack;
2704
2705         // Notify the profiler that a catcher has been found
2706         if (fGiveDebuggerAndProfilerNotification)
2707         {
2708             EEToProfilerExceptionInterfaceWrapper::ExceptionSearchCatcherFound(pFunc);
2709             EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc);
2710         }
2711
2712 #ifdef DEBUGGING_SUPPORTED
2713         //
2714         // Notify debugger that a catcher has been found.
2715         //
2716         if (fIsILStub)
2717         {
2718             EEToDebuggerExceptionInterfaceWrapper::NotifyOfCHFFilter(pExInfo->m_pExceptionPointers, pILStubFrame);
2719         }
2720         else
2721         if (fGiveDebuggerAndProfilerNotification &&
2722             CORDebuggerAttached() && !pExInfo->m_ExceptionFlags.DebuggerInterceptInfo())
2723         {
2724             _ASSERTE(pData);
2725             // We just need *any* address within the method. This will let the debugger
2726             // resolve the EnC version of the method.
2727             PCODE pMethodAddr = GetControlPC(regs);            
2728
2729             EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedExceptionCatcherFound(pThread,
2730                                                                                            pData->pFunc, pMethodAddr,
2731                                                                                            (SIZE_T)pData->pStack,
2732                                                                                            &EHClause);
2733         }
2734 #endif // DEBUGGING_SUPPORTED
2735
2736         return SWA_ABORT;
2737     }
2738     if (fGiveDebuggerAndProfilerNotification)
2739         EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc);
2740     return SWA_CONTINUE;
2741 } // StackWalkAction COMPlusThrowCallback()
2742
2743
2744 //==========================================================================
2745 // COMPlusUnwindCallback
2746 //==========================================================================
2747
2748 #if defined(_MSC_VER)
2749 #pragma warning(push)
2750 #pragma warning (disable : 4740) // There is inline asm code in this function, which disables
2751                                  // global optimizations.
2752 #pragma warning (disable : 4731)
2753 #endif
2754 StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData)
2755 {
2756     STATIC_CONTRACT_THROWS;
2757     STATIC_CONTRACT_GC_NOTRIGGER;
2758     STATIC_CONTRACT_MODE_COOPERATIVE;
2759
2760     _ASSERTE(pData->bIsUnwind);
2761
2762     Frame *pFrame = pCf->GetFrame();
2763     MethodDesc *pFunc = pCf->GetFunction();
2764
2765     #if defined(_DEBUG)
2766     #define METHODNAME(pFunc) (pFunc?pFunc->m_pszDebugMethodName:"<n/a>")
2767     #else
2768     #define METHODNAME(pFunc) "<n/a>"
2769     #endif
2770     STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: STACKCRAWL method:%pM ('%s'), Frame:%p, FrameVtable = %pV\n",
2771         pFunc, METHODNAME(pFunc), pFrame, pCf->IsFrameless()?0:(*(void**)pFrame));
2772     #undef METHODNAME
2773
2774     if (pFrame && pData->pTopFrame == pFrame)
2775         /* Don't look past limiting frame if there is one */
2776         return SWA_ABORT;
2777
2778     if (!pFunc)
2779         return SWA_CONTINUE;
2780
2781     if (!pCf->IsFrameless())
2782         return SWA_CONTINUE;
2783
2784     Thread *pThread = GetThread();
2785
2786     // If the thread is being RudeAbort, we will not run any finally
2787     if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pCf))
2788     {
2789         return SWA_CONTINUE;
2790     }
2791
2792     IJitManager* pJitManager = pCf->GetJitManager();
2793     _ASSERTE(pJitManager);
2794
2795     ExInfo *pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
2796
2797     PREGDISPLAY regs = pCf->GetRegisterSet();
2798     BYTE *pStack = (BYTE *) GetRegdisplaySP(regs);
2799
2800     TypeHandle thrownType = TypeHandle();
2801
2802     BOOL fCanMethodHandleException = TRUE;
2803 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2804     // MethodDesc's security information (i.e. whether it is critical or transparent) is calculated lazily.
2805     // If this method's security information was not precalculated, then it would have been in the first pass
2806     // already using Security::IsMethodCritical which could take have taken us down a path which is GC_TRIGGERS.
2807     //
2808     // 
2809     // However, this unwind callback (for X86) is GC_NOTRIGGER and at this point the security information would have been
2810     // calculated already. Hence, we wouldnt endup in the GC_TRIGGERS path. Thus, to keep SCAN.EXE (static contract analyzer) happy, 
2811     // we will pass a FALSE to the CanMethodHandleException call, indicating we dont need to calculate security information (and thus,
2812     // not go down the GC_TRIGGERS path.
2813     //
2814     // Check if the exception can be delivered to the method? It will check if the exception
2815     // is a CE or not. If it is, it will check if the method can process it or not.
2816     CorruptionSeverity currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity();
2817     
2818     // We have to do this check for x86 since, unlike 64bit which will setup a new exception tracker for longjmp,
2819     // x86 only sets up new trackers in the first pass (and longjmp is 2nd pass only exception). Hence, we pass
2820     // this information in the callback structure without affecting any existing exception tracker (incase longjmp was
2821     // a nested exception).
2822     if (pData->m_fIsLongJump)
2823     {
2824         // Longjump is not a CSE. With a CSE in progress, this can be invoked by either:
2825         //
2826         // 1) Managed code (e.g. finally/fault/catch), OR
2827         // 2) By native code
2828         //
2829         // In scenario (1), managed code can invoke it only if it was attributed with HPCSE attribute. Thus,
2830         // longjmp is no different than managed code doing a "throw new Exception();".
2831         //
2832         // In scenario (2), longjmp is no different than any other non-CSE native exception raised.
2833         //
2834         // In both these case, longjmp should be treated as non-CSE. Since x86 does not setup a tracker for 
2835         // it (see comment above), we pass this information (of whether the current exception is a longjmp or not)
2836         // to this callback (from UnwindFrames) to setup the correct corruption severity.
2837         //
2838         // http://www.nynaeve.net/?p=105 has a brief description of how exception-safe setjmp/longjmp works.
2839         currentSeverity = NotCorrupting;
2840     }
2841     {
2842         MethodDesc * pFuncWithCEAttribute = pFunc;
2843         Frame * pILStubFrame = NULL;
2844         if (pFunc->IsILStub())
2845         {
2846             // We must defer to the MethodDesc of the user method instead of the IL stub
2847             // itself because the user can specify the policy on a per-method basis and 
2848             // that won't be reflected via the IL stub's MethodDesc.
2849             pFuncWithCEAttribute = GetUserMethodForILStub(pThread, (UINT_PTR)pStack, pFunc, &pILStubFrame);
2850         }
2851         fCanMethodHandleException = CEHelper::CanMethodHandleException(currentSeverity, pFuncWithCEAttribute, FALSE);
2852     }
2853 #endif // FEATURE_CORRUPTING_EXCEPTIONS
2854
2855 #ifdef DEBUGGING_SUPPORTED
2856     LOG((LF_EH, LL_INFO1000, "COMPlusUnwindCallback: Intercept %d, pData->pFunc 0x%X, pFunc 0x%X, pData->pStack 0x%X, pStack 0x%X\n",
2857          pExInfo->m_ExceptionFlags.DebuggerInterceptInfo(),
2858          pData->pFunc,
2859          pFunc,
2860          pData->pStack,
2861          pStack));
2862
2863     //
2864     // If the debugger wants to intercept this exception here, go do that.
2865     //
2866     if (pExInfo->m_ExceptionFlags.DebuggerInterceptInfo() && (pData->pFunc == pFunc) && (pData->pStack == pStack))
2867     {
2868         goto LDoDebuggerIntercept;
2869     }
2870 #endif
2871
2872     bool fGiveDebuggerAndProfilerNotification;
2873     fGiveDebuggerAndProfilerNotification = !pFunc->IsILStub();
2874
2875     // Notify the profiler of the function we're dealing with in the unwind phase
2876     if (fGiveDebuggerAndProfilerNotification)
2877         EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pFunc);
2878
2879     EH_CLAUSE_ENUMERATOR pEnumState;
2880     unsigned EHCount;
2881
2882 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2883     if (!fCanMethodHandleException)
2884     {
2885         LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pFunc));
2886
2887         // Set the flag to skip this frame since the CE cannot be delivered
2888         _ASSERTE(currentSeverity == ProcessCorrupting);
2889
2890         // Force EHClause count to be zero
2891         EHCount = 0;
2892     }
2893     else
2894 #endif // FEATURE_CORRUPTING_EXCEPTIONS
2895     {
2896         EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
2897     }
2898
2899     if (EHCount == 0)
2900     {
2901         // Inform the profiler that we're leaving, and what pass we're on
2902         if (fGiveDebuggerAndProfilerNotification)
2903             EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pFunc);
2904
2905         return SWA_CONTINUE;
2906     }
2907
2908     // if we are being called on an unwind for an exception that we did not try to catch, eg.
2909     // an internal EE exception, then pThread->GetThrowable will be null
2910     {
2911         OBJECTREF  throwable = pThread->GetThrowable();
2912         if (throwable != NULL)
2913         {
2914             throwable = PossiblyUnwrapThrowable(throwable, pCf->GetAssembly());
2915             thrownType = TypeHandle(throwable->GetTrueMethodTable());
2916         }
2917     }
2918 #ifdef DEBUGGING_SUPPORTED
2919     BYTE *pHandlerEBP;
2920     pHandlerEBP = (BYTE *) GetRegdisplayFP(regs);
2921 #endif
2922
2923     DWORD offs;
2924     offs = (DWORD)pCf->GetRelOffset();  //= (BYTE*) (*regs->pPC) - (BYTE*) pCf->GetStartAddress();
2925
2926     LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback: current EIP offset in method 0x%x, \n", offs));
2927
2928     EE_ILEXCEPTION_CLAUSE EHClause;
2929     unsigned start_adjust, end_adjust;
2930
2931     start_adjust = !(pCf->HasFaulted() || pCf->IsIPadjusted());
2932     end_adjust = pCf->IsActiveFunc();
2933
2934     for(ULONG i=0; i < EHCount; i++)
2935     {
2936           pJitManager->GetNextEHClause(&pEnumState, &EHClause);
2937          _ASSERTE(IsValidClause(&EHClause));
2938
2939         STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: considering '%s' clause [%d,%d], offs:%d\n",
2940                 (IsFault(&EHClause) ? "fault" : (
2941                  IsFinally(&EHClause) ? "finally" : (
2942                  IsFilterHandler(&EHClause) ? "filter" : (
2943                  IsTypedHandler(&EHClause) ? "typed" : "unknown")))),
2944                 EHClause.TryStartPC,
2945                 EHClause.TryEndPC,
2946                 offs
2947                 );
2948
2949         // Checking the exception range is a bit tricky because
2950         // on CPU faults (null pointer access, div 0, ..., the IP points
2951         // to the faulting instruction, but on calls, the IP points
2952         // to the next instruction.
2953         // This means that we should not include the start point on calls
2954         // as this would be a call just preceding the try block.
2955         // Also, we should include the end point on calls, but not faults.
2956
2957         if (   IsFilterHandler(&EHClause)
2958             && (   offs > EHClause.FilterOffset
2959                 || (offs == EHClause.FilterOffset && !start_adjust) )
2960             && (   offs < EHClause.HandlerStartPC
2961                 || (offs == EHClause.HandlerStartPC && !end_adjust) )
2962             ) {
2963             STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: Fault inside filter [%d,%d] startAdj %d endAdj %d\n",
2964                         EHClause.FilterOffset, EHClause.HandlerStartPC, start_adjust, end_adjust);
2965
2966             // Make the filter as done. See comment in CallJitEHFilter
2967             // on why we have to do it here.
2968             Frame* pFilterFrame = pThread->GetFrame();
2969             _ASSERTE(pFilterFrame->GetVTablePtr() == ExceptionFilterFrame::GetMethodFrameVPtr());
2970             ((ExceptionFilterFrame*)pFilterFrame)->SetFilterDone();
2971
2972             // Inform the profiler that we're leaving, and what pass we're on
2973             if (fGiveDebuggerAndProfilerNotification)
2974                 EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pFunc);
2975
2976             return SWA_ABORT;
2977         }
2978
2979         if ( (offs <  EHClause.TryStartPC) ||
2980              (offs > EHClause.TryEndPC) ||
2981              (offs == EHClause.TryStartPC && start_adjust) ||
2982              (offs == EHClause.TryEndPC && end_adjust))
2983             continue;
2984
2985         // <TODO>@PERF : Is this too expensive? Consider storing the nesting level
2986         // instead of the HandlerEndPC.</TODO>
2987
2988         // Determine the nesting level of EHClause. Just walk the table
2989         // again, and find out how many handlers enclose it
2990
2991         DWORD nestingLevel = ComputeEnclosingHandlerNestingLevel(pJitManager,
2992                                                                  pCf->GetMethodToken(),
2993                                                                  EHClause.HandlerStartPC);
2994
2995         // We just need *any* address within the method. This will let the debugger
2996         // resolve the EnC version of the method.
2997         PCODE pMethodAddr = GetControlPC(regs);
2998
2999         UINT_PTR uStartAddress = (UINT_PTR)pCf->GetCodeInfo()->GetStartAddress();
3000
3001         if (IsFaultOrFinally(&EHClause))
3002         {
3003             COUNTER_ONLY(GetPerfCounters().m_Excep.cFinallysExecuted++);
3004
3005             if (fGiveDebuggerAndProfilerNotification)
3006                 EEToDebuggerExceptionInterfaceWrapper::ExceptionHandle(pFunc, pMethodAddr, EHClause.HandlerStartPC, pHandlerEBP);
3007
3008             pExInfo->m_EHClauseInfo.SetInfo(COR_PRF_CLAUSE_FINALLY,
3009                                             uStartAddress + EHClause.HandlerStartPC,
3010                                             StackFrame((UINT_PTR)pHandlerEBP));
3011             
3012             // Notify the profiler that we are about to execute the finally code
3013             if (fGiveDebuggerAndProfilerNotification)
3014                 EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFinallyEnter(pFunc);
3015
3016             LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback: finally clause [%d,%d] - call\n", EHClause.TryStartPC, EHClause.TryEndPC));
3017
3018             pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE);
3019             
3020             ::CallJitEHFinally(pCf, (BYTE *)uStartAddress, &EHClause, nestingLevel);
3021             
3022             pExInfo->m_EHClauseInfo.SetManagedCodeEntered(FALSE);
3023
3024             LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback: finally - returned\n"));
3025
3026             // Notify the profiler that we are done with the finally code
3027             if (fGiveDebuggerAndProfilerNotification)
3028                 EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFinallyLeave();
3029
3030             pExInfo->m_EHClauseInfo.ResetInfo();
3031
3032             continue;
3033         }
3034
3035         // Current is not a finally, check if it's the catching handler (or filter).
3036         if (pData->pFunc != pFunc || (ULONG)(pData->dHandler) != i || pData->pStack != pStack)
3037         {
3038             continue;
3039         }
3040
3041 #ifdef _DEBUG
3042         gLastResumedExceptionFunc = pCf->GetFunction();
3043         gLastResumedExceptionHandler = i;
3044 #endif
3045
3046         // save clause information in the exinfo
3047         pExInfo->m_EHClauseInfo.SetInfo(COR_PRF_CLAUSE_CATCH,
3048                                         uStartAddress  + EHClause.HandlerStartPC,
3049                                         StackFrame((UINT_PTR)pHandlerEBP));
3050
3051         // Notify the profiler that we are about to resume at the catcher.         
3052         if (fGiveDebuggerAndProfilerNotification)
3053         {
3054             DACNotify::DoExceptionCatcherEnterNotification(pFunc, EHClause.HandlerStartPC);
3055
3056             EEToProfilerExceptionInterfaceWrapper::ExceptionCatcherEnter(pThread, pFunc);
3057
3058             EEToDebuggerExceptionInterfaceWrapper::ExceptionHandle(pFunc, pMethodAddr, EHClause.HandlerStartPC, pHandlerEBP);
3059         }
3060
3061         STRESS_LOG4(LF_EH, LL_INFO100, "COMPlusUnwindCallback: offset 0x%x matches clause [0x%x, 0x%x) matches in method %pM\n",
3062                     offs, EHClause.TryStartPC, EHClause.TryEndPC, pFunc);
3063
3064         // ResumeAtJitEH will set pExInfo->m_EHClauseInfo.m_fManagedCodeEntered = TRUE; at the appropriate time
3065         ::ResumeAtJitEH(pCf, (BYTE *)uStartAddress, &EHClause, nestingLevel, pThread, pData->bUnwindStack);   
3066         //UNREACHABLE_MSG("ResumeAtJitEH shouldn't have returned!");
3067         
3068         // we do not set pExInfo->m_EHClauseInfo.m_fManagedCodeEntered = FALSE here, 
3069         // that happens when the catch clause calls back to COMPlusEndCatch 
3070         
3071     }
3072
3073     STRESS_LOG1(LF_EH, LL_INFO100, "COMPlusUnwindCallback: no handler found in method %pM\n", pFunc);
3074     if (fGiveDebuggerAndProfilerNotification)
3075         EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pFunc);
3076
3077     return SWA_CONTINUE;
3078
3079
3080 #ifdef DEBUGGING_SUPPORTED
3081 LDoDebuggerIntercept:
3082
3083     STRESS_LOG1(LF_EH|LF_CORDB, LL_INFO100, "COMPlusUnwindCallback: Intercepting in method %pM\n", pFunc);
3084
3085     //
3086     // Setup up the easy parts of the context to restart at.
3087     //
3088     EHContext context;
3089
3090     //
3091     // Note: EAX ECX EDX are scratch
3092     //
3093     context.Esp = (DWORD)(size_t)(GetRegdisplaySP(regs));
3094     context.Ebx = *regs->pEbx;
3095     context.Esi = *regs->pEsi;
3096     context.Edi = *regs->pEdi;
3097     context.Ebp = *regs->pEbp;
3098     
3099     //
3100     // Set scratch registers to 0 to avoid reporting incorrect values to GC in case of debugger changing the IP 
3101     // in the middle of a scratch register lifetime (see Dev10 754922)
3102     // 
3103     context.Eax = 0;
3104     context.Ecx = 0;
3105     context.Edx = 0;
3106
3107     //
3108     // Ok, now set the target Eip to the address the debugger requested.
3109     //
3110     ULONG_PTR nativeOffset;
3111     pExInfo->m_DebuggerExState.GetDebuggerInterceptInfo(NULL, NULL, NULL, NULL, &nativeOffset, NULL);
3112     context.Eip = GetControlPC(regs) - (pCf->GetRelOffset() - nativeOffset);
3113
3114     //
3115     // Finally we need to get the correct Esp for this nested level
3116     //
3117
3118     context.Esp = pCf->GetCodeManager()->GetAmbientSP(regs,
3119                                                       pCf->GetCodeInfo(),
3120                                                       nativeOffset,
3121                                                       pData->dHandler,
3122                                                       pCf->GetCodeManState()
3123                                                      );
3124     //
3125     // In case we see unknown FS:[0] handlers we delay the interception point until we reach the handler that protects the interception point.
3126     // This way we have both FS:[0] handlers being poped up by RtlUnwind and managed capital F Frames being unwinded by managed stackwalker.
3127     //
3128     BOOL fCheckForUnknownHandler  = TRUE;
3129     if (PopNestedExceptionRecords((LPVOID)(size_t)context.Esp, fCheckForUnknownHandler))
3130     {
3131         // Let ClrDebuggerDoUnwindAndIntercept RtlUnwind continue to unwind frames until we reach the handler protected by COMPlusNestedExceptionHandler.
3132         pExInfo->m_InterceptionContext = context;
3133         pExInfo->m_ValidInterceptionContext = TRUE;
3134         STRESS_LOG0(LF_EH|LF_CORDB, LL_INFO100, "COMPlusUnwindCallback: Skip interception until unwinding reaches the actual handler protected by COMPlusNestedExceptionHandler\n");
3135     }
3136     else
3137     {
3138         //
3139         // Pop off all the Exception information up to this point in the stack
3140         //
3141         UnwindExceptionTrackerAndResumeInInterceptionFrame(pExInfo, &context);
3142     }
3143     return SWA_ABORT;
3144 #endif // DEBUGGING_SUPPORTED
3145 } // StackWalkAction COMPlusUnwindCallback ()
3146 #if defined(_MSC_VER)
3147 #pragma warning(pop)
3148 #endif
3149
3150 #if defined(_MSC_VER)
3151 #pragma warning(push)
3152 #pragma warning (disable : 4740) // There is inline asm code in this function, which disables
3153                                  // global optimizations.
3154 #pragma warning (disable : 4731)
3155 #endif
3156 void ResumeAtJitEH(CrawlFrame* pCf,
3157                    BYTE* startPC,
3158                    EE_ILEXCEPTION_CLAUSE *EHClausePtr,
3159                    DWORD nestingLevel,
3160                    Thread *pThread,
3161                    BOOL unwindStack)
3162 {
3163     // No dynamic contract here because this function doesn't return and destructors wouldn't be executed
3164     WRAPPER_NO_CONTRACT;
3165
3166     EHContext context;
3167
3168     context.Setup(PCODE(startPC + EHClausePtr->HandlerStartPC), pCf->GetRegisterSet());
3169
3170     size_t * pShadowSP = NULL; // Write Esp to *pShadowSP before jumping to handler
3171     size_t * pHandlerEnd = NULL;
3172
3173     OBJECTREF throwable = PossiblyUnwrapThrowable(pThread->GetThrowable(), pCf->GetAssembly());
3174
3175     pCf->GetCodeManager()->FixContext(ICodeManager::CATCH_CONTEXT,
3176                                       &context,
3177                                       pCf->GetCodeInfo(),
3178                                       EHClausePtr->HandlerStartPC,
3179                                       nestingLevel,
3180                                       throwable,
3181                                       pCf->GetCodeManState(),
3182                                       &pShadowSP,
3183                                       &pHandlerEnd);
3184
3185     if (pHandlerEnd)
3186     {
3187         *pHandlerEnd = EHClausePtr->HandlerEndPC;
3188     }
3189
3190     // save esp so that endcatch can restore it (it always restores, so want correct value)
3191     ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
3192     pExInfo->m_dEsp = (LPVOID)context.GetSP();
3193     LOG((LF_EH, LL_INFO1000, "ResumeAtJitEH: current m_dEsp set to %p\n", context.GetSP()));
3194
3195     PVOID dEsp = GetCurrentSP();
3196
3197     if (!unwindStack)
3198     {
3199         // If we don't want to unwind the stack, then the guard page had better not be gone!
3200         _ASSERTE(pThread->DetermineIfGuardPagePresent());
3201
3202         // so down below won't really update esp
3203         context.SetSP(dEsp);
3204         pExInfo->m_pShadowSP = pShadowSP; // so that endcatch can zero it back
3205
3206         if  (pShadowSP)
3207         {
3208             *pShadowSP = (size_t)dEsp;
3209         }
3210     }
3211     else
3212     {
3213         // so shadow SP has the real SP as we are going to unwind the stack
3214         dEsp = (LPVOID)context.GetSP();
3215
3216         // BEGIN: pExInfo->UnwindExInfo(dEsp);
3217         ExInfo *pPrevNestedInfo = pExInfo->m_pPrevNestedInfo;
3218
3219         while (pPrevNestedInfo && pPrevNestedInfo->m_StackAddress < dEsp)
3220         {
3221             LOG((LF_EH, LL_INFO1000, "ResumeAtJitEH: popping nested ExInfo at 0x%p\n", pPrevNestedInfo->m_StackAddress));
3222
3223             pPrevNestedInfo->DestroyExceptionHandle();
3224             pPrevNestedInfo->m_StackTraceInfo.FreeStackTrace();
3225
3226 #ifdef DEBUGGING_SUPPORTED
3227             if (g_pDebugInterface != NULL)
3228             {
3229                 g_pDebugInterface->DeleteInterceptContext(pPrevNestedInfo->m_DebuggerExState.GetDebuggerInterceptContext());
3230             }
3231 #endif // DEBUGGING_SUPPORTED
3232
3233             pPrevNestedInfo = pPrevNestedInfo->m_pPrevNestedInfo;
3234         }
3235
3236         pExInfo->m_pPrevNestedInfo = pPrevNestedInfo;
3237
3238         _ASSERTE(pExInfo->m_pPrevNestedInfo == 0 || pExInfo->m_pPrevNestedInfo->m_StackAddress >= dEsp);
3239
3240         // Before we unwind the SEH records, get the Frame from the top-most nested exception record.
3241         Frame* pNestedFrame = GetCurrFrame(FindNestedEstablisherFrame(GetCurrentSEHRecord()));
3242
3243         PopNestedExceptionRecords((LPVOID)(size_t)dEsp);
3244
3245         EXCEPTION_REGISTRATION_RECORD* pNewBottomMostHandler = GetCurrentSEHRecord();
3246
3247         pExInfo->m_pShadowSP = pShadowSP;
3248
3249         // The context and exception record are no longer any good.
3250         _ASSERTE(pExInfo->m_pContext < dEsp);   // It must be off the top of the stack.
3251         pExInfo->m_pContext = 0;                // Whack it.
3252         pExInfo->m_pExceptionRecord = 0;
3253         pExInfo->m_pExceptionPointers = 0;
3254
3255         // We're going to put one nested record back on the stack before we resume.  This is
3256         // where it goes.
3257         NestedHandlerExRecord *pNestedHandlerExRecord = (NestedHandlerExRecord*)((BYTE*)dEsp - ALIGN_UP(sizeof(NestedHandlerExRecord), STACK_ALIGN_SIZE));
3258
3259         // The point of no return.  The next statement starts scribbling on the stack.  It's
3260         // deep enough that we won't hit our own locals.  (That's important, 'cuz we're still
3261         // using them.)
3262         //
3263         _ASSERTE(dEsp > &pCf);
3264         pNestedHandlerExRecord->m_handlerInfo.m_hThrowable=NULL; // This is random memory.  Handle
3265                                                                  // must be initialized to null before
3266                                                                  // calling Init(), as Init() will try
3267                                                                  // to free any old handle.
3268         pNestedHandlerExRecord->Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, pNestedFrame);
3269
3270         INSTALL_EXCEPTION_HANDLING_RECORD(&(pNestedHandlerExRecord->m_ExReg));
3271
3272         context.SetSP(pNestedHandlerExRecord);
3273
3274         // We might have moved the bottommost handler.  The nested record itself is never
3275         // the bottom most handler -- it's pushed afte the fact.  So we have to make the
3276         // bottom-most handler the one BEFORE the nested record.
3277         if (pExInfo->m_pBottomMostHandler < pNewBottomMostHandler)
3278         {
3279             STRESS_LOG3(LF_EH, LL_INFO10000, "ResumeAtJitEH: setting ExInfo:0x%p m_pBottomMostHandler from 0x%p to 0x%p\n", 
3280                 pExInfo, pExInfo->m_pBottomMostHandler, pNewBottomMostHandler);
3281           pExInfo->m_pBottomMostHandler = pNewBottomMostHandler;
3282         }
3283
3284         if  (pShadowSP)
3285         {
3286             *pShadowSP = context.GetSP();
3287         }
3288     }
3289
3290     STRESS_LOG3(LF_EH, LL_INFO100, "ResumeAtJitEH: resuming at EIP = %p  ESP = %p EBP = %p\n",
3291                 context.Eip, context.GetSP(), context.GetFP());
3292
3293 #ifdef STACK_GUARDS_DEBUG
3294     // We are transitioning back to managed code, so ensure that we are in 
3295     // SO-tolerant mode before we do so. 
3296     RestoreSOToleranceState();
3297 #endif
3298
3299     // we want this to happen as late as possible but certainly after the notification
3300     // that the handle for the current ExInfo has been freed has been delivered
3301     pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE);
3302
3303     ETW::ExceptionLog::ExceptionCatchBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
3304
3305     ResumeAtJitEHHelper(&context);
3306     UNREACHABLE_MSG("Should never return from ResumeAtJitEHHelper!");
3307
3308     // we do not set pExInfo->m_EHClauseInfo.m_fManagedCodeEntered = FALSE here, 
3309     // that happens when the catch clause calls back to COMPlusEndCatch 
3310     // we don't return to this point so it would be moot (see unreachable_msg above)
3311     
3312 }
3313 #if defined(_MSC_VER)
3314 #pragma warning(pop)
3315 #endif    
3316
3317 // Must be in a separate function because INSTALL_COMPLUS_EXCEPTION_HANDLER has a filter
3318 int CallJitEHFilterWorker(size_t *pShadowSP, EHContext *pContext)
3319 {
3320     STATIC_CONTRACT_THROWS;
3321     STATIC_CONTRACT_GC_TRIGGERS;
3322     STATIC_CONTRACT_MODE_COOPERATIVE;
3323     STATIC_CONTRACT_SO_INTOLERANT;
3324
3325     int retVal = EXCEPTION_CONTINUE_SEARCH;
3326
3327     BEGIN_CALL_TO_MANAGED();
3328
3329     retVal = CallJitEHFilterHelper(pShadowSP, pContext);
3330
3331     END_CALL_TO_MANAGED();
3332
3333     return retVal;
3334 }
3335
3336 int CallJitEHFilter(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, OBJECTREF thrownObj)
3337 {
3338     STATIC_CONTRACT_THROWS;
3339     STATIC_CONTRACT_GC_TRIGGERS;
3340     STATIC_CONTRACT_MODE_COOPERATIVE;
3341
3342     int retVal = EXCEPTION_CONTINUE_SEARCH;
3343     size_t * pShadowSP = NULL;
3344     EHContext context;
3345
3346     context.Setup(PCODE(startPC + EHClausePtr->FilterOffset), pCf->GetRegisterSet());
3347
3348     size_t * pEndFilter = NULL; // Write
3349     pCf->GetCodeManager()->FixContext(ICodeManager::FILTER_CONTEXT, &context, pCf->GetCodeInfo(),
3350                                       EHClausePtr->FilterOffset, nestingLevel, thrownObj, pCf->GetCodeManState(),
3351                                       &pShadowSP, &pEndFilter);
3352
3353     // End of the filter is the same as start of handler
3354     if (pEndFilter)
3355     {
3356         *pEndFilter = EHClausePtr->HandlerStartPC;
3357     }
3358
3359     // ExceptionFilterFrame serves two purposes:
3360     //
3361     // 1. It serves as a frame that stops the managed search for handler 
3362     // if we fault in the filter. ThrowCallbackType.pTopFrame is going point 
3363     // to this frame during search for exception handler inside filter.
3364     // The search for handler needs a frame to stop. If we had no frame here,
3365     // the exceptions in filters would not be swallowed correctly since we would
3366     // walk past the EX_TRY/EX_CATCH block in COMPlusThrowCallbackHelper.
3367     //
3368     // 2. It allows setting of SHADOW_SP_FILTER_DONE flag in UnwindFrames() 
3369     // if we fault in the filter. We have to set this flag together with unwinding
3370     // of the filter frame. Using a regular C++ holder to clear this flag here would cause 
3371     // GC holes. The stack would be in inconsistent state when we trigger gc just before
3372     // returning from UnwindFrames.
3373
3374     FrameWithCookie<ExceptionFilterFrame> exceptionFilterFrame(pShadowSP);
3375     
3376     ETW::ExceptionLog::ExceptionFilterBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
3377     
3378     retVal = CallJitEHFilterWorker(pShadowSP, &context);
3379
3380     ETW::ExceptionLog::ExceptionFilterEnd();
3381
3382     exceptionFilterFrame.Pop();
3383
3384     return retVal;
3385 }
3386
3387 void CallJitEHFinally(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel)
3388 {
3389     WRAPPER_NO_CONTRACT;
3390
3391     EHContext context;
3392     context.Setup(PCODE(startPC + EHClausePtr->HandlerStartPC), pCf->GetRegisterSet());
3393
3394     size_t * pShadowSP = NULL; // Write Esp to *pShadowSP before jumping to handler
3395
3396     size_t * pFinallyEnd = NULL;
3397     pCf->GetCodeManager()->FixContext(
3398         ICodeManager::FINALLY_CONTEXT, &context, pCf->GetCodeInfo(),
3399         EHClausePtr->HandlerStartPC, nestingLevel, ObjectToOBJECTREF((Object *) NULL), pCf->GetCodeManState(),
3400         &pShadowSP, &pFinallyEnd);
3401
3402     if (pFinallyEnd)
3403     {
3404         *pFinallyEnd = EHClausePtr->HandlerEndPC;
3405     }
3406
3407     ETW::ExceptionLog::ExceptionFinallyBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
3408     
3409     CallJitEHFinallyHelper(pShadowSP, &context);
3410
3411     ETW::ExceptionLog::ExceptionFinallyEnd();
3412
3413     //
3414     // Update the registers using new context
3415     //
3416     // This is necessary to reflect GC pointer changes during the middle of a unwind inside a 
3417     // finally clause, because:
3418     // 1. GC won't see the part of stack inside try (which has thrown an exception) that is already 
3419     // unwinded and thus GC won't update GC pointers for this portion of the stack, but rather the 
3420     // call stack in finally.
3421     // 2. upon return of finally, the unwind process continues and unwinds stack based on the part 
3422     // of stack inside try and won't see the updated values in finally.
3423     // As a result, we need to manually update the context using register values upon return of finally
3424     //
3425     // Note that we only update the registers for finally clause because
3426     // 1. For filter handlers, stack walker is able to see the whole stack (including the try part)
3427     // with the help of ExceptionFilterFrame as filter handlers are called in first pass
3428     // 2. For catch handlers, the current unwinding is already finished
3429     //
3430     context.UpdateFrame(pCf->GetRegisterSet());
3431     
3432     // This does not need to be guarded by a holder because the frame is dead if an exception gets thrown.  Filters are different
3433     //  since they are run in the first pass, so we must update the shadowSP reset in CallJitEHFilter.
3434     if (pShadowSP) {
3435         *pShadowSP = 0;  // reset the shadowSP to 0
3436     }
3437 }
3438 #if defined(_MSC_VER)
3439 #pragma warning (default : 4731)
3440 #endif
3441
3442 //=====================================================================
3443 // *********************************************************************
3444 BOOL ComPlusFrameSEH(EXCEPTION_REGISTRATION_RECORD* pEHR)
3445 {
3446     LIMITED_METHOD_CONTRACT;
3447
3448     return ((LPVOID)pEHR->Handler == (LPVOID)COMPlusFrameHandler || (LPVOID)pEHR->Handler == (LPVOID)COMPlusNestedExceptionHandler);
3449 }
3450
3451
3452 //
3453 //-------------------------------------------------------------------------
3454 // This is installed when we call COMPlusFrameHandler to provide a bound to
3455 // determine when are within a nested exception
3456 //-------------------------------------------------------------------------
3457 EXCEPTION_HANDLER_IMPL(COMPlusNestedExceptionHandler)
3458 {
3459     WRAPPER_NO_CONTRACT;
3460
3461     if (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
3462     {
3463         LOG((LF_EH, LL_INFO100, "    COMPlusNestedHandler(unwind) with %x at %x\n", pExceptionRecord->ExceptionCode,
3464             pContext ? GetIP(pContext) : 0));
3465
3466
3467         // We're unwinding past a nested exception record, which means that we've thrown
3468         // a new exception out of a region in which we're handling a previous one.  The
3469         // previous exception is overridden -- and needs to be unwound.
3470
3471         // The preceding is ALMOST true.  There is one more case, where we use setjmp/longjmp
3472         // from withing a nested handler.  We won't have a nested exception in that case -- just
3473         // the unwind.
3474
3475         Thread* pThread = GetThread();
3476         _ASSERTE(pThread);
3477         ExInfo* pExInfo = &(pThread->GetExceptionState()->m_currentExInfo);
3478         ExInfo* pPrevNestedInfo = pExInfo->m_pPrevNestedInfo;
3479
3480         if (pPrevNestedInfo == &((NestedHandlerExRecord*)pEstablisherFrame)->m_handlerInfo)
3481         {
3482             _ASSERTE(pPrevNestedInfo);
3483
3484             LOG((LF_EH, LL_INFO100, "COMPlusNestedExceptionHandler: PopExInfo(): popping nested ExInfo at 0x%p\n", pPrevNestedInfo));
3485
3486             pPrevNestedInfo->DestroyExceptionHandle();
3487             pPrevNestedInfo->m_StackTraceInfo.FreeStackTrace();
3488
3489 #ifdef DEBUGGING_SUPPORTED
3490             if (g_pDebugInterface != NULL)
3491             {
3492                 g_pDebugInterface->DeleteInterceptContext(pPrevNestedInfo->m_DebuggerExState.GetDebuggerInterceptContext());
3493             }
3494 #endif // DEBUGGING_SUPPORTED
3495
3496             pExInfo->m_pPrevNestedInfo = pPrevNestedInfo->m_pPrevNestedInfo;
3497
3498         } else {
3499             // The whacky setjmp/longjmp case.  Nothing to do.
3500         }
3501
3502     } else {
3503         LOG((LF_EH, LL_INFO100, "    InCOMPlusNestedHandler with %x at %x\n", pExceptionRecord->ExceptionCode,
3504             pContext ? GetIP(pContext) : 0));
3505     }
3506
3507
3508     // There is a nasty "gotcha" in the way exception unwinding, finally's, and nested exceptions
3509     // interact.  Here's the scenario ... it involves two exceptions, one normal one, and one
3510     // raised in a finally.
3511     //
3512     // The first exception occurs, and is caught by some handler way up the stack.  That handler
3513     // calls RtlUnwind -- and handlers that didn't catch this first exception are called again, with
3514     // the UNWIND flag set.  If, one of the handlers throws an exception during
3515     // unwind (like, a throw from a finally) -- then that same handler is not called during
3516     // the unwind pass of the second exception.  [ASIDE: It is called on first-pass.]
3517     //
3518     // What that means is -- the COMPlusExceptionHandler, can't count on unwinding itself correctly
3519     // if an exception is thrown from a finally.  Instead, it relies on the NestedExceptionHandler
3520     // that it pushes for this.
3521     //
3522
3523     EXCEPTION_DISPOSITION retval = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler);
3524     LOG((LF_EH, LL_INFO100, "Leaving COMPlusNestedExceptionHandler with %d\n", retval));
3525     return retval;
3526 }
3527
3528 EXCEPTION_REGISTRATION_RECORD *FindNestedEstablisherFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame)
3529 {
3530     LIMITED_METHOD_CONTRACT;
3531
3532     while (pEstablisherFrame->Handler != (PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler) {
3533         pEstablisherFrame = pEstablisherFrame->Next;
3534         _ASSERTE(pEstablisherFrame != EXCEPTION_CHAIN_END);   // should always find one
3535     }
3536     return pEstablisherFrame;
3537 }
3538
3539 EXCEPTION_HANDLER_IMPL(FastNExportExceptHandler)
3540 {
3541     WRAPPER_NO_CONTRACT;
3542
3543     // Most of our logic is in commin with COMPlusFrameHandler.
3544     EXCEPTION_DISPOSITION retval = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler);
3545
3546 #ifdef _DEBUG
3547     // If the exception is escaping the last CLR personality routine on the stack,
3548     // then state a flag on the thread to indicate so.
3549     if (retval == ExceptionContinueSearch)
3550     {
3551         SetReversePInvokeEscapingUnhandledExceptionStatus(IS_UNWINDING(pExceptionRecord->ExceptionFlags), pEstablisherFrame);
3552     }
3553 #endif // _DEBUG
3554
3555     return retval;  
3556 }
3557
3558
3559 // Just like a regular NExport handler -- except it pops an extra frame on unwind.  A handler
3560 // like this is needed by the COMMethodStubProlog code.  It first pushes a frame -- and then
3561 // pushes a handler.  When we unwind, we need to pop the extra frame to avoid corrupting the
3562 // frame chain in the event of an unmanaged catcher.
3563 //
3564 EXCEPTION_HANDLER_IMPL(UMThunkPrestubHandler)
3565 {
3566     // @todo: we'd like to have a dynamic contract here, but there's a problem. (Bug 129180) Enter on the CRST used
3567     // in HandleManagedFault leaves the no-trigger count incremented. The destructor of this contract will restore
3568     // it to zero, then when we leave the CRST in LinkFrameAndThrow, we assert because we're trying to decrement the
3569     // gc-trigger count down past zero. The solution is to fix what we're doing with this CRST. </TODO>
3570     STATIC_CONTRACT_THROWS; // COMPlusFrameHandler throws
3571     STATIC_CONTRACT_GC_TRIGGERS;
3572     STATIC_CONTRACT_MODE_ANY;
3573
3574     EXCEPTION_DISPOSITION retval = ExceptionContinueSearch;
3575     
3576     BEGIN_CONTRACT_VIOLATION(SOToleranceViolation);
3577     
3578     // We must forward to the COMPlusFrameHandler. This will unwind the Frame Chain up to here, and also leave the
3579     // preemptive GC mode set correctly.
3580     retval = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler);
3581
3582 #ifdef _DEBUG
3583     // If the exception is escaping the last CLR personality routine on the stack,
3584     // then state a flag on the thread to indicate so.
3585     if (retval == ExceptionContinueSearch)
3586     {
3587         SetReversePInvokeEscapingUnhandledExceptionStatus(IS_UNWINDING(pExceptionRecord->ExceptionFlags), pEstablisherFrame);
3588     }
3589 #endif // _DEBUG
3590
3591     if (IS_UNWINDING(pExceptionRecord->ExceptionFlags))
3592     {
3593         // Pops an extra frame on unwind.
3594
3595         GCX_COOP();     // Must be cooperative to modify frame chain.
3596
3597         Thread *pThread = GetThread();
3598         _ASSERTE(pThread);
3599         Frame *pFrame = pThread->GetFrame();
3600         pFrame->ExceptionUnwind();
3601         pFrame->Pop(pThread);
3602     }
3603
3604     END_CONTRACT_VIOLATION;
3605     
3606     return retval;
3607 }
3608
3609 #ifdef FEATURE_COMINTEROP
3610 // The reverse COM interop path needs to be sure to pop the ComMethodFrame that is pushed, but we do not want
3611 // to have an additional FS:0 handler between the COM callsite and the call into managed.  So we push this
3612 // FS:0 handler, which will defer to the usual COMPlusFrameHandler and then perform the cleanup of the
3613 // ComMethodFrame, if needed.
3614 EXCEPTION_HANDLER_IMPL(COMPlusFrameHandlerRevCom)
3615 {
3616     STATIC_CONTRACT_THROWS;
3617     STATIC_CONTRACT_GC_TRIGGERS;
3618     STATIC_CONTRACT_MODE_ANY;
3619
3620     // Defer to COMPlusFrameHandler
3621     EXCEPTION_DISPOSITION result = EXCEPTION_HANDLER_FWD(COMPlusFrameHandler);
3622
3623     if (pExceptionRecord->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
3624     {
3625         // Do cleanup as needed
3626         ComMethodFrame::DoSecondPassHandlerCleanup(GetCurrFrame(pEstablisherFrame));
3627     }
3628
3629     return result;
3630 }
3631 #endif // FEATURE_COMINTEROP
3632 #endif // !DACCESS_COMPILE
3633 #endif // !WIN64EXCEPTIONS
3634
3635 #ifndef DACCESS_COMPILE
3636 LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv)
3637 {
3638 #ifndef WIN64EXCEPTIONS
3639     WRAPPER_NO_CONTRACT;
3640     STATIC_CONTRACT_ENTRY_POINT;
3641
3642     LONG result = EXCEPTION_CONTINUE_SEARCH;
3643
3644     // This function can be called during the handling of a SO
3645     //BEGIN_ENTRYPOINT_VOIDRET;
3646
3647     result = CLRVectoredExceptionHandler(pExceptionInfo);
3648
3649     if (EXCEPTION_EXECUTE_HANDLER == result)
3650     {
3651         result = EXCEPTION_CONTINUE_SEARCH;
3652     }
3653
3654     //END_ENTRYPOINT_VOIDRET;
3655
3656     return result;
3657 #else  // !WIN64EXCEPTIONS
3658     return EXCEPTION_CONTINUE_SEARCH;
3659 #endif // !WIN64EXCEPTIONS
3660 }
3661 #endif // !DACCESS_COMPILE
3662
3663 // Returns TRUE if caller should resume execution.
3664 BOOL
3665 AdjustContextForVirtualStub(
3666         EXCEPTION_RECORD *pExceptionRecord,
3667         CONTEXT *pContext)
3668 {
3669     LIMITED_METHOD_CONTRACT;
3670
3671     Thread * pThread = GetThread();
3672
3673     // We may not have a managed thread object. Example is an AV on the helper thread.
3674     // (perhaps during StubManager::IsStub)
3675     if (pThread == NULL)
3676     {
3677         return FALSE;
3678     }
3679
3680     PCODE f_IP = GetIP(pContext);
3681
3682     VirtualCallStubManager::StubKind sk;
3683     /* VirtualCallStubManager *pMgr = */ VirtualCallStubManager::FindStubManager(f_IP, &sk);
3684
3685     if (sk == VirtualCallStubManager::SK_DISPATCH)
3686     {
3687         if (*PTR_WORD(f_IP) != X86_INSTR_CMP_IND_ECX_IMM32)
3688         {
3689             _ASSERTE(!"AV in DispatchStub at unknown instruction");
3690             return FALSE;
3691         }
3692     }
3693     else
3694     if (sk == VirtualCallStubManager::SK_RESOLVE)
3695     {
3696         if (*PTR_WORD(f_IP) != X86_INSTR_MOV_EAX_ECX_IND)
3697         {
3698             _ASSERTE(!"AV in ResolveStub at unknown instruction");
3699             return FALSE;
3700         }
3701
3702         SetSP(pContext, dac_cast<PCODE>(dac_cast<PTR_BYTE>(GetSP(pContext)) + sizeof(void*))); // rollback push eax
3703     }
3704     else
3705     {
3706         return FALSE;
3707     }
3708
3709     PCODE callsite = GetAdjustedCallAddress(*dac_cast<PTR_PCODE>(GetSP(pContext)));
3710     pExceptionRecord->ExceptionAddress = (PVOID)callsite;
3711     SetIP(pContext, callsite);
3712
3713     // put ESP back to what it was before the call.
3714     SetSP(pContext, dac_cast<PCODE>(dac_cast<PTR_BYTE>(GetSP(pContext)) + sizeof(void*)));
3715
3716     return TRUE;
3717 }