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 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 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 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 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