|
|
/***
*frame.cxx - The frame handler and everything associated with it. * * Copyright (c) 1993-2001, 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 * 08-06-95 JWM Typo fixed (Orion #6509); Alpha-specific. * 04-18-97 JWM In __InternalCxxFrameHandler(), 'recursive' changed to * BOOLEAN. * 06-01-97 TGL Added P7 specific code * 08-22-97 TGL More P7 fixes * 11-14-98 JWM Merge with P7 sources. * 02-11-99 TGL EH: correct catch in exe calling dll. * 05-17-99 PML Remove all Macintosh support. * 07-12-99 RDL Image relative fixes under CC_P7_SOFT25. * 10-17-99 PML Update EH state before each unwind action, instead of * once at end (vs7#5419) * 10-19-99 TGL More P7/Win64 fixes * 10-22-99 PML Add EHTRACE support * 12-10-99 GB Add Uncaught exception Support by adding a new function * __uncaught_exception(); * 02-15-99 PML Can't put __try/__finally around call to * _UnwindNestedFrames (vs7#79460) * 03-03-00 GB made __DestructExceptionObject export from dll. * 03-21-00 KBF Check for C++ exception in __CxxExceptionFilter * 03-22-00 PML Remove CC_P7_SOFT25, which is now on permanently. * 03-28-00 GB Check for no buildobj in __CxxExceptionFilter. * 04-06-00 GB Added more functions for com+ eh support. * 04-19-00 GB ComPlus EH bug fixes. * 05-23-00 GB Don't catch BreakPoint generated Exceptions. * 05-30-00 GB ComPlus EH bug fixes. * 06-08-00 RDL VS#111429: IA64 workaround for AV while handling throw. * 06-21-00 GB Fix the difference in order of destruction and * construction depending on inlining. * 07-26-00 GB Fixed multiple destruction problem in COM+ eh. * 08-23-00 GB Fixed problem in BuildCatchObject when called from * __CxxExceptionFilter. * 02-23-01 PML Add __CxxCallUnwindDtor COM+ wrapper (vs7#217108) * 04-09-01 GB Add uncaught_exception support for COM+ C++ App. * 04-13-01 GB Fixed problems with Seh and catch(...). (vc7#236286) * 04-26-01 GB Fixed a problem with a rethrow without a throw * and catch(...) * 06-05-01 GB AMD64 Eh support Added. * ****/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#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 // defined(_NTSUBSET_)
#include <windows.h>
#include <internal.h>
#include <mtdll.h> // CRT internal header file
#include <ehassert.h> // This project's versions of standard assert macros
#include <ehdata.h> // Declarations of all types used for EH
#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
#include <trnsctrl.h> // Routines to handle transfer of control (trnsctrl.asm)
#if defined(_M_IA64) /*IFSTRIP=IGN*/
#include <kxia64.h>
#include <ia64inst.h>
#include <cvconst.h>
#endif
#pragma hdrstop // PCH is created from here
////////////////////////////////////////////////////////////////////////////////
//
// WIN64 specific definitions
//
#define __GetRangeOfTrysToCheck(a, b, c, d, e, f, g) \
_GetRangeOfTrysToCheck(a, b, c, d, e, f, g) #define __CallSETranslator(a, b, c, d, e, f, g, h) \
_CallSETranslator(a, b, c, d, e, f, g) #define __GetUnwindState(a, b, c) \
GetCurrentState(a, b, c) #define __OffsetToAddress(a, b, c) \
OffsetToAddress(a, b) #define __GetAddress(a, b) \
(void*)(a) #define REAL_FP(a, b) \
(a) #define __ResetException(a)
#ifdef _MT
#define pExitContext (*((CONTEXT **)&(_getptd()->_pExitContext)))
#else
static CONTEXT *pExitContext = NULL; // context to assist the return to the continuation point
#endif // _MT
// The throw site
#undef CT_PTD
#define CT_PTD(ct) (CT_PTD_IB(ct, _GetThrowImageBase()))
#undef CT_COPYFUNC
#define CT_COPYFUNC(ct) ((ct).copyFunction? CT_COPYFUNC_IB(ct, _GetThrowImageBase()):NULL)
#undef THROW_FORWARDCOMPAT
#define THROW_FORWARDCOMPAT(ti) ((ti).pForwardCompat? THROW_FORWARDCOMPAT_IB(ti, _GetThrowImageBase()):NULL)
#undef THROW_COUNT
#define THROW_COUNT(ti) THROW_COUNT_IB(ti, _GetThrowImageBase())
#undef THROW_CTLIST
#define THROW_CTLIST(ti) THROW_CTLIST_IB(ti, _GetThrowImageBase())
// The catch site
#undef HT_HANDLER
#define HT_HANDLER(ht) (HT_HANDLER_IB(ht, _GetImageBase()))
#undef UWE_ACTION
#define UWE_ACTION(uwe) ((uwe).action? UWE_ACTION_IB(uwe, _GetImageBase()):NULL)
#undef FUNC_UNWIND
#define FUNC_UNWIND(fi,st) (FUNC_PUNWINDMAP(fi,_GetImageBase())[st])
#undef TBME_CATCH
#define TBME_CATCH(hm,n) (TBME_PLIST(hm,_GetImageBase())[n])
#undef TBME_PCATCH
#define TBME_PCATCH(hm,n) (&(TBME_PLIST(hm,_GetImageBase())[n]))
#undef HT_PTD
#define HT_PTD(ht) ((TypeDescriptor*)((ht).dispType? HT_PTD_IB(ht,_GetImageBase()):NULL))
#undef abnormal_termination
#define abnormal_termination() FALSE
extern "C" { typedef struct { unsigned long dwSig; unsigned long uoffDestination; unsigned long dwCode; unsigned long uoffFramePointer; } _NLG_INFO;
extern _NLG_INFO _NLG_Destination; }
////////////////////////////////////////////////////////////////////////////////
//
// Forward declaration of local functions:
//
// M00TODO: all these parameters should be declared const
// The local unwinder must be external (see __CxxLongjmpUnwind 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 CatchIt( EHExceptionRecord *, EHRegistrationNode *, CONTEXT *, DispatcherContext *, FuncInfo *, HandlerType *, CatchableType *, TryBlockMapEntry *, int, EHRegistrationNode *, BOOLEAN );
static void * CallCatchBlock( EHExceptionRecord *, EHRegistrationNode *, CONTEXT *, FuncInfo *, void *, int, unsigned long, FRAMEINFO * );
static void BuildCatchObject( EHExceptionRecord *, void *, HandlerType *, CatchableType * );
static __inline int TypeMatch( HandlerType *, CatchableType *, ThrowInfo * );
static void * AdjustPointer( void *, const PMD& );
static void FindHandlerForForeignException( EHExceptionRecord *, EHRegistrationNode *, CONTEXT *, DispatcherContext *, FuncInfo *, __ehstate_t, int, EHRegistrationNode * );
static int FrameUnwindFilter( EXCEPTION_POINTERS * );
static int ExFilterRethrow( EXCEPTION_POINTERS * );
extern "C" void _CRTIMP __DestructExceptionObject( EHExceptionRecord *, BOOLEAN );
//
// Make sure the terminate wrapper is dragged in:
//
static void *pMyUnhandledExceptionFilter = #if defined(_NTSUBSET_)
0; #else
&__CxxUnhandledExceptionFilter; #endif
//
// This describes the most recently handled exception, in case of a rethrow:
//
#ifdef _MT
#define _pCurrentException (*((EHExceptionRecord **)&(_getptd()->_curexception)))
#define _pCurrentExContext (*((CONTEXT **)&(_getptd()->_curcontext)))
#define __ProcessingThrow _getptd()->_ProcessingThrow
#else
EHExceptionRecord *_pCurrentException = NULL; CONTEXT *_pCurrentExContext = NULL; int __ProcessingThrow = 0; #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
CONTEXT *pContext, // Context info
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
BOOLEAN recursive // Are we handling a translation?
) { EHTRACE_ENTER_FMT2("%s, pRN = 0x%p", IS_UNWINDING(PER_FLAGS(pExcept)) ? "Unwinding" : "Searching", pRN);
DASSERT(FUNC_MAGICNUM(*pFuncInfo) == EH_MAGIC_NUMBER1);
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)
if (FUNC_MAXSTATE(*pFuncInfo) != 0 && CatchDepth == 0) { // Only unwind if there's something to unwind
// AND we're being called through the primary RN.
// 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))) {
// Save the target context to be used in 'CatchIt' to jump to
// the continuation point.
DASSERT(pExitContext != NULL); _MoveContext(pExitContext, pContext);
// This is how we give control back to _UnwindNestedFrames
_MoveContext(pContext, _GetUnwindContext());
EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); return ExceptionContinueSearch; }
else if (IS_TARGET_UNWIND(PER_FLAGS(pExcept)) && PER_CODE(pExcept) == STATUS_LONGJUMP) { #if defined(_M_IA64)
__ehstate_t target_state = _StateFromIp(pFuncInfo, pDC, pContext->StIIP);
#elif defined(_M_AMD64)
__ehstate_t target_state = _StateFromIp(pFuncInfo, pDC, pContext->Rip); #else
#error "No Target Architecture"
#endif
DASSERT(target_state >= EH_EMPTY_STATE && target_state < FUNC_MAXSTATE(*pFuncInfo));
__FrameUnwindToState(pRN, pDC, pFuncInfo, target_state); EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); return ExceptionContinueSearch; } __FrameUnwindToEmptyState(pRN, pDC, pFuncInfo); }
EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); 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?
int (__cdecl *pfn)(...);
if (PER_CODE(pExcept) == EH_EXCEPTION_NUMBER && PER_MAGICNUM(pExcept) > EH_MAGIC_NUMBER1 && (pfn = 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(DEBUG)
if (_ValidateExecute((FARPROC)pfn)) { #endif
EXCEPTION_DISPOSITION result = (EXCEPTION_DISPOSITION)pfn(pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN, recursive); EHTRACE_HANDLER_EXIT(result); return result; #if 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.
EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); 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
CONTEXT *pContext, // Context info
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
) { EHTRACE_ENTER;
BOOLEAN IsRethrow = FALSE;
// Get the current state (machine-dependent)
__ehstate_t curState = _StateFromControlPc(pFuncInfo, pDC); #if defined(_M_AMD64) // Will be used when unwinding.
EHRegistrationNode EstablisherFrame; _GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFrame); if (curState > GetUnwindTryBlock(pRN, pDC, pFuncInfo)) { SetState(&EstablisherFrame, pDC, pFuncInfo, curState); } #endif
DASSERT(curState >= EH_EMPTY_STATE && curState < FUNC_MAXSTATE(*pFuncInfo));
// 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.
EHTRACE_EXIT; return; }
pExcept = _pCurrentException; pContext = _pCurrentExContext; IsRethrow = TRUE; _SetThrowImageBase((unsigned __int64)pExcept->params.pThrowImageBase);
DASSERT(_ValidateRead(pExcept)); DASSERT(!PER_IS_MSVC_EH(pExcept) || PER_PTHROW(pExcept) != NULL); }
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;
TryBlockMapEntry *pEntry = __GetRangeOfTrysToCheck(pRN, pFuncInfo, CatchDepth, curState, &curTry, &end, pDC);
// Scan the try blocks in the function:
for (; curTry < end; curTry++, pEntry++) { HandlerType *pCatch; __int32 const *ppCatchable; CatchableType *pCatchable; int catches; int catchables;
if (TBME_LOW(*pEntry) > curState || curState > TBME_HIGH(*pEntry)) { continue; }
// Try block was in scope for current state. Scan catches for this
// try:
pCatch = TBME_PCATCH(*pEntry, 0); for (catches = TBME_NCATCHES(*pEntry); catches > 0; catches--, pCatch++) {
// Scan all types that thrown object can be converted to:
ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept)); for (catchables = THROW_COUNT(*PER_PTHROW(pExcept)); catchables > 0; catchables--, ppCatchable++) {
pCatchable = (CatchableType *)(_GetThrowImageBase() + *ppCatchable); if (!TypeMatch(pCatch, pCatchable, PER_PTHROW(pExcept))) { continue; }
// OK. We finally found a match. Activate the catch. If
// control gets back here, the catch did a re-throw, so
// keep searching.
SetUnwindTryBlock(pRN, pDC, pFuncInfo, /*curTry*/ curState); CatchIt(pExcept, pRN, pContext, pDC, pFuncInfo, pCatch, pCatchable, pEntry, CatchDepth, pMarkerRN, IsRethrow); #if defined(_M_IA64) /*IFSTRIP=IGN*/
goto EndOfTryScan; #else
goto NextTryBlock; #endif
} // Scan posible conversions
} // Scan catch clauses
#if !defined(_M_IA64) /*IFSTRIP=IGN*/
NextTryBlock: ; #endif
} // Scan try blocks
#if defined(_M_IA64) /*IFSTRIP=IGN*/
EndOfTryScan: #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.
__DestructExceptionObject(pExcept, TRUE); }
} // It was a C++ EH exception
else { // Not ours. But maybe someone told us how to make it ours.
if (!recursive) { FindHandlerForForeignException(pExcept, pRN, pContext, pDC, pFuncInfo, curState, CatchDepth, pMarkerRN); } 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
EHTRACE_EXIT; }
////////////////////////////////////////////////////////////////////////////////
//
// 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
) { EHTRACE_ENTER;
unsigned curTry; unsigned end; TryBlockMapEntry *pEntry; // We don't want to touch BreakPoint generated Exception.
if (PER_CODE(pExcept) == STATUS_BREAKPOINT) { EHTRACE_EXIT; return; }
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 (__CallSETranslator(pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN, TDTransOffset)) { EHTRACE_EXIT; return; } }
// Didn't have a translator, or the translator returned normally (i.e.
// didn't translate it). Still need to check for match with ellipsis:
pEntry = __GetRangeOfTrysToCheck(pRN, pFuncInfo, CatchDepth, curState, &curTry, &end, pDC);
// 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))) { continue; }
// Found an ellipsis. Handle exception.
SetUnwindTryBlock(pRN, pDC, pFuncInfo, /*curTry*/ curState); CatchIt(pExcept, pRN, pContext, pDC, pFuncInfo, TBME_PCATCH(*pEntry, TBME_NCATCHES(*pEntry) - 1), NULL, pEntry, CatchDepth, pMarkerRN, TRUE);
// If it returns, handler re-threw. Keep searching.
} // Search for try
EHTRACE_EXIT;
// If we got here, that means we didn't have anything to do with the
// exception. Continue search.
}
////////////////////////////////////////////////////////////////////////////////
//
// TypeMatch - Check if the catch type matches the given throw conversion.
//
// Returns:
// TRUE if the catch can catch using this throw conversion, FALSE 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; the basic types match if it's the same record *or* the
// names are identical.
if (HT_PTD(*pCatch) != CT_PTD(*pCatchable) && strcmp(HT_NAME(*pCatch), CT_NAME(*pCatchable)) != 0) { return FALSE; }
// Basic types match. The actual conversion is valid if:
// caught by ref if ref required *and*
// the qualifiers are compatible *and*
// the alignments match *and*
// the volatility matches
return (!CT_BYREFONLY(*pCatchable) || HT_ISREFERENCE(*pCatch)) && (!THROW_ISCONST(*pThrow) || HT_ISCONST(*pCatch)) && (!THROW_ISUNALIGNED(*pThrow) || HT_ISUNALIGNED(*pCatch)) && (!THROW_ISVOLATILE(*pThrow) || HT_ISVOLATILE(*pCatch)); }
////////////////////////////////////////////////////////////////////////////////
//
// FrameUnwindFilter - Allows possibility of continuing through SEH during
// unwind.
//
static int FrameUnwindFilter( EXCEPTION_POINTERS *pExPtrs ) { EHTRACE_ENTER;
EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord;
switch (PER_CODE(pExcept)) { case EH_EXCEPTION_NUMBER: __ProcessingThrow = 0; terminate();
#ifdef ALLOW_UNWIND_ABORT
case EH_ABORT_FRAME_UNWIND_PART: EHTRACE_EXIT; return EXCEPTION_EXECUTE_HANDLER; #endif
default: EHTRACE_EXIT; return EXCEPTION_CONTINUE_SEARCH; } }
////////////////////////////////////////////////////////////////////////////////
//
// __FrameUnwindToState - Unwind this frame until specified state is reached.
//
// Returns:
// 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.
extern "C" void __FrameUnwindToState ( 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
) { EHTRACE_ENTER;
__ehstate_t curState = __GetUnwindState(pRN, pDC, pFuncInfo); __ProcessingThrow++; __try { while (curState != EH_EMPTY_STATE && curState > targetState) { DASSERT((curState > EH_EMPTY_STATE) && (curState < FUNC_MAXSTATE(*pFuncInfo)));
// Get state after next unwind action
__ehstate_t nxtState = UWE_TOSTATE(FUNC_UNWIND(*pFuncInfo, curState));
__try { // Call the unwind action (if one exists):
if (UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)) != NULL) {
// Before calling unwind action, adjust state as if it were
// already completed:
SetState(pRN, pDC, pFuncInfo, nxtState);
EHTRACE_FMT2("Unwind from state %d to state %d", curState, nxtState); _CallSettingFrame(__GetAddress(UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), pDC), REAL_FP(pRN, pFuncInfo), 0x103); }
} __except(EHTRACE_EXCEPT(FrameUnwindFilter(exception_info()))) { }
curState = nxtState; } } __finally { if (__ProcessingThrow > 0) { __ProcessingThrow--; } }
// Now that we're done, set the frame to reflect the final state.
DASSERT(curState == EH_EMPTY_STATE || curState <= targetState);
EHTRACE_FMT2("Move from state %d to state %d", __GetUnwindState(pRN, pDC, pFuncInfo), curState); SetState(pRN, pDC, pFuncInfo, curState);
EHTRACE_EXIT; }
////////////////////////////////////////////////////////////////////////////////
//
// 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
CONTEXT *pContext, // Context info
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
BOOLEAN IsRethrow // Is this a rethrow ?
) { EHTRACE_ENTER_FMT1("Catching object @ 0x%p", PER_PEXCEPTOBJ(pExcept));
void *continuationAddress; EHRegistrationNode *pEstablisher = pRN;
FRAMEINFO FrameInfo; FRAMEINFO *pFrameInfo; CONTEXT ExitContext;
PVOID pExceptionObjectDestroyed = NULL; EHRegistrationNode EstablisherFramePointers; pEstablisher = _GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers);
// 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) { BuildCatchObject(pExcept, pEstablisher, pCatch, pConv); }
// Unwind stack objects to the entry of the try that caught this exception.
pExitContext = &ExitContext; _UnwindNestedFrames(pRN, pExcept, pContext #ifdef _M_AMD64
, pDC #endif
); if( _pCurrentException != NULL && _ExecutionInCatch(pDC, pFuncInfo) && ! IsRethrow) { __DestructExceptionObject(_pCurrentException, TRUE); pExceptionObjectDestroyed = PER_PEXCEPTOBJ(_pCurrentException); }
// Create FrameInfo before we attempt to unwind with __FrameUnwindToState()
// pExitContext must be setup in advance just in case a DTOR throws a new exception. VS7:#202440
pFrameInfo = _CreateFrameInfo(&FrameInfo, pDC, pExitContext, -2, pExceptionObjectDestroyed, pExcept); __FrameUnwindToState(pEstablisher, pDC, pFuncInfo, TBME_LOW(*pEntry));
// Call the catch. Separated out because it introduces a new registration
// node.
#if defined(_M_IA64) /*IFSTRIP=IGN*/
UNWINDSTATE(pEstablisher->MemoryStackFp, FUNC_DISPUNWINDHELP(*pFuncInfo)) = GetCurrentState(pEstablisher,pDC,pFuncInfo); #endif
if(IsRethrow) { pFrameInfo->isRethrow = TRUE; } else if( pExcept != NULL && pExceptionObjectDestroyed == NULL ) { pFrameInfo->pExceptionObjectToBeDestroyed = PER_PEXCEPTOBJ(pExcept); }
continuationAddress = CallCatchBlock(pExcept, pEstablisher, pContext, pFuncInfo, __GetAddress(HT_HANDLER(*pCatch), pDC), CatchDepth, 0x100, pFrameInfo );
// Transfer control to the continuation address. If no continuation then
// it's a re-throw, so return.
if (continuationAddress != NULL) {
#if defined(_M_AMD64)
UNWINDHELP(*pEstablisher, FUNC_DISPUNWINDHELP(*pFuncInfo)) = -2; FRAMEINFO * pContFrameInfo = _FindFrameInfo(continuationAddress, pFrameInfo); if( pContFrameInfo != NULL && !pContFrameInfo->isRethrow && pContFrameInfo->pExceptionObjectToBeDestroyed && !_IsExceptionObjectDestroyed(pContFrameInfo->pExceptionObjectToBeDestroyed,pFrameInfo) ) { __DestructExceptionObject(pContFrameInfo->pExcept, TRUE); _MarkExceptionObjectDestroyed(pContFrameInfo->pExcept); } #elif defined(_M_IA64) /*IFSTRIP=IGN*/
UNWINDHELP(pEstablisher->MemoryStackFp, FUNC_DISPUNWINDHELP(*pFuncInfo)) = -2; FRAMEINFO * pContFrameInfo = _FindFrameInfo(continuationAddress, pFrameInfo); if( pContFrameInfo != NULL && !pContFrameInfo->isRethrow && pContFrameInfo->pExceptionObjectToBeDestroyed && !_IsExceptionObjectDestroyed(pContFrameInfo->pExceptionObjectToBeDestroyed,pFrameInfo) ) { __DestructExceptionObject(pContFrameInfo->pExcept, TRUE); } else if( pFrameInfo != NULL && pFrameInfo != pContFrameInfo && !_IsExceptionObjectDestroyed(PER_PEXCEPTOBJ(pExcept),pFrameInfo) ) { __DestructExceptionObject(pExcept, TRUE); } #else
#error "No Target Architecture:
#endif
__ResetException(pExcept); pExitContext = NULL; _JumpToContinuation((unsigned __int64)continuationAddress, _FindAndUnlinkFrame(continuationAddress, pFrameInfo), pExcept );
} else { _UnlinkFrame(pFrameInfo); }
EHTRACE_EXIT; }
////////////////////////////////////////////////////////////////////////////////
//
// CallCatchBlock - continuation of CatchIt.
//
// This is seperated from CatchIt because it needs to introduce an SEH/EH 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
int CatchDepth, // How deeply nested in catch blocks
// are we?
unsigned long NLGCode, // NLG destination code
FRAMEINFO *pFrameInfo ) { EHTRACE_ENTER;
// Address where execution resumes after exception handling completed.
// Initialized to non-NULL (value doesn't matter) to distinguish from
// re-throw in __finally.
void *continuationAddress = handlerAddress;
BOOL ExceptionObjectDestroyed = FALSE;
// 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.
continuationAddress = _CallSettingFrame(handlerAddress, REAL_FP(pRN, pFuncInfo), NLGCode);
} __except(EHTRACE_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.
continuationAddress = NULL; } } __finally { EHTRACE_SAVE_LEVEL; EHTRACE_FMT1("Executing __finally, %snormal termination", _abnormal_termination() ? "ab" : "");
// 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 and the object isn't also in use by a more deeply nested
// catch. Note that the catch handles destruction of its parameter.
if (PER_IS_MSVC_EH(pExcept) && !ExceptionObjectDestroyed && continuationAddress != NULL && !_IsExceptionObjectDestroyed(PER_PEXCEPTOBJ(pExcept),pFrameInfo) && !pFrameInfo->isRethrow ) { pFrameInfo->dtorThrowFlag = TRUE; __DestructExceptionObject(pExcept, abnormal_termination()); }
EHTRACE_RESTORE_LEVEL(!!_abnormal_termination()); } EHTRACE_EXIT; pFrameInfo->dtorThrowFlag = FALSE; return continuationAddress; }
////////////////////////////////////////////////////////////////////////////////
//
// 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 has no exception information.
if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == NULL) { return EXCEPTION_EXECUTE_HANDLER; } else { return EXCEPTION_CONTINUE_SEARCH; } }
////////////////////////////////////////////////////////////////////////////////
//
// 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?)
static void BuildCatchObject( EHExceptionRecord *pExcept, // Original exception thrown
void *pRN, // This is a pointer to the object
// that we want to build while doing
// COM+ eh. If we are in our own eh,
// then this is a Registration node of
// catching function
HandlerType *pCatch, // The catch clause that got it
CatchableType *pConv // The conversion to use
) { EHTRACE_ENTER;
// 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!
if (HT_IS_TYPE_ELLIPSIS(*pCatch) || (!HT_DISPCATCH(*pCatch) && !HT_ISCOMPLUSEH(*pCatch))) { EHTRACE_EXIT; return; }
void **pCatchBuffer; if ( HT_ISCOMPLUSEH(*pCatch)) { pCatchBuffer = (void **)pRN; } else { #if defined(_M_IA64) /*IFSTRIP=IGN*/
pCatchBuffer = (void **)__OffsetToAddress( HT_DISPCATCH(*pCatch), ((EHRegistrationNode *)pRN)->MemoryStackFp, HT_FRAMENEST(*pCatch) ); #elif defined(_M_AMD64)
pCatchBuffer = (void **)__OffsetToAddress( HT_DISPCATCH(*pCatch), *((EHRegistrationNode *)pRN), HT_FRAMENEST(*pCatch) ); #else
#error "No Target Architecture"
#endif
} __try { 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, i.e.
// pExceptionObject is a (machine) pointer to T. Adjust as
// required.
if (_ValidateRead(PER_PEXCEPTOBJ(pExcept)) && _ValidateWrite(pCatchBuffer)) { *pCatchBuffer = PER_PEXCEPTOBJ(pExcept); *pCatchBuffer = AdjustPointer(*pCatchBuffer, CT_THISDISP(*pConv)); } else { _inconsistency(); // Does not return; TKB
} } 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.
if (_ValidateRead(PER_PEXCEPTOBJ(pExcept)) && _ValidateWrite(pCatchBuffer)) { memmove(pCatchBuffer, PER_PEXCEPTOBJ(pExcept), CT_SIZE(*pConv));
if (CT_SIZE(*pConv) == sizeof(void*) && *pCatchBuffer != NULL) { *pCatchBuffer = AdjustPointer(*pCatchBuffer, CT_THISDISP(*pConv)); } } else { _inconsistency(); // Does not return; TKB
} } 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.
if (_ValidateRead(PER_PEXCEPTOBJ(pExcept)) && _ValidateWrite(pCatchBuffer)) { memmove(pCatchBuffer, AdjustPointer(PER_PEXCEPTOBJ(pExcept), CT_THISDISP(*pConv)), CT_SIZE(*pConv)); } else { _inconsistency(); // Does not return; TKB
} } else {
// It's a UDT: make a copy using copy ctor
#pragma warning(disable:4191)
if (_ValidateRead(PER_PEXCEPTOBJ(pExcept)) && _ValidateWrite(pCatchBuffer) && _ValidateExecute((FARPROC)CT_COPYFUNC(*pConv))) {
#pragma warning(default:4191)
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))); } } else { _inconsistency(); // Does not return; TKB
} } } } __except(EHTRACE_EXCEPT(EXCEPTION_EXECUTE_HANDLER)) { // Something went wrong when building the catch object.
terminate(); }
EHTRACE_EXIT; }
////////////////////////////////////////////////////////////////////////////////
//
// __DestructExceptionObject - Call the destructor (if any) of the original
// exception object.
//
// Returns: None.
//
// Side-effects:
// 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.
extern "C" void _CRTIMP __DestructExceptionObject( EHExceptionRecord *pExcept, // The original exception record
BOOLEAN fThrowNotAllowed // TRUE if destructor not allowed to
// throw
) { EHTRACE_ENTER_FMT1("Destroying object @ 0x%p", PER_PEXCEPTOBJ(pExcept));
if (pExcept != NULL && THROW_UNWINDFUNC(*PER_PTHROW(pExcept)) != NULL) {
__try {
// M00REVIEW: A destructor has additional hidden arguments, doesn't
// it?
_MarkExceptionObjectDestroyed(pExcept); _CallMemberFunction0(PER_PEXCEPTOBJ(pExcept), THROW_UNWINDFUNC_IB(*PER_PTHROW(pExcept),(unsigned __int64)PER_PTHROWIB(pExcept))); __ResetException(pExcept);
} __except(EHTRACE_EXCEPT(fThrowNotAllowed ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)) {
// Can't have new exceptions when we're unwinding due to another
// exception.
terminate(); } }
EHTRACE_EXIT; }
////////////////////////////////////////////////////////////////////////////////
//
// 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) { pRet += *(__int32 *)((char *)*(ptrdiff_t *)((char *)pThis + pmd.pdisp) + (unsigned _int64)pmd.vdisp); pRet += pmd.pdisp; }
return pRet; }
///////////////////////////////////////////////////////////////////////////////
//
// __uncaught_exception() - Returns true after completing of a throw-expression
// untils completing initialization of the
// exception-declaration in the matching handler.
//
bool __uncaught_exception() { return (__ProcessingThrow != 0); }
#if !defined(_M_IA64) && !defined(_M_AMD64) // Enable&fix for IA64 when COM+ C++ EH support available there
////////////////////////////////////////////////////////////////////////////////
// Model of C++ eh in COM+
//
// void func()
// {
// try {
// TryBody();
// } catch (cpp_object o)
// {
// CatchOBody();
// } catch (...)
// {
// CatchAllBody();
// }
// }
//
// Turns into this:
//
//
// void func()
// {
// int rethrow;
// // One per try block
// int isCxxException;
// // One per catch(...)
// __try {
// TryBody();
// }
// __except(__CxxExceptionFilter(exception,
// typeinfo(cpp_object),
// flags,
// &o))
// // This is how it's done already
// {
// // Begin catch(object) prefix
// char *storage = _alloca(__CxxQueryExceptionSize());
// rethrow = false;
// __CxxRegisterExceptionObject(exception,
// storage);
// __try {
// __try {
// // End catch(object) prefix
// CatchOBody();
// // Begin catch(object) suffix
// } __except(rethrow = __CxxDetectRethrow(exception),
// EXCEPTION_CONTINUE_SEARCH)
// {}
// }
// __finally
// {
// __CxxUnregisterExceptionObject(storage,
// rethrow);
// }
// // End catch(object) suffix
// }
// __except(1)
// {
// // Begin catch(...) prefix
// char *storage = _alloca(__CxxQueryExceptionSize());
// rethrow = false;
// isCxxException = __CxxRegisterExceptionObject(exception,
// storage);
// __try
// {
// __try
// {
// // End catch(...) prefix
// CatchAllBody();
// // Begin catch(...) suffix
// } __except(rethrow = __CxxDetectRethrow(exception),
// EXCEPTION_CONTINUE_SEARCH)
// {}
// } __finally
// {
// if (isCxxException)
// __CxxUnregisterExceptionObject(storage, rethrow);
// }
// // End catch(...) suffix
// }
// }
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// __CxxExceptionFilter() - Returns EXCEPTION_EXECUTE_HANDLER when the pType
// matches with the objects we can catch. Returns
// EXCEPTION_CONTINUE_SEARCH when pType is not one of
// the catchable type for the thrown object. This
// function is made for use with COM+ EH, where they
// attempt to do C++ EH as well.
//
extern "C" int __cdecl __CxxExceptionFilter( void *ppExcept, // Information for this (logical)
// exception
void *pType, // Info about the datatype.
int adjectives, // Extra Info about the datatype.
void *pBuildObj // Pointer to datatype.
) { struct _s_HandlerType pCatch; __int32 const *ppCatchable; CatchableType *pCatchable; int catchables; EHExceptionRecord *pExcept;
if (!ppExcept) return EXCEPTION_CONTINUE_SEARCH; pExcept = *(EHExceptionRecord **)ppExcept; // If catch all, always return EXCEPTION_EXECUTE_HANDLER
if ( TD_IS_TYPE_ELLIPSIS((TypeDescriptor *)pType)) { if (PER_IS_MSVC_EH(pExcept)) { if ( PER_PTHROW(pExcept) == NULL) { if ( _pCurrentException != NULL) *(EHExceptionRecord **)ppExcept = _pCurrentException; else return EXCEPTION_CONTINUE_SEARCH; } } __ProcessingThrow++; return EXCEPTION_EXECUTE_HANDLER; } if (PER_IS_MSVC_EH(pExcept)) { if ( PER_PTHROW(pExcept) == NULL) { if (_pCurrentException == NULL) return EXCEPTION_CONTINUE_SEARCH; pExcept = _pCurrentException; } pCatch.pType = (TypeDescriptor *)pType; pCatch.adjectives = adjectives; SET_HT_ISCOMPLUSEH(pCatch);
// Scan all types that thrown object can be converted to:
ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept)); for (catchables = THROW_COUNT(*PER_PTHROW(pExcept)); catchables > 0; catchables--, ppCatchable++) { pCatchable = (CatchableType *)(_GetThrowImageBase() + *ppCatchable);
if (TypeMatch(&pCatch, pCatchable, PER_PTHROW(pExcept))) { // SucessFull. Now build the object.
__ProcessingThrow++; if (pBuildObj != NULL) BuildCatchObject(pExcept, pBuildObj, &pCatch, pCatchable); // We set the current exception.
if ( PER_PTHROW(*(EHExceptionRecord **)ppExcept) == NULL) *(EHExceptionRecord **)ppExcept = _pCurrentException; return EXCEPTION_EXECUTE_HANDLER; } } // Scan posible conversions
} return EXCEPTION_CONTINUE_SEARCH; }
////////////////////////////////////////////////////////////////////////////////
//
// __CxxRgisterExceptionObject() - Registers Exception Object and saves it to
// This is same as first part of
// CallCatchBlock.
//
extern "C" int __cdecl __CxxRegisterExceptionObject( void *ppExcept, void *pStorage ) { // This function is only called for C++ EH.
EHExceptionRecord *pExcept; FRAMEINFO *pFrameInfo = (FRAMEINFO *)pStorage; EHExceptionRecord **ppSaveException; CONTEXT **ppSaveExContext; ppSaveException = (EHExceptionRecord **)(&pFrameInfo[1]); ppSaveExContext = (CONTEXT **)(&ppSaveException[1]); pExcept = *(EHExceptionRecord **)ppExcept; pFrameInfo = _CreateFrameInfo(pFrameInfo, PER_PEXCEPTOBJ(pExcept)); *ppSaveException = _pCurrentException; *ppSaveExContext = _pCurrentExContext; _pCurrentException = pExcept; __ProcessingThrow--; if ( __ProcessingThrow < 0) __ProcessingThrow = 0; return 1; }
////////////////////////////////////////////////////////////////////////////////
//
// __CxxDetectRethrow() - Looks at the Exception and returns true if rethrow,
// false if not a rethrow. This is then used for
// destructing the exception object in
// __CxxUnregisterExceptionObject().
//
extern "C" int __cdecl __CxxDetectRethrow( void *ppExcept ) { EHExceptionRecord *pExcept; if (!ppExcept) return 0; pExcept = *(EHExceptionRecord **)ppExcept; if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == NULL) { *(EHExceptionRecord **)ppExcept = _pCurrentException; return 1; } else if (*(EHExceptionRecord **)ppExcept == _pCurrentException) return 1; return 0; }
////////////////////////////////////////////////////////////////////////////////
//
// __CxxUnregisterExceptionObject - Destructs Exception Objects if rethrow ==
// true. Also set __pCurrentException and
// __pCurrentExContext() to current value.
//
extern "C" void __cdecl __CxxUnregisterExceptionObject( void *pStorage, int rethrow ) { FRAMEINFO *pFrameInfo = (FRAMEINFO *)pStorage; EHExceptionRecord **ppSaveException; CONTEXT **ppSaveExContext; ppSaveException = (EHExceptionRecord **)(&pFrameInfo[1]); ppSaveExContext = (CONTEXT **)(&ppSaveException[1]); _FindAndUnlinkFrame(pFrameInfo); if ( !rethrow && PER_IS_MSVC_EH(_pCurrentException) && IsExceptionObjectToBeDestroyed(PER_PEXCEPTOBJ(_pCurrentException))) { __DestructExceptionObject(_pCurrentException, TRUE); } _pCurrentException = *ppSaveException; _pCurrentExContext = *ppSaveExContext; }
////////////////////////////////////////////////////////////////////////////////
//
// __CxxQueryExceptionSize - returns the value of Storage needed to save
// FrameInfo + two pointers.
//
extern "C" int __cdecl __CxxQueryExceptionSize( void ) { return sizeof(FRAMEINFO) + sizeof(void *) + sizeof(void *); }
////////////////////////////////////////////////////////////////////////////////
//
// __CxxCallUnwindDtor - Calls a destructor during unwind. For COM+, the dtor
// call needs to be wrapped inside a __try/__except to
// get correct terminate() behavior when an exception
// occurs during the dtor call.
//
extern "C" void __cdecl __CxxCallUnwindDtor( void (__thiscall * pDtor)(void*), void *pThis ) { __try { (*pDtor)(pThis); } __except(FrameUnwindFilter(exception_info())) { } }
#endif // !defined(_M_IA64) && !defined(_AMD64_)
|