• 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/config.h"   // May define GOOGLE_ENABLE_SIGNAL_HANDLERS.
16 #endif
17 
18 #if defined(GOOGLE_ENABLE_SIGNAL_HANDLERS)
19     #include "base/process_state.h"
SetupCrashHandler()20     void SetupCrashHandler() { InstallSignalHandlers(); }
21 
22 #else
23 
24     #if defined(SK_BUILD_FOR_MAC)
25         // We only use local unwinding, so we can define this to select a faster implementation.
26         #define UNW_LOCAL_ONLY
27         #include <libunwind.h>
28         #include <cxxabi.h>
29 
handler(int sig)30         static void handler(int sig) {
31             unw_context_t context;
32             unw_getcontext(&context);
33 
34             unw_cursor_t cursor;
35             unw_init_local(&cursor, &context);
36 
37             SkDebugf("\nSignal %d:\n", sig);
38             while (unw_step(&cursor) > 0) {
39                 static const size_t kMax = 256;
40                 char mangled[kMax], demangled[kMax];
41                 unw_word_t offset;
42                 unw_get_proc_name(&cursor, mangled, kMax, &offset);
43 
44                 int ok;
45                 size_t len = kMax;
46                 abi::__cxa_demangle(mangled, demangled, &len, &ok);
47 
48                 SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
49             }
50             SkDebugf("\n");
51 
52             // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
53             _Exit(sig);
54         }
55 
56     #elif defined(SK_BUILD_FOR_UNIX)
57         // We'd use libunwind here too, but it's a pain to get installed for
58         // both 32 and 64 bit on bots.  Doesn't matter much: catchsegv is best anyway.
59         #include <cxxabi.h>
60         #include <dlfcn.h>
61         #include <string.h>
62 #if defined(__Fuchsia__)
63         #include <stdint.h>
64 
65         // syslog crash reporting from Fuchsia's backtrace_request.h
66         //
67         // Special value we put in the first register to let the exception handler know
68         // that we are just requesting a backtrace and we should resume the thread.
69         #define BACKTRACE_REQUEST_MAGIC ((uint64_t)0xee726573756d65ee)
70 
71         // Prints a backtrace, resuming the thread without killing the process.
backtrace_request(void)72         __attribute__((always_inline)) static inline void backtrace_request(void) {
73           // Two instructions: one that sets a software breakpoint ("int3" on x64,
74           // "brk" on arm64) and one that writes the "magic" value in the first
75           // register ("a" on x64, "x0" on arm64).
76           //
77           // We set a software breakpoint to trigger the exception handling in
78           // crashsvc, which will print the debug info, including the backtrace.
79           //
80           // We write the "magic" value in the first register so that the exception
81           // handler can check for it and resume the thread if present.
82           #ifdef __x86_64__
83             __asm__("int3" : : "a"(BACKTRACE_REQUEST_MAGIC));
84           #endif
85           #ifdef __aarch64__
86             // This is what gdb uses.
87             __asm__(
88                 "mov x0, %0\n"
89                 "\tbrk 0"
90                 :
91                 : "r"(BACKTRACE_REQUEST_MAGIC)
92                 : "x0");
93           #endif
94         }
95 #else
96         #include <execinfo.h>
97 #endif
98 
handler(int sig)99         static void handler(int sig) {
100 #if defined(__Fuchsia__)
101             backtrace_request();
102 #else
103             void* stack[64];
104             const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
105             char** symbols = backtrace_symbols(stack, count);
106 
107             SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
108             for (int i = 0; i < count; i++) {
109                 Dl_info info;
110                 if (dladdr(stack[i], &info) && info.dli_sname) {
111                     char demangled[256];
112                     size_t len = SK_ARRAY_COUNT(demangled);
113                     int ok;
114 
115                     abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
116                     if (ok == 0) {
117                         SkDebugf("    %s\n", demangled);
118                         continue;
119                     }
120                 }
121                 SkDebugf("    %s\n", symbols[i]);
122             }
123 #endif
124             // Exit NOW.  Don't notify other threads, don't call anything registered with
125             // atexit().
126             _Exit(sig);
127         }
128     #endif
129 
130     #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
131         #include <signal.h>
132 
SetupCrashHandler()133         void SetupCrashHandler() {
134             static const int kSignals[] = {
135                 SIGABRT,
136                 SIGBUS,
137                 SIGFPE,
138                 SIGILL,
139                 SIGSEGV,
140                 SIGTRAP,
141             };
142 
143             for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
144                 // Register our signal handler unless something's already done so (e.g. catchsegv).
145                 void (*prev)(int) = signal(kSignals[i], handler);
146                 if (prev != SIG_DFL) {
147                     signal(kSignals[i], prev);
148                 }
149             }
150         }
151 
152 /*
153     #elif defined(SK_BUILD_FOR_WIN)
154 
155         #include <DbgHelp.h>
156         #include "include/private/SkMalloc.h"
157 
158         static const struct {
159             const char* name;
160             const DWORD code;
161         } kExceptions[] = {
162         #define _(E) {#E, E}
163             _(EXCEPTION_ACCESS_VIOLATION),
164             _(EXCEPTION_BREAKPOINT),
165             _(EXCEPTION_INT_DIVIDE_BY_ZERO),
166             _(EXCEPTION_STACK_OVERFLOW),
167             // TODO: more?
168         #undef _
169         };
170 
171         static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
172             const DWORD code = e->ExceptionRecord->ExceptionCode;
173             SkDebugf("\nCaught exception %lu", code);
174             for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
175                 if (kExceptions[i].code == code) {
176                     SkDebugf(" %s", kExceptions[i].name);
177                 }
178             }
179             SkDebugf("\n");
180 
181             // We need to run SymInitialize before doing any of the stack walking below.
182             HANDLE hProcess = GetCurrentProcess();
183             SymInitialize(hProcess, 0, true);
184 
185             STACKFRAME64 frame;
186             sk_bzero(&frame, sizeof(frame));
187             // Start frame off from the frame that triggered the exception.
188             CONTEXT* c = e->ContextRecord;
189             frame.AddrPC.Mode      = AddrModeFlat;
190             frame.AddrStack.Mode   = AddrModeFlat;
191             frame.AddrFrame.Mode   = AddrModeFlat;
192         #if defined(_X86_)
193             frame.AddrPC.Offset    = c->Eip;
194             frame.AddrStack.Offset = c->Esp;
195             frame.AddrFrame.Offset = c->Ebp;
196             const DWORD machineType = IMAGE_FILE_MACHINE_I386;
197         #elif defined(_AMD64_)
198             frame.AddrPC.Offset    = c->Rip;
199             frame.AddrStack.Offset = c->Rsp;
200             frame.AddrFrame.Offset = c->Rbp;
201             const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
202         #elif defined(_M_ARM64)
203             frame.AddrPC.Offset    = c->Pc;
204             frame.AddrStack.Offset = c->Sp;
205             frame.AddrFrame.Offset = c->Fp;
206             const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
207         #endif
208 
209         #if !defined(SK_WINUWP)
210             while (StackWalk64(machineType,
211                                GetCurrentProcess(),
212                                GetCurrentThread(),
213                                &frame,
214                                c,
215                                nullptr,
216                                SymFunctionTableAccess64,
217                                SymGetModuleBase64,
218                                nullptr)) {
219                 // Buffer to store symbol name in.
220                 static const int kMaxNameLength = 1024;
221                 uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
222                 sk_bzero(buffer, sizeof(buffer));
223 
224                 // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
225                 // how much space it can use.
226                 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
227                 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
228                 symbol->MaxNameLength = kMaxNameLength - 1;
229 
230                 // Translate the current PC into a symbol and byte offset from the symbol.
231                 DWORD64 offset;
232                 SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
233 
234                 SkDebugf("%s +%llx\n", symbol->Name, offset);
235             }
236         #endif //SK_WINUWP
237 
238             // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
239             _exit(1);
240 
241             // The compiler wants us to return something.  This is what we'd do
242             // if we didn't _exit().
243             return EXCEPTION_EXECUTE_HANDLER;
244         }
245 
246         void SetupCrashHandler() {
247             SetUnhandledExceptionFilter(handler);
248         }
249 */
250 
251     #else
252 
SetupCrashHandler()253         void SetupCrashHandler() { }
254 
255     #endif
256 #endif // SK_BUILD_FOR_GOOGLE3?
257