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