1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 ****************************************************************************/
23
24 #include "common/os.h"
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <assert.h>
28 #include <algorithm>
29 #include <mutex>
30
31 #if SWR_ENABLE_ASSERTS || SWR_ENABLE_REL_ASSERTS
32
33 #if defined(_WIN32)
34 #pragma comment(lib, "user32.lib")
35 #endif // _WIN32
36
37 enum TextColor
38 {
39 TEXT_BLACK = 0,
40 TEXT_RED = 1,
41 TEXT_GREEN = 2,
42 TEXT_BLUE = 4,
43 TEXT_PURPLE = TEXT_RED | TEXT_BLUE,
44 TEXT_CYAN = TEXT_GREEN | TEXT_BLUE,
45 TEXT_YELLOW = TEXT_RED | TEXT_GREEN,
46 TEXT_WHITE = TEXT_RED | TEXT_GREEN | TEXT_BLUE,
47 };
48
49 enum TextStyle
50 {
51 TEXT_NORMAL = 0,
52 TEXT_INTENSITY = 1,
53 };
54
SetTextColor(FILE * stream,TextColor color=TEXT_WHITE,TextStyle style=TEXT_NORMAL)55 void SetTextColor(FILE* stream, TextColor color = TEXT_WHITE, TextStyle style = TEXT_NORMAL)
56 {
57 #if defined(_WIN32)
58
59 HANDLE hConsoleHandle = nullptr;
60 if (stream == stderr)
61 {
62 hConsoleHandle = GetStdHandle(STD_ERROR_HANDLE);
63 }
64 else if (stream == stdout)
65 {
66 hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
67 }
68 else
69 {
70 // Not a console stream, do nothing
71 return;
72 }
73
74 WORD textAttributes = 0;
75 if (color & TEXT_RED)
76 {
77 textAttributes |= FOREGROUND_RED;
78 }
79 if (color & TEXT_GREEN)
80 {
81 textAttributes |= FOREGROUND_GREEN;
82 }
83 if (color & TEXT_BLUE)
84 {
85 textAttributes |= FOREGROUND_BLUE;
86 }
87 if (style & TEXT_INTENSITY)
88 {
89 textAttributes |= FOREGROUND_INTENSITY;
90 }
91 SetConsoleTextAttribute(hConsoleHandle, textAttributes);
92
93 #else // !_WIN32
94
95 // Print ANSI codes
96 uint32_t cc = 30 + (style ? 60 : 0) + color;
97 fprintf(stream, "\033[0m\033[%d;%dm", style, cc);
98
99 #endif
100 }
101
ResetTextColor(FILE * stream)102 void ResetTextColor(FILE* stream)
103 {
104 #if defined(_WIN32)
105
106 SetTextColor(stream);
107
108 #else // !_WIN32
109
110 // Print ANSI codes
111 fprintf(stream, "\033[0m");
112
113 #endif
114 }
115
116 static std::mutex g_stderrMutex;
117
SwrTrace(const char * pFileName,uint32_t lineNum,const char * function,const char * pFmtString,...)118 void SwrTrace(
119 const char* pFileName,
120 uint32_t lineNum,
121 const char* function,
122 const char* pFmtString,
123 ...)
124 {
125 std::lock_guard<std::mutex> l(g_stderrMutex);
126
127 SetTextColor(stderr, TEXT_CYAN, TEXT_NORMAL);
128
129 fprintf(stderr, "%s(%d): TRACE in %s:\n", pFileName, lineNum, function);
130
131 if (pFmtString)
132 {
133 SetTextColor(stderr, TEXT_PURPLE, TEXT_INTENSITY);
134 fprintf(stderr, "\t");
135 va_list args;
136 va_start(args, pFmtString);
137 vfprintf(stderr, pFmtString, args);
138 va_end(args);
139 fprintf(stderr, "\n");
140 }
141 ResetTextColor(stderr);
142 fflush(stderr);
143
144 #if defined(_WIN32)
145 static const int MAX_MESSAGE_LEN = 2048;
146 char msgBuf[MAX_MESSAGE_LEN];
147
148 sprintf_s(msgBuf, "%s(%d): TRACE in %s\n", pFileName, lineNum, function);
149 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
150 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
151 OutputDebugStringA(msgBuf);
152
153 int offset = 0;
154
155 if (pFmtString)
156 {
157 va_list args;
158 va_start(args, pFmtString);
159 offset = _vsnprintf_s(
160 msgBuf,
161 sizeof(msgBuf),
162 sizeof(msgBuf),
163 pFmtString,
164 args);
165 va_end(args);
166
167 if (offset < 0) { return; }
168
169 OutputDebugStringA("\t");
170 OutputDebugStringA(msgBuf);
171 OutputDebugStringA("\n");
172 }
173 #endif // _WIN32
174 }
175
SwrAssert(bool chkDebugger,bool & enabled,const char * pExpression,const char * pFileName,uint32_t lineNum,const char * pFunction,const char * pFmtString,...)176 bool SwrAssert(
177 bool chkDebugger,
178 bool& enabled,
179 const char* pExpression,
180 const char* pFileName,
181 uint32_t lineNum,
182 const char* pFunction,
183 const char* pFmtString /* = nullptr */,
184 ...)
185 {
186 {
187 std::lock_guard<std::mutex> l(g_stderrMutex);
188
189 SetTextColor(stderr, TEXT_CYAN, TEXT_NORMAL);
190
191 fprintf(stderr, "%s(%d): ", pFileName, lineNum);
192
193 SetTextColor(stderr, TEXT_RED, TEXT_INTENSITY);
194
195 fprintf(stderr, "ASSERT: %s\n", pExpression);
196
197 SetTextColor(stderr, TEXT_CYAN, TEXT_INTENSITY);
198 fprintf(stderr, "\t%s\n", pFunction);
199
200 if (pFmtString)
201 {
202 SetTextColor(stderr, TEXT_YELLOW, TEXT_INTENSITY);
203 fprintf(stderr, "\t");
204 va_list args;
205 va_start(args, pFmtString);
206 vfprintf(stderr, pFmtString, args);
207 va_end(args);
208 fprintf(stderr, "\n");
209 }
210 ResetTextColor(stderr);
211 fflush(stderr);
212 }
213
214 #if defined(_WIN32)
215 static const int MAX_MESSAGE_LEN = 2048;
216 char msgBuf[MAX_MESSAGE_LEN];
217
218 sprintf_s(msgBuf, "%s(%d): ASSERT: %s\n", pFileName, lineNum, pExpression);
219 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
220 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
221 OutputDebugStringA(msgBuf);
222
223 sprintf_s(msgBuf, "\t%s\n", pFunction);
224 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
225 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
226 OutputDebugStringA(msgBuf);
227
228 int offset = 0;
229
230 if (pFmtString)
231 {
232 va_list args;
233 va_start(args, pFmtString);
234 offset = _vsnprintf_s(
235 msgBuf,
236 sizeof(msgBuf),
237 sizeof(msgBuf),
238 pFmtString,
239 args);
240 va_end(args);
241
242 if (offset < 0) { return true; }
243
244 OutputDebugStringA("\t");
245 OutputDebugStringA(msgBuf);
246 OutputDebugStringA("\n");
247 }
248
249 if (enabled && KNOB_ENABLE_ASSERT_DIALOGS)
250 {
251 int retval = sprintf_s(
252 &msgBuf[offset],
253 MAX_MESSAGE_LEN - offset,
254 "\n\n"
255 "File: %s\n"
256 "Line: %d\n"
257 "\n"
258 "Expression: %s\n\n"
259 "Cancel: Disable this assert for the remainder of the process\n"
260 "Try Again: Break into the debugger\n"
261 "Continue: Continue execution (but leave assert enabled)",
262 pFileName,
263 lineNum,
264 pExpression);
265
266 if (retval < 0) { return true; }
267
268 offset += retval;
269
270 if (!IsDebuggerPresent())
271 {
272 sprintf_s(
273 &msgBuf[offset],
274 MAX_MESSAGE_LEN - offset,
275 "\n\n*** NO DEBUGGER DETECTED ***\n\nPressing \"Try Again\" will cause a program crash!");
276 }
277
278 retval = MessageBoxA(nullptr, msgBuf, "Assert Failed", MB_CANCELTRYCONTINUE | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
279
280 switch (retval)
281 {
282 case IDCANCEL:
283 enabled = false;
284 return false;
285
286 case IDTRYAGAIN:
287 return true;
288
289 case IDCONTINUE:
290 return false;
291 }
292 }
293 else
294 {
295 return (IsDebuggerPresent() || !chkDebugger) && enabled;
296 }
297 #endif // _WIN32
298
299 return enabled;
300 }
301
302 #endif // SWR_ENABLE_ASSERTS
303