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