1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// DebugMacros.h
6//
7// Wrappers for Debugging purposes.
8//
9//*****************************************************************************
10
11#ifndef __DebugMacros_h__
12#define __DebugMacros_h__
13
14#include "stacktrace.h"
15#include "debugmacrosext.h"
16
17#undef _ASSERTE
18#undef VERIFY
19
20#ifdef __cplusplus
21extern "C" {
22#endif // __cplusplus
23
24#if defined(_DEBUG)
25
26class SString;
27bool GetStackTraceAtContext(SString & s, struct _CONTEXT * pContext);
28
29void _cdecl DbgWriteEx(LPCTSTR szFmt, ...);
30bool _DbgBreakCheck(LPCSTR szFile, int iLine, LPCSTR szExpr, BOOL fConstrained = FALSE);
31
32extern VOID DbgAssertDialog(const char *szFile, int iLine, const char *szExpr);
33
34#define TRACE_BUFF_SIZE (cchMaxAssertStackLevelStringLen * cfrMaxAssertStackLevels + cchMaxAssertExprLen + 1)
35extern char g_szExprWithStack[TRACE_BUFF_SIZE];
36
37extern int _DbgBreakCount;
38
39#define PRE_ASSERTE /* if you need to change modes before doing asserts override */
40#define POST_ASSERTE /* put it back */
41
42#if !defined(_ASSERTE_MSG)
43 #define _ASSERTE_MSG(expr, msg) \
44 do { \
45 if (!(expr)) { \
46 PRE_ASSERTE \
47 DbgAssertDialog(__FILE__, __LINE__, msg); \
48 POST_ASSERTE \
49 } \
50 } while (0)
51#endif // _ASSERTE_MSG
52
53#if !defined(_ASSERTE)
54 #define _ASSERTE(expr) _ASSERTE_MSG(expr, #expr)
55#endif // !_ASSERTE
56
57
58#define VERIFY(stmt) _ASSERTE((stmt))
59
60#define _ASSERTE_ALL_BUILDS(file, expr) _ASSERTE((expr))
61
62#define FreeBuildDebugBreak() DebugBreak()
63
64#else // !_DEBUG
65
66#define _DbgBreakCount 0
67
68#define _ASSERTE(expr) ((void)0)
69#define _ASSERTE_MSG(expr, msg) ((void)0)
70#define VERIFY(stmt) (void)(stmt)
71
72void __FreeBuildDebugBreak();
73void DECLSPEC_NORETURN __FreeBuildAssertFail(const char *szFile, int iLine, const char *szExpr);
74
75#define FreeBuildDebugBreak() __FreeBuildDebugBreak()
76
77// At this point, EEPOLICY_HANDLE_FATAL_ERROR may or may not be defined. It will be defined
78// if we are building the VM folder, but outside VM, its not necessarily defined.
79//
80// Thus, if EEPOLICY_HANDLE_FATAL_ERROR is not defined, we will call into __FreeBuildAssertFail,
81// but if it is defined, we will use it.
82//
83// Failing here implies an error in the runtime - hence we use COR_E_EXECUTIONENGINE.
84
85#ifdef EEPOLICY_HANDLE_FATAL_ERROR
86#define _ASSERTE_ALL_BUILDS(file, expr) if (!(expr)) EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
87#else // !EEPOLICY_HANDLE_FATAL_ERROR
88#define _ASSERTE_ALL_BUILDS(file, expr) if (!(expr)) __FreeBuildAssertFail(file, __LINE__, #expr);
89#endif // EEPOLICY_HANDLE_FATAL_ERROR
90
91#endif
92
93
94#define ASSERT_AND_CHECK(x) { \
95 BOOL bResult = x; \
96 if (!bResult) \
97 { \
98 _ASSERTE(x); \
99 return FALSE; \
100 } \
101}
102
103
104#ifdef _DEBUG_IMPL
105
106// A macro to execute a statement only in _DEBUG_IMPL.
107#define DEBUG_IMPL_STMT(stmt) stmt
108
109#define _ASSERTE_IMPL(expr) _ASSERTE((expr))
110
111#if defined(_M_IX86)
112#if defined(_MSC_VER)
113#define _DbgBreak() __asm { int 3 }
114#elif defined(__GNUC__)
115#define _DbgBreak() __asm__ ("int $3");
116#else
117#error Unknown compiler
118#endif
119#else
120#define _DbgBreak() DebugBreak()
121#endif
122
123extern VOID DebBreak();
124extern VOID DebBreakHr(HRESULT hr);
125
126#ifndef IfFailGoto
127#define IfFailGoto(EXPR, LABEL) \
128do { hr = (EXPR); if(FAILED(hr)) { DebBreakHr(hr); goto LABEL; } } while (0)
129#endif
130
131#ifndef IfFailRet
132#define IfFailRet(EXPR) \
133do { hr = (EXPR); if(FAILED(hr)) { DebBreakHr(hr); return (hr); } } while (0)
134#endif
135
136#ifndef IfFailWin32Ret
137#define IfFailWin32Ret(EXPR) \
138do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); DebBreakHr(hr); return hr;} } while (0)
139#endif
140
141#ifndef IfFailWin32Goto
142#define IfFailWin32Goto(EXPR, LABEL) \
143do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); DebBreakHr(hr); goto LABEL; } } while (0)
144#endif
145
146#ifndef IfFailGo
147#define IfFailGo(EXPR) IfFailGoto(EXPR, ErrExit)
148#endif
149
150#ifndef IfFailWin32Go
151#define IfFailWin32Go(EXPR) IfFailWin32Goto(EXPR, ErrExit)
152#endif
153
154#else // _DEBUG_IMPL
155
156#define _DbgBreak() {}
157
158#define DEBUG_IMPL_STMT(stmt)
159
160#define _ASSERTE_IMPL(expr)
161
162#define IfFailGoto(EXPR, LABEL) \
163do { hr = (EXPR); if(FAILED(hr)) { goto LABEL; } } while (0)
164
165#define IfFailRet(EXPR) \
166do { hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0)
167
168#define IfFailWin32Ret(EXPR) \
169do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); return hr;} } while (0)
170
171#define IfFailWin32Goto(EXPR, LABEL) \
172do { hr = (EXPR); if(hr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(hr); goto LABEL; } } while (0)
173
174#define IfFailGo(EXPR) IfFailGoto(EXPR, ErrExit)
175
176#define IfFailWin32Go(EXPR) IfFailWin32Goto(EXPR, ErrExit)
177
178#endif // _DEBUG_IMPL
179
180
181#define IfNullGoto(EXPR, LABEL) \
182 do { if ((EXPR) == NULL) { OutOfMemory(); IfFailGoto(E_OUTOFMEMORY, LABEL); } } while (false)
183
184#ifndef IfNullRet
185#define IfNullRet(EXPR) \
186 do { if ((EXPR) == NULL) { OutOfMemory(); return E_OUTOFMEMORY; } } while (false)
187#endif //!IfNullRet
188
189#define IfNullGo(EXPR) IfNullGoto(EXPR, ErrExit)
190
191#ifdef __cplusplus
192}
193
194#endif // __cplusplus
195
196
197#undef assert
198#define assert _ASSERTE
199#undef _ASSERT
200#define _ASSERT _ASSERTE
201
202
203#if defined(_DEBUG) && !defined(FEATURE_PAL)
204
205// This function returns the EXE time stamp (effectively a random number)
206// Under retail it always returns 0. This is meant to be used in the
207// RandomOnExe macro
208unsigned DbgGetEXETimeStamp();
209
210// returns true 'fractionOn' amount of the time using the EXE timestamp
211// as the random number seed. For example DbgRandomOnExe(.1) returns true 1/10
212// of the time. We use the line number so that different uses of DbgRandomOnExe
213// will not be coorelated with each other (9973 is prime). Returns false on a retail build
214#define DbgRandomOnHashAndExe(hash, fractionOn) \
215 (((DbgGetEXETimeStamp() * __LINE__ * ((hash) ? (hash) : 1)) % 9973) < \
216 unsigned(fractionOn * 9973))
217#define DbgRandomOnExe(fractionOn) DbgRandomOnHashAndExe(0, fractionOn)
218#define DbgRandomOnStringAndExe(string, fractionOn) DbgRandomOnHashAndExe(HashStringA(string), fractionOn)
219
220#else
221
222#define DbgGetEXETimeStamp() 0
223#define DbgRandomOnHashAndExe(hash, fractionOn) 0
224#define DbgRandomOnExe(fractionOn) 0
225#define DbgRandomOnStringAndExe(fractionOn) 0
226
227#endif // _DEBUG && !FEATUREPAL
228
229#ifdef _DEBUG
230namespace clr
231{
232 namespace dbg
233 {
234 // In debug builds, this can be used to write known bad values into
235 // memory. One example is in ComUtil::IUnknownCommon::~IUnknownCommon,
236 // which overwrites its instance memory with a known bad value after
237 // completing its destructor.
238 template < typename T >
239 void PoisonMem(T &val)
240 {
241 ZeroMemory((void*)&val, sizeof(T));
242 }
243
244 template < typename T >
245 void PoisonMem(T* ptr, size_t len)
246 {
247 ZeroMemory((void*)ptr, sizeof(T)* len);
248 }
249 }
250}
251#else
252
253// Empty versions of the functions in retail that will be inlined
254// and completely elided.
255namespace clr
256{
257 namespace dbg
258 {
259 template < typename T >
260 inline void PoisonMem(T &) {}
261
262 template < typename T >
263 void PoisonMem(T* ptr, size_t len){}
264 }
265}
266#endif
267
268#endif
269