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