/*** *trnsctrl.cpp - Routines for doing control transfers * * Copyright (c) 1993-1995, Microsoft Corporation. All rights reserved. * *Purpose: * Routines for doing control transfers; written using inline * assembly in naked functions. Contains the public routine * _CxxFrameHandler, the entry point for the frame handler * *Revision History: * 05-24-93 BES Module created * 08-07-95 RKP Support for VC++ V4.0 Non-Local Goto * ****/ #if defined(_NTSUBSET_) extern "C" { #include #include #include #include // STATUS_UNHANDLED_EXCEPTION #include #include // ExRaiseException } #endif #include #include #include #include #include #include #pragma hdrstop #include #include #include "ehunwind.h" #include "bridge.h" ///////////////////////////////////////////////////////////////////////////// // // _CxxFrameHandler - Real entry point to the runtime; this thunk fixes up // the parameters, and then calls the workhorse. // extern "C" EXCEPTION_DISPOSITION __cdecl __InternalCxxFrameHandler( EHExceptionRecord *pExcept, // Information for this exception EHRegistrationNode *pRN, // Dynamic information for this frame void *pContext, // Context info DispatcherContext *pDC, // More dynamic info for this frame FuncInfo *pFuncInfo, // Static information for this frame int CatchDepth, // Unused on Alpha EHRegistrationNode *pMarkerRN, // Unused on Alpha BOOL recursive); // True if this is a translation exception extern "C" _CRTIMP EXCEPTION_DISPOSITION __cdecl _CxxFrameHandler( EHExceptionRecord *pExcept, // Information for this exception EHRegistrationNode *pRN, // Dynamic information for this frame void *pContext, // Context info DispatcherContext *pDC // More dynamic info for this frame ) { return __InternalCxxFrameHandler ( pExcept, pRN, pContext, pDC, 0, 0, NULL, FALSE ); } ///////////////////////////////////////////////////////////////////////////// // // Call RtlUnwind in a returning fassion (hack required) // extern "C" VOID _UnwindNestedFrames ( IN EHRegistrationNode *TargetFrame, IN EHExceptionRecord *ExceptionRecord ) { RtlUnwindActions( (PVOID)TargetFrame, (PEXCEPTION_RECORD)ExceptionRecord ); } ///////////////////////////////////////////////////////////////////////////// // // _JumpToContinuation - unwind the stack to the specified frame and jump // to the specified address. // // Does not return. // void _JumpToContinuation( void *TargetIp, // The target address EHRegistrationNode *TargetFrame // The target virtual frame ptr ) { // // MIPS does not call NLG_Notify in _JumpToContinuation // so ALPHA doesn't either // RtlUnwind ( (void *)TargetFrame, (void *)TargetIp, NULL, NULL ); } ///////////////////////////////////////////////////////////////////////////// // // __CxxInternalEHGoto - unwind the stack to the specified frame AND STATE // then jump to the specified address. Only Called from __CxxEHGoto // // Does not return. // extern "C" _CRTIMP void __CxxInternalEHGoto( void * target_address, LONG target_state, void * target_real_fp ) { void * target_virtual_fp; EXCEPTION_RECORD GotoException; GotoException.ExceptionCode = STATUS_UNWIND; GotoException.ExceptionFlags = EXCEPTION_UNWINDING; GotoException.ExceptionRecord = NULL; GotoException.ExceptionAddress = 0; GotoException.NumberParameters = 1; GotoException.ExceptionInformation[0] = target_state; // // NLG_Notify uses Real FP + 1 instead of Virtual FP // This maintains the debugger invariant of Actual SP < Target FP // target_virtual_fp = (char *)target_real_fp + 1; _NLG_Notify ( target_address, target_virtual_fp, 0x2 /*NLG_CATCH_LEAVE*/ ); RtlUnwindRfp( target_real_fp, target_address, &GotoException, 0 ); // // Control should not return to this point // DASSERT(0); } ///////////////////////////////////////////////////////////////////////////// // // CallSEHTranslator - calls the SEH translator, and handles the translation // exception. // // Assumes that a valid translator exists. // // Method: // The user written translator function is called through a "bridge" routine // which is written in assembly so that it may specify a custom frame handler. // This frame handler will capture the translated exception thrown by the // translator (if any) and pass it back into the C++ EH run-time. // // If the exception is not fully handled, the handler returns control to here, // so that this function can return to resume the normal search for a handler // for the original exception. // // Returns: TRUE if translator had a translation (handled or not) // FALSE if there was no translation // Does not return if translation was fully handled // BOOL _CallSETranslator( EHExceptionRecord *pExcept, // The exception to be translated EHRegistrationNode *pRN, // Dynamic info of function with catch void *pContext, // Context info (we don't care what's in it) DispatcherContext *pDC, // More dynamic info of function with catch (ignored) FuncInfo *pFuncInfo, // Static info of function with catch int CatchDepth, // How deeply nested in catch blocks are we? EHRegistrationNode *pMarkerRN // Marker for parent context ) { // // Call the translator; assume it will NOT give a translation // _EXCEPTION_POINTERS pointers = { (PEXCEPTION_RECORD)pExcept, (PCONTEXT)pContext }; BOOL DidTranslate = FALSE; __CxxSETranslatorBridge( __pSETranslator, // _se_translator_function PER_CODE(pExcept), // DWORD &pointers, // _EXCEPTION_POINTERS * pDC, // DispatcherContext * &DidTranslate); // BOOL * // // If control returned here the exception was either not translated or // was re-thrown. // return DidTranslate; } ///////////////////////////////////////////////////////////////////////////// // // TranslatorGuardHandler - frame handler for the SEH translator bridge // function __CxxSETranslatorBridge (see bridge.s). // // On search: // This frame handler will check if there is a catch at the current level // for the translated exception. If there is no handler or the handler // did a re-throw, control is transfered back into CallSEHTranslator. // // Note that this handler must reference several values in the bridge // function's frame. Always use the offset macros defined in bridge.h to // ensure that both this routine and the bridge function are in sync. // // Does not return. // // On unwind: // Sets the DidUnwind flag in the bridge function's frame, and returns. // extern "C" EXCEPTION_DISPOSITION __CxxTranslatorGuardHandler( EHExceptionRecord *pExcept, // Information for this exception EHRegistrationNode *pRN, // not sure what on Alpha CONTEXT *pContext, // Translated Exception Context DispatcherContext *pDC // Bridge Frame Dispatcher Context ) { // // Virtual Frame Pointer to the __CxxSETranslatorBridge frame // for which this frame handler was established. // char * BridgeVfp = (char *)(pDC -> EstablisherFrame); if (IS_UNWINDING(PER_FLAGS(pExcept))) { // // Indicate that translation occured. // BOOL *pDidTranslate = *((BOOL **)(BridgeVfp+BrTrpDidTrans_vfp)); *pDidTranslate = TRUE; return ExceptionContinueSearch; } else { // // Check for a handler: // DispatcherContext *EHpDC = *((DispatcherContext **)(BridgeVfp+BrTrEHpDC_vfp)); __InternalCxxFrameHandler ( pExcept, 0, pContext, EHpDC, 0, 0, 0, TRUE ); // // Transfer control back to establisher (i.e. the bridge). // void *BrTrContinue = *((void **)(BridgeVfp+BrTrpContinue_vfp)); // // No debugger notification needed for unwinding back to the bridge // RtlUnwind( (void *)BridgeVfp, BrTrContinue, NULL, NULL ); // Unreached. return ExceptionContinueSearch; } }