1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6//
7
8#ifndef __EXCEPTION_HANDLING_h__
9#define __EXCEPTION_HANDLING_h__
10
11#ifdef WIN64EXCEPTIONS
12
13#include "eexcp.h"
14#include "exstatecommon.h"
15
16#if defined(_TARGET_ARM_) || defined(_TARGET_X86_)
17#define USE_PER_FRAME_PINVOKE_INIT
18#endif // _TARGET_ARM_ || _TARGET_X86_
19
20// This address lies in the NULL pointer partition of the process memory.
21// Accessing it will result in AV.
22#define INVALID_RESUME_ADDRESS 0x000000000000bad0
23
24EXTERN_C EXCEPTION_DISPOSITION
25ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord
26 WIN64_ARG(IN ULONG64 MemoryStackFp)
27 NOT_WIN64_ARG(IN ULONG MemoryStackFp),
28 IN OUT PT_CONTEXT pContextRecord,
29 IN OUT PT_DISPATCHER_CONTEXT pDispatcherContext);
30
31enum CLRUnwindStatus { UnwindPending, FirstPassComplete, SecondPassComplete };
32
33enum TrackerMemoryType
34{
35 memManaged = 0x0001,
36 memUnmanaged = 0x0002,
37 memBoth = 0x0003,
38};
39
40// Enum that specifies the type of EH funclet we are about to invoke
41enum EHFuncletType
42{
43 Filter = 0x0001,
44 FaultFinally = 0x0002,
45 Catch = 0x0004,
46};
47
48typedef DPTR(class ExceptionTracker) PTR_ExceptionTracker;
49class ExceptionTracker
50{
51 friend class TrackerAllocator;
52 friend class ThreadExceptionState;
53 friend class ClrDataExceptionState;
54#ifdef DACCESS_COMPILE
55 friend class ClrDataAccess;
56#endif // DACCESS_COMPILE
57
58 friend void FreeTrackerMemory(ExceptionTracker* pTracker, TrackerMemoryType mem);
59
60private:
61 class StackRange;
62public:
63
64 ExceptionTracker() :
65 m_pThread(NULL),
66 m_hThrowable(NULL)
67 {
68#ifndef DACCESS_COMPILE
69 m_StackTraceInfo.Init();
70#endif // DACCESS_COMPILE
71
72#ifndef FEATURE_PAL
73 // Init the WatsonBucketTracker
74 m_WatsonBucketTracker.Init();
75#endif // !FEATURE_PAL
76
77#ifdef FEATURE_CORRUPTING_EXCEPTIONS
78 // Initialize the default exception severity to NotCorrupting
79 m_CorruptionSeverity = NotSet;
80#endif // FEATURE_CORRUPTING_EXCEPTIONS
81
82 // By default, mark the tracker as not having delivered the first
83 // chance exception notification
84 m_fDeliveredFirstChanceNotification = FALSE;
85
86 m_sfFirstPassTopmostFrame.Clear();
87
88 m_dwIndexClauseForCatch = 0;
89 m_sfEstablisherOfActualHandlerFrame.Clear();
90 m_sfCallerOfActualHandlerFrame.Clear();
91
92 m_fFixupCallerSPForGCReporting = false;
93
94 m_fResetEnclosingClauseSPForCatchFunclet = FALSE;
95
96 m_sfCurrentEstablisherFrame.Clear();
97 m_sfLastUnwoundEstablisherFrame.Clear();
98 m_pInitialExplicitFrame = NULL;
99 m_pLimitFrame = NULL;
100 m_csfEHClauseOfCollapsedTracker.Clear();
101
102#ifdef FEATURE_PAL
103 m_fOwnsExceptionPointers = FALSE;
104#endif
105 }
106
107 ExceptionTracker(DWORD_PTR dwExceptionPc,
108 PTR_EXCEPTION_RECORD pExceptionRecord,
109 PTR_CONTEXT pContextRecord) :
110 m_pPrevNestedInfo((ExceptionTracker*)NULL),
111 m_pThread(GetThread()),
112 m_hThrowable(NULL),
113 m_uCatchToCallPC(NULL),
114 m_pSkipToParentFunctionMD(NULL),
115// these members were added for resume frame processing
116 m_pClauseForCatchToken(NULL),
117// end resume frame members
118 m_ExceptionCode(pExceptionRecord->ExceptionCode)
119 {
120 m_ptrs.ExceptionRecord = pExceptionRecord;
121 m_ptrs.ContextRecord = pContextRecord;
122
123 m_pLimitFrame = NULL;
124
125 if (IsInstanceTaggedSEHCode(pExceptionRecord->ExceptionCode) && ::WasThrownByUs(pExceptionRecord, pExceptionRecord->ExceptionCode))
126 {
127 m_ExceptionFlags.SetWasThrownByUs();
128 }
129
130 m_StackTraceInfo.Init();
131
132#ifndef FEATURE_PAL
133 // Init the WatsonBucketTracker
134 m_WatsonBucketTracker.Init();
135#endif // !FEATURE_PAL
136
137#ifdef FEATURE_CORRUPTING_EXCEPTIONS
138 // Initialize the default exception severity to NotCorrupting
139 m_CorruptionSeverity = NotSet;
140#endif // FEATURE_CORRUPTING_EXCEPTIONS
141
142 // By default, mark the tracker as not having delivered the first
143 // chance exception notification
144 m_fDeliveredFirstChanceNotification = FALSE;
145
146 m_dwIndexClauseForCatch = 0;
147 m_sfEstablisherOfActualHandlerFrame.Clear();
148 m_sfCallerOfActualHandlerFrame.Clear();
149
150 m_sfFirstPassTopmostFrame.Clear();
151
152 m_fFixupCallerSPForGCReporting = false;
153
154 m_fResetEnclosingClauseSPForCatchFunclet = FALSE;
155
156 m_sfCurrentEstablisherFrame.Clear();
157 m_sfLastUnwoundEstablisherFrame.Clear();
158 m_pInitialExplicitFrame = NULL;
159 m_csfEHClauseOfCollapsedTracker.Clear();
160
161#ifdef FEATURE_PAL
162 m_fOwnsExceptionPointers = FALSE;
163#endif
164 }
165
166 ~ExceptionTracker()
167 {
168 ReleaseResources();
169 }
170
171 enum StackTraceState
172 {
173 STS_Append,
174 STS_FirstRethrowFrame,
175 STS_NewException,
176 };
177
178 static void InitializeCrawlFrame(CrawlFrame* pcfThisFrame, Thread* pThread, StackFrame sf, REGDISPLAY* pRD,
179 PT_DISPATCHER_CONTEXT pDispatcherContext, DWORD_PTR ControlPCForEHSearch,
180 UINT_PTR* puMethodStartPC,
181 ExceptionTracker *pCurrentTracker);
182
183 void InitializeCurrentContextForCrawlFrame(CrawlFrame* pcfThisFrame, PT_DISPATCHER_CONTEXT pDispatcherContext, StackFrame sfEstablisherFrame);
184
185 static void InitializeCrawlFrameForExplicitFrame(CrawlFrame* pcfThisFrame, Frame* pFrame, MethodDesc *pMD);
186
187#ifndef DACCESS_COMPILE
188 static void ResetThreadAbortStatus(PTR_Thread pThread, CrawlFrame *pCf, StackFrame sfCurrentStackFrame);
189#endif // !DACCESS_COMPILE
190
191 CLRUnwindStatus ProcessOSExceptionNotification(
192 PEXCEPTION_RECORD pExceptionRecord,
193 PT_CONTEXT pContextRecord,
194 PT_DISPATCHER_CONTEXT pDispatcherContext,
195 DWORD dwExceptionFlags,
196 StackFrame sf,
197 Thread* pThread,
198 StackTraceState STState
199#ifdef USE_PER_FRAME_PINVOKE_INIT
200 , PVOID pICFSetAsLimitFrame
201#endif // USE_PER_FRAME_PINVOKE_INIT
202 );
203
204 CLRUnwindStatus ProcessExplicitFrame(
205 CrawlFrame* pcfThisFrame,
206 StackFrame sf,
207 BOOL fIsFirstPass,
208 StackTraceState& STState
209 );
210
211 CLRUnwindStatus ProcessManagedCallFrame(
212 CrawlFrame* pcfThisFrame,
213 StackFrame sf,
214 StackFrame sfEstablisherFrame,
215 EXCEPTION_RECORD* pExceptionRecord,
216 StackTraceState STState,
217 UINT_PTR uMethodStartPC,
218 DWORD dwExceptionFlags,
219 DWORD dwTACatchHandlerClauseIndex,
220 StackFrame sfEstablisherOfActualHandlerFrame
221 );
222
223 bool UpdateScannedStackRange(StackFrame sf, bool fIsFirstPass);
224
225 void FirstPassIsComplete();
226 void SecondPassIsComplete(MethodDesc* pMD, StackFrame sfResumeStackFrame);
227
228 CLRUnwindStatus HandleFunclets(bool* pfProcessThisFrame, bool fIsFirstPass,
229 MethodDesc * pMD, bool fFunclet, StackFrame sf);
230
231 static OBJECTREF CreateThrowable(
232 PEXCEPTION_RECORD pExceptionRecord,
233 BOOL bAsynchronousThreadStop
234 );
235
236 DWORD GetExceptionCode() { return m_ExceptionCode; }
237 INDEBUG(inline bool IsValid());
238 INDEBUG(static UINT_PTR DebugComputeNestingLevel());
239
240 inline OBJECTREF GetThrowable()
241 {
242 CONTRACTL
243 {
244 MODE_COOPERATIVE;
245 NOTHROW;
246 GC_NOTRIGGER;
247 }
248 CONTRACTL_END;
249
250 if (NULL != m_hThrowable)
251 {
252 return ObjectFromHandle(m_hThrowable);
253 }
254
255 return NULL;
256 }
257
258 // Return a StackFrame of the current frame for parent frame checking purposes.
259 // Don't use this StackFrame in any way except to pass it back to the ExceptionTracker
260 // via IsUnwoundToTargetParentFrame().
261 static StackFrame GetStackFrameForParentCheck(CrawlFrame * pCF);
262
263 static bool IsInStackRegionUnwoundBySpecifiedException(CrawlFrame * pCF, PTR_ExceptionTracker pExceptionTracker);
264 static bool IsInStackRegionUnwoundByCurrentException(CrawlFrame * pCF);
265
266 static bool HasFrameBeenUnwoundByAnyActiveException(CrawlFrame * pCF);
267 void SetCurrentEstablisherFrame(StackFrame sfEstablisher)
268 {
269 LIMITED_METHOD_CONTRACT;
270
271 m_sfCurrentEstablisherFrame = sfEstablisher;
272 }
273
274 StackFrame GetCurrentEstablisherFrame()
275 {
276 LIMITED_METHOD_CONTRACT;
277
278 return m_sfCurrentEstablisherFrame;
279 }
280
281 void SetLastUnwoundEstablisherFrame(StackFrame sfEstablisher)
282 {
283 LIMITED_METHOD_CONTRACT;
284
285 m_sfLastUnwoundEstablisherFrame = sfEstablisher;
286 }
287
288 StackFrame GetLastUnwoundEstablisherFrame()
289 {
290 LIMITED_METHOD_CONTRACT;
291
292 return m_sfLastUnwoundEstablisherFrame;
293 }
294
295 PTR_Frame GetInitialExplicitFrame()
296 {
297 LIMITED_METHOD_CONTRACT;
298
299 return m_pInitialExplicitFrame;
300 }
301
302#ifdef FEATURE_PAL
303 // Reset the range of explicit frames, the limit frame and the scanned
304 // stack range before unwinding a sequence of native frames. These frames
305 // will be in the unwound part of the stack.
306 void CleanupBeforeNativeFramesUnwind()
307 {
308 m_pInitialExplicitFrame = NULL;
309 m_pLimitFrame = NULL;
310 m_ScannedStackRange.Reset();
311 }
312#endif // FEATURE_PAL
313
314 // Determines if we have unwound to the specified parent method frame.
315 // Currently this is only used for funclet skipping.
316 static bool IsUnwoundToTargetParentFrame(CrawlFrame * pCF, StackFrame sfParent);
317 static bool IsUnwoundToTargetParentFrame(StackFrame sfToCheck, StackFrame sfParent);
318
319 // Given the CrawlFrame for a funclet frame, return the frame pointer of the enclosing funclet frame.
320 // For filter funclet frames and a normal method frames, this function returns a NULL StackFrame.
321 //
322 // <WARNING>
323 // It is not valid to call this function on an arbitrary funclet. You have to be doing a full stackwalk from
324 // the leaf frame and skipping method frames as indicated by the return value of this function. This function
325 // relies on the ExceptionTrackers, which are collapsed in the second pass when a nested exception escapes.
326 // When this happens, we'll lose information on the funclet represented by the collapsed tracker.
327 // </WARNING>
328 //
329 // Return Value:
330 // StackFrame.IsNull() - no skipping is necessary
331 // StackFrame.IsMaxVal() - skip one frame and then ask again
332 // Anything else - skip to the method frame indicated by the return value and ask again
333 static StackFrame FindParentStackFrameForStackWalk(CrawlFrame* pCF, bool fForGCReporting = false);
334
335 // Given the CrawlFrame for a filter funclet frame, return the frame pointer of the parent method frame.
336 // It also returns the relative offset and the caller SP of the parent method frame.
337 //
338 // <WARNING>
339 // The same warning for FindParentStackFrameForStackWalk() also applies here. Moreoever, although
340 // this function seems to be more convenient, it may potentially trigger a full stackwalk! Do not
341 // call this unless you know absolutely what you are doing. In most cases FindParentStackFrameForStackWalk()
342 // is what you need.
343 // </WARNING>
344 //
345 // Return Value:
346 // StackFrame.IsNull() - no skipping is necessary
347 // Anything else - the StackFrame of the parent method frame
348 static StackFrame FindParentStackFrameEx(CrawlFrame* pCF,
349 DWORD* pParentOffset,
350 UINT_PTR* pParentCallerSP);
351
352 static void
353 PopTrackers(StackFrame sfResumeFrame,
354 bool fPopWhenEqual);
355
356 static void
357 PopTrackers(void* pvStackPointer);
358
359 static void
360 PopTrackerIfEscaping(void* pvStackPointer);
361
362 static ExceptionTracker*
363 GetOrCreateTracker(UINT_PTR ControlPc,
364 StackFrame sf,
365 EXCEPTION_RECORD* pExceptionRecord,
366 T_CONTEXT* pContextRecord,
367 BOOL bAsynchronousThreadStop,
368 bool fIsFirstPass,
369 StackTraceState* pSTState);
370
371 static void
372 ResumeExecution(T_CONTEXT* pContextRecord,
373 EXCEPTION_RECORD* pExceptionRecord
374 );
375
376 void ResetLimitFrame();
377
378#ifdef DACCESS_COMPILE
379 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
380#endif // DACCESS_COMPILE
381
382 static void DebugLogTrackerRanges(__in_z const char *pszTag);
383
384 bool IsStackOverflowException();
385
386#if defined(FEATURE_PAL) && !defined(CROSS_COMPILE)
387 void TakeExceptionPointersOwnership(PAL_SEHException* ex)
388 {
389 _ASSERTE(ex->GetExceptionRecord() == m_ptrs.ExceptionRecord);
390 _ASSERTE(ex->GetContextRecord() == m_ptrs.ContextRecord);
391 ex->Clear();
392 m_fOwnsExceptionPointers = TRUE;
393 }
394#endif // FEATURE_PAL && !CROSS_COMPILE
395
396private:
397 DWORD_PTR
398 CallHandler(UINT_PTR dwHandlerStartPC,
399 StackFrame sf,
400 EE_ILEXCEPTION_CLAUSE* pEHClause,
401 MethodDesc* pMD,
402 EHFuncletType funcletType
403 X86_ARG(PT_CONTEXT pContextRecord)
404 ARM_ARG(PT_CONTEXT pContextRecord)
405 ARM64_ARG(PT_CONTEXT pContextRecord)
406 );
407
408 inline static BOOL
409 ClauseCoversPC(EE_ILEXCEPTION_CLAUSE* pEHClause,
410 DWORD dwOffset);
411
412 static bool
413 IsFilterStartOffset(EE_ILEXCEPTION_CLAUSE* pEHClause, DWORD_PTR dwHandlerStartPC);
414
415#ifndef DACCESS_COMPILE
416 void DestroyExceptionHandle()
417 {
418 // Never, ever destroy a preallocated exception handle.
419 if ((m_hThrowable != NULL) && !CLRException::IsPreallocatedExceptionHandle(m_hThrowable))
420 {
421 DestroyHandle(m_hThrowable);
422 }
423
424 m_hThrowable = NULL;
425 }
426#endif // !DACCESS_COMPILE
427
428 void SaveStackTrace();
429
430 inline BOOL CanAllocateMemory()
431 {
432 CONTRACTL
433 {
434 MODE_COOPERATIVE;
435 NOTHROW;
436 GC_NOTRIGGER;
437 }
438 CONTRACTL_END;
439
440 OBJECTREF oThrowable = GetThrowable();
441
442 return !(oThrowable == CLRException::GetPreallocatedOutOfMemoryException()) &&
443 !(oThrowable == CLRException::GetPreallocatedStackOverflowException());
444 }
445
446 INDEBUG(inline BOOL ThrowableIsValid());
447
448 bool HandleNestedExceptionEscape(StackFrame sf, bool fIsFirstPass);
449
450#if defined(DEBUGGING_SUPPORTED)
451 BOOL NotifyDebuggerOfStub(Thread* pThread, StackFrame sf, Frame* pCurrentFrame);
452
453 void
454 MakeCallbacksRelatedToHandler(bool fBeforeCallingHandler,
455 Thread* pThread,
456 MethodDesc* pMD,
457 EE_ILEXCEPTION_CLAUSE* pEHClause,
458 DWORD_PTR dwHandlerStartPC,
459 StackFrame sf);
460#else // !DEBUGGING_SUPPORTED
461 void
462 MakeCallbacksRelatedToHandler(bool fBeforeCallingHandler,
463 Thread* pThread,
464 MethodDesc* pMD,
465 EE_ILEXCEPTION_CLAUSE* pEHClause,
466 DWORD_PTR dwHandlerStartPC,
467 StackFrame sf) {return;}
468#endif // !DEBUGGING_SUPPORTED
469
470 // private helpers
471 static StackFrame GetCallerSPOfParentOfNonExceptionallyInvokedFunclet(CrawlFrame *pCF);
472
473 static StackFrame FindParentStackFrameHelper(CrawlFrame* pCF,
474 bool* pfRealParent,
475 DWORD* pParentOffset,
476 UINT_PTR* pParentCallerSP,
477 bool fForGCReporting = false);
478
479 static StackFrame RareFindParentStackFrame(CrawlFrame* pCF,
480 DWORD* pParentOffset,
481 UINT_PTR* pParentCallerSP);
482
483 static StackWalkAction RareFindParentStackFrameCallback(CrawlFrame* pCF, LPVOID pData);
484
485 struct DAC_EXCEPTION_POINTERS
486 {
487 PTR_EXCEPTION_RECORD ExceptionRecord;
488 PTR_CONTEXT ContextRecord;
489 };
490
491public:
492
493 static UINT_PTR FinishSecondPass(Thread* pThread, UINT_PTR uResumePC, StackFrame sf,
494 T_CONTEXT* pContextRecord, ExceptionTracker *pTracker, bool* pfAborting = NULL);
495 UINT_PTR CallCatchHandler(T_CONTEXT* pContextRecord, bool* pfAborting = NULL);
496
497 static bool FindNonvolatileRegisterPointers(Thread* pThread, UINT_PTR uOriginalSP, REGDISPLAY* pRegDisplay, TADDR uResumeFrameFP);
498 static void UpdateNonvolatileRegisters(T_CONTEXT* pContextRecord, REGDISPLAY *pRegDisplay, bool fAborting);
499
500 PTR_Frame GetLimitFrame()
501 {
502 LIMITED_METHOD_CONTRACT;
503 return m_pLimitFrame;
504 }
505
506 StackRange GetScannedStackRange()
507 {
508 LIMITED_METHOD_CONTRACT;
509
510 return m_ScannedStackRange;
511 }
512
513 UINT_PTR GetCatchToCallPC()
514 {
515 LIMITED_METHOD_CONTRACT;
516
517 return m_uCatchToCallPC;
518 }
519
520 EE_ILEXCEPTION_CLAUSE GetEHClauseForCatch()
521 {
522 return m_ClauseForCatch;
523 }
524
525 // Returns the topmost frame seen during the first pass.
526 StackFrame GetTopmostStackFrameFromFirstPass()
527 {
528 LIMITED_METHOD_CONTRACT;
529
530 return m_sfFirstPassTopmostFrame;
531 }
532
533#ifdef _DEBUG
534 StackFrame GetResumeStackFrame()
535 {
536 LIMITED_METHOD_CONTRACT;
537
538 return m_sfResumeStackFrame;
539 }
540
541 PTR_EXCEPTION_CLAUSE_TOKEN GetCatchHandlerExceptionClauseToken()
542 {
543 LIMITED_METHOD_CONTRACT;
544
545 return m_pClauseForCatchToken;
546 }
547#endif // _DEBUG
548
549 DWORD GetCatchHandlerExceptionClauseIndex()
550 {
551 LIMITED_METHOD_CONTRACT;
552
553 return m_dwIndexClauseForCatch;
554 }
555
556 StackFrame GetEstablisherOfActualHandlingFrame()
557 {
558 LIMITED_METHOD_CONTRACT;
559
560 return m_sfEstablisherOfActualHandlerFrame;
561 }
562
563 StackFrame GetCallerOfActualHandlingFrame()
564 {
565 LIMITED_METHOD_CONTRACT;
566
567 return m_sfCallerOfActualHandlerFrame;
568 }
569
570 StackFrame GetCallerOfEnclosingClause()
571 {
572 LIMITED_METHOD_CONTRACT;
573
574 return m_EnclosingClauseInfoForGCReporting.GetEnclosingClauseCallerSP();
575 }
576
577 StackFrame GetCallerOfCollapsedEnclosingClause()
578 {
579 LIMITED_METHOD_CONTRACT;
580
581 return m_EnclosingClauseInfoOfCollapsedTracker.GetEnclosingClauseCallerSP();
582 }
583
584#ifndef FEATURE_PAL
585private:
586 EHWatsonBucketTracker m_WatsonBucketTracker;
587public:
588 inline PTR_EHWatsonBucketTracker GetWatsonBucketTracker()
589 {
590 LIMITED_METHOD_CONTRACT;
591 return PTR_EHWatsonBucketTracker(PTR_HOST_MEMBER_TADDR(ExceptionTracker, this, m_WatsonBucketTracker));
592 }
593#endif // !FEATURE_PAL
594
595#ifdef FEATURE_CORRUPTING_EXCEPTIONS
596private:
597 CorruptionSeverity m_CorruptionSeverity;
598public:
599 inline CorruptionSeverity GetCorruptionSeverity()
600 {
601 LIMITED_METHOD_CONTRACT;
602
603 return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_CorruptionSeverity);
604 }
605
606 inline void SetCorruptionSeverity(CorruptionSeverity severityToSet)
607 {
608 LIMITED_METHOD_CONTRACT;
609
610 m_CorruptionSeverity = severityToSet;
611 }
612#endif // FEATURE_CORRUPTING_EXCEPTIONS
613
614private:
615 BOOL m_fDeliveredFirstChanceNotification;
616
617public:
618 inline BOOL DeliveredFirstChanceNotification()
619 {
620 LIMITED_METHOD_CONTRACT;
621
622 return m_fDeliveredFirstChanceNotification;
623 }
624
625 inline void SetFirstChanceNotificationStatus(BOOL fDelivered)
626 {
627 LIMITED_METHOD_CONTRACT;
628
629 m_fDeliveredFirstChanceNotification = fDelivered;
630 }
631
632 // Returns the exception tracker previous to the current
633 inline PTR_ExceptionTracker GetPreviousExceptionTracker()
634 {
635 LIMITED_METHOD_CONTRACT;
636
637 return m_pPrevNestedInfo;
638 }
639
640 // Returns the throwble associated with the tracker as handle
641 inline OBJECTHANDLE GetThrowableAsHandle()
642 {
643 LIMITED_METHOD_CONTRACT;
644
645 return m_hThrowable;
646 }
647
648 bool IsInFirstPass()
649 {
650 return !m_ExceptionFlags.UnwindHasStarted();
651 }
652
653 EHClauseInfo* GetEHClauseInfo()
654 {
655 return &m_EHClauseInfo;
656 }
657
658private: ;
659
660 void ReleaseResources();
661
662 void SetEnclosingClauseInfo(bool fEnclosingClauseIsFunclet,
663 DWORD dwEnclosingClauseOffset,
664 UINT_PTR uEnclosingClauseCallerSP);
665
666 class StackRange
667 {
668 public:
669 StackRange();
670 void Reset();
671 bool IsEmpty();
672 bool IsSupersededBy(StackFrame sf);
673 void CombineWith(StackFrame sfCurrent, StackRange* pPreviousRange);
674 bool Contains(StackFrame sf);
675 void ExtendUpperBound(StackFrame sf);
676 void ExtendLowerBound(StackFrame sf);
677 void TrimLowerBound(StackFrame sf);
678 StackFrame GetLowerBound();
679 StackFrame GetUpperBound();
680 INDEBUG(bool IsDisjointWithAndLowerThan(StackRange* pOtherRange));
681 private:
682 INDEBUG(bool IsConsistent());
683
684 private:
685 // <TODO> can we use a smaller encoding? </TODO>
686 StackFrame m_sfLowBound;
687 StackFrame m_sfHighBound;
688 };
689
690 struct EnclosingClauseInfo
691 {
692 public:
693 EnclosingClauseInfo();
694 EnclosingClauseInfo(bool fEnclosingClauseIsFunclet, DWORD dwEnclosingClauseOffset, UINT_PTR uEnclosingClauseCallerSP);
695
696 bool EnclosingClauseIsFunclet();
697 DWORD GetEnclosingClauseOffset();
698 UINT_PTR GetEnclosingClauseCallerSP();
699 void SetEnclosingClauseCallerSP(UINT_PTR callerSP);
700
701 bool operator==(const EnclosingClauseInfo & rhs);
702
703 private:
704 UINT_PTR m_uEnclosingClauseCallerSP;
705 DWORD m_dwEnclosingClauseOffset;
706 bool m_fEnclosingClauseIsFunclet;
707 };
708
709 PTR_ExceptionTracker m_pPrevNestedInfo;
710 Thread* m_pThread; // this is used as an IsValid/IsFree field -- if it's NULL, the allocator can
711 // reuse its memory, if it's non-NULL, it better be a valid thread pointer
712
713 StackRange m_ScannedStackRange;
714 DAC_EXCEPTION_POINTERS m_ptrs;
715#ifdef FEATURE_PAL
716 BOOL m_fOwnsExceptionPointers;
717#endif
718 OBJECTHANDLE m_hThrowable;
719 StackTraceInfo m_StackTraceInfo;
720 UINT_PTR m_uCatchToCallPC;
721 BOOL m_fResetEnclosingClauseSPForCatchFunclet;
722
723 union
724 {
725 MethodDesc* m_pSkipToParentFunctionMD; // SKIPTOPARENT
726 MethodDesc* m_pMethodDescOfCatcher;
727 };
728
729 StackFrame m_sfResumeStackFrame; // RESUMEFRAME
730 StackFrame m_sfFirstPassTopmostFrame; // Topmost frame seen during first pass
731 PTR_EXCEPTION_CLAUSE_TOKEN m_pClauseForCatchToken; // RESUMEFRAME
732 EE_ILEXCEPTION_CLAUSE m_ClauseForCatch;
733 // Index of EH clause that will catch the exception
734 DWORD m_dwIndexClauseForCatch;
735
736 // Establisher frame of the managed frame that contains
737 // the handler for the exception (corresponding
738 // to the EH index we save off in m_dwIndexClauseForCatch)
739 StackFrame m_sfEstablisherOfActualHandlerFrame;
740 StackFrame m_sfCallerOfActualHandlerFrame;
741
742 ExceptionFlags m_ExceptionFlags;
743 DWORD m_ExceptionCode;
744
745 PTR_Frame m_pLimitFrame;
746
747#ifdef DEBUGGING_SUPPORTED
748 //
749 // DEBUGGER STATE
750 //
751 DebuggerExState m_DebuggerExState;
752#endif // DEBUGGING_SUPPORTED
753
754 //
755 // Information for the funclet we are calling
756 //
757 EHClauseInfo m_EHClauseInfo;
758
759 // This flag indicates whether the SP we pass to a funclet is for an enclosing funclet.
760 EnclosingClauseInfo m_EnclosingClauseInfo;
761
762 // This stores the actual callerSP of the frame that is about to execute the funclet.
763 // It differs from "m_EnclosingClauseInfo" where upon detecting a nested exception,
764 // the latter can contain the callerSP of the original funclet instead of that of the
765 // current frame.
766 EnclosingClauseInfo m_EnclosingClauseInfoForGCReporting;
767 bool m_fFixupCallerSPForGCReporting;
768
769 StackFrame m_sfCurrentEstablisherFrame;
770 StackFrame m_sfLastUnwoundEstablisherFrame;
771 PTR_Frame m_pInitialExplicitFrame;
772 CallerStackFrame m_csfEHClauseOfCollapsedTracker;
773 EnclosingClauseInfo m_EnclosingClauseInfoOfCollapsedTracker;
774};
775
776PTR_ExceptionTracker GetEHTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, PTR_ExceptionTracker pStartingEHTracker);
777
778class TrackerAllocator
779{
780public:
781 void Init();
782 void Terminate();
783 ExceptionTracker* GetTrackerMemory();
784 void FreeTrackerMemory(ExceptionTracker* pTracker);
785
786private:
787
788 struct Page;
789
790 struct PageHeader
791 {
792 Page* m_pNext;
793 LONG m_idxFirstFree;
794 };
795
796 enum
797 {
798 //
799 // Due to the unexpected growth of the ExceptionTracker struct,
800 // GetOsPageSize() does not seem appropriate anymore on x64, and
801 // we should behave the same on x64 as on ia64 regardless of
802 // the difference between the page sizes on the platforms.
803 //
804 TRACKER_ALLOCATOR_PAGE_SIZE = 8*1024,
805 TRACKER_ALLOCATOR_MAX_OOM_SPINS = 20,
806 TRACKER_ALLOCATOR_OOM_SPIN_DELAY = 100,
807 NUM_TRACKERS_PER_PAGE = ((TRACKER_ALLOCATOR_PAGE_SIZE - sizeof(PageHeader)) / sizeof(ExceptionTracker)),
808 };
809
810 struct Page
811 {
812 PageHeader m_header;
813 ExceptionTracker m_rgTrackers[NUM_TRACKERS_PER_PAGE];
814 };
815
816 static_assert_no_msg(sizeof(Page) <= TRACKER_ALLOCATOR_PAGE_SIZE);
817
818 Page* m_pFirstPage;
819 Crst* m_pCrst;
820};
821
822#endif // WIN64EXCEPTIONS
823
824#endif // __EXCEPTION_HANDLING_h__
825