// Copyright (c) Microsoft Corporation. All rights reserved. #pragma once #include "ehdata4_export.h" #include "ehdata.h" #if !defined(RENAME_EH_EXTERN) #define RENAME_EH_EXTERN(x) x #endif #if _EH_RELATIVE_FUNCINFO inline uintptr_t __FuncRelToRealOffset( DispatcherContext *pDC, unsigned int funcRelOffset ) { return (uintptr_t)(pDC->ImageBase + pDC->FunctionEntry->BeginAddress + funcRelOffset); } inline uintptr_t __RVAtoRealOffset( DispatcherContext *pDC, int RVA ) { return (uintptr_t)(pDC->ImageBase + RVA); } #endif class RENAME_EH_EXTERN(__FrameHandler3) { public: using FuncInfo = FuncInfo; using HandlerType = HandlerType; using TryBlockMapEntry = TryBlockMapEntry; static TryBlockMapEntry * CatchTryBlock( FuncInfo *pFuncInfo, __ehstate_t curState ); static bool ExecutionInCatch( DispatcherContext *pDC, FuncInfo *pFuncInfo ); static __ehstate_t StateFromControlPc( FuncInfo *pFuncInfo, DispatcherContext *pDC ); static __ehstate_t StateFromIp( FuncInfo *pFuncInfo, DispatcherContext *pDC, uintptr_t Ip ); static void FrameUnwindToState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo, __ehstate_t targetState ); static void FrameUnwindToEmptyState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo ); inline static __ehstate_t GetHandlerSearchState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo ); static __ehstate_t GetMaxState( DispatcherContext* /*pDC*/, FuncInfo *pFuncInfo ) { return pFuncInfo->maxState; }; static int TypeMatch( HandlerType *pCatch, CatchableType *pCatchable, ThrowInfo *pThrow ); #if _EH_RELATIVE_FUNCINFO static EHRegistrationNode * GetEstablisherFrame( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo, EHRegistrationNode *pEstablisher ); #endif static int BuildCatchObjectHelper( EHExceptionRecord *pExcept, void *pRN, HandlerType *pCatch, CatchableType *pConv ); static void BuildCatchObject( EHExceptionRecord *pExcept, void *pRN, HandlerType *pCatch, CatchableType *pConv ); #if _EH_RELATIVE_FUNCINFO static void UnwindNestedFrames( EHRegistrationNode *pFrame, EHExceptionRecord *pExcept, CONTEXT *pContext, EHRegistrationNode *pEstablisher, void *Handler, FuncInfo *pFuncInfo, __ehstate_t TargetUnwindState, __ehstate_t CatchState, HandlerType *pCatch, DispatcherContext *pDC, BOOLEAN recursive ); #endif inline static bool isEHs(FuncInfo* pFuncInfo) { return !!(FUNC_FLAGS(*pFuncInfo) & FI_EHS_FLAG); } inline static bool isNoExcept(FuncInfo* pFuncInfo) { return !!(FUNC_FLAGS(*pFuncInfo) & FI_EHNOEXCEPT_FLAG); } inline static uint32_t getMagicNum(FuncInfo* pFuncInfo) { return FUNC_MAGICNUM(*pFuncInfo); } inline static ESTypeList* getESTypes(FuncInfo* pFuncInfo); static __ehstate_t GetCurrentState( EHRegistrationNode *pFrame, DispatcherContext *pDC, FuncInfo *pFuncInfo ); static void SetState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo, __ehstate_t newState ); static void SetUnwindTryBlock( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo, int curState ); static __ehstate_t GetUnwindTryBlock( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo ); static void * CxxCallCatchBlock(EXCEPTION_RECORD* pExcept); class TryBlockMap { public: TryBlockMap(FuncInfo *pFuncInfo, uintptr_t imageBase) : _pFuncInfo(pFuncInfo), _imageBase(imageBase) {} class iterator { public: iterator(TryBlockMap &tryBlockMap, unsigned index): _tryBlockMap(tryBlockMap), _index(index) {} iterator& operator++() { _index++; return *this; } TryBlockMapEntry operator*() { #if _EH_RELATIVE_FUNCINFO return *(FUNC_PTRYBLOCK(*_tryBlockMap._pFuncInfo, _index, (uintptr_t)(_tryBlockMap._imageBase))); #else return *(FUNC_PTRYBLOCK(*_tryBlockMap._pFuncInfo, _index)); #endif } bool operator!=(const iterator &other) const { return (_index != other._index); } bool operator<(const iterator &other) const { return (_index < other._index); } iterator& operator=(const iterator &other) { this->_index = other._index; return *this; } private: TryBlockMap & _tryBlockMap; unsigned _index; }; unsigned getNumTryBlocks() { return FUNC_NTRYBLOCKS(*_pFuncInfo); } using IteratorPair = std::pair; private: FuncInfo* _pFuncInfo; uintptr_t _imageBase; }; static TryBlockMap::IteratorPair GetRangeOfTrysToCheck( TryBlockMap &TryBlockMap, __ehstate_t curState, DispatcherContext *pDC, FuncInfo *pFuncInfo, int CatchDepth ); class HandlerMap { public: #pragma warning(push) #pragma warning(disable: 4100) // unreferenced formal parameter HandlerMap(TryBlockMapEntry *tryMap, uintptr_t imageBase, uint32_t functionStart) { #if _EH_RELATIVE_FUNCINFO _handler = (HandlerType *)((uintptr_t)(imageBase + tryMap->dispHandlerArray)); #else _handler = (HandlerType *)tryMap->pHandlerArray; #endif _numHandlers = tryMap->nCatches; } #pragma warning(pop) class iterator { public: iterator(HandlerMap & handlerMap, unsigned currBlock) : _handlerMap(handlerMap), _currBlock(currBlock) {} iterator& operator++() { _currBlock++; return *this; } HandlerType operator*() { return *((HandlerType *)(_handlerMap._handler + _currBlock)); } bool operator==(const iterator &other) const { return (_currBlock == other._currBlock); } bool operator!=(const iterator &other) const { return !(*this == other); } private: HandlerMap & _handlerMap; unsigned _currBlock; }; iterator begin() { return iterator(*this, 0); } iterator end() { return iterator(*this, _numHandlers); } HandlerType* getLastEntry() { return (HandlerType *)(_handler + _numHandlers - 1); } private: unsigned _numHandlers; HandlerType *_handler; }; }; class RENAME_EH_EXTERN(__FrameHandler4) { public: using FuncInfo = FH4::FuncInfo4; using HandlerType = FH4::HandlerType4; using TryBlockMapEntry = FH4::TryBlockMapEntry4; using UWMap = FH4::UWMap4; using TryBlockMap = FH4::TryBlockMap4; using HandlerMap = FH4::HandlerMap4; static bool ExecutionInCatch( DispatcherContext *pDC, FuncInfo *pFuncInfo ); static __ehstate_t StateFromControlPc( FuncInfo *pFuncInfo, DispatcherContext *pDC ); static __ehstate_t StateFromIp( FuncInfo *pFuncInfo, DispatcherContext *pDC, uintptr_t Ip ); static void FrameUnwindToState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo, __ehstate_t targetState ); static void FrameUnwindToEmptyState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo ); inline static __ehstate_t GetHandlerSearchState( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo ); #if _EH_RELATIVE_FUNCINFO static __ehstate_t GetMaxState( DispatcherContext *pDC, FuncInfo *pFuncInfo ) { if (pFuncInfo->dispUnwindMap) { uint8_t * buffer = reinterpret_cast(__RVAtoRealOffset(pDC, pFuncInfo->dispUnwindMap)); return FH4::ReadUnsigned(&buffer); } return 0; } #endif static int TypeMatch( HandlerType *pCatch, CatchableType *pCatchable, ThrowInfo *pThrow ); static int BuildCatchObjectHelper( EHExceptionRecord *pExcept, void *pRN, HandlerType *pCatch, CatchableType *pConv ); static void BuildCatchObject( EHExceptionRecord *pExcept, void *pRN, HandlerType *pCatch, CatchableType *pConv ); static void UnwindNestedFrames( EHRegistrationNode *pFrame, EHExceptionRecord *pExcept, CONTEXT *pContext, EHRegistrationNode *pEstablisher, void *Handler, FuncInfo *pFuncInfo, __ehstate_t TargetUnwindState, __ehstate_t CatchState, HandlerType *pCatch, DispatcherContext *pDC, BOOLEAN recursive ); static EHRegistrationNode * GetEstablisherFrame( EHRegistrationNode *pRN, DispatcherContext *pDC, FuncInfo *pFuncInfo, EHRegistrationNode *pEstablisher ); inline static bool isEHs(FuncInfo* pFuncInfo) { return pFuncInfo->header.EHs; } inline static bool isNoExcept(FuncInfo* pFuncInfo) { return pFuncInfo->header.NoExcept; } // For simplicity in merging, treat FrameHandler4 as having a magic number inline static uint32_t getMagicNum(FuncInfo* /*pFuncInfo*/) { return EH_MAGIC_NUMBER3; } // Not supported under FrameHandler4 inline static ESTypeList* getESTypes(FuncInfo* /*pFuncInfo*/) { return nullptr; } static void * CxxCallCatchBlock(EXCEPTION_RECORD* pExcept); static TryBlockMap::IteratorPair GetRangeOfTrysToCheck( TryBlockMap &TryBlockMap, __ehstate_t curState, DispatcherContext *pDC, FuncInfo *pFuncInfo, int CatchDepth ); };