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