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