Home | History | Annotate | Download | only in common
      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