Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

573 lines
16 KiB

/***
*trnsctrl.cxx - global (per-thread) variables and functions for EH callbacks
*
* Copyright (c) 1993-1995, Microsoft Corporation. All rights reserved.
*
*Purpose:
* PowerMac specific EH routines
*
*Revision History:
* 08-09-95 JWM Enabled CFM-to-CFM throws (Olympus bug 15162).
* 08-21-95 JWM Bug fix: Olympus 16608.
*
****/
//#pragma optimize("",off)
#include <ehassert.h>
#include <ehdata.h>
#include <trnsctrl.h>
#include <eh.h>
#include <ehhooks.h>
#include <search.h>
#include <dbgint.h>
#pragma hdrstop
typedef void (*PMFN0)(void *);
typedef void (*PMFN1)(void *, void*);
typedef void (*PMFN2)(void *, void*, int);
//linker created symbol
extern "C" {
extern FTINFO _FTInfo;
}
PFTINFO _pftinfo = &_FTInfo;
PFTINFO _pftinfoCRT = &_FTInfo;
PFTINFO _pftinfoLast = NULL;
unsigned long dwRTOC = 0;
unsigned long cNested = 0;
unsigned long fStaticNested = 0;
unsigned long fNestedInSameFrame = 0;
PFRAMEINFO _pFrameInfoChain = NULL;
PRUNTIME_FUNCTION pFuncEntryLast;
#define OFSFTINFO 64
//assembly
extern "C" {
extern void *GetSP(void);
extern void *GetR4(void);
extern void *GetRTOC(void);
extern unsigned int dwSPStartup;
}
PRUNTIME_FUNCTION GetFunctionEntry(PPMSTACK spCur, PFTINFO *ppftinfoOut);
//PowerMac version of stack walking to find a C++ exception handler
//Assume:
// _pftinfo
//
void MacExceptionDispatch(PEXCEPTION_RECORD pExceptionRecord)
{
PPMSTACK spCur;
PPMSTACK spCurCatch;
DispatcherContext curDC;
PRUNTIME_FUNCTION pFunctionEntry;
PRUNTIME_FUNCTION pFunctionEntryCatch = NULL;
PFTINFO pftinfoTOC;
PPMSTACK pFrame;
unsigned long cNestedTmp;
PFRAMEINFO pframeinfo;
spCur = (PMSTACK *)GetSP();
//Loop through the frames backwards on the stack to find a frame which has an EH handler
//Assume:
// End of Stack: when the save area link register is NULL
// .pdata has Exception Handler points to CxxFrameHandler if an EH Frame
// Exception Data points to FuncInfo
spCur = spCur->pSpBackChain; //this should be in CxxThrowException frame
spCur = spCur->pSpBackChain; //this should be in caller of CxxThrowException frame
//Is this a cross TOC call? Do we need to switch RTOC???!!!
if ( (spCur->dwLNKreg >= _pftinfo->dwEntryCF) && (spCur->dwLNKreg <= ((unsigned long)((char *)_pftinfo->dwEntryCF+ _pftinfo->dwSizeCF))) || spCur->dwTOCreg == (unsigned long)GetRTOC())
{
// okay, we are throw in the same code fragment as CRT, CRT being statically linked in, or the same as last throw
}
else if ( (spCur->dwLNKreg >= _pftinfoCRT->dwEntryCF) && (spCur->dwLNKreg <= ((unsigned long)((char *)_pftinfoCRT->dwEntryCF+ _pftinfoCRT->dwSizeCF))) || spCur->dwTOCreg == (unsigned long)GetRTOC())
{
_pftinfo = _pftinfoCRT;
}
else
{
// make _pftinfo point to the code fragment which has thrown the exception, CRT must be a DLL now
_ASSERTE(spCur->dwTOCreg);
_pftinfo = (PFTINFO)(*(unsigned long *)((char *)spCur->dwTOCreg + OFSFTINFO));
dwRTOC = spCur->dwTOCreg;
}
while (spCur->dwLNKreg)
{
if (_pFrameInfoChain)
{
// we should only look the outer nested scope for handlers and we should skip catch handler frame
// because the actual frame called the catch handler is way down
if ( (spCur > _pFrameInfoChain->pExitContext) && (spCur < _pFrameInfoChain->pSp) )
{
spCur = spCur->pSpBackChain;
continue;
}
if (cNested > 0)
{
cNestedTmp = cNested;
pframeinfo = _pFrameInfoChain;
while (cNestedTmp-- && pframeinfo)
{
// This means we are throw in the catch
if ( (spCur->pSpBackChain == pframeinfo->pExitContext) )
{
pFunctionEntryCatch = GetFunctionEntry(spCur, &pftinfoTOC);
spCurCatch = spCur;
break;
}
pframeinfo = pframeinfo->pNext;
}
if (pframeinfo)
{
spCur = spCur->pSpBackChain;
continue;
}
}
}
pFunctionEntry = GetFunctionEntry(spCur, &pftinfoTOC);
if (pFunctionEntry && (pFunctionEntry->ExceptionHandler != NULL))
{
//stack point, old PC(in linker register, execution point==state), Registers in Context
pFrame = spCur;
curDC.ControlPc = spCur->dwLNKreg;
curDC.FunctionEntry = pFunctionEntry;
curDC.EstablisherFrame = spCur;
curDC.pExcept = pExceptionRecord;
if (_pftinfo != pftinfoTOC)
{
// we are calling catch which is in different code fragment
curDC.pftinfo = pftinfoTOC;
curDC.pftinfo->pFrameInfo = _pFrameInfoChain;
_pftinfo->pFrameInfo = _pFrameInfoChain;
_pFrameInfoChain = 0; //reset
cNested = 0;
}
else
{
curDC.pftinfo = _pftinfo;
curDC.pftinfo->pFrameInfo = _pFrameInfoChain;
}
if (dwRTOC == 0)
{
dwRTOC = (unsigned long)GetRTOC(); //not CRT as DLL case
}
//dwRTOC has throw object RTOC
//curDC has handler's info
if (pFunctionEntryCatch == pFunctionEntry)
{
// we have to update the return address in original catch frame
if (spCurCatch->dwLNKreg > curDC.ControlPc)
{
curDC.ControlPc = spCurCatch->dwLNKreg;
}
//we have to remeber the current return from catch's throw, so we can unwinding properly.
//the return in the frame is adjusted to next state, so it can be off for unwinding
//Note: we only need all the trouble for statically nested case
curDC.ControlPcOld = spCurCatch->dwLNKreg;
fStaticNested = 1;
}
(*pFunctionEntry->ExceptionHandler)(pExceptionRecord, pFrame, (void *)dwRTOC, &curDC);
if (_pftinfo != pftinfoTOC)
{
_pFrameInfoChain = (PFRAMEINFO)_pftinfo->pFrameInfo; //reset our globals if we come back;STILL problem!!!
pframeinfo = _pFrameInfoChain;
while (pframeinfo)
{
// This means we are throw in the catch
cNested++;
pframeinfo = pframeinfo->pNext;
}
}
fStaticNested = 0;
pFuncEntryLast = pFunctionEntry;
}
spCur = spCur->pSpBackChain;
if (dwSPStartup)
{
if (spCur->dwLNKreg && (spCur > (PPMSTACK)dwSPStartup))
{
//we are at second to last of stack frame, break out the loop
break;
}
}
else
{
// we don't know our bottom of stack, didn't go through this instance of mainCRTStartup
// let's break out the loop if we encounter 68k frame
if ((unsigned int)spCur & 0x01)
{
break;
}
}
}
//We don't have a handler, we should just exit out of the program
terminate();
}
int ComparePCInFunction(const void* pdwPC, const void* pFuncEntry1)
{
unsigned long dwPC;
PRUNTIME_FUNCTION pFuncEntry;
dwPC = *(unsigned long *)(pdwPC);
pFuncEntry = (PRUNTIME_FUNCTION)pFuncEntry1;
if ( dwPC >= (pFuncEntry)->BeginAddress && dwPC <= pFuncEntry->EndAddress)
{
//found it
return 0;
}
else if (dwPC > pFuncEntry->EndAddress)
{
//after this function
return 1;
}
else if (dwPC < pFuncEntry->BeginAddress)
{
//before this function
return -1;
}
return 1;
}
PRUNTIME_FUNCTION GetFunctionEntry(PPMSTACK spCur, PFTINFO *ppftinfoOut)
{
PRUNTIME_FUNCTION pFuncEntry;
PFTINFO pftinfo;
unsigned long dwPC;
//first check if the address is in the thrown code fragment
if ( (spCur->dwLNKreg >= _pftinfo->dwEntryCF) && (spCur->dwLNKreg <= ((unsigned long)((char *)_pftinfo->dwEntryCF+ _pftinfo->dwSizeCF))) )
{
pftinfo = _pftinfo;
}
else if ( (_pftinfoCRT !=NULL) && (spCur->dwLNKreg >= _pftinfoCRT->dwEntryCF) && (spCur->dwLNKreg <= ((unsigned long)((char *)_pftinfoCRT->dwEntryCF+ _pftinfoCRT->dwSizeCF))) )
{
pftinfo = _pftinfoCRT; //if CRT code or in CRT fragment, not a thrown fragment
if (pftinfo->rgFuncTable == NULL)
{
*ppftinfoOut = pftinfo;
return NULL;
}
}
else //This is not thrown Code Fragment, Is this from last Cross TOC call CF? otherwise, assume we can find the funciton table through TOC
{
if (_pftinfoLast != NULL)
{
if ( (spCur->dwLNKreg >= _pftinfoLast->dwEntryCF) && (spCur->dwLNKreg <= ((unsigned long)((char *)_pftinfoLast->dwEntryCF+ _pftinfoLast->dwSizeCF))) )
{
pftinfo = _pftinfoLast;
}
else
{
if (spCur->dwTOCreg == NULL)
{
//this is a error!!!
*ppftinfoOut = _pftinfo;
return NULL;
}
pftinfo = (PFTINFO)(*(unsigned long *)((char *)spCur->dwTOCreg + OFSFTINFO));
_pftinfoLast = pftinfo;
}
}
else { // _pftinfoLast == NULL
if (spCur->dwTOCreg == NULL)
{
//this is a error!!!
*ppftinfoOut = _pftinfo;
return NULL;
}
pftinfo = (PFTINFO)(*(unsigned long *)((char *)spCur->dwTOCreg + OFSFTINFO));
_pftinfoLast = pftinfo;
}
}
//use offset to search instead
dwPC = spCur->dwLNKreg - pftinfo->dwEntryCF;
pFuncEntry = (PRUNTIME_FUNCTION)bsearch ((void *)(unsigned long *)&dwPC, (void *)((PRUNTIME_FUNCTION)pftinfo->rgFuncTable), pftinfo->cFuncTable, sizeof(RUNTIME_FUNCTION), ComparePCInFunction );
*ppftinfoOut = pftinfo;
return pFuncEntry;
}
void _UnwindNestedFrames(
EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame
EHExceptionRecord *pExcept // The exception that initiated this unwind
//void *pContext // Context info for current exception
) {
PPMSTACK spCur;
PPMSTACK spCurCatch;
DispatcherContext curDC;
PFTINFO pftinfoTOC;
PRUNTIME_FUNCTION pFunctionEntry;
PRUNTIME_FUNCTION pFunctionEntryCatch = NULL;
unsigned long cNestedTmp;
PFRAMEINFO pframeinfo;
spCur = (PPMSTACK)GetSP();
//Loop through the frames backwards on the stack to destroy objects until target frame
//Assume:
spCur = spCur->pSpBackChain;
while (spCur < pFrame)
{
// we should only look the frame which hasn't been looked
if (_pFrameInfoChain)
{
if ((spCur > _pFrameInfoChain->pExitContext) && (spCur < _pFrameInfoChain->pSp))
{
spCur = spCur->pSpBackChain;
continue;
}
if (cNested > 0)
{
cNestedTmp = cNested;
pframeinfo = _pFrameInfoChain;
while (cNestedTmp-- && pframeinfo)
{
if ( (spCur->pSpBackChain == pframeinfo->pExitContext) )
{
pFunctionEntryCatch = GetFunctionEntry(spCur, &pftinfoTOC);
spCurCatch = spCur;
break;
}
pframeinfo = pframeinfo->pNext;
}
if (pframeinfo)
{
spCur = spCur->pSpBackChain;
continue;
}
}
}
pFunctionEntry = GetFunctionEntry(spCur, &pftinfoTOC);
if (pFunctionEntry && pFunctionEntry->ExceptionHandler != NULL)
{
//set unwinding flag
//stack point, old PC(in linker register, execution point==state), Registers in Context
PER_FLAGS(pExcept) |= EXCEPTION_UNWINDING;
curDC.ControlPc = spCur->dwLNKreg;
curDC.FunctionEntry = pFunctionEntry; //what else to save?!
curDC.EstablisherFrame = spCur;
curDC.pftinfo = pftinfoTOC;
if (pFunctionEntryCatch == pFunctionEntry)
{
// we have to update the return address in original catch frame
if (spCurCatch->dwLNKreg > curDC.ControlPc)
{
curDC.ControlPc = spCurCatch->dwLNKreg;
}
}
(*pFunctionEntry->ExceptionHandler)(pExcept, spCur, NULL, &curDC);
}
spCur = spCur->pSpBackChain;
}
//
// clear the unwinding flag, in case exception is rethown
//
PER_FLAGS(pExcept) &= ~EXCEPTION_UNWINDING;
return;
}
//
// Prototype for the internal handler
//
extern "C" EXCEPTION_DISPOSITION __InternalCxxFrameHandler(
EHExceptionRecord *pExcept, // Information for this exception
EHRegistrationNode *pRN, // Dynamic information for this frame
void *pContext, // Context info
DispatcherContext *pDC, // More dynamic info for this frame
FuncInfo *pFuncInfo, // Static information for this frame
int CatchDepth, // How deeply nested are we?
EHRegistrationNode *pMarkerRN, // Marker node for when checking inside
// catch block
BOOL recursive); // True if this is a translation exception
//
// __CxxFrameHandler - Real entry point to the runtime
//
extern "C" _CRTIMP EXCEPTION_DISPOSITION __CxxFrameHandler(
EHExceptionRecord *pExcept, // Information for this exception
EHRegistrationNode *pFrame, // Dynamic information for this frame
void *pContext, // Context info
DispatcherContext *pDC // More dynamic info for this frame
) {
FuncInfo *pFuncInfo;
EXCEPTION_DISPOSITION result;
PFRAMEINFO pframeinfo;
if (!(IS_UNWINDING(PER_FLAGS(pExcept))) && ((unsigned long)pContext != (unsigned long)GetRTOC()) )
{
// we are calling catch from different CFM, re-initialize our globals
_pFrameInfoChain =(PFRAMEINFO) pDC->pftinfo->pFrameInfo;
_pftinfo->pFrameInfo = pDC->pftinfo->pFrameInfo;
cNested = 0;
pframeinfo = (PFRAMEINFO)_pftinfo->pFrameInfo;
while (pframeinfo)
{
cNested++;
pframeinfo = pframeinfo->pNext;
}
}
pFuncInfo = (FuncInfo*)pDC->FunctionEntry->HandlerData;
result = __InternalCxxFrameHandler( pExcept, pFrame, pContext, pDC, pFuncInfo, 0, NULL, FALSE );
return result;
}
//
// Save the frame information for this scope. Put it at the end of the linked-list.
//
FRAMEINFO* _CreateFrameInfo(
FRAMEINFO *pFrameInfo,
DispatcherContext *pDC,
void * pContext)
{
pFrameInfo->pftinfo = pDC->pftinfo;
pFrameInfo->pExitContext = NULL;
pFrameInfo->pSp = pDC->EstablisherFrame;
pFrameInfo->pExcept = pDC->pExcept;
pFrameInfo->dwRTOC = (unsigned long)pContext;
pFrameInfo->pNext = _pFrameInfoChain;
_pFrameInfoChain = pFrameInfo;
cNested++;
return pFrameInfo;
}
void *CallCatchBlock(
EHExceptionRecord *pExcept,
EHRegistrationNode *pRN, // Dynamic info of function with catch
void *pContext, // ignored
DispatcherContext *pDC, // Context within subject frame
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 int *pSp
)
{
FRAMEINFO frameinfo;
PFRAMEINFO pframeinfo;
EHExceptionRecord *pExceptTmp;
unsigned char *pRetAddr;
_CreateFrameInfo(&frameinfo, pDC, pContext);
frameinfo.pExitContext = (void *)GetSP();
if (pDC->pftinfo == _pftinfo)
{
// okay we are throw and catch in the same code fragment
_pftinfo->pFrameInfo = _pFrameInfoChain;
}
else
{
// we are not throw and catch in the same code fragment
// we need to chain the _pFrameInfoChain after the pDC->pftinof->pFrameInfo
// we should have got all the Frames saved so far, no matter how many code fragments we have been through
if (pDC->pftinfo->pFrameInfo != NULL)
{
// not chain if the case where CRT Is a DLL for everyone
if ( pDC->pftinfo->pFrameInfo != _pFrameInfoChain->pNext)
{
_pFrameInfoChain->pNext = (PFRAMEINFO)(pDC->pftinfo->pFrameInfo);
}
}
}
//call the handler
pRetAddr = (unsigned char *)_CallSettingFrame(handlerAddress, pRN);
*pSp = (unsigned int)GetR4();
//destructing the object
if (pExcept && (*(unsigned int *)pExcept != 0xffffffff))
{
DestructExceptionObject(pExcept, TRUE, pContext);
}
if (_pFrameInfoChain)
{
// don't forget to clear out the frame info the handler we are about
// to remove since most if not all off them are stack elements
_ASSERTE(_pFrameInfoChain->pftinfo != NULL);
_ASSERTE(_pFrameInfoChain->pftinfo->pFrameInfo != NULL);
pframeinfo = (PFRAMEINFO)_pFrameInfoChain->pftinfo->pFrameInfo;
if (pframeinfo)
_pFrameInfoChain->pftinfo->pFrameInfo = pframeinfo->pNext;
_pFrameInfoChain = _pFrameInfoChain->pNext; //remove current handler from the chain
cNested--;
_pftinfo->pFrameInfo = _pFrameInfoChain;
}
pframeinfo = _pFrameInfoChain;
pExceptTmp = pExcept;
while (pframeinfo && (pframeinfo->pSp <= (PPMSTACK)pRN))
{
// we should destruct any exception objects before this handler's frame
if ((EHExceptionRecord *)(pframeinfo->pExcept) != pExceptTmp)
{
// this is not a re-throw, do destroy
DestructExceptionObject((EHExceptionRecord *)pframeinfo->pExcept, TRUE, (void *)pframeinfo->dwRTOC);
pExceptTmp = (EHExceptionRecord *)(pframeinfo->pExcept);
*(unsigned int *)(pframeinfo->pExcept) = 0xffffffff;
pframeinfo->pExcept = NULL; //???
}
pframeinfo = pframeinfo->pNext;
_pFrameInfoChain = pframeinfo; //remove handler frame from the list
cNested--;
_pftinfo->pFrameInfo = _pFrameInfoChain;
}
return (void *)pRetAddr;
}
extern "C" void _CallMemberFunction0(void * pThis, void * pmfn, void *pRTOC)
{
(*(PMFN0)pmfn)(pThis);
return;
}
extern "C" void _CallMemberFunction1(void * pThis, void * pmfn, void * pArg1, void* pRTOC)
{
(*(PMFN1)pmfn)(pThis, pArg1);
return;
}
extern "C" void _CallMemberFunction2(void * pThis, void * pmfn, void * pArg1, unsigned int fvb, void *pRTOC)
{
(*(PMFN2)pmfn)(pThis, pArg1, fvb);
return;
}