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