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 namespace ConsoleUtils
38 {
39 enum class TextColor
40 {
41 BLACK = 0,
42 #if defined(_WIN32)
43 RED = 4,
44 GREEN = 2,
45 BLUE = 1,
46 #else
47 RED = 1,
48 GREEN = 2,
49 BLUE = 4,
50 #endif // _WIN32
51 PURPLE = static_cast<uint32_t>(RED) | static_cast<uint32_t>(BLUE),
52 CYAN = static_cast<uint32_t>(GREEN) | static_cast<uint32_t>(BLUE),
53 YELLOW = static_cast<uint32_t>(RED) | static_cast<uint32_t>(GREEN),
54 WHITE = static_cast<uint32_t>(RED) | static_cast<uint32_t>(GREEN) | static_cast<uint32_t>(BLUE),
55 };
56
57 enum class TextStyle
58 {
59 NORMAL = 0,
60 INTENSITY = 1,
61 };
62
SetTextColor(FILE * stream,TextColor color=TextColor::WHITE,TextStyle style=TextStyle::NORMAL)63 void SetTextColor(FILE* stream, TextColor color = TextColor::WHITE, TextStyle style = TextStyle::NORMAL)
64 {
65 #if defined(_WIN32)
66
67 HANDLE hConsoleHandle = nullptr;
68 if (stream == stderr)
69 {
70 hConsoleHandle = GetStdHandle(STD_ERROR_HANDLE);
71 }
72 else if (stream == stdout)
73 {
74 hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
75 }
76 else
77 {
78 // Not a console stream, do nothing
79 return;
80 }
81
82 WORD textAttributes = static_cast<WORD>(color);
83 if (style == TextStyle::INTENSITY)
84 {
85 textAttributes |= FOREGROUND_INTENSITY;
86 }
87 SetConsoleTextAttribute(hConsoleHandle, textAttributes);
88
89 #else // !_WIN32
90
91 // Print ANSI codes
92 uint32_t cc = 30 + ((style == TextStyle::INTENSITY) ? 60 : 0) + static_cast<uint32_t>(color);
93 fprintf(stream, "\033[0m\033[%d;%dm", static_cast<uint32_t>(style), cc);
94
95 #endif
96 }
97
ResetTextColor(FILE * stream)98 void ResetTextColor(FILE* stream)
99 {
100 #if defined(_WIN32)
101
102 SetTextColor(stream);
103
104 #else // !_WIN32
105
106 // Print ANSI codes
107 fprintf(stream, "\033[0m");
108
109 #endif
110 }
111
112 static std::mutex g_stderrMutex;
113 } // ns ConsoleUtils
114
SwrAssert(bool chkDebugger,bool & enabled,const char * pExpression,const char * pFileName,uint32_t lineNum,const char * pFunction,const char * pFmtString,...)115 bool SwrAssert(
116 bool chkDebugger,
117 bool& enabled,
118 const char* pExpression,
119 const char* pFileName,
120 uint32_t lineNum,
121 const char* pFunction,
122 const char* pFmtString,
123 ...)
124 {
125 using namespace ConsoleUtils;
126 std::lock_guard<std::mutex> l(g_stderrMutex);
127
128 SetTextColor(stderr, TextColor::CYAN, TextStyle::NORMAL);
129
130 fprintf(stderr, "%s(%d): ", pFileName, lineNum);
131
132 SetTextColor(stderr, TextColor::RED, TextStyle::INTENSITY);
133
134 fprintf(stderr, "ASSERT: %s\n", pExpression);
135
136 SetTextColor(stderr, TextColor::CYAN, TextStyle::INTENSITY);
137 fprintf(stderr, "\t%s\n", pFunction);
138
139 if (pFmtString)
140 {
141 SetTextColor(stderr, TextColor::YELLOW, TextStyle::INTENSITY);
142 fprintf(stderr, "\t");
143 va_list args;
144 va_start(args, pFmtString);
145 vfprintf(stderr, pFmtString, args);
146 va_end(args);
147 fprintf(stderr, "\n");
148 }
149 ResetTextColor(stderr);
150 fflush(stderr);
151
152 #if defined(_WIN32)
153 static const int MAX_MESSAGE_LEN = 2048;
154 char msgBuf[MAX_MESSAGE_LEN];
155
156 sprintf_s(msgBuf, "%s(%d): ASSERT: %s\n", pFileName, lineNum, pExpression);
157 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
158 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
159 OutputDebugStringA(msgBuf);
160
161 sprintf_s(msgBuf, "\t%s\n", pFunction);
162 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
163 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
164 OutputDebugStringA(msgBuf);
165
166 int offset = 0;
167
168 if (pFmtString)
169 {
170 va_list args;
171 va_start(args, pFmtString);
172 offset = _vsnprintf_s(
173 msgBuf,
174 sizeof(msgBuf),
175 sizeof(msgBuf),
176 pFmtString,
177 args);
178 va_end(args);
179
180 if (offset < 0) { return true; }
181
182 OutputDebugStringA("\t");
183 OutputDebugStringA(msgBuf);
184 OutputDebugStringA("\n");
185 }
186
187 if (enabled && KNOB_ENABLE_ASSERT_DIALOGS)
188 {
189 int retval = sprintf_s(
190 &msgBuf[offset],
191 MAX_MESSAGE_LEN - offset,
192 "\n\n"
193 "File: %s\n"
194 "Line: %d\n"
195 "\n"
196 "Expression: %s\n\n"
197 "Cancel: Disable this assert for the remainder of the process\n"
198 "Try Again: Break into the debugger\n"
199 "Continue: Continue execution (but leave assert enabled)",
200 pFileName,
201 lineNum,
202 pExpression);
203
204 if (retval < 0) { return true; }
205
206 offset += retval;
207
208 if (!IsDebuggerPresent())
209 {
210 sprintf_s(
211 &msgBuf[offset],
212 MAX_MESSAGE_LEN - offset,
213 "\n\n*** NO DEBUGGER DETECTED ***\n\nPressing \"Try Again\" will cause a program crash!");
214 }
215
216 retval = MessageBoxA(nullptr, msgBuf, "Assert Failed", MB_CANCELTRYCONTINUE | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
217
218 switch (retval)
219 {
220 case IDCANCEL:
221 enabled = false;
222 return false;
223
224 case IDTRYAGAIN:
225 return true;
226
227 case IDCONTINUE:
228 return false;
229 }
230 }
231 else
232 {
233 return (IsDebuggerPresent() || !chkDebugger) && enabled;
234 }
235 #endif // _WIN32
236
237 return enabled;
238 }
239
SwrTrace(const char * pFileName,uint32_t lineNum,const char * pFunction,const char * pFmtString,...)240 void SwrTrace(
241 const char* pFileName,
242 uint32_t lineNum,
243 const char* pFunction,
244 const char* pFmtString,
245 ...)
246 {
247 using namespace ConsoleUtils;
248 std::lock_guard<std::mutex> l(g_stderrMutex);
249
250 SetTextColor(stderr, TextColor::CYAN, TextStyle::NORMAL);
251
252 fprintf(stderr, "%s(%d): TRACE in %s:\n", pFileName, lineNum, pFunction);
253
254 if (pFmtString)
255 {
256 SetTextColor(stderr, TextColor::PURPLE, TextStyle::INTENSITY);
257 fprintf(stderr, "\t");
258 va_list args;
259 va_start(args, pFmtString);
260 vfprintf(stderr, pFmtString, args);
261 va_end(args);
262 fprintf(stderr, "\n");
263 }
264 ResetTextColor(stderr);
265 fflush(stderr);
266
267 #if defined(_WIN32)
268 static const int MAX_MESSAGE_LEN = 2048;
269 char msgBuf[MAX_MESSAGE_LEN];
270
271 sprintf_s(msgBuf, "%s(%d): TRACE in %s\n", pFileName, lineNum, pFunction);
272 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
273 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
274 OutputDebugStringA(msgBuf);
275
276 int offset = 0;
277
278 if (pFmtString)
279 {
280 va_list args;
281 va_start(args, pFmtString);
282 offset = _vsnprintf_s(
283 msgBuf,
284 sizeof(msgBuf),
285 sizeof(msgBuf),
286 pFmtString,
287 args);
288 va_end(args);
289
290 if (offset < 0) { return; }
291
292 OutputDebugStringA("\t");
293 OutputDebugStringA(msgBuf);
294 OutputDebugStringA("\n");
295 }
296 #endif // _WIN32
297 }
298
299 #endif // SWR_ENABLE_ASSERTS
300