mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
8.5 KiB
284 lines
8.5 KiB
/***
|
|
*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 <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntstatus.h> // STATUS_UNHANDLED_EXCEPTION
|
|
#include <ntos.h>
|
|
#include <ex.h> // ExRaiseException
|
|
}
|
|
#endif
|
|
#include <windows.h>
|
|
|
|
#include <mtdll.h>
|
|
|
|
#include <ehdata.h>
|
|
#include <trnsctrl.h>
|
|
#include <eh.h>
|
|
#include <ehhooks.h>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <setjmp.h>
|
|
#include <ehassert.h>
|
|
#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;
|
|
}
|
|
}
|