Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2003, 2006, 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2007-2009 Torch Mobile, Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 // The vprintf_stderr_common function triggers this error in the Mac build.
     28 // Feel free to remove this pragma if this file builds on Mac.
     29 // According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
     30 // we need to place this directive before any data or functions are defined.
     31 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
     32 
     33 #include "config.h"
     34 #include "Assertions.h"
     35 
     36 #include <stdio.h>
     37 #include <stdarg.h>
     38 #include <string.h>
     39 
     40 #if PLATFORM(MAC)
     41 #include <CoreFoundation/CFString.h>
     42 #endif
     43 
     44 #if COMPILER(MSVC) && !OS(WINCE) && !PLATFORM(BREWMP)
     45 #ifndef WINVER
     46 #define WINVER 0x0500
     47 #endif
     48 #ifndef _WIN32_WINNT
     49 #define _WIN32_WINNT 0x0500
     50 #endif
     51 #include <crtdbg.h>
     52 #endif
     53 
     54 #if OS(WINDOWS)
     55 #include <windows.h>
     56 #endif
     57 
     58 #if PLATFORM(BREWMP)
     59 #include <AEEdbg.h>
     60 #include <wtf/Vector.h>
     61 #endif
     62 
     63 #if PLATFORM(MAC)
     64 #include <cxxabi.h>
     65 #include <dlfcn.h>
     66 #include <execinfo.h>
     67 #endif
     68 
     69 extern "C" {
     70 
     71 #if PLATFORM(BREWMP)
     72 
     73 static void printLog(const Vector<char>& buffer)
     74 {
     75     // Each call to DBGPRINTF generates at most 128 bytes of output on the Windows SDK.
     76     // On Qualcomm chipset targets, DBGPRINTF() comes out the diag port (though this may change).
     77     // The length of each output string is constrained even more than on the Windows SDK.
     78 #if COMPILER(MSVC)
     79     const int printBufferSize = 128;
     80 #else
     81     const int printBufferSize = 32;
     82 #endif
     83 
     84     char printBuffer[printBufferSize + 1];
     85     printBuffer[printBufferSize] = 0; // to guarantee null termination
     86 
     87     const char* p = buffer.data();
     88     const char* end = buffer.data() + buffer.size();
     89     while (p < end) {
     90         strncpy(printBuffer, p, printBufferSize);
     91         dbg_Message(printBuffer, DBG_MSG_LEVEL_HIGH, __FILE__, __LINE__);
     92         p += printBufferSize;
     93     }
     94 }
     95 
     96 #endif
     97 
     98 WTF_ATTRIBUTE_PRINTF(1, 0)
     99 static void vprintf_stderr_common(const char* format, va_list args)
    100 {
    101 #if PLATFORM(MAC)
    102     if (strstr(format, "%@")) {
    103         CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);
    104         CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
    105 
    106         int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
    107         char* buffer = (char*)malloc(length + 1);
    108 
    109         CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);
    110 
    111         fputs(buffer, stderr);
    112 
    113         free(buffer);
    114         CFRelease(str);
    115         CFRelease(cfFormat);
    116         return;
    117     }
    118 #elif PLATFORM(BREWMP)
    119     // When str is 0, the return value is the number of bytes needed
    120     // to accept the result including null termination.
    121     int size = vsnprintf(0, 0, format, args);
    122     if (size > 0) {
    123         Vector<char> buffer(size);
    124         vsnprintf(buffer.data(), size, format, args);
    125         printLog(buffer);
    126     }
    127 
    128 #elif HAVE(ISDEBUGGERPRESENT)
    129     if (IsDebuggerPresent()) {
    130         size_t size = 1024;
    131 
    132         do {
    133             char* buffer = (char*)malloc(size);
    134 
    135             if (buffer == NULL)
    136                 break;
    137 
    138             if (_vsnprintf(buffer, size, format, args) != -1) {
    139 #if OS(WINCE)
    140                 // WinCE only supports wide chars
    141                 wchar_t* wideBuffer = (wchar_t*)malloc(size * sizeof(wchar_t));
    142                 if (wideBuffer == NULL)
    143                     break;
    144                 for (unsigned int i = 0; i < size; ++i) {
    145                     if (!(wideBuffer[i] = buffer[i]))
    146                         break;
    147                 }
    148                 OutputDebugStringW(wideBuffer);
    149                 free(wideBuffer);
    150 #else
    151                 OutputDebugStringA(buffer);
    152 #endif
    153                 free(buffer);
    154                 break;
    155             }
    156 
    157             free(buffer);
    158             size *= 2;
    159         } while (size > 1024);
    160     }
    161 #endif
    162 #if OS(SYMBIAN)
    163     vfprintf(stdout, format, args);
    164 #else
    165     vfprintf(stderr, format, args);
    166 #endif
    167 }
    168 
    169 WTF_ATTRIBUTE_PRINTF(1, 2)
    170 static void printf_stderr_common(const char* format, ...)
    171 {
    172     va_list args;
    173     va_start(args, format);
    174     vprintf_stderr_common(format, args);
    175     va_end(args);
    176 }
    177 
    178 static void printCallSite(const char* file, int line, const char* function)
    179 {
    180 #if OS(WINDOWS) && !OS(WINCE) && defined(_DEBUG)
    181     _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
    182 #else
    183     // By using this format, which matches the format used by MSVC for compiler errors, developers
    184     // using Visual Studio can double-click the file/line number in the Output Window to have the
    185     // editor navigate to that line of code. It seems fine for other developers, too.
    186     printf_stderr_common("%s(%d) : %s\n", file, line, function);
    187 #endif
    188 }
    189 
    190 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
    191 {
    192     if (assertion)
    193         printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
    194     else
    195         printf_stderr_common("SHOULD NEVER BE REACHED\n");
    196     printCallSite(file, line, function);
    197 }
    198 
    199 void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
    200 {
    201     printf_stderr_common("ASSERTION FAILED: ");
    202     va_list args;
    203     va_start(args, format);
    204     vprintf_stderr_common(format, args);
    205     va_end(args);
    206     printf_stderr_common("\n%s\n", assertion);
    207     printCallSite(file, line, function);
    208 }
    209 
    210 void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
    211 {
    212     printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
    213     printCallSite(file, line, function);
    214 }
    215 
    216 void WTFReportBacktrace()
    217 {
    218 #if PLATFORM(MAC)
    219     static const int maxFrames = 32;
    220     void* samples[maxFrames];
    221     int frames = backtrace(samples, maxFrames);
    222 
    223     for (int i = 1; i < frames; ++i) {
    224         void* pointer = samples[i];
    225 
    226         // Try to get a symbol name from the dynamic linker.
    227         Dl_info info;
    228         if (dladdr(pointer, &info) && info.dli_sname) {
    229             const char* mangledName = info.dli_sname;
    230 
    231             // Assume c++ & try to demangle the name.
    232             char* demangledName = abi::__cxa_demangle(mangledName, 0, 0, 0);
    233             if (demangledName) {
    234                 fprintf(stderr, "%-3d %s\n", i, demangledName);
    235                 free(demangledName);
    236             } else
    237                 fprintf(stderr, "%-3d %s\n", i, mangledName);
    238         } else
    239             fprintf(stderr, "%-3d %p\n", i, pointer);
    240     }
    241 #endif
    242 }
    243 
    244 void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
    245 {
    246     printf_stderr_common("FATAL ERROR: ");
    247     va_list args;
    248     va_start(args, format);
    249     vprintf_stderr_common(format, args);
    250     va_end(args);
    251     printf_stderr_common("\n");
    252     printCallSite(file, line, function);
    253 }
    254 
    255 void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
    256 {
    257     printf_stderr_common("ERROR: ");
    258     va_list args;
    259     va_start(args, format);
    260     vprintf_stderr_common(format, args);
    261     va_end(args);
    262     printf_stderr_common("\n");
    263     printCallSite(file, line, function);
    264 }
    265 
    266 void WTFLog(WTFLogChannel* channel, const char* format, ...)
    267 {
    268     if (channel->state != WTFLogChannelOn)
    269         return;
    270 
    271     va_list args;
    272     va_start(args, format);
    273     vprintf_stderr_common(format, args);
    274     va_end(args);
    275     if (format[strlen(format) - 1] != '\n')
    276         printf_stderr_common("\n");
    277 }
    278 
    279 void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
    280 {
    281     if (channel->state != WTFLogChannelOn)
    282         return;
    283 
    284     va_list args;
    285     va_start(args, format);
    286     vprintf_stderr_common(format, args);
    287     va_end(args);
    288     if (format[strlen(format) - 1] != '\n')
    289         printf_stderr_common("\n");
    290     printCallSite(file, line, function);
    291 }
    292 
    293 } // extern "C"
    294