📄 frame.cpp
字号:
// This function is invoked to determine that exception object can be destroyed
// or not:
//
// return TRUE means that the object can be destructed; FALSE otherwise.
//
// Note:
// The object we are trying to delete is from the throw line, constructed by
// copy constructor.
// Example: throw a0; the copy of a0 is the exception object that
// we are talking about here.
//
// _pCurrentException is actually the previous exception besides pExcept
//
static BOOLEAN CanThisExceptionObjectBeDestructed(EHExceptionRecord *pExcept,
BOOLEAN abnormalTermination)
{
BOOLEAN ret = FALSE;
DEBUGMSG(DBGEH,(TEXT("Checking: pExcept(%08x), obj(%08x), abnormalTermination(%d)\r\n"),
pExcept, PER_PEXCEPTOBJ(pExcept), abnormalTermination));
DEBUGMSG(DBGEH,(TEXT("Checking: _pCurrExceptRethrow(%08x), _pCurrentException(%08x)\r\n"),
_pCurrExceptRethrow, _pCurrentException));
if ( abnormalTermination )
{
// as long as pExcept is not the same as _pCurrExceptRethrow
if ( pExcept!=_pCurrExceptRethrow )
{
ret = TRUE;
}
}
else
{
// Important point:
// Just because we found normal exit from a catch does not imply that we can destroy
// the source of the local exception object (original exception object). This is
// because a catch may be nested inside another. After exiting a nested catch, we
// may find a rethrow of the original exception object. For this reason, we can only
// destroy the original exception object once we have left the scope of the catch which
// caught it.
//
// For normal termination we destroy pExcept if any of the following are true:
// 1) No pCurrExceptRethrow at all.
// 2) pExcept is the same of pCurrExceptRethrow, and pExcept itself
// is not a rethrow of _pCurrentException.
// 3) Exception is rethrow and _pCurrExceptRethrow is not the previous recorded exception
// because another rethrow might be thrown.
if ( !_pCurrExceptRethrow ||
( pExcept==_pCurrExceptRethrow &&
!IS_RETHROW(pExcept, _pCurrentException) ) ||
( IS_RETHROW((EHExceptionRecord *)_pCurrExceptRethrow, pExcept) &&
_pCurrExceptRethrow!=_pCurrentException ) )
{
ret = TRUE;
}
}
DEBUGMSG(DBGEH,(TEXT("Checking: EXIT ret:%08x\r\n"),
ret));
return ret;
}
////////////////////////////////////////////////////////////////////////////////
//
// CallCatchBlock
//
// This function is called after the shx\target frame has been unwound (all unwind
// actions have been performed. The catch block is now invoked.
//
//
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
unsigned long NLGCode // NLG destination code
)
{
// 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;
#if !defined(_X86_)
FRAMEINFO NewFrame;
#if defined(_M_ARM)
CATCHFRAMEINFO NewCatchFrame;
#endif // _M_ARM
#endif // !defined(_X86_)
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: ENTER, to invoke handler @%08x pRN=%08x\r\n"),
handlerAddress, pRN));
// 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 ;
CONTEXT *pSaveExContext ;
// Save the current rethrow exception. This is because rethrows can be nested. To be
// restored when the catch exits.
EHExceptionRecord *pSaveRethrowException ;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: save _pCurrentException=%08x _pCurrentExContext=%08x\r\n"),
_pCurrentException, _pCurrentExContext));
pSaveException = _pCurrentException;
pSaveExContext = _pCurrentExContext;
pSaveRethrowException = (EHExceptionRecord *)_pCurrExceptRethrow;
_pCurrentException = pExcept;
_pCurrentExContext = pContext;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: put pExcept=%08x into _pCurrentException\r\n"),
pExcept));
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: put pContext=%08x into _pCurrentExContext\r\n"),
pContext));
__try {
#if defined(_X86_)
// The current stack pointer is stored just ahead of the
// registration node. We need to add it to the context
// structure (for the continuation) before calling the catch
// block because it will be changed in the catch block if
// there's a nested try/catch block.
pContext->Esp = *((unsigned long*)pRN - 1);
continuationAddress = _CallCatchBlock2(pRN, pFuncInfo, handlerAddress,
CatchDepth, 0);
// Get frame pointer by looking past the exception
// registration node on the stack per __CallSettingFrame
pContext->Ebp = (unsigned long) pRN + sizeof(EHRegistrationNode);
#else
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: Fill NewFrame fields all but pCatchRN...\r\n")));
// this will be set in CallSetttingFrame
NewFrame.pCatchRN = NULL;
NewFrame.pRN = pRN;
NewFrame.state = (FUNC_UNWIND(*pFuncInfo,
TBME_LOW(*TargetEntry))).toState;
NewFrame.NestLevel = HT_FRAMENEST(TBME_CATCH(*TargetEntry, 0));
NewFrame.next = pFrameInfoChain;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: NewFrame=%08x pRN=%08x state=%d NestLevel=%d next=%08x\r\n"),
&NewFrame, NewFrame.pRN, NewFrame.state, NewFrame.NestLevel, NewFrame.next));
pFrameInfoChain = &NewFrame;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: insert NewFrame=%08x into pFrameInfoChain\r\n"),
&NewFrame));
#if defined(_M_ARM)
NewCatchFrame.pRN=pRN;
NewCatchFrame.NestLevel = HT_FRAMENEST(TBME_CATCH(*TargetEntry, 0));
NewCatchFrame.pFuncInfo = pFuncInfo ;
NewCatchFrame.next = pCatchChain;
pCatchChain = &NewCatchFrame;
pRN=FindCatchFrame (pRN, HT_FRAMENEST(TBME_CATCH(*TargetEntry, 0)));
#endif // _M_ARM
continuationAddress = _CallSettingFrame(handlerAddress, pRN,
pContext, &NewFrame );
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: from _CallSettingFrame: pCatchRN=%08x\r\n"),
NewFrame.pCatchRN));
#endif // _X86_
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: from _CallSettingFrame continuationAddress %08x\r\n"),
continuationAddress));
} __finally {
// DEBUGCHK(pExcept==_pCurrentException);
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: Restore the _pCurrentException\r\n")));
_pCurrentException = pSaveException;
_pCurrentExContext = pSaveExContext;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: _pCurrentException=%08x _pCurrentExContext=%08x\r\n"),
_pCurrentException, _pCurrentExContext));
// Destroy the original exception object if we're not exiting on a
// re-throw. Note that the catch handles destruction of its parameter.
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: pExcept(0x%08x), PER_PTHROW(pExcept):%08x, PER_PEXCEPTOBJ(pExcept):%08x _pCurrentException=%08x\r\n"),
pExcept, PER_PTHROW(pExcept), PER_PEXCEPTOBJ(pExcept), _pCurrentException));
#if !defined(_X86_)
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: abnormal_termination(%d) _pCurrExceptRethrow(0x%08x)\r\n"),
abnormal_termination(), _pCurrExceptRethrow));
#endif // !defined(_X86_)
if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) != NULL
&& CanThisExceptionObjectBeDestructed(pExcept, abnormal_termination()))
{
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: calling DestructExceptionObject pExcept=%08x, obj(%08x)\r\n"),
pExcept, PER_PEXCEPTOBJ(pExcept)));
_DestructExceptionObject(pExcept, abnormal_termination());
}
_pCurrExceptRethrow = pSaveRethrowException;
#if !defined(_X86_)
//
// If the catch block raised an exception, save the pRN and state
// for unwinding through the associated try block. The lifetime of
// these values is from here until the next call to FrameUnwindToState
//
if (abnormal_termination()) {
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: abnormal_termination. Catch Block Raised an exception ")));
CatchExceptRN = NewFrame.pRN;
CatchExceptState = NewFrame.state;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: save CatchExceptRN=%08x CatchExceptState=%d from NewFrame\r\n"),
CatchExceptRN, CatchExceptState));
}
#if defined(_M_ARM)
//
// Remove current catch frame from list
//
CATCHFRAMEINFO *lcurFrame = pCatchChain;
CATCHFRAMEINFO **lnextFrame = &pCatchChain;
while ( lcurFrame != NULL ){
if (lcurFrame == &NewCatchFrame ) {
*lnextFrame = lcurFrame->next;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: Removing %08x: pCatchChain=%08x\r\n"),
lcurFrame, pCatchChain));
}
lnextFrame = &lcurFrame->next;
lcurFrame = lcurFrame->next;
}
#endif // _M_ARM
#endif // !defined(_X86_)
} // finally
#ifndef _M_IX86
// to update pFrameInfoChain here.
// we remove not only NewFrame when normal_termination occurs, but also residing FrameInfo
// which had been created by previous CallCatchBlock while abnormal_termination happened.
// If the state of pFrameInfo on the pFrameInfoChain is bigger than NewFrame's state,
// we are sure that pFrameInfo is enclosed by NewFrame's state, given that try/catch
// can not be overlapped.
{
FRAMEINFO *prevFrame = NULL;
FRAMEINFO *curFrame = pFrameInfoChain;
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: normal_termination. update pFrameChainInfo ")));
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: remove NewFrame(%08x) from pFrameInfoChain(%08x)\r\n"),
&NewFrame, pFrameInfoChain));
// iterate the pFrameInfoChain to look for NewFrame to remove
// Assumption: stack grows while memory decreases.
while ( curFrame != NULL ) {
if ( curFrame->pRN <= NewFrame.pRN ) {
// curFrame's establisher frame was established after NewFrame's.
// curFrame can be safely removed from the chain.
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: Removing curFrame=%08x from pFrameInfoChain=%08x\r\n"),
curFrame, pFrameInfoChain));
if ( curFrame == pFrameInfoChain ) {
pFrameInfoChain = curFrame->next;
} else {
prevFrame->next = curFrame->next;
}
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: curFrame: pRN=%08x CatchRN=%08x state=%d NestLevel=%d\r\n"),
curFrame->pRN, curFrame->pCatchRN,
curFrame->state, curFrame->NestLevel));
}
prevFrame = curFrame;
curFrame = curFrame->next;
}
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: After removal NewFrame(%08x), pFrameInfoChain(%08x)\r\n"),
&NewFrame, pFrameInfoChain));
}
#endif // _M_IX86
DEBUGMSG(DBGEH,(TEXT("CallCatchBlock: EXIT pExcept(%08x) with continuationAddress=%08x\r\n"),
pExcept, continuationAddress));
return continuationAddress;
} // CallCatchBlock
////////////////////////////////////////////////////////////////////////////////
//
// 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
EHRegistrationNode *pRN, // Registration node of catching function
HandlerType *pCatch, // The catch clause that got it
CatchableType *pConv // The conversion to use
)
{
// 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)) {
return;
}
void **pCatchBuffer = (void **)__OffsetToAddress(HT_DISPCATCH(*pCatch), pRN,
HT_FRAMENEST(*pCatch));
#ifndef _M_IX86
DEBUGMSG(DBGEH,(TEXT("BuildCatchObject pRN=%08x Level=%d\r\n"),pRN,
HT_FRAMENEST(*pCatch)));
#endif // _M_IX86
__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.
DEBUGMSG(DBGEH,(TEXT("Object thrown is HT_ISREFERENCE\r\n")));
*pCatchBuffer = PER_PEXCEPTOBJ(pExcept);
*pCatchBuffer = AdjustPointer(*pCatchBuffer, CT_THISDISP(*pConv));
} else if (CT_ISSIMPLETYPE(*pConv)) {
// Object thrown is of simple type (this including pointers) copy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -