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 #if OS(ANDROID)
     70 #include <utils/Log.h>
     71 #endif
     72 
     73 extern "C" {
     74 
     75 #if PLATFORM(BREWMP)
     76 
     77 static void printLog(const Vector<char>& buffer)
     78 {
     79     // Each call to DBGPRINTF generates at most 128 bytes of output on the Windows SDK.
     80     // On Qualcomm chipset targets, DBGPRINTF() comes out the diag port (though this may change).
     81     // The length of each output string is constrained even more than on the Windows SDK.
     82 #if COMPILER(MSVC)
     83     const int printBufferSize = 128;
     84 #else
     85     const int printBufferSize = 32;
     86 #endif
     87 
     88     char printBuffer[printBufferSize + 1];
     89     printBuffer[printBufferSize] = 0; // to guarantee null termination
     90 
     91     const char* p = buffer.data();
     92     const char* end = buffer.data() + buffer.size();
     93     while (p < end) {
     94         strncpy(printBuffer, p, printBufferSize);
     95         dbg_Message(printBuffer, DBG_MSG_LEVEL_HIGH, __FILE__, __LINE__);
     96         p += printBufferSize;
     97     }
     98 }
     99 
    100 #endif
    101 
    102 WTF_ATTRIBUTE_PRINTF(1, 0)
    103 static void vprintf_stderr_common(const char* format, va_list args)
    104 {
    105 #if PLATFORM(MAC)
    106     if (strstr(format, "%@")) {
    107         CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);
    108         CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
    109 
    110         int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
    111         char* buffer = (char*)malloc(length + 1);
    112 
    113         CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);
    114 
    115         fputs(buffer, stderr);
    116 
    117         free(buffer);
    118         CFRelease(str);
    119         CFRelease(cfFormat);
    120         return;
    121     }
    122 #elif PLATFORM(BREWMP)
    123     // When str is 0, the return value is the number of bytes needed
    124     // to accept the result including null termination.
    125     int size = vsnprintf(0, 0, format, args);
    126     if (size > 0) {
    127         Vector<char> buffer(size);
    128         vsnprintf(buffer.data(), size, format, args);
    129         printLog(buffer);
    130     }
    131 #elif OS(ANDROID)
    132     LOG_PRI_VA(ANDROID_LOG_DEBUG, "WebKit", format, args);
    133     return;
    134 #elif HAVE(ISDEBUGGERPRESENT)
    135     if (IsDebuggerPresent()) {
    136         size_t size = 1024;
    137 
    138         do {
    139             char* buffer = (char*)malloc(size);
    140 
    141             if (buffer == NULL)
    142                 break;
    143 
    144             if (_vsnprintf(buffer, size, format, args) != -1) {
    145 #if OS(WINCE)
    146                 // WinCE only supports wide chars
    147                 wchar_t* wideBuffer = (wchar_t*)malloc(size * sizeof(wchar_t));
    148                 if (wideBuffer == NULL)
    149                     break;
    150                 for (unsigned int i = 0; i < size; ++i) {
    151                     if (!(wideBuffer[i] = buffer[i]))
    152                         break;
    153                 }
    154                 OutputDebugStringW(wideBuffer);
    155                 free(wideBuffer);
    156 #else
    157                 OutputDebugStringA(buffer);
    158 #endif
    159                 free(buffer);
    160                 break;
    161             }
    162 
    163             free(buffer);
    164             size *= 2;
    165         } while (size > 1024);
    166     }
    167 #endif
    168 #if OS(SYMBIAN)
    169     vfprintf(stdout, format, args);
    170 #else
    171     vfprintf(stderr, format, args);
    172 #endif
    173 }
    174 
    175 WTF_ATTRIBUTE_PRINTF(1, 2)
    176 static void printf_stderr_common(const char* format, ...)
    177 {
    178     va_list args;
    179     va_start(args, format);
    180     vprintf_stderr_common(format, args);
    181     va_end(args);
    182 }
    183 
    184 static void printCallSite(const char* file, int line, const char* function)
    185 {
    186 #if OS(WINDOWS) && !OS(WINCE) && defined(_DEBUG)
    187     _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
    188 #else
    189     // By using this format, which matches the format used by MSVC for compiler errors, developers
    190     // using Visual Studio can double-click the file/line number in the Output Window to have the
    191     // editor navigate to that line of code. It seems fine for other developers, too.
    192     printf_stderr_common("%s(%d) : %s\n", file, line, function);
    193 #endif
    194 }
    195 
    196 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
    197 {
    198     if (assertion)
    199         printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
    200     else
    201         printf_stderr_common("SHOULD NEVER BE REACHED\n");
    202     printCallSite(file, line, function);
    203 }
    204 
    205 void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
    206 {
    207     printf_stderr_common("ASSERTION FAILED: ");
    208     va_list args;
    209     va_start(args, format);
    210     vprintf_stderr_common(format, args);
    211     va_end(args);
    212     printf_stderr_common("\n%s\n", assertion);
    213     printCallSite(file, line, function);
    214 }
    215 
    216 void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
    217 {
    218     printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
    219     printCallSite(file, line, function);
    220 }
    221 
    222 void WTFReportBacktrace()
    223 {
    224 #if PLATFORM(MAC)
    225     static const int maxFrames = 32;
    226     void* samples[maxFrames];
    227     int frames = backtrace(samples, maxFrames);
    228 
    229     for (int i = 1; i < frames; ++i) {
    230         void* pointer = samples[i];
    231 
    232         // Try to get a symbol name from the dynamic linker.
    233         Dl_info info;
    234         if (dladdr(pointer, &info) && info.dli_sname) {
    235             const char* mangledName = info.dli_sname;
    236 
    237             // Assume c++ & try to demangle the name.
    238             char* demangledName = abi::__cxa_demangle(mangledName, 0, 0, 0);
    239             if (demangledName) {
    240                 fprintf(stderr, "%-3d %s\n", i, demangledName);
    241                 free(demangledName);
    242             } else
    243                 fprintf(stderr, "%-3d %s\n", i, mangledName);
    244         } else
    245             fprintf(stderr, "%-3d %p\n", i, pointer);
    246     }
    247 #endif
    248 }
    249 
    250 void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
    251 {
    252     printf_stderr_common("FATAL ERROR: ");
    253     va_list args;
    254     va_start(args, format);
    255     vprintf_stderr_common(format, args);
    256     va_end(args);
    257     printf_stderr_common("\n");
    258     printCallSite(file, line, function);
    259 }
    260 
    261 void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
    262 {
    263     printf_stderr_common("ERROR: ");
    264     va_list args;
    265     va_start(args, format);
    266     vprintf_stderr_common(format, args);
    267     va_end(args);
    268     printf_stderr_common("\n");
    269     printCallSite(file, line, function);
    270 }
    271 
    272 void WTFLog(WTFLogChannel* channel, const char* format, ...)
    273 {
    274     if (channel->state != WTFLogChannelOn)
    275         return;
    276 
    277     va_list args;
    278     va_start(args, format);
    279     vprintf_stderr_common(format, args);
    280     va_end(args);
    281     if (format[strlen(format) - 1] != '\n')
    282         printf_stderr_common("\n");
    283 }
    284 
    285 void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
    286 {
    287     if (channel->state != WTFLogChannelOn)
    288         return;
    289 
    290     va_list args;
    291     va_start(args, format);
    292     vprintf_stderr_common(format, args);
    293     va_end(args);
    294     if (format[strlen(format) - 1] != '\n')
    295         printf_stderr_common("\n");
    296     printCallSite(file, line, function);
    297 }
    298 
    299 } // extern "C"
    300