/**************************************************************************** * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. ****************************************************************************/ #include "common/os.h" #include #include #include #include #include #if SWR_ENABLE_ASSERTS || SWR_ENABLE_REL_ASSERTS #if defined(_WIN32) #pragma comment(lib, "user32.lib") #endif // _WIN32 enum TextColor { TEXT_BLACK = 0, TEXT_RED = 1, TEXT_GREEN = 2, TEXT_BLUE = 4, TEXT_PURPLE = TEXT_RED | TEXT_BLUE, TEXT_CYAN = TEXT_GREEN | TEXT_BLUE, TEXT_YELLOW = TEXT_RED | TEXT_GREEN, TEXT_WHITE = TEXT_RED | TEXT_GREEN | TEXT_BLUE, }; enum TextStyle { TEXT_NORMAL = 0, TEXT_INTENSITY = 1, }; void SetTextColor(FILE* stream, TextColor color = TEXT_WHITE, TextStyle style = TEXT_NORMAL) { #if defined(_WIN32) HANDLE hConsoleHandle = nullptr; if (stream == stderr) { hConsoleHandle = GetStdHandle(STD_ERROR_HANDLE); } else if (stream == stdout) { hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); } else { // Not a console stream, do nothing return; } WORD textAttributes = 0; if (color & TEXT_RED) { textAttributes |= FOREGROUND_RED; } if (color & TEXT_GREEN) { textAttributes |= FOREGROUND_GREEN; } if (color & TEXT_BLUE) { textAttributes |= FOREGROUND_BLUE; } if (style & TEXT_INTENSITY) { textAttributes |= FOREGROUND_INTENSITY; } SetConsoleTextAttribute(hConsoleHandle, textAttributes); #else // !_WIN32 // Print ANSI codes uint32_t cc = 30 + (style ? 60 : 0) + color; fprintf(stream, "\033[0m\033[%d;%dm", style, cc); #endif } void ResetTextColor(FILE* stream) { #if defined(_WIN32) SetTextColor(stream); #else // !_WIN32 // Print ANSI codes fprintf(stream, "\033[0m"); #endif } static std::mutex g_stderrMutex; void SwrTrace( const char* pFileName, uint32_t lineNum, const char* function, const char* pFmtString, ...) { std::lock_guard l(g_stderrMutex); SetTextColor(stderr, TEXT_CYAN, TEXT_NORMAL); fprintf(stderr, "%s(%d): TRACE in %s:\n", pFileName, lineNum, function); if (pFmtString) { SetTextColor(stderr, TEXT_PURPLE, TEXT_INTENSITY); fprintf(stderr, "\t"); va_list args; va_start(args, pFmtString); vfprintf(stderr, pFmtString, args); va_end(args); fprintf(stderr, "\n"); } ResetTextColor(stderr); fflush(stderr); #if defined(_WIN32) static const int MAX_MESSAGE_LEN = 2048; char msgBuf[MAX_MESSAGE_LEN]; sprintf_s(msgBuf, "%s(%d): TRACE in %s\n", pFileName, lineNum, function); msgBuf[MAX_MESSAGE_LEN - 2] = '\n'; msgBuf[MAX_MESSAGE_LEN - 1] = 0; OutputDebugStringA(msgBuf); int offset = 0; if (pFmtString) { va_list args; va_start(args, pFmtString); offset = _vsnprintf_s( msgBuf, sizeof(msgBuf), sizeof(msgBuf), pFmtString, args); va_end(args); if (offset < 0) { return; } OutputDebugStringA("\t"); OutputDebugStringA(msgBuf); OutputDebugStringA("\n"); } #endif // _WIN32 } bool SwrAssert( bool chkDebugger, bool& enabled, const char* pExpression, const char* pFileName, uint32_t lineNum, const char* pFunction, const char* pFmtString /* = nullptr */, ...) { { std::lock_guard l(g_stderrMutex); SetTextColor(stderr, TEXT_CYAN, TEXT_NORMAL); fprintf(stderr, "%s(%d): ", pFileName, lineNum); SetTextColor(stderr, TEXT_RED, TEXT_INTENSITY); fprintf(stderr, "ASSERT: %s\n", pExpression); SetTextColor(stderr, TEXT_CYAN, TEXT_INTENSITY); fprintf(stderr, "\t%s\n", pFunction); if (pFmtString) { SetTextColor(stderr, TEXT_YELLOW, TEXT_INTENSITY); fprintf(stderr, "\t"); va_list args; va_start(args, pFmtString); vfprintf(stderr, pFmtString, args); va_end(args); fprintf(stderr, "\n"); } ResetTextColor(stderr); fflush(stderr); } #if defined(_WIN32) static const int MAX_MESSAGE_LEN = 2048; char msgBuf[MAX_MESSAGE_LEN]; sprintf_s(msgBuf, "%s(%d): ASSERT: %s\n", pFileName, lineNum, pExpression); msgBuf[MAX_MESSAGE_LEN - 2] = '\n'; msgBuf[MAX_MESSAGE_LEN - 1] = 0; OutputDebugStringA(msgBuf); sprintf_s(msgBuf, "\t%s\n", pFunction); msgBuf[MAX_MESSAGE_LEN - 2] = '\n'; msgBuf[MAX_MESSAGE_LEN - 1] = 0; OutputDebugStringA(msgBuf); int offset = 0; if (pFmtString) { va_list args; va_start(args, pFmtString); offset = _vsnprintf_s( msgBuf, sizeof(msgBuf), sizeof(msgBuf), pFmtString, args); va_end(args); if (offset < 0) { return true; } OutputDebugStringA("\t"); OutputDebugStringA(msgBuf); OutputDebugStringA("\n"); } if (enabled && KNOB_ENABLE_ASSERT_DIALOGS) { int retval = sprintf_s( &msgBuf[offset], MAX_MESSAGE_LEN - offset, "\n\n" "File: %s\n" "Line: %d\n" "\n" "Expression: %s\n\n" "Cancel: Disable this assert for the remainder of the process\n" "Try Again: Break into the debugger\n" "Continue: Continue execution (but leave assert enabled)", pFileName, lineNum, pExpression); if (retval < 0) { return true; } offset += retval; if (!IsDebuggerPresent()) { sprintf_s( &msgBuf[offset], MAX_MESSAGE_LEN - offset, "\n\n*** NO DEBUGGER DETECTED ***\n\nPressing \"Try Again\" will cause a program crash!"); } retval = MessageBoxA(nullptr, msgBuf, "Assert Failed", MB_CANCELTRYCONTINUE | MB_ICONEXCLAMATION | MB_SETFOREGROUND); switch (retval) { case IDCANCEL: enabled = false; return false; case IDTRYAGAIN: return true; case IDCONTINUE: return false; } } else { return (IsDebuggerPresent() || !chkDebugger) && enabled; } #endif // _WIN32 return enabled; } #endif // SWR_ENABLE_ASSERTS