mirror of
https://github.com/Chuyu-Team/VC-LTL5.git
synced 2026-10-21 07:55:48 +08:00
815 lines
29 KiB
C++
815 lines
29 KiB
C++
/***
|
|
*risctrnsctrl.cpp -
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* Common control transfer helpers required for RISC and AMD64 architecture
|
|
* EH.
|
|
****/
|
|
|
|
#if 0
|
|
#include <vcruntime_internal.h>
|
|
#endif
|
|
#include <eh.h>
|
|
#include <ehassert.h>
|
|
#include <ehdata.h>
|
|
#include <ehdata4.h>
|
|
#include <ehhooks.h>
|
|
#include <trnsctrl.h>
|
|
#include "ehhelpers.h"
|
|
#include <winnt.h>
|
|
#if 1
|
|
#include "framework.h"
|
|
#endif
|
|
|
|
#if !defined(RENAME_EH_EXTERN_HYBRID)
|
|
#define RENAME_EH_EXTERN_HYBRID(x) x
|
|
#endif
|
|
|
|
#if _EH_RELATIVE_FUNCINFO
|
|
|
|
#if WindowsTargetPlatformMinVersion >= WindowsTargetPlatformWindows10_10240
|
|
#define _ImageBase (RENAME_BASE_PTD(__vcrt_getptd)()->_ImageBase)
|
|
#elif WindowsTargetPlatformMinVersion >= WindowsTargetPlatformWindows6
|
|
#define _ImageBase (((_ptd_msvcrt_win6_shared*)__vcrt_getptd())->_ImageBase)
|
|
#else
|
|
#include <ptd_downlevel.h>
|
|
#define _ImageBaseWin6 (((_ptd_msvcrt_win6_shared*)__vcrt_getptd())->_ImageBase)
|
|
#define _ImageBasedownlevel (__LTL_get_ptd_downlevel()->_ImageBase)
|
|
#define _ImageBase (__LTL_GetOsMinVersion() >= MakeMiniVersion(6,0) ? _ImageBaseWin6 : _ImageBasedownlevel)
|
|
#endif
|
|
extern "C" uintptr_t __cdecl _GetImageBase()
|
|
{
|
|
return _ImageBase;
|
|
}
|
|
|
|
extern "C" void __cdecl _SetImageBase(uintptr_t ImageBaseToRestore)
|
|
{
|
|
_ImageBase = ImageBaseToRestore;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _EH_RELATIVE_TYPEINFO
|
|
|
|
#if WindowsTargetPlatformMinVersion >= WindowsTargetPlatformWindows10_10240
|
|
#define _ThrowImageBase (RENAME_BASE_PTD(__vcrt_getptd)()->_ThrowImageBase)
|
|
#elif WindowsTargetPlatformMinVersion >= WindowsTargetPlatformWindows6
|
|
#define _ThrowImageBase (((_ptd_msvcrt_win6_shared*)__vcrt_getptd())->_ThrowImageBase)
|
|
#else
|
|
#include <ptd_downlevel.h>
|
|
#define _ThrowImageBaseWin6 (((_ptd_msvcrt_win6_shared*)__vcrt_getptd())->_ThrowImageBase)
|
|
#define _ThrowImageBasedownlevel (__LTL_get_ptd_downlevel()->_ThrowImageBase)
|
|
#define _ThrowImageBase (__LTL_GetOsMinVersion() >= MakeMiniVersion(6,0) ? _ThrowImageBaseWin6 : _ThrowImageBasedownlevel)
|
|
#endif
|
|
|
|
extern "C" uintptr_t __cdecl _GetThrowImageBase()
|
|
{
|
|
return _ThrowImageBase;
|
|
}
|
|
|
|
extern "C" void __cdecl _SetThrowImageBase(uintptr_t NewThrowImageBase)
|
|
{
|
|
_ThrowImageBase = NewThrowImageBase;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _EH_RELATIVE_FUNCINFO
|
|
#if _VCRT_BUILD_FH4
|
|
//
|
|
// Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer.
|
|
//
|
|
EHRegistrationNode * RENAME_EH_EXTERN(__FrameHandler4)::GetEstablisherFrame
|
|
(
|
|
EHRegistrationNode *pRN,
|
|
DispatcherContext *pDC,
|
|
FuncInfo *pFuncInfo,
|
|
EHRegistrationNode *pEstablisher
|
|
)
|
|
{
|
|
|
|
*pEstablisher = *pRN;
|
|
|
|
if (RENAME_EH_EXTERN(__FrameHandler4)::ExecutionInCatch(pDC, pFuncInfo))
|
|
{
|
|
|
|
#if defined(_M_ARM64EC)
|
|
|
|
if (RtlIsEcCode(pDC->ControlPc)) {
|
|
*pEstablisher = *(EHRegistrationNode *)*pEstablisher;
|
|
} else {
|
|
*pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pFuncInfo->dispFrame, *pRN);
|
|
}
|
|
|
|
#elif defined(_M_X64)
|
|
|
|
*pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pFuncInfo->dispFrame, *pRN);
|
|
|
|
#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_)
|
|
|
|
*pEstablisher = *(EHRegistrationNode *)*pEstablisher;
|
|
|
|
#else // architecture
|
|
|
|
#error Unknown processor architecture.
|
|
|
|
#endif // architecture
|
|
}
|
|
|
|
return pEstablisher;
|
|
}
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
//
|
|
// Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer.
|
|
//
|
|
#if 0
|
|
EHRegistrationNode * RENAME_EH_EXTERN(__FrameHandler3)::GetEstablisherFrame(
|
|
EHRegistrationNode *pRN,
|
|
DispatcherContext *pDC,
|
|
FuncInfo *pFuncInfo,
|
|
EHRegistrationNode *pEstablisher
|
|
)
|
|
{
|
|
TryBlockMapEntry *pEntry;
|
|
HandlerType *pHandler;
|
|
ULONG_PTR HandlerAdd, ImageBase;
|
|
unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
unsigned index, i;
|
|
__ehstate_t curState;
|
|
|
|
curState = StateFromControlPc(pFuncInfo, pDC);
|
|
*pEstablisher = *pRN;
|
|
for (index = num_of_try_blocks; index > 0; index--) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
|
|
if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
|
|
// Get catch handler address.
|
|
HandlerAdd = (*RENAME_EH_EXTERN(RtlLookupFunctionEntry)(pDC->ControlPc,
|
|
&ImageBase,
|
|
nullptr)).BeginAddress;
|
|
pHandler = TBME_PLIST(*pEntry, ImageBase);
|
|
for ( i = 0;
|
|
i < (unsigned)TBME_NCATCHES(*pEntry) &&
|
|
static_cast<ULONG_PTR>(pHandler[i].dispOfHandler) != HandlerAdd
|
|
; i++);
|
|
if ( i < (unsigned)TBME_NCATCHES(*pEntry)) {
|
|
|
|
#if defined(_M_ARM64EC)
|
|
|
|
if (RtlIsEcCode(pDC->ControlPc)) {
|
|
*pEstablisher = *(EHRegistrationNode *)*pEstablisher;
|
|
} else {
|
|
*pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN);
|
|
}
|
|
|
|
#elif defined(_M_X64)
|
|
|
|
*pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN);
|
|
|
|
#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_)
|
|
|
|
*pEstablisher = *(EHRegistrationNode *)*pEstablisher;
|
|
|
|
#else
|
|
|
|
#error Unknown processor architecture.
|
|
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return pEstablisher;
|
|
}
|
|
#endif
|
|
|
|
// This function returns the try block for the given state if the state is in a
|
|
// catch; otherwise, nullptr is returned.
|
|
|
|
#if 0
|
|
TryBlockMapEntry * RENAME_EH_EXTERN(__FrameHandler3)::CatchTryBlock(
|
|
FuncInfo *pFuncInfo,
|
|
__ehstate_t curState
|
|
) {
|
|
TryBlockMapEntry *pEntry;
|
|
unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
unsigned index;
|
|
|
|
for (index = num_of_try_blocks; index > 0; index--) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, _ImageBase);
|
|
if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) {
|
|
return pEntry;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// This routine returns TRUE if we are executing from within a catch. Otherwise, FALSE is returned.
|
|
//
|
|
#if _VCRT_BUILD_FH4
|
|
bool RENAME_EH_EXTERN(__FrameHandler4)::ExecutionInCatch(
|
|
DispatcherContext* /*pDC*/,
|
|
FuncInfo *pFuncInfo
|
|
)
|
|
{
|
|
return pFuncInfo->header.isCatch;
|
|
}
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
#if 0
|
|
bool RENAME_EH_EXTERN(__FrameHandler3)::ExecutionInCatch(
|
|
DispatcherContext *pDC,
|
|
FuncInfo *pFuncInfo
|
|
)
|
|
{
|
|
__ehstate_t curState = StateFromControlPc(pFuncInfo, pDC);
|
|
return CatchTryBlock(pFuncInfo, curState)? TRUE : FALSE;
|
|
}
|
|
#endif
|
|
|
|
// The name of this function is rather misleading. This function won't really unwind
|
|
// to empty state. This function will unwind to lowest possible state for current block.
|
|
// Here is an example
|
|
//
|
|
// try {
|
|
// // State = 1;
|
|
// } catch (...) {
|
|
// // State when we enter catch is 2
|
|
// // State inside catch is 3-5;
|
|
// }
|
|
// if __FrameUnwindToEmptyState is called for the main function, the target state will
|
|
// be -1 but if __FrameUnwindToEmptyState is called for catch block, the target state for
|
|
// __FrameUnwindToState will be 2 not -1. This way we are able to unwind the stack block
|
|
// by block not the whole function in single call.
|
|
#if _VCRT_BUILD_FH4
|
|
void RENAME_EH_EXTERN(__FrameHandler4)::FrameUnwindToEmptyState(
|
|
EHRegistrationNode *pRN,
|
|
DispatcherContext *pDC,
|
|
FuncInfo *pFuncInfo
|
|
)
|
|
{
|
|
EHRegistrationNode EstablisherFramePointers, *pEstablisher;
|
|
|
|
pEstablisher = GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers);
|
|
|
|
FrameUnwindToState(pEstablisher, pDC, pFuncInfo, EH_EMPTY_STATE);
|
|
}
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
#if 0
|
|
void RENAME_EH_EXTERN(__FrameHandler3)::FrameUnwindToEmptyState(
|
|
EHRegistrationNode *pRN,
|
|
DispatcherContext *pDC,
|
|
FuncInfo *pFuncInfo
|
|
)
|
|
{
|
|
__ehstate_t stateFromControlPC;
|
|
TryBlockMapEntry *pEntry;
|
|
EHRegistrationNode EstablisherFramePointers, *pEstablisher;
|
|
|
|
pEstablisher = GetEstablisherFrame(pRN,
|
|
pDC,
|
|
pFuncInfo,
|
|
&EstablisherFramePointers);
|
|
|
|
stateFromControlPC = StateFromControlPc(pFuncInfo, pDC);
|
|
pEntry = CatchTryBlock(pFuncInfo, stateFromControlPC);
|
|
|
|
FrameUnwindToState(pEstablisher, pDC, pFuncInfo,
|
|
pEntry == nullptr ? EH_EMPTY_STATE : TBME_HIGH(*pEntry));
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
//
|
|
// __CxxFrameHandler3 - Real entry point to the runtime
|
|
// __CxxFrameHandler2 is an alias for __CxxFrameHandler3
|
|
// since they are compatible in VC version of CRT
|
|
// These functions should be separated out if a change makes
|
|
// __CxxFrameHandler3 incompatible with __CxxFrameHandler2
|
|
//
|
|
extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl RENAME_EH_EXTERN_HYBRID(__CxxFrameHandler3)(
|
|
EHExceptionRecord *pExcept, // Information for this exception
|
|
EHRegistrationNode RN, // Dynamic information for this frame
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC // More dynamic info for this frame
|
|
) {
|
|
FuncInfo *pFuncInfo;
|
|
EXCEPTION_DISPOSITION result;
|
|
EHRegistrationNode EstablisherFrame = RN;
|
|
|
|
_ImageBase = pDC->ImageBase;
|
|
#ifdef _ThrowImageBase
|
|
_ThrowImageBase = (uintptr_t)pExcept->params.pThrowImageBase;
|
|
#endif
|
|
pFuncInfo = (FuncInfo*)(_ImageBase +*(PULONG)pDC->HandlerData);
|
|
result = __InternalCxxFrameHandlerWrapper<RENAME_EH_EXTERN(__FrameHandler3)>(pExcept, &EstablisherFrame, pContext, pDC, pFuncInfo, 0, nullptr, FALSE);
|
|
return result;
|
|
}
|
|
#endif // 0
|
|
|
|
#if _VCRT_BUILD_FH4 && WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 19041)
|
|
extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl RENAME_EH_EXTERN_HYBRID(__CxxFrameHandler4)(
|
|
EHExceptionRecord *pExcept, // Information for this exception
|
|
EHRegistrationNode RN, // Dynamic information for this frame
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC // More dynamic info for this frame
|
|
) {
|
|
FH4::FuncInfo4 FuncInfo;
|
|
EXCEPTION_DISPOSITION result;
|
|
EHRegistrationNode EstablisherFrame = RN;
|
|
|
|
_ImageBase = pDC->ImageBase;
|
|
#ifdef _ThrowImageBase
|
|
_ThrowImageBase = (uintptr_t)pExcept->params.pThrowImageBase;
|
|
#endif
|
|
PBYTE buffer = (PBYTE)(_ImageBase + *(PULONG)pDC->HandlerData);
|
|
|
|
FH4::DecompFuncInfo(buffer, FuncInfo, pDC->ImageBase, pDC->FunctionEntry->BeginAddress);
|
|
|
|
result = __InternalCxxFrameHandlerWrapper<RENAME_EH_EXTERN(__FrameHandler4)>(pExcept, &EstablisherFrame, pContext, pDC, &FuncInfo, 0, nullptr, FALSE);
|
|
return result;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(RENAME_EH_EXTERN_HYBRID(__CxxFrameHandler4));
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
#if !defined(_CHPE_X86_ARM64_EH_)
|
|
|
|
#if 0
|
|
//
|
|
// __CxxFrameHandler2 - Remove after compiler is updated
|
|
//
|
|
extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler2(
|
|
EHExceptionRecord *pExcept, // Information for this exception
|
|
EHRegistrationNode RN, // Dynamic information for this frame
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC // More dynamic info for this frame
|
|
)
|
|
{
|
|
return __CxxFrameHandler3(pExcept, RN, pContext, pDC);
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler(
|
|
EHExceptionRecord *pExcept, // Information for this exception
|
|
EHRegistrationNode RN, // Dynamic information for this frame
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC // More dynamic info for this frame
|
|
)
|
|
{
|
|
return __CxxFrameHandler3(pExcept, RN, pContext, pDC);
|
|
}
|
|
#endif // 0
|
|
|
|
#endif
|
|
|
|
// Call the SEH to EH translator.
|
|
template <class T>
|
|
static int SehTransFilter(
|
|
EXCEPTION_POINTERS *ExPtrs,
|
|
EHExceptionRecord *pExcept,
|
|
EHRegistrationNode *pRN,
|
|
CONTEXT *pContext,
|
|
DispatcherContext *pDC,
|
|
typename T::FuncInfo *pFuncInfo,
|
|
__ehstate_t curState,
|
|
BOOL *pResult
|
|
) {
|
|
|
|
UNREFERENCED_PARAMETER(curState);
|
|
_pForeignExcept = pExcept;
|
|
_ImageBase = pDC->ImageBase;
|
|
#ifdef _ThrowImageBase
|
|
_ThrowImageBase = (uintptr_t)((EHExceptionRecord *)ExPtrs->ExceptionRecord)->params.pThrowImageBase;
|
|
#endif
|
|
|
|
#if _VCRT_BUILD_FH4
|
|
if constexpr (std::is_same_v<T, RENAME_EH_EXTERN(__FrameHandler4)>)
|
|
{
|
|
// For FH4, the catch state from rethrow is transient and only readable one time before being reset.
|
|
// This path reprocesses a throw which means the transient state needs to be set again so the correct state is used.
|
|
CatchStateInParent = curState;
|
|
}
|
|
#endif
|
|
|
|
__InternalCxxFrameHandlerWrapper<T>((EHExceptionRecord *)ExPtrs->ExceptionRecord,
|
|
pRN,
|
|
pContext,
|
|
pDC,
|
|
pFuncInfo,
|
|
0,
|
|
nullptr,
|
|
TRUE );
|
|
_pForeignExcept = nullptr;
|
|
*pResult = TRUE;
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
template <class T>
|
|
BOOL _CallSETranslator(
|
|
EHExceptionRecord *pExcept, // The exception to be translated
|
|
EHRegistrationNode *pRN, // Dynamic info of function with catch
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC, // More dynamic info of function with catch (ignored)
|
|
typename T::FuncInfo *pFuncInfo, // Static info of function with catch
|
|
ULONG CatchDepth, // How deeply nested in catch blocks are we?
|
|
EHRegistrationNode *pMarkerRN, // Marker for parent context
|
|
__ehstate_t curState // Current state
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(pMarkerRN);
|
|
|
|
BOOL result = FALSE;
|
|
pRN;
|
|
pDC;
|
|
pFuncInfo;
|
|
CatchDepth;
|
|
|
|
// Call the translator.
|
|
|
|
_EXCEPTION_POINTERS excptr = { (PEXCEPTION_RECORD)pExcept, pContext };
|
|
|
|
__try {
|
|
_se_translator_function pSETranslator;
|
|
pSETranslator = __pSETranslator;
|
|
pSETranslator(PER_CODE(pExcept), &excptr);
|
|
result = FALSE;
|
|
} __except(SehTransFilter<T>(exception_info(),
|
|
pExcept,
|
|
pRN,
|
|
pContext,
|
|
pDC,
|
|
pFuncInfo,
|
|
curState,
|
|
&result
|
|
)) {}
|
|
|
|
// If we got back, then we were unable to translate it.
|
|
|
|
return result;
|
|
}
|
|
|
|
#if _VCRT_BUILD_FH4
|
|
template
|
|
BOOL _CallSETranslator<RENAME_EH_EXTERN(__FrameHandler4)>(
|
|
EHExceptionRecord *pExcept, // The exception to be translated
|
|
EHRegistrationNode *pRN, // Dynamic info of function with catch
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC, // More dynamic info of function with catch (ignored)
|
|
RENAME_EH_EXTERN(__FrameHandler4)::FuncInfo *pFuncInfo, // Static info of function with catch
|
|
ULONG CatchDepth, // How deeply nested in catch blocks are we?
|
|
EHRegistrationNode *pMarkerRN, // Marker for parent context
|
|
__ehstate_t curState // Current state
|
|
);
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
#if 0
|
|
template
|
|
BOOL _CallSETranslator<RENAME_EH_EXTERN(__FrameHandler3)>(
|
|
EHExceptionRecord *pExcept, // The exception to be translated
|
|
EHRegistrationNode *pRN, // Dynamic info of function with catch
|
|
CONTEXT *pContext, // Context info
|
|
DispatcherContext *pDC, // More dynamic info of function with catch (ignored)
|
|
RENAME_EH_EXTERN(__FrameHandler3)::FuncInfo *pFuncInfo, // Static info of function with catch
|
|
ULONG CatchDepth, // How deeply nested in catch blocks are we?
|
|
EHRegistrationNode *pMarkerRN, // Marker for parent context
|
|
__ehstate_t curState // Current state
|
|
);
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetRangeOfTrysToCheck - determine which try blocks are of interest.
|
|
//
|
|
// The try blocks of interest are the ones in current catch block or function block.
|
|
// We will not try to call the catch that are outside the scope of this block. Consider
|
|
// the example.
|
|
//
|
|
// foo() {
|
|
// try { // Try block 1
|
|
// try { // Try block 2
|
|
// throw 1; // Throw1
|
|
// } catch (int) { // Catch block 1
|
|
// try { // Try block 3
|
|
// throw 1; // Throw2
|
|
// } catch (int) { // Catch block 2
|
|
// throw; // Throw3
|
|
// }
|
|
// }
|
|
// } catch (int) { // Catch block 3
|
|
// }
|
|
// }
|
|
//
|
|
// When we have exception from Throw1, our block of concern is function foo. Here the
|
|
// try blocks of interest are Try block 2 and Try block 1.
|
|
//
|
|
// When we have exception for Throw2, we are in Catch block 1 and thus try block of
|
|
// concern is Try block 3. We don't really need to care about Try block 1 here as
|
|
// we have the main function block still on the stack and exception handler will also
|
|
// be called for that block.
|
|
//
|
|
// Returns:
|
|
// Address of first try block of interest is returned
|
|
// pStart and pEnd get the indices of the range in question
|
|
//
|
|
#if _VCRT_BUILD_FH4
|
|
RENAME_EH_EXTERN(__FrameHandler4)::TryBlockMap::IteratorPair RENAME_EH_EXTERN(__FrameHandler4)::GetRangeOfTrysToCheck(
|
|
TryBlockMap &tryBlockMap,
|
|
__ehstate_t curState,
|
|
DispatcherContext * /*pDC*/,
|
|
FuncInfo * /*pFuncInfo*/,
|
|
int /*CatchDepth*/
|
|
)
|
|
{
|
|
auto iterStart = tryBlockMap.begin();
|
|
auto iterEnd = tryBlockMap.begin();
|
|
tryBlockMap.setBuffer(iterStart);
|
|
|
|
for (auto iter = tryBlockMap.begin(); iter != tryBlockMap.end(); ++iter)
|
|
{
|
|
auto tryBlock = *iter;
|
|
if (curState >= tryBlock.tryLow && curState <= tryBlock.tryHigh) {
|
|
if (iterStart != tryBlockMap.begin()) {
|
|
iterStart = iter;
|
|
}
|
|
iterEnd = iter;
|
|
}
|
|
}
|
|
// change to be (start, end]
|
|
iterEnd.incrementToSentinel();
|
|
// Reset so when we start reading it starts at the correct location
|
|
tryBlockMap.setBuffer(iterStart);
|
|
return TryBlockMap::IteratorPair(iterStart, iterEnd);
|
|
}
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
#if 0
|
|
RENAME_EH_EXTERN(__FrameHandler3)::TryBlockMap::IteratorPair RENAME_EH_EXTERN(__FrameHandler3)::GetRangeOfTrysToCheck(
|
|
TryBlockMap &tryBlockMap,
|
|
__ehstate_t curState,
|
|
DispatcherContext *pDC,
|
|
FuncInfo *pFuncInfo,
|
|
int /*CatchDepth*/
|
|
)
|
|
{
|
|
TryBlockMapEntry *pEntry, *pCurCatchEntry = nullptr;
|
|
unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo);
|
|
unsigned int index;
|
|
__ehstate_t ipState = StateFromControlPc(pFuncInfo, pDC);
|
|
|
|
_VCRT_VERIFY(num_of_try_blocks > 0);
|
|
|
|
unsigned start = static_cast<unsigned>(-1);
|
|
unsigned end = start;
|
|
for (index = num_of_try_blocks; index > 0; index--) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
|
|
if (ipState > TBME_HIGH(*pEntry) && ipState <= TBME_CATCHHIGH(*pEntry)) {
|
|
break;
|
|
}
|
|
}
|
|
if (index) {
|
|
pCurCatchEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase);
|
|
}
|
|
for(index = 0; index < num_of_try_blocks; index++ ) {
|
|
pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index, pDC->ImageBase);
|
|
// if in catch block, check for try-catch only in current block
|
|
if (pCurCatchEntry) {
|
|
if (TBME_LOW(*pEntry) <= TBME_HIGH(*pCurCatchEntry) ||
|
|
TBME_HIGH(*pEntry) > TBME_CATCHHIGH(*pCurCatchEntry))
|
|
continue;
|
|
}
|
|
if (curState >= TBME_LOW(*pEntry) && curState <= TBME_HIGH(*pEntry)) {
|
|
if (start == -1) {
|
|
start = index;
|
|
}
|
|
end = index;
|
|
}
|
|
}
|
|
|
|
// change to be (start, end]
|
|
++end;
|
|
if (start == -1){
|
|
start = 0;
|
|
end = 0;
|
|
}
|
|
|
|
auto iterStart = TryBlockMap::iterator(tryBlockMap, start);
|
|
auto iterEnd = TryBlockMap::iterator(tryBlockMap, end);
|
|
|
|
return TryBlockMap::IteratorPair(iterStart, iterEnd);
|
|
}
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < WindowsTargetPlatformWindows10_10240
|
|
extern "C" FRAMEINFO * __cdecl RENAME_EH_EXTERN(_CreateFrameInfo)(
|
|
FRAMEINFO * pFrameInfo,
|
|
PVOID pExceptionObject
|
|
) {
|
|
pFrameInfo->pExceptionObject = pExceptionObject;
|
|
pFrameInfo->pNext = (pFrameInfo < pFrameInfoChain)? pFrameInfoChain : nullptr;
|
|
pFrameInfoChain = pFrameInfo;
|
|
return pFrameInfo;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(_CreateFrameInfo);
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// _FindAndUnlinkFrame - Pop the frame information for this scope that was
|
|
// pushed by _CreateFrameInfo. This should be the first frame in the list,
|
|
// but the code will look for a nested frame and pop all frames, just in
|
|
// case.
|
|
//
|
|
#if WindowsTargetPlatformMinVersion < WindowsTargetPlatformWindows10_10240
|
|
extern "C" void __cdecl RENAME_EH_EXTERN(_FindAndUnlinkFrame)(
|
|
FRAMEINFO * pFrameInfo
|
|
) {
|
|
_VCRT_VERIFY(pFrameInfo == pFrameInfoChain);
|
|
|
|
for (FRAMEINFO *pCurFrameInfo = pFrameInfoChain;
|
|
pCurFrameInfo;
|
|
pCurFrameInfo = pCurFrameInfo->pNext)
|
|
{
|
|
if (pFrameInfo == pCurFrameInfo) {
|
|
pFrameInfoChain = pCurFrameInfo->pNext;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Should never be reached.
|
|
abort();
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(_FindAndUnlinkFrame);
|
|
#endif
|
|
|
|
#if _VCRT_BUILD_FH4
|
|
void RENAME_EH_EXTERN(__FrameHandler4)::UnwindNestedFrames(
|
|
EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame
|
|
EHExceptionRecord *pExcept, // The exception that initiated this unwind
|
|
CONTEXT *pContext, // Context info for current exception
|
|
EHRegistrationNode *pEstablisher,
|
|
void *Handler,
|
|
FuncInfo* /*pFuncInfo*/,
|
|
__ehstate_t TargetUnwindState,
|
|
__ehstate_t CatchState, // State outside of current try but inside of any enclosing trys
|
|
HandlerType *pCatch,
|
|
DispatcherContext *pDC,
|
|
BOOLEAN recursive
|
|
)
|
|
{
|
|
static const EXCEPTION_RECORD ExceptionTemplate = // A generic exception record
|
|
{
|
|
STATUS_UNWIND_CONSOLIDATE, // STATUS_UNWIND_CONSOLIDATE
|
|
EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume)
|
|
nullptr, // Additional record (none)
|
|
nullptr, // Address of exception (OS fills in)
|
|
15, // Number of parameters
|
|
{ EH_MAGIC_NUMBER1, // Our version control magic number
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0
|
|
} // pThrowInfo
|
|
};
|
|
|
|
EXCEPTION_RECORD ExceptionRecord = ExceptionTemplate;
|
|
ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)CxxCallCatchBlock;
|
|
// Address of call back function
|
|
ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)pEstablisher;
|
|
// Used by callback function
|
|
ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)Handler;
|
|
// Used by callback function to call catch block
|
|
ExceptionRecord.ExceptionInformation[3] = (ULONG_PTR)TargetUnwindState;
|
|
// Used by CxxFrameHandler to unwind to target_state
|
|
ExceptionRecord.ExceptionInformation[4] = (ULONG_PTR)pContext;
|
|
// used to set pCurrentExContext in callback function
|
|
ExceptionRecord.ExceptionInformation[5] = pCatch->continuationAddress[0] + pDC->ImageBase;
|
|
// Used in callback function for continuation address lookup
|
|
ExceptionRecord.ExceptionInformation[6] = (ULONG_PTR)pExcept;
|
|
// Used for passing current Exception
|
|
ExceptionRecord.ExceptionInformation[7] = (ULONG_PTR)recursive;
|
|
// Used for translated Exceptions
|
|
ExceptionRecord.ExceptionInformation[8] = EH_MAGIC_NUMBER1;
|
|
// Used in __InternalCxxFrameHandler to detect if it's being
|
|
// called from _UnwindNestedFrames.
|
|
|
|
// TODO: make these contiguous
|
|
ExceptionRecord.ExceptionInformation[9] = pCatch->continuationAddress[1] + pDC->ImageBase;
|
|
// Used in callback function for continuation address lookup
|
|
|
|
#if defined(_M_ARM64EC)
|
|
|
|
if (RtlIsEcCode(pDC->ControlPc)) {
|
|
ExceptionRecord.ExceptionInformation[10] = static_cast<ULONG_PTR>(-1);
|
|
}
|
|
|
|
#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_)
|
|
|
|
ExceptionRecord.ExceptionInformation[10] = static_cast<ULONG_PTR>(-1);
|
|
// ARM/ARM64-specific: used to hold a pointer to the non-volatile
|
|
// registers
|
|
|
|
#elif !defined(_M_X64)
|
|
|
|
#error Unknown processor architecture.
|
|
|
|
#endif
|
|
|
|
// Used to associate Catch Handler state to parent state
|
|
ExceptionRecord.ExceptionInformation[11] = CatchState;
|
|
|
|
RtlUnwindEx((void *)*pFrame,
|
|
(void *)pDC->ControlPc, // Address where control left function
|
|
&ExceptionRecord,
|
|
nullptr,
|
|
pDC->ContextRecord,
|
|
(PUNWIND_HISTORY_TABLE)pDC->HistoryTable);
|
|
}
|
|
#endif // _VCRT_BUILD_FH4
|
|
|
|
#if 0
|
|
void RENAME_EH_EXTERN(__FrameHandler3)::UnwindNestedFrames(
|
|
EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame
|
|
EHExceptionRecord *pExcept, // The exception that initiated this unwind
|
|
CONTEXT *pContext, // Context info for current exception
|
|
EHRegistrationNode *pEstablisher,
|
|
void *Handler,
|
|
FuncInfo *pFuncInfo,
|
|
__ehstate_t TargetUnwindState,
|
|
__ehstate_t /*CatchState*/,
|
|
HandlerType* /*pCatch*/,
|
|
DispatcherContext *pDC,
|
|
BOOLEAN recursive
|
|
)
|
|
{
|
|
static const EXCEPTION_RECORD ExceptionTemplate = // A generic exception record
|
|
{
|
|
STATUS_UNWIND_CONSOLIDATE, // STATUS_UNWIND_CONSOLIDATE
|
|
EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume)
|
|
nullptr, // Additional record (none)
|
|
nullptr, // Address of exception (OS fills in)
|
|
15, // Number of parameters
|
|
{ EH_MAGIC_NUMBER1, // Our version control magic number
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0
|
|
} // pThrowInfo
|
|
};
|
|
|
|
EXCEPTION_RECORD ExceptionRecord = ExceptionTemplate;
|
|
ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)CxxCallCatchBlock;
|
|
// Address of call back function
|
|
ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)pEstablisher;
|
|
// Used by callback function
|
|
ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)Handler;
|
|
// Used by callback function to call catch block
|
|
ExceptionRecord.ExceptionInformation[3] = (ULONG_PTR)TargetUnwindState;
|
|
// Used by CxxFrameHandler to unwind to target_state
|
|
ExceptionRecord.ExceptionInformation[4] = (ULONG_PTR)pContext;
|
|
// used to set pCurrentExContext in callback function
|
|
ExceptionRecord.ExceptionInformation[5] = (ULONG_PTR)pFuncInfo;
|
|
// Used in callback function to set state on stack to -2
|
|
ExceptionRecord.ExceptionInformation[6] = (ULONG_PTR)pExcept;
|
|
// Used for passing current Exception
|
|
ExceptionRecord.ExceptionInformation[7] = (ULONG_PTR)recursive;
|
|
// Used for translated Exceptions
|
|
ExceptionRecord.ExceptionInformation[8] = EH_MAGIC_NUMBER1;
|
|
// Used in __InternalCxxFrameHandler to detect if it's being
|
|
// called from _UnwindNestedFrames.
|
|
|
|
#if defined(_M_ARM64EC)
|
|
|
|
if (RtlIsEcCode(pDC->ControlPc)) {
|
|
ExceptionRecord.ExceptionInformation[10] = static_cast<ULONG_PTR>(-1);
|
|
}
|
|
|
|
#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_)
|
|
|
|
ExceptionRecord.ExceptionInformation[10] = static_cast<ULONG_PTR>(-1);
|
|
// ARM/ARM64-specific: used to hold a pointer to the non-volatile
|
|
// registers
|
|
|
|
#elif !defined(_M_X64)
|
|
|
|
#error Unknown processor architecture.
|
|
|
|
#endif
|
|
|
|
RtlUnwindEx((void *)*pFrame,
|
|
(void *)pDC->ControlPc, // Address where control left function
|
|
&ExceptionRecord,
|
|
nullptr,
|
|
pDC->ContextRecord,
|
|
(PUNWIND_HISTORY_TABLE)pDC->HistoryTable);
|
|
}
|
|
#endif // 0
|
|
|
|
#endif // _EH_RELATIVE_FUNCINFO
|