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