summaryrefslogtreecommitdiff
path: root/src/inc/debugmacros.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/inc/debugmacros.h')
-rw-r--r--src/inc/debugmacros.h270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/inc/debugmacros.h b/src/inc/debugmacros.h
new file mode 100644
index 0000000..e1468a7
--- /dev/null
+++ b/src/inc/debugmacros.h
@@ -0,0 +1,270 @@
+// 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.
+//*****************************************************************************
+// DebugMacros.h
+//
+// Wrappers for Debugging purposes.
+//
+//*****************************************************************************
+
+#ifndef __DebugMacros_h__
+#define __DebugMacros_h__
+
+#include "stacktrace.h"
+#include "debugmacrosext.h"
+
+#undef _ASSERTE
+#undef VERIFY
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#if defined(_DEBUG)
+
+class SString;
+bool GetStackTraceAtContext(SString & s, struct _CONTEXT * pContext);
+
+void _cdecl DbgWriteEx(LPCTSTR szFmt, ...);
+bool _DbgBreakCheck(LPCSTR szFile, int iLine, LPCSTR szExpr, BOOL fConstrained = FALSE);
+
+extern VOID DbgAssertDialog(const char *szFile, int iLine, const char *szExpr);
+
+#define TRACE_BUFF_SIZE (cchMaxAssertStackLevelStringLen * cfrMaxAssertStackLevels + cchMaxAssertExprLen + 1)
+extern char g_szExprWithStack[TRACE_BUFF_SIZE];
+
+extern int _DbgBreakCount;
+
+#define PRE_ASSERTE /* if you need to change modes before doing asserts override */
+#define POST_ASSERTE /* put it back */
+
+#if !defined(_ASSERTE_MSG)
+ #define _ASSERTE_MSG(expr, msg) \
+ do { \
+ if (!(expr)) { \
+ PRE_ASSERTE \
+ DbgAssertDialog(__FILE__, __LINE__, msg); \
+ POST_ASSERTE \
+ } \
+ } while (0)
+#endif // _ASSERTE_MSG
+
+#if !defined(_ASSERTE)
+ #define _ASSERTE(expr) _ASSERTE_MSG(expr, #expr)
+#endif // !_ASSERTE
+
+
+#define VERIFY(stmt) _ASSERTE((stmt))
+
+#define _ASSERTE_ALL_BUILDS(file, expr) _ASSERTE((expr))
+
+#define FreeBuildDebugBreak() DebugBreak()
+
+#else // !_DEBUG
+
+#define _DbgBreakCount 0
+
+#define _ASSERTE(expr) ((void)0)
+#define _ASSERTE_MSG(expr, msg) ((void)0)
+#define VERIFY(stmt) (void)(stmt)
+
+void __FreeBuildDebugBreak();
+void DECLSPEC_NORETURN __FreeBuildAssertFail(const char *szFile, int iLine, const char *szExpr);
+
+#define FreeBuildDebugBreak() __FreeBuildDebugBreak()
+
+// At this point, EEPOLICY_HANDLE_FATAL_ERROR may or may not be defined. It will be defined
+// if we are building the VM folder, but outside VM, its not necessarily defined. Currently,
+// this is applicable to the usage of RetailAssertIfExpectedClean that is used from outside
+// the VM folder and uses _ASSERTE_ALL_BUILDS macro as well.
+//
+// Thus, if EEPOLICY_HANDLE_FATAL_ERROR is not defined, we will call into __FreeBuildAssertFail,
+// but if it is defined, we will use it.
+//
+// Failing here implies an error in the runtime - hence we use COR_E_EXECUTIONENGINE.
+
+#ifdef EEPOLICY_HANDLE_FATAL_ERROR
+#define _ASSERTE_ALL_BUILDS(file, expr) if (!(expr)) EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
+#else // !EEPOLICY_HANDLE_FATAL_ERROR
+#define _ASSERTE_ALL_BUILDS(file, expr) if (!(expr)) __FreeBuildAssertFail(file, __LINE__, #expr);
+#endif // EEPOLICY_HANDLE_FATAL_ERROR
+
+#endif
+
+
+#define ASSERT_AND_CHECK(x) { \
+ BOOL bResult = x; \
+ if (!bResult) \
+ { \
+ _ASSERTE(x); \
+ return FALSE; \
+ } \
+}
+
+
+#ifdef _DEBUG_IMPL
+
+// A macro to execute a statement only in _DEBUG_IMPL.
+#define DEBUG_IMPL_STMT(stmt) stmt
+
+#define _ASSERTE_IMPL(expr) _ASSERTE((expr))
+
+#if defined(_M_IX86)
+#if defined(_MSC_VER)
+#define _DbgBreak() __asm { int 3 }
+#elif defined(__GNUC__)
+#define _DbgBreak() __asm__ ("int $3");
+#else
+#error Unknown compiler
+#endif
+#else
+#define _DbgBreak() DebugBreak()
+#endif
+
+extern VOID DebBreak();
+extern VOID DebBreakHr(HRESULT hr);
+
+#ifndef IfFailGoto
+#define IfFailGoto(EXPR, LABEL) \
+do { hr = (EXPR); if(FAILED(hr)) { DebBreakHr(hr); goto LABEL; } } while (0)
+#endif
+
+#ifndef IfFailRet
+#define IfFailRet(EXPR) \
+do { hr = (EXPR); if(FAILED(hr)) { DebBreakHr(hr); return (hr); } } while (0)
+#endif
+
+#ifndef IfFailWin32Ret
+#define IfFailWin32Ret(EXPR) \
+do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); DebBreakHr(hr); return hr;} } while (0)
+#endif
+
+#ifndef IfFailWin32Goto
+#define IfFailWin32Goto(EXPR, LABEL) \
+do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); DebBreakHr(hr); goto LABEL; } } while (0)
+#endif
+
+#ifndef IfFailGo
+#define IfFailGo(EXPR) IfFailGoto(EXPR, ErrExit)
+#endif
+
+#ifndef IfFailWin32Go
+#define IfFailWin32Go(EXPR) IfFailWin32Goto(EXPR, ErrExit)
+#endif
+
+#else // _DEBUG_IMPL
+
+#define _DbgBreak() {}
+
+#define DEBUG_IMPL_STMT(stmt)
+
+#define _ASSERTE_IMPL(expr)
+
+#define IfFailGoto(EXPR, LABEL) \
+do { hr = (EXPR); if(FAILED(hr)) { goto LABEL; } } while (0)
+
+#define IfFailRet(EXPR) \
+do { hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0)
+
+#define IfFailWin32Ret(EXPR) \
+do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); return hr;} } while (0)
+
+#define IfFailWin32Goto(EXPR, LABEL) \
+do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); goto LABEL; } } while (0)
+
+#define IfFailGo(EXPR) IfFailGoto(EXPR, ErrExit)
+
+#define IfFailWin32Go(EXPR) IfFailWin32Goto(EXPR, ErrExit)
+
+#endif // _DEBUG_IMPL
+
+
+#define IfNullGoto(EXPR, LABEL) \
+ do { if ((EXPR) == NULL) { OutOfMemory(); IfFailGoto(E_OUTOFMEMORY, LABEL); } } while (false)
+
+#ifndef IfNullRet
+#define IfNullRet(EXPR) \
+ do { if ((EXPR) == NULL) { OutOfMemory(); return E_OUTOFMEMORY; } } while (false)
+#endif //!IfNullRet
+
+#define IfNullGo(EXPR) IfNullGoto(EXPR, ErrExit)
+
+#ifdef __cplusplus
+}
+
+#endif // __cplusplus
+
+
+#undef assert
+#define assert _ASSERTE
+#undef _ASSERT
+#define _ASSERT _ASSERTE
+
+
+#if defined(_DEBUG) && !defined(FEATURE_PAL)
+
+// This function returns the EXE time stamp (effectively a random number)
+// Under retail it always returns 0. This is meant to be used in the
+// RandomOnExe macro
+unsigned DbgGetEXETimeStamp();
+
+// returns true 'fractionOn' amount of the time using the EXE timestamp
+// as the random number seed. For example DbgRandomOnExe(.1) returns true 1/10
+// of the time. We use the line number so that different uses of DbgRandomOnExe
+// will not be coorelated with each other (9973 is prime). Returns false on a retail build
+#define DbgRandomOnHashAndExe(hash, fractionOn) \
+ (((DbgGetEXETimeStamp() * __LINE__ * ((hash) ? (hash) : 1)) % 9973) < \
+ unsigned(fractionOn * 9973))
+#define DbgRandomOnExe(fractionOn) DbgRandomOnHashAndExe(0, fractionOn)
+#define DbgRandomOnStringAndExe(string, fractionOn) DbgRandomOnHashAndExe(HashStringA(string), fractionOn)
+
+#else
+
+#define DbgGetEXETimeStamp() 0
+#define DbgRandomOnHashAndExe(hash, fractionOn) 0
+#define DbgRandomOnExe(fractionOn) 0
+#define DbgRandomOnStringAndExe(fractionOn) 0
+
+#endif // _DEBUG && !FEATUREPAL
+
+#ifdef _DEBUG
+namespace clr
+{
+ namespace dbg
+ {
+ // In debug builds, this can be used to write known bad values into
+ // memory. One example is in ComUtil::IUnknownCommon::~IUnknownCommon,
+ // which overwrites its instance memory with a known bad value after
+ // completing its destructor.
+ template < typename T >
+ void PoisonMem(T &val)
+ {
+ ZeroMemory((void*)&val, sizeof(T));
+ }
+
+ template < typename T >
+ void PoisonMem(T* ptr, size_t len)
+ {
+ ZeroMemory((void*)ptr, sizeof(T)* len);
+ }
+ }
+}
+#else
+
+// Empty versions of the functions in retail that will be inlined
+// and completely elided.
+namespace clr
+{
+ namespace dbg
+ {
+ template < typename T >
+ inline void PoisonMem(T &) {}
+
+ template < typename T >
+ void PoisonMem(T* ptr, size_t len){}
+ }
+}
+#endif
+
+#endif