| 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 | |