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