1 /* 2 * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2007-2009 Torch Mobile, Inc. 4 * Copyright (C) 2011 University of Szeged. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 // The vprintf_stderr_common function triggers this error in the Mac build. 29 // Feel free to remove this pragma if this file builds on Mac. 30 // According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas 31 // we need to place this directive before any data or functions are defined. 32 #pragma GCC diagnostic ignored "-Wmissing-format-attribute" 33 34 #include "config.h" 35 #include "Assertions.h" 36 37 #include "Compiler.h" 38 #include "OwnArrayPtr.h" 39 40 #include <stdio.h> 41 #include <stdarg.h> 42 #include <string.h> 43 44 #if HAVE(SIGNAL_H) 45 #include <signal.h> 46 #endif 47 48 #if USE(CF) 49 #include <AvailabilityMacros.h> 50 #include <CoreFoundation/CFString.h> 51 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 52 #define WTF_USE_APPLE_SYSTEM_LOG 1 53 #include <asl.h> 54 #endif 55 #endif // USE(CF) 56 57 #if COMPILER(MSVC) 58 #include <crtdbg.h> 59 #endif 60 61 #if OS(WINDOWS) 62 #include <windows.h> 63 #endif 64 65 #if (OS(DARWIN) || (OS(LINUX) && !defined(__UCLIBC__))) && !OS(ANDROID) 66 #include <cxxabi.h> 67 #include <dlfcn.h> 68 #include <execinfo.h> 69 #endif 70 71 #if OS(ANDROID) 72 #include "android/log.h" 73 #endif 74 75 extern "C" { 76 77 WTF_ATTRIBUTE_PRINTF(1, 0) 78 static void vprintf_stderr_common(const char* format, va_list args) 79 { 80 #if USE(CF) && !OS(WINDOWS) 81 if (strstr(format, "%@")) { 82 CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8); 83 84 #if COMPILER(CLANG) 85 #pragma clang diagnostic push 86 #pragma clang diagnostic ignored "-Wformat-nonliteral" 87 #endif 88 CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args); 89 #if COMPILER(CLANG) 90 #pragma clang diagnostic pop 91 #endif 92 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8); 93 char* buffer = (char*)malloc(length + 1); 94 95 CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8); 96 97 #if USE(APPLE_SYSTEM_LOG) 98 asl_log(0, 0, ASL_LEVEL_NOTICE, "%s", buffer); 99 #endif 100 fputs(buffer, stderr); 101 102 free(buffer); 103 CFRelease(str); 104 CFRelease(cfFormat); 105 return; 106 } 107 108 #if USE(APPLE_SYSTEM_LOG) 109 va_list copyOfArgs; 110 va_copy(copyOfArgs, args); 111 asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs); 112 va_end(copyOfArgs); 113 #endif 114 115 // Fall through to write to stderr in the same manner as other platforms. 116 117 #elif OS(ANDROID) 118 __android_log_vprint(ANDROID_LOG_WARN, "WebKit", format, args); 119 #elif HAVE(ISDEBUGGERPRESENT) 120 if (IsDebuggerPresent()) { 121 size_t size = 1024; 122 123 do { 124 char* buffer = (char*)malloc(size); 125 126 if (buffer == NULL) 127 break; 128 129 if (_vsnprintf(buffer, size, format, args) != -1) { 130 OutputDebugStringA(buffer); 131 free(buffer); 132 break; 133 } 134 135 free(buffer); 136 size *= 2; 137 } while (size > 1024); 138 } 139 #endif 140 vfprintf(stderr, format, args); 141 } 142 143 #if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0)) 144 #pragma GCC diagnostic push 145 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 146 #endif 147 148 static void vprintf_stderr_with_prefix(const char* prefix, const char* format, va_list args) 149 { 150 size_t prefixLength = strlen(prefix); 151 size_t formatLength = strlen(format); 152 OwnArrayPtr<char> formatWithPrefix = adoptArrayPtr(new char[prefixLength + formatLength + 1]); 153 memcpy(formatWithPrefix.get(), prefix, prefixLength); 154 memcpy(formatWithPrefix.get() + prefixLength, format, formatLength); 155 formatWithPrefix[prefixLength + formatLength] = 0; 156 157 vprintf_stderr_common(formatWithPrefix.get(), args); 158 } 159 160 static void vprintf_stderr_with_trailing_newline(const char* format, va_list args) 161 { 162 size_t formatLength = strlen(format); 163 if (formatLength && format[formatLength - 1] == '\n') { 164 vprintf_stderr_common(format, args); 165 return; 166 } 167 168 OwnArrayPtr<char> formatWithNewline = adoptArrayPtr(new char[formatLength + 2]); 169 memcpy(formatWithNewline.get(), format, formatLength); 170 formatWithNewline[formatLength] = '\n'; 171 formatWithNewline[formatLength + 1] = 0; 172 173 vprintf_stderr_common(formatWithNewline.get(), args); 174 } 175 176 #if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0)) 177 #pragma GCC diagnostic pop 178 #endif 179 180 WTF_ATTRIBUTE_PRINTF(1, 2) 181 static void printf_stderr_common(const char* format, ...) 182 { 183 va_list args; 184 va_start(args, format); 185 vprintf_stderr_common(format, args); 186 va_end(args); 187 } 188 189 static void printCallSite(const char* file, int line, const char* function) 190 { 191 #if OS(WINDOWS) && defined(_DEBUG) 192 _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function); 193 #else 194 // By using this format, which matches the format used by MSVC for compiler errors, developers 195 // using Visual Studio can double-click the file/line number in the Output Window to have the 196 // editor navigate to that line of code. It seems fine for other developers, too. 197 printf_stderr_common("%s(%d) : %s\n", file, line, function); 198 #endif 199 } 200 201 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion) 202 { 203 if (assertion) 204 printf_stderr_common("ASSERTION FAILED: %s\n", assertion); 205 else 206 printf_stderr_common("SHOULD NEVER BE REACHED\n"); 207 printCallSite(file, line, function); 208 } 209 210 void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) 211 { 212 va_list args; 213 va_start(args, format); 214 vprintf_stderr_with_prefix("ASSERTION FAILED: ", format, args); 215 va_end(args); 216 printf_stderr_common("\n%s\n", assertion); 217 printCallSite(file, line, function); 218 } 219 220 void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion) 221 { 222 printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion); 223 printCallSite(file, line, function); 224 } 225 226 void WTFGetBacktrace(void** stack, int* size) 227 { 228 #if (OS(DARWIN) || (OS(LINUX) && !defined(__UCLIBC__))) && !OS(ANDROID) 229 *size = backtrace(stack, *size); 230 #elif OS(WINDOWS) 231 // The CaptureStackBackTrace function is available in XP, but it is not defined 232 // in the Windows Server 2003 R2 Platform SDK. So, we'll grab the function 233 // through GetProcAddress. 234 typedef WORD (NTAPI* RtlCaptureStackBackTraceFunc)(DWORD, DWORD, PVOID*, PDWORD); 235 HMODULE kernel32 = ::GetModuleHandleW(L"Kernel32.dll"); 236 if (!kernel32) { 237 *size = 0; 238 return; 239 } 240 RtlCaptureStackBackTraceFunc captureStackBackTraceFunc = reinterpret_cast<RtlCaptureStackBackTraceFunc>( 241 ::GetProcAddress(kernel32, "RtlCaptureStackBackTrace")); 242 if (captureStackBackTraceFunc) 243 *size = captureStackBackTraceFunc(0, *size, stack, 0); 244 else 245 *size = 0; 246 #else 247 *size = 0; 248 #endif 249 } 250 251 void WTFReportBacktrace() 252 { 253 static const int framesToShow = 31; 254 static const int framesToSkip = 2; 255 void* samples[framesToShow + framesToSkip]; 256 int frames = framesToShow + framesToSkip; 257 258 WTFGetBacktrace(samples, &frames); 259 WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip); 260 } 261 262 void WTFPrintBacktrace(void** stack, int size) 263 { 264 for (int i = 0; i < size; ++i) { 265 const char* mangledName = 0; 266 char* cxaDemangled = 0; 267 #if OS(DARWIN) || (OS(LINUX) && !OS(ANDROID)) 268 Dl_info info; 269 if (dladdr(stack[i], &info) && info.dli_sname) 270 mangledName = info.dli_sname; 271 if (mangledName) 272 cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0); 273 #endif 274 const int frameNumber = i + 1; 275 if (mangledName || cxaDemangled) 276 printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName); 277 else 278 printf_stderr_common("%-3d %p\n", frameNumber, stack[i]); 279 free(cxaDemangled); 280 } 281 } 282 283 static WTFCrashHookFunction globalHook = 0; 284 285 void WTFSetCrashHook(WTFCrashHookFunction function) 286 { 287 globalHook = function; 288 } 289 290 void WTFInvokeCrashHook() 291 { 292 if (globalHook) 293 globalHook(); 294 } 295 296 #if HAVE(SIGNAL_H) 297 static NO_RETURN void dumpBacktraceSignalHandler(int sig) 298 { 299 WTFReportBacktrace(); 300 exit(128 + sig); 301 } 302 303 static void installSignalHandlersForFatalErrors(void (*handler)(int)) 304 { 305 signal(SIGILL, handler); // 4: illegal instruction (not reset when caught). 306 signal(SIGTRAP, handler); // 5: trace trap (not reset when caught). 307 signal(SIGFPE, handler); // 8: floating point exception. 308 signal(SIGBUS, handler); // 10: bus error. 309 signal(SIGSEGV, handler); // 11: segmentation violation. 310 signal(SIGSYS, handler); // 12: bad argument to system call. 311 signal(SIGPIPE, handler); // 13: write on a pipe with no reader. 312 signal(SIGXCPU, handler); // 24: exceeded CPU time limit. 313 signal(SIGXFSZ, handler); // 25: exceeded file size limit. 314 } 315 316 static void resetSignalHandlersForFatalErrors() 317 { 318 installSignalHandlersForFatalErrors(SIG_DFL); 319 } 320 #endif 321 322 void WTFInstallReportBacktraceOnCrashHook() 323 { 324 #if HAVE(SIGNAL_H) 325 // Needed otherwise we are going to dump the stack trace twice 326 // in case we hit an assertion. 327 WTFSetCrashHook(&resetSignalHandlersForFatalErrors); 328 installSignalHandlersForFatalErrors(&dumpBacktraceSignalHandler); 329 #endif 330 } 331 332 void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) 333 { 334 va_list args; 335 va_start(args, format); 336 vprintf_stderr_with_prefix("FATAL ERROR: ", format, args); 337 va_end(args); 338 printf_stderr_common("\n"); 339 printCallSite(file, line, function); 340 } 341 342 void WTFReportError(const char* file, int line, const char* function, const char* format, ...) 343 { 344 va_list args; 345 va_start(args, format); 346 vprintf_stderr_with_prefix("ERROR: ", format, args); 347 va_end(args); 348 printf_stderr_common("\n"); 349 printCallSite(file, line, function); 350 } 351 352 void WTFLog(WTFLogChannel* channel, const char* format, ...) 353 { 354 if (channel->state != WTFLogChannelOn) 355 return; 356 357 va_list args; 358 va_start(args, format); 359 vprintf_stderr_with_trailing_newline(format, args); 360 va_end(args); 361 } 362 363 void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) 364 { 365 if (channel->state != WTFLogChannelOn) 366 return; 367 368 va_list args; 369 va_start(args, format); 370 vprintf_stderr_with_trailing_newline(format, args); 371 va_end(args); 372 373 printCallSite(file, line, function); 374 } 375 376 void WTFLogAlways(const char* format, ...) 377 { 378 va_list args; 379 va_start(args, format); 380 vprintf_stderr_with_trailing_newline(format, args); 381 va_end(args); 382 } 383 384 } // extern "C" 385