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.
1961 lines
68 KiB
1961 lines
68 KiB
/***
|
|
*frame.cxx - The frame handler and everything associated with it.
|
|
*
|
|
* Copyright (c) 1993-1995, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* The frame handler and everything associated with it.
|
|
*
|
|
* Entry points:
|
|
* _CxxFrameHandler - the frame handler.
|
|
*
|
|
* Open issues:
|
|
* * Handling re-throw from dynamicly nested scope.
|
|
* * Fault-tolerance (checking for data structure validity).
|
|
*
|
|
*Revision History:
|
|
* 05-20-93 BS Module created
|
|
* 03-03-94 TL Added Mips specific code
|
|
* 06-19-94 AD Added Alpha specific code (Al Dosser)
|
|
* 10-17-94 BWT Disable code for PPC.
|
|
* 11-23-94 JWM Removed obsolete 'hash' check in TypeMatch().
|
|
* 11-29-94 JWM AdjustPointer() now adds in pdisp, not vdisp.
|
|
* 01-13-95 JWM Added _NLG_Destination struct; dwCode set for catch
|
|
* blocks & local destructors.
|
|
* 02-09-95 JWM Mac merge.
|
|
* 02-10-95 JWM UnhandledExceptionFilter() now called if exception
|
|
* raised during stack unwind.
|
|
* 03-22-95 PML Add const for read-only compiler-gen'd structs
|
|
* 04-14-95 JWM Re-fix EH/SEH exception handling.
|
|
* 04-17-95 JWM FrameUnwindFilter() must be #ifdef _WIN32.
|
|
* 04-21-95 JWM _NLG_Destination moved to exsup3.asm (_M_X86 only).
|
|
* 04-21-95 TGL Added Mips fixes.
|
|
* 04-27-95 JWM EH_ABORT_FRAME_UNWIND_PART now #ifdef ALLOW_UNWIND_ABORT.
|
|
* 05-19-95 DAK Don't initialize the kernel handler
|
|
* 06-07-95 JWM Various NLG additions.
|
|
* 06-14-95 JWM Unneeded LastError calls removed.
|
|
* 06-19-95 JWM NLG no longer uses per-thread data (X86 only).
|
|
* 09-26-95 AMP PowerMac avoids re-throws to same catch clause
|
|
*
|
|
****/
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
#ifdef _WIN32
|
|
#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> // CRT internal header file
|
|
#endif
|
|
|
|
#include <ehassert.h> // This project's versions of standard assert macros
|
|
#include <ehdata.h> // Declarations of all types used for EH
|
|
#include <trnsctrl.h> // Routines to handle transfer of control (trnsctrl.asm)
|
|
#include <ehstate.h> // Declarations of state management stuff
|
|
#include <eh.h> // User-visible routines for eh
|
|
#include <ehhooks.h> // Declarations of hook variables and callbacks
|
|
|
|
#pragma hdrstop // Pch is created from here
|
|
|
|
#ifdef _WIN32
|
|
extern "C" {
|
|
typedef struct {
|
|
unsigned long dwSig;
|
|
unsigned long uoffDestination;
|
|
unsigned long dwCode;
|
|
unsigned long uoffFramePointer;
|
|
} _NLG_INFO;
|
|
#if defined(_M_IX86) || defined(_M_MRX000) || defined(_M_PPC) || defined(_M_ALPHA) /*IFSTRIP=IGN*/
|
|
extern _NLG_INFO _NLG_Destination;
|
|
#else
|
|
_CRTIMP _NLG_INFO _NLG_Destination = {EH_MAGIC_NUMBER1,0,0,0};
|
|
#endif
|
|
}
|
|
#else
|
|
extern "C" {
|
|
extern __declspec(allocate("_CODE")) struct {
|
|
unsigned long dwSig;
|
|
unsigned long uoffDestination;
|
|
unsigned long dwCode;
|
|
unsigned long uoffFramePointer;
|
|
} _NLG_Destination;
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Forward declaration of local functions:
|
|
//
|
|
|
|
// M00TODO: all these parameters should be declared const
|
|
|
|
#ifdef _WIN32
|
|
// The local unwinder must be external (see __CxxLongjmpUnwind
|
|
// in in\trnsctrl.cpp)
|
|
extern "C" void __FrameUnwindToState( EHRegistrationNode*, DispatcherContext*, FuncInfo*, __ehstate_t );
|
|
static void FindHandler ( EHExceptionRecord*, EHRegistrationNode*, CONTEXT*, DispatcherContext*, FuncInfo*, BOOLEAN, int, EHRegistrationNode* );
|
|
static void FindHandlerForForeignException( EHExceptionRecord*, EHRegistrationNode*, CONTEXT*, DispatcherContext*, FuncInfo*, __ehstate_t, int, EHRegistrationNode* );
|
|
static void CatchIt ( EHExceptionRecord*, EHRegistrationNode*, CONTEXT*, DispatcherContext*, FuncInfo*, HandlerType*, CatchableType*, TryBlockMapEntry*, int, EHRegistrationNode* );
|
|
#if defined(_M_IX86) || defined(_M_MRX000) || defined(_M_PPC) || defined(_M_ALPHA) /*IFSTRIP=IGN*/
|
|
static void * CallCatchBlock ( EHExceptionRecord*, EHRegistrationNode*, CONTEXT*, FuncInfo*, void*, int, unsigned long );
|
|
#else
|
|
static void * CallCatchBlock ( EHExceptionRecord*, EHRegistrationNode*, CONTEXT*, FuncInfo*, void*, int );
|
|
#endif
|
|
static int ExFilterRethrow ( EXCEPTION_POINTERS * );
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
static TryBlockMapEntry*
|
|
GetRangeOfTrysToCheck( EHRegistrationNode*, FuncInfo*, int, __ehstate_t, unsigned*, unsigned*);
|
|
#else
|
|
static TryBlockMapEntry*
|
|
GetRangeOfTrysToCheck( FuncInfo*, int, __ehstate_t, unsigned*, unsigned*);
|
|
#endif
|
|
static void BuildCatchObject ( EHExceptionRecord*, EHRegistrationNode*, HandlerType*, CatchableType* );
|
|
static void DestructExceptionObject( EHExceptionRecord*, BOOLEAN );
|
|
#else
|
|
static void __FrameUnwindToState ( EHRegistrationNode*, DispatcherContext*, FuncInfo*, __ehstate_t );
|
|
static void FindHandler ( EHExceptionRecord*, EHRegistrationNode*, void*, DispatcherContext*, FuncInfo*, BOOLEAN, int, EHRegistrationNode* );
|
|
static void FindHandlerForForeignException( EHExceptionRecord*, EHRegistrationNode*, void*, DispatcherContext*, FuncInfo*, __ehstate_t, int, EHRegistrationNode* );
|
|
static void CatchIt ( EHExceptionRecord*, EHRegistrationNode*, void*, DispatcherContext*, FuncInfo*, HandlerType*, CatchableType*, TryBlockMapEntry*, int, EHRegistrationNode* );
|
|
extern void * CallCatchBlock ( EHExceptionRecord*, EHRegistrationNode*, void*, DispatcherContext*, FuncInfo*, void*, int, unsigned int * );
|
|
static TryBlockMapEntry*
|
|
GetRangeOfTrysToCheck( EHRegistrationNode*, FuncInfo*, int, __ehstate_t, unsigned*, unsigned*);
|
|
static void BuildCatchObject ( EHExceptionRecord*, EHRegistrationNode*, HandlerType*, CatchableType*, void *);
|
|
void DestructExceptionObject( EHExceptionRecord*, BOOLEAN, void * );
|
|
#endif // ifdef _WIN32
|
|
|
|
#if !defined(_M_IX86) && !defined(_M_MRX000) && !defined(_M_PPC) && !defined(_M_ALPHA) /*IFSTRIP=IGN*/
|
|
extern "C" void __cdecl __SetNLGCode(unsigned long);
|
|
extern "C" unsigned long __cdecl __GetNLGCode();
|
|
#endif
|
|
|
|
static inline int TypeMatch ( HandlerType*, CatchableType*, ThrowInfo* );
|
|
static void * AdjustPointer ( void*, const PMD& );
|
|
|
|
#ifdef _WIN32
|
|
//
|
|
// Make sure the terminate wrapper is dragged in:
|
|
//
|
|
static void *pMyUnhandledExceptionFilter =
|
|
#if defined(_NTSUBSET_)
|
|
0;
|
|
#else
|
|
&__CxxUnhandledExceptionFilter;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
//
|
|
// This describes the most recently handled exception, in case of a rethrow:
|
|
//
|
|
#ifdef _MT
|
|
#define pCurrentException (*((EHExceptionRecord**) &(_getptd()->_curexception)))
|
|
#ifdef _WIN32
|
|
#define pCurrentExContext (*((CONTEXT **) &(_getptd()->_curcontext)))
|
|
#else
|
|
#define pCurrentExContext (*((void **) &(_getptd()->_curcontext)))
|
|
#endif // ifdef _WIN32
|
|
#else
|
|
static EHExceptionRecord *pCurrentException = NULL;
|
|
#ifdef _WIN32
|
|
static CONTEXT *pCurrentExContext = NULL;
|
|
#else
|
|
static void *pCurrentExContext = NULL;
|
|
#endif // ifdef _WIN32
|
|
#endif
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
#define VER41_C2(p) (HT_ADJECTIVES(TBME_CATCH(FUNC_TRYBLOCK(*p,0), 0)) & 0x20)
|
|
#ifdef _MT
|
|
#define pExitContext (*((CONTEXT **) &(_getptd()->_pExitContext)))
|
|
#define iPendingTryBlock _getptd()->_MipsPtdDelta
|
|
#define iControlTryBlock _getptd()->_MipsPtdEpsilon
|
|
#else
|
|
static CONTEXT *pExitContext = NULL; // context to assist the return to the continuation point
|
|
static INT iPendingTryBlock = -1; // remembers the last try-block index in this frame
|
|
static INT iControlTryBlock = -1; // remembers the control try-block index in this frame
|
|
#endif // _MT
|
|
#elif defined(_M_PPC)
|
|
extern "C" CONTEXT* _GetUnwindContext(VOID);
|
|
#ifdef _MT
|
|
#define pExitContext (*((CONTEXT **) &(_getptd()->_pExitContext)))
|
|
#else
|
|
static CONTEXT *pExitContext = NULL; // context to assist the return to the continuation point
|
|
#endif // _MT
|
|
#endif // _M_PPC
|
|
|
|
#ifdef _M_MPPC
|
|
extern PFRAMEINFO _pFrameInfoChain; // used to remember nested frames
|
|
extern unsigned long fStaticNested;
|
|
int __fInsideDestructor = FALSE;
|
|
static FuncInfo *pCurrentFuncInfo = NULL;
|
|
static unsigned long fThrowFromCatch = 0;
|
|
static EHRegistrationNode *pRememberStack = NULL;
|
|
static HandlerType* pPreviousCatch = NULL;
|
|
#endif
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __InternalCxxFrameHandler - the frame handler for all functions with C++ EH
|
|
// information.
|
|
//
|
|
// If exception is handled, this doesn't return.
|
|
// Otherwise, it returns ExceptionContinueSearch.
|
|
//
|
|
// Note that this is called three ways:
|
|
// From __CxxFrameHandler: primary usage, called to inspect whole function.
|
|
// CatchDepth==0, pMarkerRN==NULL
|
|
// From CatchGuardHandler: If an exception occurred within a catch, this is
|
|
// called to check for try blocks within that catch only, and does not
|
|
// handle unwinds.
|
|
// From TranslatorGuardHandler: Called to handle the translation of a non-C++
|
|
// EH exception. Context considered is that of parent.
|
|
//
|
|
extern "C" EXCEPTION_DISPOSITION __cdecl __InternalCxxFrameHandler(
|
|
EHExceptionRecord *pExcept, // Information for this exception
|
|
EHRegistrationNode *pRN, // Dynamic information for this frame
|
|
#ifdef _WIN32
|
|
CONTEXT *pContext, // Context info
|
|
#else
|
|
void *pContext, // Context info (we don't care what's in it)
|
|
#endif
|
|
DispatcherContext *pDC, // Context within subject frame
|
|
FuncInfo *pFuncInfo, // Static information for this frame
|
|
int CatchDepth, // How deeply nested are we?
|
|
EHRegistrationNode *pMarkerRN, // Marker node for when checking inside
|
|
// catch block
|
|
BOOL recursive // Are we handling a translation?
|
|
) {
|
|
#if defined(_M_ALPHA)
|
|
//
|
|
// on Alpha - these values synthesized from DispatcherContext
|
|
//
|
|
pFuncInfo = (FuncInfo *)(pDC -> FunctionEntry -> HandlerData);
|
|
pRN = (EHRegistrationNode *)VIRTUAL_FP(pDC);
|
|
#endif
|
|
|
|
DASSERT(FUNC_MAGICNUM(*pFuncInfo) == EH_MAGIC_NUMBER1);
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
//
|
|
// We have to remember the most recent try-block index, in order to handle
|
|
// nested try blocks. The controlPc is always pointing to the address where
|
|
// control left the routine, which may not coincide with the catch handler we
|
|
// are interested in. If the routine we see here is a catch handler, we save
|
|
// the corresponding try-block index in our global variable if it's greater than
|
|
// the last one seen. When we arrive at the 'real' function that contains the try-blocks,
|
|
// we use this variable as the starting try-block index, if it happens to be greater than
|
|
// the one corresponding to the ControlPc's try-block.
|
|
//
|
|
if (IS_DISPATCHING(PER_FLAGS(pExcept))) {
|
|
if( FUNC_TRYBLOCKINDEX(*pFuncInfo) >= 0 && FUNC_NTRYBLOCKS(*pFuncInfo) == 0 ) {
|
|
if( iPendingTryBlock == -1 ) {
|
|
iPendingTryBlock = FUNC_TRYBLOCKINDEX(*pFuncInfo);
|
|
}
|
|
else if( FUNC_TRYBLOCKINDEX(*pFuncInfo) > iPendingTryBlock) {
|
|
//
|
|
// A transition to a nested try happened
|
|
//
|
|
iControlTryBlock = iPendingTryBlock;
|
|
iPendingTryBlock = FUNC_TRYBLOCKINDEX(*pFuncInfo);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
iPendingTryBlock = -1;
|
|
iControlTryBlock = -1;
|
|
}
|
|
#endif
|
|
|
|
#if defined(_M_ALPHA)
|
|
//
|
|
// A special case to support gotos out of nested catch handlers
|
|
// and setjmp/longjmp.
|
|
//
|
|
// See __CxxEHGoto in alpha\trnsctrl.cxx for details.
|
|
//
|
|
if (IS_TARGET_UNWIND(PER_FLAGS(pExcept)))
|
|
{
|
|
if (PER_CODE(pExcept) == STATUS_UNWIND &&
|
|
PER_NPARAMS(pExcept) == 1)
|
|
{
|
|
__ehstate_t target_state = (__ehstate_t)
|
|
((PEXCEPTION_RECORD)(pExcept)) -> ExceptionInformation[0];
|
|
|
|
DASSERT((target_state >= EH_EMPTY_STATE) &&
|
|
(target_state < FUNC_MAXSTATE(*pFuncInfo)));
|
|
|
|
__FrameUnwindToState(pRN, pDC, pFuncInfo, target_state);
|
|
return ExceptionContinueSearch;
|
|
}
|
|
else {
|
|
return ExceptionContinueSearch;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IS_UNWINDING(PER_FLAGS(pExcept)))
|
|
{
|
|
//
|
|
// We're at the unwinding stage of things. Don't care about the
|
|
// exception itself. (Check this first because it's easier)
|
|
//
|
|
|
|
#ifdef _M_PPC
|
|
if (FUNC_MAXSTATE(*pFuncInfo) != 0)
|
|
#else
|
|
if (FUNC_MAXSTATE(*pFuncInfo) != 0 && CatchDepth == 0)
|
|
#endif
|
|
{
|
|
//
|
|
// Only unwind if there's something to unwind
|
|
// AND we're being called through the primary RN.
|
|
//
|
|
#if defined(_M_MRX000) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
//
|
|
// If we are exiting to the continuation point, we don't want to
|
|
// use the unwind map again. Unwinding continues until the dispatcher finds
|
|
// the target frame, at which point the dispatcher will jump to the
|
|
// continuation point
|
|
//
|
|
// Don't unwind the target frame if the unwind was initiated by UnwindNestedFrames
|
|
//
|
|
if( (_GetUnwindContext() != NULL) && IS_TARGET_UNWIND(PER_FLAGS(pExcept)) ) {
|
|
#ifdef _M_PPC
|
|
//
|
|
// Virtually unwind the target frame to recover the value of r2.
|
|
// We must take care to not unwind a glue sequence that may have
|
|
// been used to reach the target frame. This is done by giving
|
|
// stack limit values that will regard any stack pointer as bad.
|
|
//
|
|
CONTEXT TocContext;
|
|
PRUNTIME_FUNCTION FunctionEntry;
|
|
BOOLEAN InFunction;
|
|
ULONG EstablisherFrame;
|
|
|
|
RtlMoveMemory((PVOID)&TocContext, pContext, sizeof(CONTEXT));
|
|
FunctionEntry = RtlLookupFunctionEntry(pDC->ControlPc);
|
|
RtlVirtualUnwind(pDC->ControlPc,
|
|
FunctionEntry,
|
|
&TocContext,
|
|
&InFunction,
|
|
&EstablisherFrame,
|
|
NULL,
|
|
0xffffffff,
|
|
0);
|
|
pContext->Gpr2 = TocContext.Gpr2;
|
|
#endif
|
|
|
|
//
|
|
// Save the target context to be used in 'CatchIt' to jump to the continuation point.
|
|
//
|
|
DASSERT(pExitContext != NULL);
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
_MoveContext(pExitContext, pContext);
|
|
//
|
|
// This is how we give control back to _UnwindNestedFrames
|
|
//
|
|
_MoveContext(pContext, _GetUnwindContext());
|
|
#else
|
|
RtlMoveMemory(pExitContext, pContext, sizeof(CONTEXT));
|
|
//
|
|
// This is how we give control back to _UnwindNestedFrames
|
|
//
|
|
RtlMoveMemory(pContext, _GetUnwindContext(), sizeof(CONTEXT));
|
|
#endif
|
|
return ExceptionContinueSearch;
|
|
}
|
|
#endif
|
|
#ifdef _M_PPC
|
|
__FrameUnwindToEmptyState(pRN, pDC, pFuncInfo);
|
|
#else
|
|
__FrameUnwindToState(pRN, pDC, pFuncInfo, EH_EMPTY_STATE);
|
|
#endif
|
|
}
|
|
|
|
return ExceptionContinueSearch; // I don't think this value matters
|
|
}
|
|
else if (FUNC_NTRYBLOCKS(*pFuncInfo) != 0)
|
|
{
|
|
//
|
|
// NT is looking for handlers. We've got handlers.
|
|
// Let's check this puppy out. Do we recognize it?
|
|
//
|
|
|
|
if ( (PER_CODE(pExcept) == EH_EXCEPTION_NUMBER)
|
|
&& (PER_MAGICNUM(pExcept) > EH_MAGIC_NUMBER1)
|
|
&& (THROW_FORWARDCOMPAT(*PER_PTHROW(pExcept)) != NULL) )
|
|
{
|
|
//
|
|
// Forward compatibility: The thrown object appears to have been
|
|
// created by a newer version of our compiler. Let that version's
|
|
// frame handler do the work (if one was specified).
|
|
//
|
|
|
|
#if defined (_WIN32) && defined (DEBUG)
|
|
if ( _ValidateExecute( (FARPROC)THROW_FORWARDCOMPAT(
|
|
*PER_PTHROW(pExcept)) ) )
|
|
{
|
|
#endif
|
|
return (EXCEPTION_DISPOSITION)
|
|
THROW_FORWARDCOMPAT( *PER_PTHROW(pExcept))
|
|
( pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN, recursive );
|
|
#if defined (_WIN32) && defined (DEBUG)
|
|
}
|
|
else
|
|
{
|
|
_inconsistency(); // Does not return; TKB
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Anything else: we'll handle it here.
|
|
//
|
|
FindHandler( pExcept, pRN, pContext, pDC, pFuncInfo, recursive, CatchDepth, pMarkerRN );
|
|
|
|
}
|
|
|
|
// If it returned, we didn't have any matches.
|
|
|
|
} /* NT was looking for a handler */
|
|
|
|
//
|
|
// We had nothing to do with it or it was rethrown. Keep searching.
|
|
//
|
|
|
|
return ExceptionContinueSearch;
|
|
|
|
} /* InternalCxxFrameHandler */
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FindHandler - find a matching handler on this frame, using all means
|
|
// available.
|
|
//
|
|
// Description:
|
|
// * If the exception thrown was an MSC++ EH, search handlers for match.
|
|
// * Otherwise, if we haven't already recursed, try to translate.
|
|
// * If we have recursed (ie we're handling the translator's exception),
|
|
// and it isn't a typed exception, call _inconsistency.
|
|
//
|
|
// Returns:
|
|
// Returns iff exception was not handled.
|
|
//
|
|
// Assumptions:
|
|
// * Only called if there are handlers in this function.
|
|
//
|
|
|
|
static void FindHandler(
|
|
EHExceptionRecord *pExcept, // Information for this (logical) exception
|
|
EHRegistrationNode *pRN, // Dynamic information for subject frame
|
|
#ifdef _WIN32
|
|
CONTEXT *pContext, // Context info
|
|
#else
|
|
void *pContext, // Context info (we don't care what's in it)
|
|
#endif
|
|
DispatcherContext *pDC, // Context within subject frame
|
|
FuncInfo *pFuncInfo, // Static information for subject frame
|
|
BOOLEAN recursive, // TRUE if we're handling the translation
|
|
int CatchDepth, // Level of nested catch that is being checked
|
|
EHRegistrationNode *pMarkerRN // Extra marker RN for nested catch handling
|
|
)
|
|
{
|
|
//
|
|
// Get the current state (mach. dep.)
|
|
//
|
|
__ehstate_t curState = GetCurrentState(pRN, pDC, pFuncInfo);
|
|
DASSERT((curState >= EH_EMPTY_STATE) && (curState < FUNC_MAXSTATE(*pFuncInfo)));
|
|
|
|
#ifdef _M_MPPC
|
|
fThrowFromCatch = FALSE;
|
|
#endif
|
|
|
|
//
|
|
// Check if it's a re-throw. Use the exception we stashed away if it is.
|
|
//
|
|
if ( PER_IS_MSVC_EH(pExcept)
|
|
&&
|
|
PER_PTHROW(pExcept) == NULL
|
|
) {
|
|
if ( pCurrentException == NULL ) {
|
|
//
|
|
// Oops! User re-threw a non-existant exception! Let it propogate.
|
|
//
|
|
return;
|
|
}
|
|
|
|
pExcept = pCurrentException;
|
|
pContext = pCurrentExContext;
|
|
|
|
#ifdef _WIN32
|
|
DASSERT( _ValidateRead(pExcept) );
|
|
#else
|
|
pDC->pExcept =(PEXCEPTION_RECORD)pCurrentException;
|
|
#endif
|
|
|
|
#if defined(_M_MPPC)
|
|
// PowerMac has to avoid re-throwing into the original catch clause. This is the
|
|
// first part - we remember (i) if we are from the same function section as last time,
|
|
// and (ii) if the frame is the same as last time (else we screw up recursion).
|
|
// If both conditions are true, we remember it in fThrowFromCatch, which gets
|
|
// read later on when we are about to go to the Catch code.
|
|
if (
|
|
(pFuncInfo == pCurrentFuncInfo) &&
|
|
(pRememberStack == pRN)
|
|
)
|
|
fThrowFromCatch = TRUE;
|
|
#endif
|
|
DASSERT( !PER_IS_MSVC_EH(pExcept) || PER_PTHROW(pExcept) != NULL );
|
|
}
|
|
|
|
#ifdef _M_MPPC
|
|
// remember how we got here for next time
|
|
pCurrentFuncInfo = pFuncInfo;
|
|
pRememberStack = pRN;
|
|
#endif
|
|
|
|
if ( PER_IS_MSVC_EH(pExcept) )
|
|
{
|
|
//
|
|
// Looks like it's ours. Let's see if we have a match:
|
|
//
|
|
// First, determine range of try blocks to consider:
|
|
// Only try blocks which are at the current catch depth are of interest.
|
|
//
|
|
unsigned curTry;
|
|
unsigned end;
|
|
|
|
#if _WIN32 && !defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
TryBlockMapEntry *pEntry = GetRangeOfTrysToCheck(pFuncInfo, CatchDepth, curState, &curTry, &end);
|
|
#else
|
|
TryBlockMapEntry *pEntry = GetRangeOfTrysToCheck(pRN, pFuncInfo, CatchDepth, curState, &curTry, &end);
|
|
#endif
|
|
|
|
//
|
|
// Scan the try blocks in the function:
|
|
//
|
|
for( ; curTry < end; curTry++, pEntry++ )
|
|
{
|
|
if (TBME_LOW(*pEntry) <= curState && curState <= TBME_HIGH(*pEntry))
|
|
{
|
|
//
|
|
// Try block was in scope for current state.
|
|
// Scan catches for this try:
|
|
//
|
|
HandlerType *pCatch = TBME_PCATCH(*pEntry, 0);
|
|
for( int catches = TBME_NCATCHES(*pEntry);
|
|
catches; catches--, pCatch++ )
|
|
{
|
|
//
|
|
// Scan all types that thrown object can be converted to:
|
|
//
|
|
|
|
CatchableType * const *ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept));
|
|
for( int catchables = THROW_COUNT(*PER_PTHROW(pExcept));
|
|
catchables; catchables--, ppCatchable++ )
|
|
{
|
|
if (TypeMatch( pCatch, *ppCatchable, PER_PTHROW(pExcept)) )
|
|
{
|
|
//
|
|
// OK. We finally found a match. Activate the catch.
|
|
// If control gets back here, the catch did a re-throw,
|
|
// so keep searching.
|
|
//
|
|
#ifdef _M_MPPC
|
|
// on PowerMac we have to avoid re-throwing back to the code
|
|
// that threw us originally. This is done by setting the
|
|
// fThrowFromCatch flag (see above) then comparing and remembering
|
|
// the last pCatch pointer.
|
|
if (
|
|
(fThrowFromCatch==0) ||
|
|
(pCatch!=pPreviousCatch)
|
|
)
|
|
#endif
|
|
{
|
|
#ifdef _M_MPPC
|
|
fThrowFromCatch = 0;
|
|
pPreviousCatch = pCatch;
|
|
#endif
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
//
|
|
// This signifies that we have a 4.1 c2.exe.
|
|
//
|
|
if( VER41_C2(pFuncInfo) ) {
|
|
PVOID pRealFrame = _OffsetToAddress(0,pRN,FUNC_FRAMENEST(*pFuncInfo));
|
|
UNWINDHELP(pRealFrame,FUNC_DISPUNWINDHELP(*pFuncInfo),0) = curTry;
|
|
}
|
|
#endif
|
|
CatchIt( pExcept, pRN, pContext, pDC, pFuncInfo,
|
|
pCatch, *ppCatchable, pEntry,
|
|
CatchDepth, pMarkerRN );
|
|
goto NextTryBlock;
|
|
}
|
|
|
|
#ifdef _M_MPPC
|
|
fThrowFromCatch = 0;
|
|
#endif
|
|
}
|
|
} /* Scan posible conversions */
|
|
} /* Scan catch clauses */
|
|
} /* Try was in scope */
|
|
NextTryBlock: ;
|
|
} /* Scan try blocks */
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
if( !VER41_C2(pFuncInfo) ) {
|
|
if( iControlTryBlock > FUNC_TRYBLOCKINDEX(*pFuncInfo) ) {
|
|
// transition to an outer try
|
|
iPendingTryBlock = iControlTryBlock;
|
|
}
|
|
else if( FUNC_TRYBLOCKINDEX(*pFuncInfo) >= 0 ) {
|
|
// save the corresponding try block level for this catch handler
|
|
iPendingTryBlock = FUNC_TRYBLOCKINDEX(*pFuncInfo);
|
|
}
|
|
else {
|
|
// exiting this non catch handler function
|
|
iPendingTryBlock = -1;
|
|
iControlTryBlock = -1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (recursive)
|
|
{
|
|
//
|
|
// A translation was provided, but this frame didn't catch it.
|
|
// Destruct the translated object before returning;
|
|
// if destruction raises an exception, issue _inconsistency.
|
|
//
|
|
|
|
#ifdef _M_MPPC
|
|
DestructExceptionObject( pExcept, TRUE, pContext );
|
|
#else
|
|
DestructExceptionObject( pExcept, TRUE);
|
|
#endif
|
|
}
|
|
|
|
} /* It was a C++ EH exception */
|
|
#ifdef _WIN32
|
|
else
|
|
{
|
|
//
|
|
// Not ours. But maybe someone told us how to make it ours.
|
|
//
|
|
|
|
if ( !recursive )
|
|
{
|
|
FindHandlerForForeignException( pExcept, pRN, pContext, pDC, pFuncInfo, curState, CatchDepth, pMarkerRN );
|
|
} /* not recursive */
|
|
else
|
|
{
|
|
//
|
|
// We're recursive, and the exception wasn't a C++ EH!
|
|
// Translator threw something uninteligable. We're outa here!
|
|
//
|
|
|
|
// M00REVIEW: Two choices here actually: we could let the new
|
|
// exception take over.
|
|
|
|
terminate();
|
|
}
|
|
} /* it wasn't our exception */
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FindHandlerForForeignException - We've got an exception which wasn't ours.
|
|
// Try to translate it into C++ EH, and also check for match with
|
|
// ellipsis.
|
|
//
|
|
// Description:
|
|
// If an SE-to-EH translator has been installed, call it. The
|
|
// translator must throw the appropriate typed exception or return. If
|
|
// the translator throws, we invoke FindHandler again as the exception
|
|
// filter.
|
|
//
|
|
// Returns:
|
|
// Returns if exception was not fully handled.
|
|
// No return value.
|
|
//
|
|
// Assumptions:
|
|
// Only called if there are handlers in this function.
|
|
//
|
|
static void FindHandlerForForeignException(
|
|
EHExceptionRecord *pExcept, // Information for this (logical) exception
|
|
EHRegistrationNode *pRN, // Dynamic information for subject frame
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC, // Context within subject frame
|
|
FuncInfo *pFuncInfo, // Static information for subject frame
|
|
__ehstate_t curState, // Current state
|
|
int CatchDepth, // Level of nested catch that is being checked
|
|
EHRegistrationNode *pMarkerRN // Extra marker RN for nested catch handling
|
|
)
|
|
{
|
|
if (__pSETranslator != NULL)
|
|
{
|
|
//
|
|
// Call the translator. If the translator knows what to
|
|
// make of it, it will throw an appropriate C++ exception.
|
|
// We intercept it and use it (recursively) for this
|
|
// frame. Don't recurse more than once.
|
|
//
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
ULONG TDTransOffset = 0;
|
|
#ifdef _MT
|
|
struct _tiddata DummyStruct;
|
|
TDTransOffset = (char*)&DummyStruct._translator - (char*)&DummyStruct;
|
|
#endif
|
|
if (_CallSETranslator( pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN,
|
|
TDTransOffset)) {
|
|
return;
|
|
}
|
|
#else
|
|
if (_CallSETranslator( pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN )) {
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Didn't have a translator, or the translator returned normally
|
|
// (ie didn't translate it). Still need to check for match
|
|
// with ellipsis:
|
|
//
|
|
|
|
unsigned curTry;
|
|
unsigned end;
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
TryBlockMapEntry *pEntry = GetRangeOfTrysToCheck(pRN, pFuncInfo, CatchDepth, curState, &curTry, &end);
|
|
#else
|
|
TryBlockMapEntry *pEntry = GetRangeOfTrysToCheck(pFuncInfo, CatchDepth, curState, &curTry, &end);
|
|
#endif
|
|
|
|
//
|
|
// Scan the try blocks in the function:
|
|
//
|
|
for( ; curTry < end; curTry++, pEntry++ )
|
|
{
|
|
//
|
|
// If the try-block was in scope
|
|
// AND
|
|
// The last catch in that try is an ellipsis (no other can be)
|
|
//
|
|
if ( (curState >= TBME_LOW(*pEntry) && curState <= TBME_HIGH(*pEntry))
|
|
&& HT_IS_TYPE_ELLIPSIS( TBME_CATCH(*pEntry,
|
|
TBME_NCATCHES(*pEntry) - 1) ) )
|
|
{
|
|
//
|
|
// Found an ellipsis. Handle exception.
|
|
//
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
//
|
|
// This signifies that we have a 4.1 c2.exe.
|
|
//
|
|
if( VER41_C2(pFuncInfo) ) {
|
|
PVOID pRealFrame = _OffsetToAddress(0,pRN,FUNC_FRAMENEST(*pFuncInfo));
|
|
UNWINDHELP(pRealFrame,FUNC_DISPUNWINDHELP(*pFuncInfo),0) = curTry;
|
|
}
|
|
#endif
|
|
CatchIt( pExcept, pRN, pContext, pDC, pFuncInfo,
|
|
TBME_PCATCH(*pEntry, TBME_NCATCHES(*pEntry) - 1),
|
|
NULL, pEntry, CatchDepth, pMarkerRN );
|
|
|
|
// If it returns, handler re-threw. Keep searching.
|
|
|
|
} /* have ellipsis in scope */
|
|
} /* search for try */
|
|
|
|
//
|
|
// If we got here, that means we didn't have anything to do with the
|
|
// exception. Continue search.
|
|
//
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetRangeOfTrysToCheck - determine which try blocks are of interest, given
|
|
// the current catch block nesting depth. We only check the trys at a single
|
|
// depth.
|
|
//
|
|
// Returns:
|
|
// Address of first try block of interest is returned
|
|
// pStart and pEnd get the indices of the range in question
|
|
//
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
static TryBlockMapEntry* GetRangeOfTrysToCheck(
|
|
EHRegistrationNode* pRN,
|
|
FuncInfo *pFuncInfo,
|
|
int CatchDepth,
|
|
__ehstate_t curState,
|
|
unsigned *pStart,
|
|
unsigned *pEnd
|
|
) {
|
|
TryBlockMapEntry *pEntry;
|
|
unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
|
|
DASSERT( num_of_try_blocks > 0 );
|
|
for( unsigned int index = 0; index < num_of_try_blocks; index++ ) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index);
|
|
if( curState >= TBME_LOW(*pEntry) && curState <= TBME_HIGH(*pEntry) ) {
|
|
*pStart = index;
|
|
//
|
|
// It would be better to return the end-index itself, but I don't want to
|
|
// change the caller's code.
|
|
//
|
|
*pEnd = TBME_CATCHHIGH(*pEntry) + 1;
|
|
DASSERT( *pEnd <= num_of_try_blocks && *pStart < *pEnd );
|
|
//
|
|
// This signifies that we have a 4.1 c2.exe.
|
|
//
|
|
if( VER41_C2(pFuncInfo) ) {
|
|
PVOID pRealFrame = _OffsetToAddress(0,pRN,FUNC_FRAMENEST(*pFuncInfo));
|
|
int SavedTryNdx = UNWINDHELP(pRealFrame,FUNC_DISPUNWINDHELP(*pFuncInfo),0);
|
|
if( SavedTryNdx != -1 ) {
|
|
*pStart = SavedTryNdx + 1;
|
|
if( *pStart < *pEnd && pEntry != NULL ) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, SavedTryNdx + 1);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// moved here from FindHandler and also from FindHandlerForForeignException
|
|
//
|
|
// Our calculation based on the ControlPc may not be valid.
|
|
// We have saved the highest try-block index during the search for
|
|
// this routine. If it is greater than our calculated value, use that
|
|
// as the starting try-block index.
|
|
//
|
|
while( (INT)*pStart <= iPendingTryBlock ) {
|
|
(*pStart)++;
|
|
if( *pStart < *pEnd && pEntry != NULL ) {
|
|
pEntry++;
|
|
}
|
|
}
|
|
}
|
|
return pEntry;
|
|
}
|
|
}
|
|
|
|
*pStart = *pEnd = 0;
|
|
return NULL;
|
|
}
|
|
|
|
#elif defined(_M_ALPHA)
|
|
|
|
//
|
|
// Alpha has a "true nested function" model for catch handlers
|
|
// so catch depth is always zero - which simplifies this function
|
|
// rather alot.
|
|
//
|
|
// Given this it would be a good idea to steal an idea from our
|
|
// friends at MIPS and use the CatchHigh field to point to the
|
|
// outermost state when states are nested.
|
|
//
|
|
static TryBlockMapEntry* GetRangeOfTrysToCheck(
|
|
FuncInfo *pFuncInfo,
|
|
int CatchDepth,
|
|
__ehstate_t curState,
|
|
unsigned *pStart,
|
|
unsigned *pEnd
|
|
) {
|
|
TryBlockMapEntry *pEntry;
|
|
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, 0);
|
|
*pStart = 0;
|
|
*pEnd = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
|
|
DASSERT( *pEnd > 0 );
|
|
|
|
return pEntry;
|
|
}
|
|
|
|
#elif defined(_M_MPPC)
|
|
|
|
static TryBlockMapEntry* GetRangeOfTrysToCheck(
|
|
EHRegistrationNode* pRN,
|
|
FuncInfo *pFuncInfo,
|
|
int CatchDepth,
|
|
__ehstate_t curState,
|
|
unsigned *pStart,
|
|
unsigned *pEnd
|
|
) {
|
|
TryBlockMapEntry *pEntry;
|
|
unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
|
|
DASSERT( num_of_try_blocks > 0 );
|
|
for( unsigned int index = 0; index < num_of_try_blocks; index++ ) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index);
|
|
if( curState >= TBME_LOW(*pEntry) && curState <= TBME_HIGH(*pEntry) ) {
|
|
*pStart = index;
|
|
//
|
|
// will this work right???
|
|
//
|
|
//*pEnd = TBME_CATCHHIGH(*pEntry) + 1;
|
|
*pEnd = num_of_try_blocks;
|
|
DASSERT( *pEnd <= num_of_try_blocks && *pStart < *pEnd );
|
|
return pEntry;
|
|
}
|
|
}
|
|
|
|
*pStart = *pEnd = 0;
|
|
return NULL;
|
|
}
|
|
|
|
#elif defined(_M_PPC)
|
|
|
|
static TryBlockMapEntry* GetRangeOfTrysToCheck(
|
|
FuncInfo *pFuncInfo,
|
|
int CatchDepth,
|
|
__ehstate_t curState,
|
|
unsigned *pStart,
|
|
unsigned *pEnd
|
|
) {
|
|
TryBlockMapEntry *pEntry = FUNC_PTRYBLOCK(*pFuncInfo, 0);
|
|
int start;
|
|
int end = FUNC_NTRYBLOCKS(*pFuncInfo) - 1;
|
|
|
|
// First, find the innermost try block that contains this state. We
|
|
// must always check this try block.
|
|
|
|
for (start = 0; start <= end; start++) {
|
|
if (TBME_LOW(pEntry[start]) <= curState
|
|
&& TBME_HIGH(pEntry[start]) >= curState) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// We may not check try block if we are already in an associated catch.
|
|
// We know our current catch depth and that the try blocks are sorted
|
|
// innermost to outermost. Therefore, we start with the outermost try
|
|
// block and remove it from list of try blocks to check, if we are in
|
|
// its catch. We continue working inward until we have accounted for
|
|
// our current catch depth.
|
|
|
|
for (; CatchDepth > 0 && start < end; end--) {
|
|
if (TBME_HIGH(pEntry[end]) < curState
|
|
&& curState <= TBME_CATCHHIGH(pEntry[end])) {
|
|
CatchDepth--;
|
|
}
|
|
}
|
|
|
|
*pStart = start;
|
|
*pEnd = end + 1;
|
|
|
|
DASSERT(*pEnd >= *pStart && *pEnd <= FUNC_NTRYBLOCKS(*pFuncInfo));
|
|
return &(pEntry[start]);
|
|
}
|
|
|
|
#else
|
|
|
|
static TryBlockMapEntry* GetRangeOfTrysToCheck(
|
|
FuncInfo *pFuncInfo,
|
|
int CatchDepth,
|
|
__ehstate_t curState,
|
|
unsigned *pStart,
|
|
unsigned *pEnd
|
|
) {
|
|
TryBlockMapEntry *pEntry = FUNC_PTRYBLOCK(*pFuncInfo, 0);
|
|
unsigned start = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
unsigned end = start;
|
|
unsigned end1 = end;
|
|
|
|
while (CatchDepth >= 0) {
|
|
DASSERT(start != -1);
|
|
start--;
|
|
if ( TBME_HIGH(pEntry[start]) < curState && curState <= TBME_CATCHHIGH(pEntry[start])
|
|
|| (start == -1)
|
|
) {
|
|
CatchDepth--;
|
|
end = end1;
|
|
end1 = start;
|
|
}
|
|
}
|
|
|
|
*pStart = ++start; // We always overshoot by 1 (we may even wrap around)
|
|
*pEnd = end;
|
|
|
|
DASSERT( end <= FUNC_NTRYBLOCKS(*pFuncInfo) && start <= end );
|
|
return &(pEntry[start]);
|
|
}
|
|
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TypeMatch - check if the catch type matches the given throw conversion.
|
|
//
|
|
// Returns TRUE if the catch can catch using this throw conversion, FLASE
|
|
// otherwise.
|
|
//
|
|
|
|
static inline int TypeMatch (
|
|
HandlerType *pCatch, // Type of the 'catch' clause
|
|
CatchableType *pCatchable, // Type conversion under consideration
|
|
ThrowInfo *pThrow // General information about the
|
|
// thrown type.
|
|
) {
|
|
//
|
|
// First, check for match with ellipsis:
|
|
//
|
|
|
|
if (HT_IS_TYPE_ELLIPSIS(*pCatch)) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Not ellipsis; check if the basic types match:
|
|
//
|
|
|
|
if ((HT_PTD(*pCatch) == CT_PTD(*pCatchable)) // It's the same record
|
|
|| // OR the names compare the same
|
|
(strcmp(HT_NAME(*pCatch), CT_NAME(*pCatchable)) == 0))
|
|
{
|
|
|
|
//
|
|
// Basic types match. Now check if the actual conversion is valid:
|
|
//
|
|
|
|
if ( (!CT_BYREFONLY(*pCatchable) || HT_ISREFERENCE(*pCatch)) // Caught by ref if ref required
|
|
&& // AND
|
|
(!THROW_ISCONST(*pThrow) || HT_ISCONST(*pCatch)) // The qualifiers are compatible
|
|
&&
|
|
(!THROW_ISVOLATILE(*pThrow) || HT_ISVOLATILE(*pCatch))
|
|
#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
&&
|
|
(!THROW_ISUNALIGNED(*pThrow) || HT_ISUNALIGNED(*pCatch))
|
|
#endif
|
|
) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If any test failed, we don't have a match.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FrameUnwindFilter - allows possibility of continuing through SEH during unwind.
|
|
//
|
|
|
|
static int FrameUnwindFilter(EXCEPTION_POINTERS* pExPtrs)
|
|
{
|
|
EHExceptionRecord *pExcept = (EHExceptionRecord*)pExPtrs->ExceptionRecord;
|
|
|
|
switch(PER_CODE(pExcept))
|
|
{
|
|
case EH_EXCEPTION_NUMBER:
|
|
terminate();
|
|
#ifdef ALLOW_UNWIND_ABORT
|
|
case EH_ABORT_FRAME_UNWIND_PART:
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
#endif
|
|
default:
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
}
|
|
#endif // _WIN32
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __FrameUnwindToState - unwind this frame until specified state is reached.
|
|
//
|
|
// No return value.
|
|
//
|
|
// Side Effects:
|
|
// * All objects on frame which go out of scope as a result of the
|
|
// unwind are destructed.
|
|
// * Registration node is updated to reflect new state.
|
|
//
|
|
// Usage:
|
|
// This function is called both to do full-frame unwind during the unwind
|
|
// phase (targetState = -1), and to do partial unwinding when the current
|
|
// frame has an appropriate catch.
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
extern "C" void __FrameUnwindToState (
|
|
#else
|
|
static void __FrameUnwindToState (
|
|
#endif
|
|
EHRegistrationNode *pRN, // Registration node for subject function
|
|
DispatcherContext *pDC, // Context within subject frame
|
|
FuncInfo *pFuncInfo, // Static information for subject function
|
|
__ehstate_t targetState // State to unwind to
|
|
) {
|
|
#if defined(_M_PPC)
|
|
__ehstate_t curState = GetUnwindState( pRN, pDC, pFuncInfo );
|
|
#else
|
|
__ehstate_t curState = GetCurrentState( pRN, pDC, pFuncInfo );
|
|
#endif
|
|
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
//
|
|
// The MIPS unwind-map may have a shortcut by using EH_EMPTY_STATE
|
|
//
|
|
while (curState != EH_EMPTY_STATE && curState != targetState) {
|
|
#else
|
|
while (curState != targetState) {
|
|
#endif
|
|
DASSERT((curState > EH_EMPTY_STATE) && (curState < FUNC_MAXSTATE(*pFuncInfo)));
|
|
|
|
#ifdef _WIN32
|
|
__try {
|
|
#endif
|
|
//
|
|
// Call the unwind action (if one exists):
|
|
//
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
//
|
|
// If this is nested function (catch block), the real frame where all locals are
|
|
// stored is the outermost function's frame.
|
|
//
|
|
PVOID pRealFrame = _OffsetToAddress(0,pRN,FUNC_FRAMENEST(*pFuncInfo));
|
|
if (UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)) != NULL &&
|
|
!UNWINDHELP(pRealFrame,FUNC_DISPUNWINDHELP(*pFuncInfo),curState)) {
|
|
UNWINDHELP(pRealFrame,FUNC_DISPUNWINDHELP(*pFuncInfo),curState) = TRUE;
|
|
#else
|
|
if (UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)) != NULL) {
|
|
#endif
|
|
#if defined(_M_ALPHA)
|
|
_CallSettingFrame(
|
|
UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), REAL_FP(pRN, pFuncInfo), 0x103 );
|
|
#else
|
|
//for debugger support, enter destructor
|
|
#if !defined(_M_IX86) && !defined(_M_MRX000) && !defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
__SetNLGCode(0x103);
|
|
#endif
|
|
|
|
#ifdef _M_MPPC
|
|
__fInsideDestructor = TRUE;
|
|
#endif
|
|
|
|
#if defined(_M_IX86) || defined(_M_MRX000) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
_CallSettingFrame( UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), pRN, 0x103 );
|
|
#else
|
|
_CallSettingFrame( UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), pRN );
|
|
#endif
|
|
|
|
#ifdef _M_MPPC
|
|
__fInsideDestructor = FALSE;
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
}
|
|
__except(FrameUnwindFilter(exception_info())) {
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Adjust the state:
|
|
//
|
|
|
|
curState = UWE_TOSTATE(FUNC_UNWIND(*pFuncInfo, curState));
|
|
}
|
|
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
DASSERT( curState == EH_EMPTY_STATE || curState == targetState );
|
|
#else
|
|
//
|
|
// Now that we're done, set the frame to reflect the final state.
|
|
//
|
|
|
|
DASSERT( curState == targetState );
|
|
|
|
#ifndef _M_MPPC
|
|
SetState( pRN, pDC, pFuncInfo, curState );
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CatchIt - A handler has been found for the thrown type. Do the work to
|
|
// transfer control.
|
|
//
|
|
// Description:
|
|
// * Builds the catch object
|
|
// * Unwinds the stack to the point of the try
|
|
// * Calls the address of the handler (funclet) with the frame set up
|
|
// for that function but without resetting the stack.
|
|
// * Handler funclet returns address to continue execution, or NULL if
|
|
// the handler re-threw ("throw;" lexically in handler)
|
|
// * If the handler throws an EH exception whose exception info is NULL,
|
|
// then it's a re-throw from a dynamicly enclosed scope.
|
|
//
|
|
// M00REVIEW: It is still an open question whether the catch object is built
|
|
// before or after the local unwind.
|
|
//
|
|
// Returns:
|
|
// No return value. Returns iff handler re-throws.
|
|
//
|
|
|
|
static void CatchIt (
|
|
EHExceptionRecord *pExcept, // The exception thrown
|
|
EHRegistrationNode *pRN, // Dynamic info of function with catch
|
|
#ifdef _WIN32
|
|
CONTEXT *pContext, // Context info
|
|
#else
|
|
void *pContext, // Context info (we don't care what's in it)
|
|
#endif
|
|
DispatcherContext *pDC, // Context within subject frame
|
|
FuncInfo *pFuncInfo, // Static info of function with catch
|
|
HandlerType *pCatch, // The catch clause selected
|
|
CatchableType *pConv, // The rules for making the conversion
|
|
TryBlockMapEntry *pEntry, // Description of the try block
|
|
int CatchDepth, // How many catches are we nested in?
|
|
EHRegistrationNode *pMarkerRN // Special node if nested in catch
|
|
) {
|
|
|
|
void *continuationAddress;
|
|
#if defined(_M_MRX000) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
FRAMEINFO FrameInfo, *pFrameInfo;
|
|
CONTEXT ExitContext;
|
|
#endif
|
|
|
|
#ifdef _M_MPPC
|
|
EHExceptionRecord *pSaveException = pCurrentException;
|
|
void *pSaveExContext = pCurrentExContext;
|
|
pCurrentException = pExcept;
|
|
pCurrentExContext = pContext;
|
|
unsigned int wSP = 0;
|
|
unsigned long ControlPcOld;
|
|
#endif
|
|
|
|
#ifdef _M_PPC
|
|
int dummy;
|
|
EHRegistrationNode *pEstablisher = _GetEstablisherFrame(pDC, &dummy);
|
|
#endif
|
|
|
|
//
|
|
// Copy the thrown object into a buffer in the handler's stack frame,
|
|
// unless the catch was by elipsis (no conversion) OR the catch was by
|
|
// type without an actual 'catch object'.
|
|
//
|
|
if ( pConv != NULL )
|
|
{
|
|
#if defined(_M_MPPC)
|
|
BuildCatchObject( pExcept, pRN, pCatch, pConv, pContext);
|
|
#elif defined(_M_PPC)
|
|
BuildCatchObject( pExcept, pEstablisher, pCatch, pConv );
|
|
#else
|
|
BuildCatchObject( pExcept, pRN, pCatch, pConv );
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Unwind stack objects to the entry of the try that caught this exception.
|
|
//
|
|
#if defined(_M_MRX000) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
pExitContext = &ExitContext;
|
|
_UnwindNestedFrames( pRN, pExcept, pContext ); // Mips specific
|
|
|
|
#elif defined(_M_ALPHA)
|
|
// Alpha specific - this calls a special version of RtlUnwind which
|
|
// walks the stack performing unwind actions but which does NOT
|
|
// restore the context to the target frame's routine. Instead it
|
|
// just returns.
|
|
_UnwindNestedFrames(pRN, pExcept);
|
|
|
|
#else
|
|
if (pMarkerRN == NULL) {
|
|
_UnwindNestedFrames( pRN, pExcept ); // Mach. dependent
|
|
} else {
|
|
_UnwindNestedFrames( pMarkerRN, pExcept );
|
|
}
|
|
#endif
|
|
|
|
#ifdef _M_MPPC
|
|
if (fStaticNested)
|
|
{
|
|
ControlPcOld = pDC->ControlPc;
|
|
pDC->ControlPc = pDC->ControlPcOld;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _M_PPC
|
|
__FrameUnwindToState( pEstablisher, pDC, pFuncInfo, TBME_LOW(*pEntry) );
|
|
#else
|
|
__FrameUnwindToState( pRN, pDC, pFuncInfo, TBME_LOW(*pEntry) );
|
|
#endif
|
|
|
|
#ifdef _M_MPPC
|
|
if (fStaticNested)
|
|
{
|
|
pDC->ControlPc = ControlPcOld;
|
|
fStaticNested = 0;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Call the catch. Separated out because it introduces a new registration
|
|
// node.
|
|
//
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
pFrameInfo = _CreateFrameInfo(&FrameInfo, pDC, pRN, pExitContext);
|
|
#elif defined(_M_PPC)
|
|
pFrameInfo = _CreateFrameInfo(&FrameInfo, pDC, pEstablisher, pExitContext, TBME_LOW(*pEntry));
|
|
#elif defined(_M_ALPHA)
|
|
SetState( pRN, pDC, pFuncInfo,
|
|
(FUNC_UNWIND(*pFuncInfo, TBME_LOW(*pEntry))).toState );
|
|
#elif defined(_M_MPPC)
|
|
SetState( pRN, pDC, pFuncInfo, TBME_HIGH(*pEntry) + 1, TBME_LOW(*pEntry));
|
|
__SetNLGCode(0x100);
|
|
#else
|
|
SetState( pRN, pDC, pFuncInfo, TBME_HIGH(*pEntry) + 1 );
|
|
|
|
//for debugger support, enter catch handler
|
|
#if !defined(_M_IX86) /*IFSTRIP=IGN*/
|
|
__SetNLGCode(0x100);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _M_MPPC
|
|
continuationAddress = CallCatchBlock( pExcept, pRN, pContext, pDC, pFuncInfo, HT_HANDLER(*pCatch), CatchDepth, &wSP );
|
|
pCurrentException = pSaveException;
|
|
pCurrentExContext = pSaveExContext;
|
|
#else
|
|
|
|
#if defined(_M_IX86) || defined(_M_MRX000) || defined(_M_ALPHA) /*IFSTRIP=IGN*/
|
|
continuationAddress = CallCatchBlock( pExcept, pRN, pContext, pFuncInfo, HT_HANDLER(*pCatch), CatchDepth, 0x100 );
|
|
#elif defined(_M_PPC)
|
|
continuationAddress = CallCatchBlock( pExcept, pEstablisher, pContext, pFuncInfo, HT_HANDLER(*pCatch), CatchDepth, 0x100 );
|
|
#else
|
|
continuationAddress = CallCatchBlock( pExcept, pRN, pContext, pFuncInfo, HT_HANDLER(*pCatch), CatchDepth );
|
|
#endif
|
|
|
|
#endif
|
|
|
|
//
|
|
// Transfer control to the continuation address. If no continuation then
|
|
// it's a re-throw, so return.
|
|
//
|
|
|
|
if (continuationAddress != NULL) {
|
|
#if defined(_M_MRX000) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
//
|
|
// Exit gracefully to the continuation adddress.
|
|
//
|
|
// We are done, but we have to blow away the stack below the frame where the try-block
|
|
// resides. In addition, we have to resore a bunch of other registers besides SP as
|
|
// well. Leave that task up to _JumpToContinuation which is MIPS specific.
|
|
// The code that is commented out below worked well until we hit the scenario of:
|
|
//
|
|
// void foo()
|
|
// {
|
|
// try {
|
|
// bar();
|
|
// }
|
|
// catch(int) {
|
|
// }
|
|
// }
|
|
//
|
|
// void bar()
|
|
// {
|
|
// __try {
|
|
// throw 1;
|
|
// }
|
|
// __finally {
|
|
// }
|
|
// }
|
|
//
|
|
// In the above example, RtlUnwind would call the __finally's handler twice.
|
|
// Once for the original unwind through the call to _UnwindNestedFrames, then here
|
|
// where all we want is to get to the continuation point.
|
|
//
|
|
// ExitContext was saved during the original unwind when we detected the target
|
|
// of the unwind in __InternalCxxFrameHandler.
|
|
//
|
|
|
|
//
|
|
// This signifies that we have a 4.1 c2.exe.
|
|
//
|
|
#ifdef _M_MRX000
|
|
if( VER41_C2(pFuncInfo) ) {
|
|
PVOID pRealFrame = _OffsetToAddress(0,pRN,FUNC_FRAMENEST(*pFuncInfo));
|
|
UNWINDHELP(pRealFrame,FUNC_DISPUNWINDHELP(*pFuncInfo),0) = -1;
|
|
}
|
|
#endif
|
|
pExitContext = NULL;
|
|
_JumpToContinuation( (ULONG)continuationAddress, _FindAndUnlinkFrame(continuationAddress, pFrameInfo) );
|
|
#elif defined(_M_MPPC)
|
|
_JumpToContinuation( continuationAddress, pRN, wSP );
|
|
#else
|
|
_JumpToContinuation( continuationAddress, pRN );
|
|
#endif
|
|
// No return.
|
|
}
|
|
else {
|
|
#ifdef _M_PPC
|
|
_FindAndUnlinkFrame(NULL, pFrameInfo);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CallCatchBlock - continuation of CatchIt.
|
|
//
|
|
// This is seperated from CatchIt because it needs to introduce an SEH frame
|
|
// in case the catch block throws. This frame cannot be added until unwind of
|
|
// nested frames has been completed (otherwise this frame would be the first
|
|
// to go).
|
|
//
|
|
|
|
static void *CallCatchBlock (
|
|
EHExceptionRecord *pExcept, // The exception thrown
|
|
EHRegistrationNode *pRN, // Dynamic info of function with catch
|
|
CONTEXT *pContext, // Context info
|
|
FuncInfo *pFuncInfo, // Static info of function with catch
|
|
void *handlerAddress, // Code address of handler
|
|
#if defined(_M_IX86) || defined(_M_MRX000) || defined(_M_PPC) || defined(_M_ALPHA) /*IFSTRIP=IGN*/
|
|
int CatchDepth, // How deeply nested in catch blocks are we?
|
|
unsigned long NLGCode // NLG destination code
|
|
#else
|
|
int CatchDepth // How deeply nested in catch blocks are we?
|
|
#endif
|
|
) {
|
|
void *continuationAddress = handlerAddress;
|
|
// Address where execution resumes after exception
|
|
// handling completed. Initialized to non-NULL (value
|
|
// doesn't matter) to distinguish from re-throw in finally.
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
BOOL ExceptionObjectDestroyed = FALSE;
|
|
#endif
|
|
|
|
#if _M_IX86 >= 300 /*IFSTRIP=IGN*/
|
|
//
|
|
// The stack pointer at entry to the try must be saved, in case there is
|
|
// another try inside this catch. We'll restore it on our way out.
|
|
//
|
|
void *saveESP = PRN_STACK(pRN);
|
|
#endif
|
|
|
|
//
|
|
// Save the current exception in case of a rethrow. Save the previous value
|
|
// on the stack, to be restored when the catch exits.
|
|
//
|
|
EHExceptionRecord *pSaveException = pCurrentException;
|
|
CONTEXT *pSaveExContext = pCurrentExContext;
|
|
pCurrentException = pExcept;
|
|
pCurrentExContext = pContext;
|
|
|
|
__try {
|
|
__try {
|
|
//
|
|
// Execute the handler as a funclet, whose return value is
|
|
// the address to resume execution.
|
|
//
|
|
#if defined(_M_IX86) /*IFSTRIP=IGN*/
|
|
continuationAddress = _CallCatchBlock2( pRN, pFuncInfo, handlerAddress, CatchDepth, NLGCode );
|
|
#elif defined(_M_MRX000) || defined(_M_PPC) /*IFSTRIP=IGN*/
|
|
continuationAddress = _CallSettingFrame( handlerAddress, pRN, NLGCode );
|
|
#elif defined (_M_ALPHA)
|
|
continuationAddress = _CallSettingFrame( handlerAddress, REAL_FP(pRN, pFuncInfo), NLGCode );
|
|
#else
|
|
continuationAddress = _CallCatchBlock2( pRN, pFuncInfo, handlerAddress, CatchDepth );
|
|
#endif
|
|
}
|
|
__except( ExFilterRethrow(exception_info()) ) {
|
|
//
|
|
// If the handler threw a typed exception without exception info
|
|
// or exception object, then it's a re-throw, so return. Otherwise
|
|
// it's a new exception, which takes precedence over this one.
|
|
//
|
|
// Note that the assign isn't redundant; see __finally
|
|
//
|
|
continuationAddress = NULL;
|
|
return NULL;
|
|
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
#if _M_IX86 >= 300 /*IFSTRIP=IGN*/
|
|
//
|
|
// Restore the saved stack pointer, so the stack can be reset when
|
|
// we're done.
|
|
//
|
|
PRN_STACK(pRN) = saveESP;
|
|
#endif
|
|
|
|
//
|
|
// Restore the 'current exception' for a possibly enclosing catch
|
|
//
|
|
pCurrentException = pSaveException;
|
|
pCurrentExContext = pSaveExContext;
|
|
|
|
//
|
|
// Destroy the original exception object if we're not exiting on a
|
|
// re-throw. (note that the catch handles destruction of its parameter).
|
|
//
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
if ( PER_IS_MSVC_EH(pExcept) && !ExceptionObjectDestroyed && (continuationAddress != NULL) )
|
|
{
|
|
DestructExceptionObject( pExcept, abnormal_termination() );
|
|
ExceptionObjectDestroyed = TRUE;
|
|
}
|
|
}
|
|
#else
|
|
if ( PER_IS_MSVC_EH(pExcept)
|
|
&& (continuationAddress != NULL) )
|
|
{
|
|
DestructExceptionObject( pExcept, abnormal_termination() );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return continuationAddress;
|
|
|
|
} /* CallCatchBlock */
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ExFilterRethrow - exception filter for re-throw exceptions.
|
|
//
|
|
// Returns:
|
|
// EXCEPTION_EXECUTE_HANDLER - exception was a re-throw
|
|
// EXCEPTION_CONTINUE_SEARCH - anything else
|
|
//
|
|
// Side-effects: NONE.
|
|
//
|
|
|
|
static int ExFilterRethrow (
|
|
EXCEPTION_POINTERS *pExPtrs
|
|
) {
|
|
//
|
|
// Get the exception record thrown (don't care about other info)
|
|
//
|
|
EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord;
|
|
|
|
//
|
|
// Check if it's ours and it's got no exception information.
|
|
//
|
|
if ( PER_IS_MSVC_EH(pExcept)
|
|
&&
|
|
(PER_PTHROW(pExcept) == NULL)
|
|
) {
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
else {
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
}
|
|
|
|
#endif // ifdef _WIN32
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BuildCatchObject - copy or construct the catch object from the object
|
|
// thrown.
|
|
//
|
|
// Returns:
|
|
// nothing.
|
|
//
|
|
// Side-effects:
|
|
// A buffer in the subject function's frame is initialized.
|
|
//
|
|
// Open issues:
|
|
// * What happens if the constructor throws? (or faults?)
|
|
//
|
|
|
|
#ifndef _M_MPPC
|
|
static void BuildCatchObject (
|
|
EHExceptionRecord *pExcept, // Original exception thrown
|
|
EHRegistrationNode *pRN, // Registration node of catching function
|
|
HandlerType *pCatch, // The catch clause that got it
|
|
CatchableType *pConv // The conversion to use
|
|
)
|
|
#else
|
|
static void BuildCatchObject (
|
|
EHExceptionRecord *pExcept, // Original exception thrown
|
|
EHRegistrationNode *pRN, // Registration node of catching function
|
|
HandlerType *pCatch, // The catch clause that got it
|
|
CatchableType *pConv, // The conversion to use
|
|
void *pContext
|
|
)
|
|
#endif
|
|
{
|
|
if (HT_IS_TYPE_ELLIPSIS(*pCatch) || !HT_DISPCATCH(*pCatch) ) {
|
|
//
|
|
// If the catch is by ellipsis, then there is no object to construct.
|
|
// If the catch is by type(No Catch Object), then leave too!
|
|
//
|
|
return;
|
|
}
|
|
|
|
#if defined(_M_MRX000) /*IFSTRIP=IGN*/
|
|
void **pCatchBuffer = (void**)_OffsetToAddress(HT_DISPCATCH(*pCatch), pRN, HT_FRAMENEST(*pCatch));
|
|
#else
|
|
void **pCatchBuffer = (void**)OffsetToAddress(HT_DISPCATCH(*pCatch), pRN);
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
__try {
|
|
#endif
|
|
if (HT_ISREFERENCE(*pCatch)) {
|
|
//
|
|
// The catch is of form 'reference to T'. At the throw point we treat
|
|
// both 'T' and 'reference to T' the same, ie pExceptionObject is a
|
|
// (machine) pointer to T.
|
|
// adjust as required.
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
if ( _ValidateRead( PER_PEXCEPTOBJ(pExcept) ) &&
|
|
_ValidateWrite( pCatchBuffer) )
|
|
#endif
|
|
{
|
|
*pCatchBuffer = PER_PEXCEPTOBJ(pExcept);
|
|
*pCatchBuffer = AdjustPointer( *pCatchBuffer,
|
|
CT_THISDISP(*pConv)
|
|
);
|
|
}
|
|
#ifdef _WIN32
|
|
else
|
|
{
|
|
_inconsistency(); // Does not return; TKB
|
|
}
|
|
#endif
|
|
}
|
|
else if (CT_ISSIMPLETYPE(*pConv)) {
|
|
//
|
|
// Object thrown is of simple type (this including pointers)
|
|
// copy specified number of bytes.
|
|
// adjust the pointer as required.
|
|
// if the thing is not a pointer, then this should be safe
|
|
// since all the entries in the THISDISP are 0.
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
if( _ValidateRead( PER_PEXCEPTOBJ(pExcept) )
|
|
&&
|
|
_ValidateWrite( pCatchBuffer ) )
|
|
#endif
|
|
|
|
{
|
|
memmove( pCatchBuffer,
|
|
PER_PEXCEPTOBJ(pExcept),
|
|
CT_SIZE(*pConv)
|
|
);
|
|
#ifdef _M_MPPC
|
|
if (*pCatchBuffer != NULL) {
|
|
#else
|
|
if (CT_SIZE(*pConv) == sizeof(void*) && *pCatchBuffer != NULL) {
|
|
#endif
|
|
*pCatchBuffer = AdjustPointer( *pCatchBuffer,
|
|
CT_THISDISP(*pConv)
|
|
);
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
else
|
|
{
|
|
_inconsistency(); // Does not return; TKB
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else {
|
|
//
|
|
// Object thrown is UDT.
|
|
//
|
|
if (CT_COPYFUNC(*pConv) == NULL) {
|
|
//
|
|
// the UDT had a simple ctor.
|
|
// adjust in the thrown object, then copy n bytes.
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
if (_ValidateRead( PER_PEXCEPTOBJ(pExcept) )
|
|
&&
|
|
_ValidateWrite( pCatchBuffer ) )
|
|
#endif
|
|
|
|
{
|
|
memmove(pCatchBuffer,
|
|
AdjustPointer( PER_PEXCEPTOBJ(pExcept),
|
|
CT_THISDISP(*pConv) ),
|
|
CT_SIZE(*pConv)
|
|
);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
else
|
|
{
|
|
_inconsistency(); // Does not return; TKB
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else {
|
|
//
|
|
// It's a UDT: make a copy using copy ctor
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
if( _ValidateRead( PER_PEXCEPTOBJ(pExcept) )
|
|
&&
|
|
_ValidateWrite( pCatchBuffer )
|
|
&&
|
|
_ValidateExecute( (FARPROC)CT_COPYFUNC( *pConv ) ) )
|
|
#endif
|
|
|
|
{
|
|
#ifdef _M_MPPC
|
|
if (CT_HASVB(*pConv)) {
|
|
_CallMemberFunction2(
|
|
(char*)pCatchBuffer,
|
|
CT_COPYFUNC(*pConv),
|
|
AdjustPointer( PER_PEXCEPTOBJ(pExcept),
|
|
CT_THISDISP(*pConv)),
|
|
1, pContext);
|
|
}
|
|
else {
|
|
_CallMemberFunction1(
|
|
(char*)pCatchBuffer,
|
|
CT_COPYFUNC(*pConv),
|
|
AdjustPointer( PER_PEXCEPTOBJ(pExcept),
|
|
CT_THISDISP(*pConv)), pContext );
|
|
}
|
|
#else
|
|
if (CT_HASVB(*pConv)) {
|
|
_CallMemberFunction2(
|
|
(char*)pCatchBuffer,
|
|
CT_COPYFUNC(*pConv),
|
|
AdjustPointer( PER_PEXCEPTOBJ(pExcept),
|
|
CT_THISDISP(*pConv)),
|
|
1);
|
|
}
|
|
else {
|
|
_CallMemberFunction1(
|
|
(char*)pCatchBuffer,
|
|
CT_COPYFUNC(*pConv),
|
|
AdjustPointer( PER_PEXCEPTOBJ(pExcept),
|
|
CT_THISDISP(*pConv)) );
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef _WIN32
|
|
else
|
|
{
|
|
_inconsistency(); // Does not return; TKB
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// Something went wrong when building the catch object.
|
|
//
|
|
terminate();
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DestructExceptionObject - call the destructor (if any) of the original
|
|
// exception object.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Side-effects(Prime Effect?):
|
|
// Original exception object is destructed.
|
|
//
|
|
// Notes:
|
|
// If destruction throws any exception, and we are destructing the
|
|
// exception object as a result of a new exception, we give up.
|
|
// If the destruction throws otherwise, we let it be.
|
|
//
|
|
|
|
#ifdef _M_MPPC
|
|
void DestructExceptionObject(
|
|
EHExceptionRecord *pExcept, // The original exception record
|
|
BOOLEAN fThrowNotAllowed, // TRUE if destructor not allowed to throw
|
|
void *pContext // Registration node of catching function
|
|
) {
|
|
#else
|
|
static void DestructExceptionObject(
|
|
EHExceptionRecord *pExcept, // The original exception record
|
|
BOOLEAN fThrowNotAllowed // TRUE if destructor not allowed to throw
|
|
) {
|
|
#endif
|
|
|
|
if ( ((pExcept)!=NULL) && THROW_UNWINDFUNC(*PER_PTHROW(pExcept)) != NULL ) {
|
|
|
|
#ifdef _WIN32
|
|
__try {
|
|
#else
|
|
__fInsideDestructor = TRUE;
|
|
#endif
|
|
|
|
// M00REVIEW: A destructor has additional hidden arguments, doesn't it?
|
|
|
|
#ifdef _M_MPPC
|
|
_CallMemberFunction0( PER_PEXCEPTOBJ(pExcept),
|
|
THROW_UNWINDFUNC(*PER_PTHROW(pExcept)), pContext);
|
|
#else
|
|
_CallMemberFunction0( PER_PEXCEPTOBJ(pExcept),
|
|
THROW_UNWINDFUNC(*PER_PTHROW(pExcept)));
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
}
|
|
__except( fThrowNotAllowed ?
|
|
EXCEPTION_EXECUTE_HANDLER
|
|
: EXCEPTION_CONTINUE_SEARCH
|
|
) {
|
|
//
|
|
// Can't have new exceptions when we're unwinding due to another
|
|
// exception.
|
|
//
|
|
terminate();
|
|
}
|
|
#else
|
|
__fInsideDestructor = FALSE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AdjustPointer - Adjust the pointer to the exception object to a pointer
|
|
// to a base instance.
|
|
//
|
|
// Output:
|
|
// The address point of the base.
|
|
//
|
|
// Side-effects:
|
|
// NONE.
|
|
//
|
|
|
|
static void *AdjustPointer(
|
|
void* pThis, // Address point of exception object
|
|
const PMD& pmd // Generalized pointer-to-member descriptor
|
|
)
|
|
{
|
|
char *pRet = (char *)pThis + pmd.mdisp;
|
|
|
|
if (pmd.pdisp >= 0) {
|
|
#ifdef _WIN32
|
|
pRet += *(ptrdiff_t*)((char*)*(ptrdiff_t*)((char*)pThis + pmd.pdisp) + pmd.vdisp);
|
|
pRet += pmd.pdisp;
|
|
#else
|
|
pRet += *(ptrdiff_t*)((char*)*(unsigned int *)((char*)pThis + pmd.pdisp) + pmd.vdisp);
|
|
#endif
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
#if !defined(_M_IX86) && !defined(_M_MRX000) && !defined(_M_PPC) && !defined(_M_ALPHA) /*IFSTRIP=IGN*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __SetNLGCode - Sets _NLG_dwCode in per-thread data.
|
|
//
|
|
// Input:
|
|
// dwCode
|
|
//
|
|
// Output:
|
|
// None.
|
|
//
|
|
// Side-effects:
|
|
// NONE.
|
|
//
|
|
|
|
extern "C" void __cdecl __SetNLGCode(unsigned long dwCode)
|
|
{
|
|
#ifdef _MT
|
|
_ptiddata ptd; /* pointer to thread's _tiddata struct */
|
|
|
|
if ((ptd = _getptd()) != NULL)
|
|
ptd->_NLG_dwCode = dwCode;
|
|
#else
|
|
_NLG_Destination.dwCode = dwCode;
|
|
#endif
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __GetNLGCode - Returns _NLG_dwCode from per-thread data.
|
|
//
|
|
// Input:
|
|
// None.
|
|
//
|
|
// Output:
|
|
// _NLG_dwCode.
|
|
//
|
|
// Side-effects:
|
|
// NONE.
|
|
//
|
|
|
|
extern "C" unsigned long __cdecl __GetNLGCode()
|
|
{
|
|
#ifdef _MT
|
|
_ptiddata ptd; /* pointer to thread's _tiddata struct */
|
|
|
|
if ((ptd = _getptd()) != NULL)
|
|
return ptd->_NLG_dwCode;
|
|
else
|
|
return 0;
|
|
#else
|
|
return _NLG_Destination.dwCode;
|
|
#endif
|
|
}
|
|
#endif
|