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 | |
24 | EXTERN_C EXCEPTION_DISPOSITION |
25 | ProcessCLRException(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 | |
31 | enum CLRUnwindStatus { UnwindPending, FirstPassComplete, SecondPassComplete }; |
32 | |
33 | enum 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 |
41 | enum EHFuncletType |
42 | { |
43 | Filter = 0x0001, |
44 | FaultFinally = 0x0002, |
45 | Catch = 0x0004, |
46 | }; |
47 | |
48 | typedef DPTR(class ExceptionTracker) PTR_ExceptionTracker; |
49 | class 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 | |
60 | private: |
61 | class StackRange; |
62 | public: |
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 | |
396 | private: |
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 | |
491 | public: |
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 |
585 | private: |
586 | EHWatsonBucketTracker m_WatsonBucketTracker; |
587 | public: |
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 |
596 | private: |
597 | CorruptionSeverity m_CorruptionSeverity; |
598 | public: |
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 | |
614 | private: |
615 | BOOL m_fDeliveredFirstChanceNotification; |
616 | |
617 | public: |
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 | |
658 | private: ; |
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 | |
776 | PTR_ExceptionTracker GetEHTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, PTR_ExceptionTracker pStartingEHTracker); |
777 | |
778 | class TrackerAllocator |
779 | { |
780 | public: |
781 | void Init(); |
782 | void Terminate(); |
783 | ExceptionTracker* GetTrackerMemory(); |
784 | void FreeTrackerMemory(ExceptionTracker* pTracker); |
785 | |
786 | private: |
787 | |
788 | struct Page; |
789 | |
790 | struct |
791 | { |
792 | Page* ; |
793 | LONG ; |
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 ; |
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 | |