CrashHandler.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright 2014 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "tools/CrashHandler.h"
  8. #include "src/core/SkLeanWindows.h"
  9. #include <stdlib.h>
  10. #if defined(SK_BUILD_FOR_GOOGLE3)
  11. #include "base/process_state.h"
  12. void SetupCrashHandler() { InstallSignalHandlers(); }
  13. #else
  14. #if defined(SK_BUILD_FOR_MAC)
  15. // We only use local unwinding, so we can define this to select a faster implementation.
  16. #define UNW_LOCAL_ONLY
  17. #include <libunwind.h>
  18. #include <cxxabi.h>
  19. static void handler(int sig) {
  20. unw_context_t context;
  21. unw_getcontext(&context);
  22. unw_cursor_t cursor;
  23. unw_init_local(&cursor, &context);
  24. SkDebugf("\nSignal %d:\n", sig);
  25. while (unw_step(&cursor) > 0) {
  26. static const size_t kMax = 256;
  27. char mangled[kMax], demangled[kMax];
  28. unw_word_t offset;
  29. unw_get_proc_name(&cursor, mangled, kMax, &offset);
  30. int ok;
  31. size_t len = kMax;
  32. abi::__cxa_demangle(mangled, demangled, &len, &ok);
  33. SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
  34. }
  35. SkDebugf("\n");
  36. // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
  37. _Exit(sig);
  38. }
  39. #elif defined(SK_BUILD_FOR_UNIX)
  40. // We'd use libunwind here too, but it's a pain to get installed for
  41. // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway.
  42. #include <cxxabi.h>
  43. #include <dlfcn.h>
  44. #include <execinfo.h>
  45. #include <string.h>
  46. static void handler(int sig) {
  47. void* stack[64];
  48. const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
  49. char** symbols = backtrace_symbols(stack, count);
  50. SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
  51. for (int i = 0; i < count; i++) {
  52. Dl_info info;
  53. if (dladdr(stack[i], &info) && info.dli_sname) {
  54. char demangled[256];
  55. size_t len = SK_ARRAY_COUNT(demangled);
  56. int ok;
  57. abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
  58. if (ok == 0) {
  59. SkDebugf(" %s\n", demangled);
  60. continue;
  61. }
  62. }
  63. SkDebugf(" %s\n", symbols[i]);
  64. }
  65. // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
  66. _Exit(sig);
  67. }
  68. #endif
  69. #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
  70. #include <signal.h>
  71. void SetupCrashHandler() {
  72. static const int kSignals[] = {
  73. SIGABRT,
  74. SIGBUS,
  75. SIGFPE,
  76. SIGILL,
  77. SIGSEGV,
  78. SIGTRAP,
  79. };
  80. for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
  81. // Register our signal handler unless something's already done so (e.g. catchsegv).
  82. void (*prev)(int) = signal(kSignals[i], handler);
  83. if (prev != SIG_DFL) {
  84. signal(kSignals[i], prev);
  85. }
  86. }
  87. }
  88. #elif defined(SK_BUILD_FOR_WIN)
  89. #include <DbgHelp.h>
  90. #include "include/private/SkMalloc.h"
  91. static const struct {
  92. const char* name;
  93. const DWORD code;
  94. } kExceptions[] = {
  95. #define _(E) {#E, E}
  96. _(EXCEPTION_ACCESS_VIOLATION),
  97. _(EXCEPTION_BREAKPOINT),
  98. _(EXCEPTION_INT_DIVIDE_BY_ZERO),
  99. _(EXCEPTION_STACK_OVERFLOW),
  100. // TODO: more?
  101. #undef _
  102. };
  103. static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
  104. const DWORD code = e->ExceptionRecord->ExceptionCode;
  105. SkDebugf("\nCaught exception %u", code);
  106. for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
  107. if (kExceptions[i].code == code) {
  108. SkDebugf(" %s", kExceptions[i].name);
  109. }
  110. }
  111. SkDebugf("\n");
  112. // We need to run SymInitialize before doing any of the stack walking below.
  113. HANDLE hProcess = GetCurrentProcess();
  114. SymInitialize(hProcess, 0, true);
  115. STACKFRAME64 frame;
  116. sk_bzero(&frame, sizeof(frame));
  117. // Start frame off from the frame that triggered the exception.
  118. CONTEXT* c = e->ContextRecord;
  119. frame.AddrPC.Mode = AddrModeFlat;
  120. frame.AddrStack.Mode = AddrModeFlat;
  121. frame.AddrFrame.Mode = AddrModeFlat;
  122. #if defined(_X86_)
  123. frame.AddrPC.Offset = c->Eip;
  124. frame.AddrStack.Offset = c->Esp;
  125. frame.AddrFrame.Offset = c->Ebp;
  126. const DWORD machineType = IMAGE_FILE_MACHINE_I386;
  127. #elif defined(_AMD64_)
  128. frame.AddrPC.Offset = c->Rip;
  129. frame.AddrStack.Offset = c->Rsp;
  130. frame.AddrFrame.Offset = c->Rbp;
  131. const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
  132. #elif defined(_M_ARM64)
  133. frame.AddrPC.Offset = c->Pc;
  134. frame.AddrStack.Offset = c->Sp;
  135. frame.AddrFrame.Offset = c->Fp;
  136. const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
  137. #endif
  138. while (StackWalk64(machineType,
  139. GetCurrentProcess(),
  140. GetCurrentThread(),
  141. &frame,
  142. c,
  143. nullptr,
  144. SymFunctionTableAccess64,
  145. SymGetModuleBase64,
  146. nullptr)) {
  147. // Buffer to store symbol name in.
  148. static const int kMaxNameLength = 1024;
  149. uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
  150. sk_bzero(buffer, sizeof(buffer));
  151. // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
  152. // how much space it can use.
  153. IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
  154. symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
  155. symbol->MaxNameLength = kMaxNameLength - 1;
  156. // Translate the current PC into a symbol and byte offset from the symbol.
  157. DWORD64 offset;
  158. SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
  159. SkDebugf("%s +%x\n", symbol->Name, offset);
  160. }
  161. // Exit NOW. Don't notify other threads, don't call anything registered with atexit().
  162. _exit(1);
  163. // The compiler wants us to return something. This is what we'd do
  164. // if we didn't _exit().
  165. return EXCEPTION_EXECUTE_HANDLER;
  166. }
  167. void SetupCrashHandler() {
  168. SetUnhandledExceptionFilter(handler);
  169. }
  170. #else
  171. void SetupCrashHandler() { }
  172. #endif
  173. #endif // SK_BUILD_FOR_GOOGLE3?