summaryrefslogtreecommitdiff
path: root/src/vm/exceptmacros.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/exceptmacros.h')
-rw-r--r--src/vm/exceptmacros.h613
1 files changed, 613 insertions, 0 deletions
diff --git a/src/vm/exceptmacros.h b/src/vm/exceptmacros.h
new file mode 100644
index 0000000000..efed993a2d
--- /dev/null
+++ b/src/vm/exceptmacros.h
@@ -0,0 +1,613 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// EXCEPTMACROS.H -
+//
+// This header file exposes mechanisms to:
+//
+// 1. Throw COM+ exceptions using the COMPlusThrow() function
+// 2. Guard a block of code using EX_TRY, and catch
+// COM+ exceptions using EX_CATCH
+//
+// from the *unmanaged* portions of the EE. Much of the EE runs
+// in a hybrid state where it runs like managed code but the code
+// is produced by a classic unmanaged-code C++ compiler.
+//
+// THROWING A COM+ EXCEPTION
+// -------------------------
+// To throw a COM+ exception, call the function:
+//
+// COMPlusThrow(OBJECTREF pThrowable);
+//
+// This function does not return. There are also various functions
+// that wrap COMPlusThrow for convenience.
+//
+// COMPlusThrow() must only be called within the scope of a EX_TRY
+// block. See below for more information.
+//
+//
+// THROWING A RUNTIME EXCEPTION
+// ----------------------------
+// COMPlusThrow() is overloaded to take a constant describing
+// the common EE-generated exceptions, e.g.
+//
+// COMPlusThrow(kOutOfMemoryException);
+//
+// See rexcep.h for list of constants (prepend "k" to get the actual
+// constant name.)
+//
+// You can also add a descriptive error string as follows:
+//
+// - Add a descriptive error string and resource id to
+// COM99\src\dlls\mscorrc\resource.h and mscorrc.rc.
+// Embed "%1", "%2" or "%3" to leave room for runtime string
+// inserts.
+//
+// - Pass the resource ID and inserts to COMPlusThrow, i.e.
+//
+// COMPlusThrow(kSecurityException,
+// IDS_CANTREFORMATCDRIVEBECAUSE,
+// W("Formatting C drive permissions not granted."));
+//
+//
+//
+// TO CATCH COMPLUS EXCEPTIONS:
+// ----------------------------
+//
+// Use the following syntax:
+//
+// #include "exceptmacros.h"
+//
+//
+// OBJECTREF pThrownObject;
+//
+// EX_TRY {
+// ...guarded code...
+// } EX_CATCH {
+// ...handler...
+// } EX_END_CATCH(SwallowAllExceptions)
+//
+//
+// EX_TRY blocks can be nested.
+//
+// From within the handler, you can call the GET_THROWABLE() macro to
+// obtain the object that was thrown.
+//
+// CRUCIAL POINTS
+// --------------
+// In order to call COMPlusThrow(), you *must* be within the scope
+// of a EX_TRY block. Under _DEBUG, COMPlusThrow() will assert
+// if you call it out of scope. This implies that just about every
+// external entrypoint into the EE has to have a EX_TRY, in order
+// to convert uncaught COM+ exceptions into some error mechanism
+// more understandable to its non-COM+ caller.
+//
+// Any function that can throw a COM+ exception out to its caller
+// has the same requirement. ALL such functions should be tagged
+// with THROWS in CONTRACT. Aside from making the code
+// self-document its contract, the checked version of this will fire
+// an assert if the function is ever called without being in scope.
+//
+//
+// AVOIDING EX_TRY GOTCHAS
+// ----------------------------
+// EX_TRY/EX_CATCH actually expands into a Win32 SEH
+// __try/__except structure. It does a lot of goo under the covers
+// to deal with pre-emptive GC settings.
+//
+// 1. Do not use C++ or SEH try/__try use EX_TRY instead.
+//
+// 2. Remember that any function marked THROWS
+// has the potential not to return. So be wary of allocating
+// non-gc'd objects around such calls because ensuring cleanup
+// of these things is not simple (you can wrap another EX_TRY
+// around the call to simulate a COM+ "try-finally" but EX_TRY
+// is relatively expensive compared to the real thing.)
+//
+//
+
+
+#ifndef __exceptmacros_h__
+#define __exceptmacros_h__
+
+struct _EXCEPTION_REGISTRATION_RECORD;
+class Thread;
+class Frame;
+class Exception;
+
+VOID DECLSPEC_NORETURN RealCOMPlusThrowOM();
+VOID DECLSPEC_NORETURN RealCOMPlusThrowSO();
+
+#include <excepcpu.h>
+#include "stackprobe.h"
+
+
+
+//==========================================================================
+// Macros to allow catching exceptions from within the EE. These are lightweight
+// handlers that do not install the managed frame handler.
+//
+// struct Param { ... } param;
+// EE_TRY_FOR_FINALLY(Param *, pParam, &param) {
+// ...<guarded code>...
+// } EE_FINALLY {
+// ...<handler>...
+// } EE_END_FINALLY
+//
+// EE_TRY(filter expr) {
+// ...<guarded code>...
+// } EE_CATCH {
+// ...<handler>...
+// }
+//==========================================================================
+
+// __GotException will only be FALSE if got all the way through the code
+// guarded by the try, otherwise it will be TRUE, so we know if we got into the
+// finally from an exception or not. In which case need to reset the GC state back
+// to what it was for the finally to run in that state.
+
+#define EE_TRY_FOR_FINALLY(ParamType, paramDef, paramRef) \
+ { \
+ struct __EEParam \
+ { \
+ BOOL fGCDisabled; \
+ BOOL GotException; \
+ ParamType param; \
+ } __EEparam; \
+ __EEparam.fGCDisabled = GetThread()->PreemptiveGCDisabled(); \
+ __EEparam.GotException = TRUE; \
+ __EEparam.param = paramRef; \
+ PAL_TRY(__EEParam *, __pEEParam, &__EEparam) \
+ { \
+ ParamType paramDef; paramDef = __pEEParam->param;
+
+#define GOT_EXCEPTION() __EEparam.GotException
+
+#define EE_FINALLY \
+ __pEEParam->GotException = FALSE; \
+ } PAL_FINALLY { \
+ if (__EEparam.GotException) { \
+ if (__EEparam.fGCDisabled != GetThread()->PreemptiveGCDisabled()) { \
+ if (__EEparam.fGCDisabled) \
+ GetThread()->DisablePreemptiveGC(); \
+ else \
+ GetThread()->EnablePreemptiveGC(); \
+ } \
+ }
+
+#define EE_END_FINALLY \
+ } \
+ PAL_ENDTRY \
+ }
+
+
+
+
+//==========================================================================
+// Helpful macros to declare exception handlers, their implementaiton,
+// and to call them.
+//==========================================================================
+
+#define _EXCEPTION_HANDLER_DECL(funcname) \
+ EXCEPTION_DISPOSITION __cdecl funcname(EXCEPTION_RECORD *pExceptionRecord, \
+ struct _EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, \
+ CONTEXT *pContext, \
+ DISPATCHER_CONTEXT *pDispatcherContext)
+
+#define EXCEPTION_HANDLER_DECL(funcname) \
+ extern "C" _EXCEPTION_HANDLER_DECL(funcname)
+
+#define EXCEPTION_HANDLER_IMPL(funcname) \
+ _EXCEPTION_HANDLER_DECL(funcname)
+
+#define EXCEPTION_HANDLER_FWD(funcname) \
+ funcname(pExceptionRecord, pEstablisherFrame, pContext, pDispatcherContext)
+
+//==========================================================================
+// Declares a COM+ frame handler that can be used to make sure that
+// exceptions that should be handled from within managed code
+// are handled within and don't leak out to give other handlers a
+// chance at them.
+//==========================================================================
+#define INSTALL_COMPLUS_EXCEPTION_HANDLER() \
+ DECLARE_CPFH_EH_RECORD(GET_THREAD()); \
+ INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE()
+
+#define INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE() \
+{ \
+ INSTALL_EXCEPTION_HANDLING_RECORD(&(___pExRecord->m_ExReg)); \
+ /* work around unreachable code warning */ \
+ if (true) {
+
+#define UNINSTALL_COMPLUS_EXCEPTION_HANDLER() \
+ } \
+ UNINSTALL_EXCEPTION_HANDLING_RECORD(&(___pExRecord->m_ExReg)); \
+}
+
+#if !defined(WIN64EXCEPTIONS)
+
+#define INSTALL_NESTED_EXCEPTION_HANDLER(frame) \
+ NestedHandlerExRecord *__pNestedHandlerExRecord = (NestedHandlerExRecord*) _alloca(sizeof(NestedHandlerExRecord)); \
+ __pNestedHandlerExRecord->m_handlerInfo.m_hThrowable = NULL; \
+ __pNestedHandlerExRecord->Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, frame); \
+ INSTALL_EXCEPTION_HANDLING_RECORD(&(__pNestedHandlerExRecord->m_ExReg));
+
+#define UNINSTALL_NESTED_EXCEPTION_HANDLER() \
+ UNINSTALL_EXCEPTION_HANDLING_RECORD(&(__pNestedHandlerExRecord->m_ExReg));
+
+#else // defined(WIN64EXCEPTIONS)
+
+#define INSTALL_NESTED_EXCEPTION_HANDLER(frame)
+#define UNINSTALL_NESTED_EXCEPTION_HANDLER()
+
+#endif // !defined(WIN64EXCEPTIONS)
+
+LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo);
+
+// Actual UEF worker prototype for use by GCUnhandledExceptionFilter.
+extern LONG InternalUnhandledExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo);
+
+//==========================================================================
+// Installs a handler to unwind exception frames, but not catch the exception
+//==========================================================================
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+// -----------------------------------------------------------------------
+// Support for Corrupted State Exceptions
+// -----------------------------------------------------------------------
+// This enumeration defines the corruption severity of an exception and
+// whether it should be reused for the next exception thrown or not.
+enum CorruptionSeverity
+{
+ UseLast = 0x0, // When specified, the last active corruption severity from TES should be used
+ NotSet = 0x1, // Corruption Severity has not been set - this is the default/reset value
+ NotCorrupting = 0x2, // Indicates exception is not corrupting
+ ProcessCorrupting = 0x4, // Indicates exception represents process corrupted state
+ ReuseForReraise = 0x2000 // Indicates that the corruption severity should be reused for the next exception thrown,
+ // provided its not nested and isnt a rethrow. This flag is used typically for propagation of
+ // severity across boundaries like Reflection invocation, AD transition etc.
+};
+
+#define GET_CORRUPTION_SEVERITY(severity) ((severity & (~ReuseForReraise)))
+#define CAN_REUSE_CORRUPTION_SEVERITY(severity) ((severity & ReuseForReraise) == ReuseForReraise)
+
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ , CorruptionSeverity severity
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+);
+
+VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL rethrow, BOOL fForStackOverflow = FALSE);
+
+#if defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
+
+#define INSTALL_UNWIND_AND_CONTINUE_HANDLER
+#define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER
+
+#define INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE
+#define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE
+#else // DACCESS_COMPILE || CROSSGEN_COMPILE
+
+void UnwindAndContinueRethrowHelperInsideCatch(Frame* pEntryFrame, Exception* pException);
+VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFrame, Exception* pException);
+
+#ifdef FEATURE_PAL
+VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHardwareException);
+
+#define INSTALL_MANAGED_EXCEPTION_DISPATCHER \
+ PAL_SEHException exCopy; \
+ bool hasCaughtException = false; \
+ try {
+
+#define UNINSTALL_MANAGED_EXCEPTION_DISPATCHER \
+ } \
+ catch (PAL_SEHException& ex) \
+ { \
+ exCopy = std::move(ex); \
+ hasCaughtException = true; \
+ } \
+ if (hasCaughtException) \
+ { \
+ DispatchManagedException(exCopy, false);\
+ }
+
+// Install trap that catches unhandled managed exception and dumps its stack
+#define INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP \
+ try {
+
+// Uninstall trap that catches unhandled managed exception and dumps its stack
+#define UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP \
+ } \
+ catch (PAL_SEHException& ex) \
+ { \
+ if (!GetThread()->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException)) \
+ { \
+ LONG disposition = InternalUnhandledExceptionFilter_Worker(&ex.ExceptionPointers); \
+ _ASSERTE(disposition == EXCEPTION_CONTINUE_SEARCH); \
+ } \
+ TerminateProcess(GetCurrentProcess(), 1); \
+ UNREACHABLE(); \
+ }
+
+#else
+
+#define INSTALL_MANAGED_EXCEPTION_DISPATCHER
+#define UNINSTALL_MANAGED_EXCEPTION_DISPATCHER
+#define INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP
+#define UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP
+
+#endif // FEATURE_PAL
+
+#define INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE \
+ { \
+ MAKE_CURRENT_THREAD_AVAILABLE(); \
+ Exception* __pUnCException = NULL; \
+ Frame* __pUnCEntryFrame = CURRENT_THREAD->GetFrame(); \
+ bool __fExceptionCatched = false; \
+ SCAN_EHMARKER(); \
+ if (true) PAL_CPP_TRY { \
+ SCAN_EHMARKER_TRY(); \
+ DEBUG_ASSURE_NO_RETURN_BEGIN(IUACH)
+
+#define INSTALL_UNWIND_AND_CONTINUE_HANDLER \
+ INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE \
+ /* The purpose of the INSTALL_UNWIND_AND_CONTINUE_HANDLER is to translate an exception to a managed */ \
+ /* exception before it hits managed code. The transition to SO_INTOLERANT code does not logically belong here. */ \
+ /* However, we don't want to miss any probe points and the intersection between a probe point and installing */ \
+ /* an INSTALL_UNWIND_AND_CONTINUE_HANDLER is very high. The probes are very cheap, so we can tolerate */ \
+ /* those few places where we are probing and don't need to. */ \
+ /* Ideally, we would instead have an encompassing ENTER_SO_INTOLERANT_CODE macro that would */ \
+ /* include INSTALL_UNWIND_AND_CONTINUE_HANDLER */ \
+ BEGIN_SO_INTOLERANT_CODE(GET_THREAD());
+
+// Optimized version for helper method frame. Avoids redundant GetThread() calls.
+#define INSTALL_UNWIND_AND_CONTINUE_HANDLER_FOR_HMF(pHelperFrame) \
+ { \
+ Exception* __pUnCException = NULL; \
+ Frame* __pUnCEntryFrame = (pHelperFrame); \
+ bool __fExceptionCatched = false; \
+ SCAN_EHMARKER(); \
+ if (true) PAL_CPP_TRY { \
+ SCAN_EHMARKER_TRY(); \
+ DEBUG_ASSURE_NO_RETURN_BEGIN(IUACH); \
+ BEGIN_SO_INTOLERANT_CODE(GET_THREAD());
+
+#define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE \
+ DEBUG_ASSURE_NO_RETURN_END(IUACH) \
+ SCAN_EHMARKER_END_TRY(); \
+ } \
+ PAL_CPP_CATCH_DERIVED (Exception, __pException) \
+ { \
+ SCAN_EHMARKER_CATCH(); \
+ CONSISTENCY_CHECK(NULL != __pException); \
+ __pUnCException = __pException; \
+ UnwindAndContinueRethrowHelperInsideCatch(__pUnCEntryFrame, __pUnCException); \
+ __fExceptionCatched = true; \
+ SCAN_EHMARKER_END_CATCH(); \
+ } \
+ PAL_CPP_ENDTRY \
+ if (__fExceptionCatched) \
+ { \
+ SCAN_EHMARKER_CATCH(); \
+ UnwindAndContinueRethrowHelperAfterCatch(__pUnCEntryFrame, __pUnCException); \
+ } \
+ } \
+
+#define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER \
+ END_SO_INTOLERANT_CODE; \
+ UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \
+
+#endif // DACCESS_COMPILE || CROSSGEN_COMPILE
+
+
+#define ENCLOSE_IN_EXCEPTION_HANDLER( func ) \
+ { \
+ struct exception_handler_wrapper \
+ { \
+ static void wrap() \
+ { \
+ INSTALL_UNWIND_AND_CONTINUE_HANDLER; \
+ func(); \
+ UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; \
+ } \
+ }; \
+ \
+ exception_handler_wrapper::wrap(); \
+ }
+
+
+//==========================================================================
+// Declares that a function can throw a COM+ exception.
+//==========================================================================
+#if defined(ENABLE_CONTRACTS) && !defined(DACCESS_COMPILE)
+
+//==========================================================================
+// Declares that a function cannot throw a COM+ exception.
+// Adds a record to the contract chain.
+//==========================================================================
+
+#define CANNOTTHROWCOMPLUSEXCEPTION() ANNOTATION_NOTHROW; \
+ COMPlusCannotThrowExceptionHelper _dummyvariable(TRUE, __FUNCTION__, __FILE__, __LINE__);
+
+extern char *g_ExceptionFile;
+extern DWORD g_ExceptionLine;
+
+#define THROWLOG() ( g_ExceptionFile = __FILE__, g_ExceptionLine = __LINE__, TRUE )
+
+#define COMPlusThrow if(THROWLOG() && 0) { } else RealCOMPlusThrow
+#define COMPlusThrowNonLocalized if(THROWLOG() && 0) { } else RealCOMPlusThrowNonLocalized
+#define COMPlusThrowHR if(THROWLOG() && 0) { } else RealCOMPlusThrowHR
+#define COMPlusThrowWin32 if(THROWLOG() && 0) { } else RealCOMPlusThrowWin32
+#define COMPlusThrowOM if(THROWLOG() && 0) { } else RealCOMPlusThrowOM
+#ifdef FEATURE_STACK_PROBE
+#define COMPlusThrowSO if(THROWLOG() && 0) { } else RealCOMPlusThrowSO
+#endif
+#define COMPlusThrowArithmetic if(THROWLOG() && 0) { } else RealCOMPlusThrowArithmetic
+#define COMPlusThrowArgumentNull if(THROWLOG() && 0) { } else RealCOMPlusThrowArgumentNull
+#define COMPlusThrowArgumentOutOfRange if(THROWLOG() && 0) { } else RealCOMPlusThrowArgumentOutOfRange
+#define COMPlusThrowArgumentException if(THROWLOG() && 0) { } else RealCOMPlusThrowArgumentException
+#define COMPlusThrowInvalidCastException if(THROWLOG() && 0) { } else RealCOMPlusThrowInvalidCastException
+#define COMPlusRareRethrow if(THROWLOG() && 0) { } else RealCOMPlusRareRethrow
+
+#else // ENABLE_CONTRACTS && !DACCESS_COMPILE
+
+#define CANNOTTHROWCOMPLUSEXCEPTION() ANNOTATION_NOTHROW
+#define BEGINCANNOTTHROWCOMPLUSEXCEPTION_SEH() ANNOTATION_NOTHROW
+#define ENDCANNOTTHROWCOMPLUSEXCEPTION_SEH()
+
+#define COMPlusThrow RealCOMPlusThrow
+#define COMPlusThrowNonLocalized RealCOMPlusThrowNonLocalized
+#ifndef DACCESS_COMPILE
+#define COMPlusThrowHR RealCOMPlusThrowHR
+#else
+#define COMPlusThrowHR ThrowHR
+#endif
+#define COMPlusThrowWin32 RealCOMPlusThrowWin32
+#define COMPlusThrowOM RealCOMPlusThrowOM
+#ifdef FEATURE_STACK_PROBE
+#define COMPlusThrowSO RealCOMPlusThrowSO
+#endif
+#define COMPlusThrowArithmetic RealCOMPlusThrowArithmetic
+#define COMPlusThrowArgumentNull RealCOMPlusThrowArgumentNull
+#define COMPlusThrowArgumentOutOfRange RealCOMPlusThrowArgumentOutOfRange
+#define COMPlusThrowArgumentException RealCOMPlusThrowArgumentException
+#define COMPlusThrowInvalidCastException RealCOMPlusThrowInvalidCastException
+
+#endif // ENABLE_CONTRACTS && !DACCESS_COMPILE
+/* Non-VM exception helpers to be rerouted inside the VM directory:
+ThrowHR
+ThrowWin32
+ThrowLastError -->ThrowWin32(GetLastError())
+ThrowOutOfMemory COMPlusThrowOM defers to this
+ThrowStackOverflow COMPlusThrowSO defers to this
+ThrowMessage ThrowHR(E_FAIL, Message)
+
+*/
+
+/* Ideally we could make these defines. But the sources in the VM directory
+ won't build with them as defines. @todo: go through VM directory and
+ eliminate calls to the non-VM style functions.
+
+#define ThrowHR COMPlusThrowHR
+#define ThrowWin32 COMPlusThrowWin32
+#define ThrowLastError() COMPlusThrowWin32(GetLastError())
+#define ThrowMessage "Don't use this in the VM directory"
+
+*/
+
+//======================================================
+// Used when we're entering the EE from unmanaged code
+// and we can assert that the gc state is cooperative.
+//
+// If an exception is thrown through this transition
+// handler, it will clean up the EE appropriately. See
+// the definition of COMPlusCooperativeTransitionHandler
+// for the details.
+//======================================================
+
+void COMPlusCooperativeTransitionHandler(Frame* pFrame);
+
+#ifdef CROSSGEN_COMPILE
+
+#define COOPERATIVE_TRANSITION_BEGIN()
+#define COOPERATIVE_TRANSITION_END()
+
+#else // CROSSGEN_COMPILE
+
+#define COOPERATIVE_TRANSITION_BEGIN() \
+ { \
+ MAKE_CURRENT_THREAD_AVAILABLE(); \
+ BEGIN_GCX_ASSERT_PREEMP; \
+ BEGIN_SO_INTOLERANT_CODE(CURRENT_THREAD); \
+ CoopTransitionHolder __CoopTransition(CURRENT_THREAD); \
+ DEBUG_ASSURE_NO_RETURN_BEGIN(COOP_TRANSITION)
+
+#define COOPERATIVE_TRANSITION_END() \
+ DEBUG_ASSURE_NO_RETURN_END(COOP_TRANSITION) \
+ __CoopTransition.SuppressRelease(); \
+ END_SO_INTOLERANT_CODE; \
+ END_GCX_ASSERT_PREEMP; \
+ }
+
+#endif // CROSSGEN_COMPILE
+
+extern LONG UserBreakpointFilter(EXCEPTION_POINTERS *ep);
+extern LONG DefaultCatchFilter(EXCEPTION_POINTERS *ep, LPVOID pv);
+extern LONG DefaultCatchNoSwallowFilter(EXCEPTION_POINTERS *ep, LPVOID pv);
+
+
+// the only valid parameter for DefaultCatchFilter
+#define COMPLUS_EXCEPTION_EXECUTE_HANDLER (PVOID)EXCEPTION_EXECUTE_HANDLER
+struct DefaultCatchFilterParam
+{
+ PVOID pv; // must be COMPLUS_EXCEPTION_EXECUTE_HANDLER
+ DefaultCatchFilterParam() {}
+ DefaultCatchFilterParam(PVOID _pv) : pv(_pv) {}
+};
+
+template <typename T>
+LPCWSTR GetPathForErrorMessagesT(T *pImgObj)
+{
+ SUPPORTS_DAC_HOST_ONLY;
+ if (pImgObj)
+ {
+ return pImgObj->GetPathForErrorMessages();
+ }
+ else
+ {
+ return W("");
+ }
+}
+
+VOID ThrowBadFormatWorker(UINT resID, LPCWSTR imageName DEBUGARG(__in_z const char *cond));
+
+template <typename T>
+NOINLINE
+VOID ThrowBadFormatWorkerT(UINT resID, T * pImgObj DEBUGARG(__in_z const char *cond))
+{
+ LPCWSTR tmpStr = GetPathForErrorMessagesT(pImgObj);
+ ThrowBadFormatWorker(resID, tmpStr DEBUGARG(cond));
+}
+
+
+// Worker macro for throwing BadImageFormat exceptions.
+//
+// resID: resource ID in mscorrc.rc. Message may not have substitutions. resID is permitted (but not encouraged) to be 0.
+// imgObj: one of Module* or PEFile* or PEImage* (must support GetPathForErrorMessages method.)
+//
+#define IfFailThrowBF(hresult, resID, imgObj) \
+ do \
+ { \
+ if (FAILED(hresult)) \
+ THROW_BAD_FORMAT(resID, imgObj); \
+ } \
+ while(0)
+
+
+#define THROW_BAD_FORMAT(resID, imgObj) THROW_BAD_FORMAT_MAYBE(FALSE, resID, imgObj)
+
+
+// Conditional version of THROW_BAD_FORMAT. Do not use for new callsites. This is really meant to be a drop-in replacement
+// for the obsolete BAD_FORMAT_ASSERT.
+
+#define THROW_BAD_FORMAT_MAYBE(cond, resID, imgObj) \
+ do \
+ { \
+ if (!(cond)) \
+ { \
+ ThrowBadFormatWorkerT((resID), (imgObj) DEBUGARG(#cond)); \
+ } \
+ } \
+ while(0)
+
+
+// Same as above, but allows you to specify your own HRESULT
+#define THROW_HR_ERROR_WITH_INFO(hr, imgObj) RealCOMPlusThrowHR(hr, hr, GetPathForErrorMessagesT(imgObj))
+
+
+#endif // __exceptmacros_h__