Coverage Report

Created: 2024-05-20 07:14

/src/skia/tools/CrashHandler.cpp
Line
Count
Source (jump to first uncovered line)
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"
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
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.
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
101
0
        static void handler(int sig) {
102
#if defined(__Fuchsia__)
103
            backtrace_request();
104
#else
105
0
            void* stack[64];
106
0
            const int count = backtrace(stack, std::size(stack));
107
0
            char** symbols = backtrace_symbols(stack, count);
108
109
0
            SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
110
0
            for (int i = 0; i < count; i++) {
111
0
                Dl_info info;
112
0
                if (dladdr(stack[i], &info) && info.dli_sname) {
113
0
                    char demangled[256];
114
0
                    size_t len = std::size(demangled);
115
0
                    int ok;
116
117
0
                    abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
118
0
                    if (ok == 0) {
119
0
                        SkDebugf("    %s\n", demangled);
120
0
                        continue;
121
0
                    }
122
0
                }
123
0
                SkDebugf("    %s\n", symbols[i]);
124
0
            }
125
0
#endif
126
            // Exit NOW.  Don't notify other threads, don't call anything registered with
127
            // atexit().
128
0
            _Exit(sig);
129
0
        }
130
    #endif
131
132
    #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
133
        #include <signal.h>
134
135
0
        void SetupCrashHandler() {
136
0
            static const int kSignals[] = {
137
0
                SIGABRT,
138
0
                SIGBUS,
139
0
                SIGFPE,
140
0
                SIGILL,
141
0
                SIGSEGV,
142
0
                SIGTRAP,
143
0
            };
144
145
0
            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
0
                void (*prev)(int) = signal(kSignals[i], handler);
148
0
                if (prev != SIG_DFL) {
149
0
                    signal(kSignals[i], prev);
150
0
                }
151
0
            }
152
0
        }
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
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
248
        void SetupCrashHandler() {
249
            SetUnhandledExceptionFilter(handler);
250
        }
251
252
    #else
253
254
        void SetupCrashHandler() { }
255
256
    #endif
257
#endif // SK_BUILD_FOR_GOOGLE3?