// // __CxxFrameHandler - Real entry point to the runtime // extern "C" _CRTIMP EXCEPTION_DISPOSITION __CxxFrameHandler( EHExceptionRecord *pExcept, // Information for this exception EHRegistrationNode *pFrame, // Dynamic information for this frame void *pContext, // Context info DispatcherContext *pDC // More dynamic info for this frame ) { FuncInfo *pFuncInfo; EXCEPTION_DISPOSITION result; PFRAMEINFO pframeinfo; if (!(IS_UNWINDING(PER_FLAGS(pExcept))) && ((unsigned long)pContext != (unsigned long)GetRTOC()) ) { // we are calling catch from different CFM, re-initialize our globals _pFrameInfoChain =(PFRAMEINFO) pDC->pftinfo->pFrameInfo; _pftinfo->pFrameInfo = pDC->pftinfo->pFrameInfo; cNested = 0; pframeinfo = (PFRAMEINFO)_pftinfo->pFrameInfo; while (pframeinfo) { cNested++; pframeinfo = pframeinfo->pNext; } } pFuncInfo = (FuncInfo*)pDC->FunctionEntry->HandlerData; result = __InternalCxxFrameHandler( pExcept, pFrame, pContext, pDC, pFuncInfo, 0, NULL, FALSE ); return result; }
void __stdcall _UnwindNestedFrames( EHRegistrationNode *pRN, // Unwind up to (but not including) this frame EHExceptionRecord *pExcept // The exception that initiated this unwind ) { EHTRACE_ENTER; void* pReturnPoint; EHRegistrationNode *pDispatcherRN; // Magic! __asm { // // Save the dispatcher's marker node // // NOTE: RtlUnwind will trash the callee-save regs EBX, ESI, and EDI. // We explicitly use them here in the inline-asm so they get preserved // and restored by the function prologue/epilogue. // mov esi, dword ptr FS:[0] // use ESI mov pDispatcherRN, esi } __asm mov pReturnPoint, offset ReturnPoint RtlUnwind(pRN, pReturnPoint, (PEXCEPTION_RECORD)pExcept, nullptr); ReturnPoint: PER_FLAGS(pExcept) &= ~EXCEPTION_UNWINDING; // Clear the 'Unwinding' flag // in case exception is rethrown __asm { // // Re-link the dispatcher's marker node // mov edi, dword ptr FS:[0] // Get the current head (use EDI) mov ebx, pDispatcherRN // Get the saved head (use EBX) mov [ebx], edi // Link saved head to current head mov dword ptr FS:[0], ebx // Make saved head current head } EHTRACE_EXIT; return; }
void _UnwindNestedFrames( EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame EHExceptionRecord *pExcept // The exception that initiated this unwind //void *pContext // Context info for current exception ) { PPMSTACK spCur; PPMSTACK spCurCatch; DispatcherContext curDC; PFTINFO pftinfoTOC; PRUNTIME_FUNCTION pFunctionEntry; PRUNTIME_FUNCTION pFunctionEntryCatch = NULL; unsigned long cNestedTmp; PFRAMEINFO pframeinfo; spCur = (PPMSTACK)GetSP(); //Loop through the frames backwards on the stack to destroy objects until target frame //Assume: spCur = spCur->pSpBackChain; while (spCur < pFrame) { // we should only look the frame which hasn't been looked if (_pFrameInfoChain) { if ((spCur > _pFrameInfoChain->pExitContext) && (spCur < _pFrameInfoChain->pSp)) { spCur = spCur->pSpBackChain; continue; } if (cNested > 0) { cNestedTmp = cNested; pframeinfo = _pFrameInfoChain; while (cNestedTmp-- && pframeinfo) { if ( (spCur->pSpBackChain == pframeinfo->pExitContext) ) { pFunctionEntryCatch = GetFunctionEntry(spCur, &pftinfoTOC); spCurCatch = spCur; break; } pframeinfo = pframeinfo->pNext; } if (pframeinfo) { spCur = spCur->pSpBackChain; continue; } } } pFunctionEntry = GetFunctionEntry(spCur, &pftinfoTOC); if (pFunctionEntry && pFunctionEntry->ExceptionHandler != NULL) { //set unwinding flag //stack point, old PC(in linker register, execution point==state), Registers in Context PER_FLAGS(pExcept) |= EXCEPTION_UNWINDING; curDC.ControlPc = spCur->dwLNKreg; curDC.FunctionEntry = pFunctionEntry; //what else to save?! curDC.EstablisherFrame = spCur; curDC.pftinfo = pftinfoTOC; if (pFunctionEntryCatch == pFunctionEntry) { // we have to update the return address in original catch frame if (spCurCatch->dwLNKreg > curDC.ControlPc) { curDC.ControlPc = spCurCatch->dwLNKreg; } } (*pFunctionEntry->ExceptionHandler)(pExcept, spCur, NULL, &curDC); } spCur = spCur->pSpBackChain; } // // clear the unwinding flag, in case exception is rethown // PER_FLAGS(pExcept) &= ~EXCEPTION_UNWINDING; return; }