14808757d7a8bbe8c773a312a894738e9ff701b5fborenet/*
24808757d7a8bbe8c773a312a894738e9ff701b5fborenet * Copyright 2014 Google Inc.
34808757d7a8bbe8c773a312a894738e9ff701b5fborenet *
44808757d7a8bbe8c773a312a894738e9ff701b5fborenet * Use of this source code is governed by a BSD-style license that can be
54808757d7a8bbe8c773a312a894738e9ff701b5fborenet * found in the LICENSE file.
64808757d7a8bbe8c773a312a894738e9ff701b5fborenet */
74808757d7a8bbe8c773a312a894738e9ff701b5fborenet
830e6e2af14e84216b1c113fd7500d0822bc81daamtklein#include "CrashHandler.h"
930e6e2af14e84216b1c113fd7500d0822bc81daamtklein
1030e6e2af14e84216b1c113fd7500d0822bc81daamtklein#include "SkTypes.h"
1130e6e2af14e84216b1c113fd7500d0822bc81daamtklein
1230e6e2af14e84216b1c113fd7500d0822bc81daamtklein#include <stdlib.h>
1330e6e2af14e84216b1c113fd7500d0822bc81daamtklein
140e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein// Disable SetupCrashHandler() unless SK_CRASH_HANDLER is defined.
150e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein#ifndef SK_CRASH_HANDLER
160e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein    void SetupCrashHandler() { }
170e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
18b47bba7c77782a9ee9e7d67a4b9c68050263e68amtklein#elif defined(GOOGLE3)
19b47bba7c77782a9ee9e7d67a4b9c68050263e68amtklein    #include "base/process_state.h"
20b47bba7c77782a9ee9e7d67a4b9c68050263e68amtklein    void SetupCrashHandler() { InstallSignalHandlers(); }
21b47bba7c77782a9ee9e7d67a4b9c68050263e68amtklein
220e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein#else
230e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
240e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein    #if defined(SK_BUILD_FOR_MAC)
250e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
260e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        // We only use local unwinding, so we can define this to select a faster implementation.
270e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #define UNW_LOCAL_ONLY
280e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #include <libunwind.h>
290e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #include <cxxabi.h>
300e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
310e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        static void handler(int sig) {
320e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            unw_context_t context;
330e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            unw_getcontext(&context);
340e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
350e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            unw_cursor_t cursor;
360e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            unw_init_local(&cursor, &context);
370e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
380e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SkDebugf("\nSignal %d:\n", sig);
390e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            while (unw_step(&cursor) > 0) {
400e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                static const size_t kMax = 256;
410e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                char mangled[kMax], demangled[kMax];
420e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                unw_word_t offset;
430e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                unw_get_proc_name(&cursor, mangled, kMax, &offset);
440e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
450e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                int ok;
460e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                size_t len = kMax;
470e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                abi::__cxa_demangle(mangled, demangled, &len, &ok);
480e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
490e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset);
500e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            }
510e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SkDebugf("\n");
520e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
530e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
540e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _Exit(sig);
550e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        }
560e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
574808757d7a8bbe8c773a312a894738e9ff701b5fborenet    #elif defined(SK_BUILD_FOR_UNIX)
580e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
590e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        // We'd use libunwind here too, but it's a pain to get installed for
600e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        // both 32 and 64 bit on bots.  Doesn't matter much: catchsegv is best anyway.
610e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #include <execinfo.h>
620e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
630e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        static void handler(int sig) {
640e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            static const int kMax = 64;
650e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            void* stack[kMax];
660e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            const int count = backtrace(stack, kMax);
670e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
680e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
690e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            backtrace_symbols_fd(stack, count, 2/*stderr*/);
700e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
710e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
720e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _Exit(sig);
7330e6e2af14e84216b1c113fd7500d0822bc81daamtklein        }
740e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
750e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein    #endif
760e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
774808757d7a8bbe8c773a312a894738e9ff701b5fborenet    #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
780e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #include <signal.h>
790e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
800e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        void SetupCrashHandler() {
810e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            static const int kSignals[] = {
820e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SIGABRT,
830e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SIGBUS,
840e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SIGFPE,
850e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SIGILL,
860e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SIGSEGV,
870e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            };
880e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
890e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
900e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                // Register our signal handler unless something's already done so (e.g. catchsegv).
910e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                void (*prev)(int) = signal(kSignals[i], handler);
920e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                if (prev != SIG_DFL) {
930e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                    signal(kSignals[i], prev);
940e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                }
950e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            }
963f73e8c8d589e0d5a1f75327b4aa22c1e745732dmtklein        }
9730e6e2af14e84216b1c113fd7500d0822bc81daamtklein
980e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein    #elif defined(SK_CRASH_HANDLER) && defined(SK_BUILD_FOR_WIN)
990e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1000e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #include <DbgHelp.h>
1010e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1020e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        static const struct {
1030e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            const char* name;
1040e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            int code;
1050e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        } kExceptions[] = {
1060e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #define _(E) {#E, E}
1070e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _(EXCEPTION_ACCESS_VIOLATION),
1080e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _(EXCEPTION_BREAKPOINT),
1090e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _(EXCEPTION_INT_DIVIDE_BY_ZERO),
1100e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _(EXCEPTION_STACK_OVERFLOW),
1110e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // TODO: more?
1120e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #undef _
1130e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        };
1140e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1150e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        static LONG WINAPI handler(EXCEPTION_POINTERS* e) {
1160e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            const DWORD code = e->ExceptionRecord->ExceptionCode;
1170e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SkDebugf("\nCaught exception %u", code);
1180e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            for (size_t i = 0; i < SK_ARRAY_COUNT(kExceptions); i++) {
1190e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                if (kExceptions[i].code == code) {
1200e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                    SkDebugf(" %s", kExceptions[i].name);
1210e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                }
1220e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            }
1230e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SkDebugf("\n");
1240e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1250e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // We need to run SymInitialize before doing any of the stack walking below.
1260e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            HANDLE hProcess = GetCurrentProcess();
1270e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SymInitialize(hProcess, 0, true);
1280e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1290e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            STACKFRAME64 frame;
1300e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            sk_bzero(&frame, sizeof(frame));
1310e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // Start frame off from the frame that triggered the exception.
1320e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            CONTEXT* c = e->ContextRecord;
1330e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrPC.Mode      = AddrModeFlat;
1340e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrStack.Mode   = AddrModeFlat;
1350e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrFrame.Mode   = AddrModeFlat;
1360e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #if defined(_X86_)
1370e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrPC.Offset    = c->Eip;
1380e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrStack.Offset = c->Esp;
1390e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrFrame.Offset = c->Ebp;
1400e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            const DWORD machineType = IMAGE_FILE_MACHINE_I386;
1410e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #elif defined(_AMD64_)
1420e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrPC.Offset    = c->Rip;
1430e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrStack.Offset = c->Rsp;
1440e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            frame.AddrFrame.Offset = c->Rbp;
1450e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
1460e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        #endif
1470e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1480e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            while (StackWalk64(machineType,
1490e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               GetCurrentProcess(),
1500e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               GetCurrentThread(),
1510e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               &frame,
1520e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               c,
1530e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               NULL,
1540e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               SymFunctionTableAccess64,
1550e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               SymGetModuleBase64,
1560e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                               NULL)) {
1570e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                // Buffer to store symbol name in.
1580e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                static const int kMaxNameLength = 1024;
1590e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                uint8_t buffer[sizeof(IMAGEHLP_SYMBOL64) + kMaxNameLength];
1600e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                sk_bzero(buffer, sizeof(buffer));
1610e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1620e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                // We have to place IMAGEHLP_SYMBOL64 at the front, and fill in
1630e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                // how much space it can use.
1640e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&buffer);
1650e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
1660e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                symbol->MaxNameLength = kMaxNameLength - 1;
1670e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1680e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                // Translate the current PC into a symbol and byte offset from the symbol.
1690e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                DWORD64 offset;
1700e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol);
1710e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1720e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein                SkDebugf("%s +%x\n", symbol->Name, offset);
1730e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            }
1740e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1750e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
1760e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            _exit(1);
1770e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1780e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // The compiler wants us to return something.  This is what we'd do
1790e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            // if we didn't _exit().
1800e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            return EXCEPTION_EXECUTE_HANDLER;
1810e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        }
1820e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1830e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        void SetupCrashHandler() {
1840e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein            SetUnhandledExceptionFilter(handler);
1850e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        }
1860e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein
1870e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein    #else  // We asked for SK_CRASH_HANDLER, but it's not Mac, Linux, or Windows.  Sorry!
18830e6e2af14e84216b1c113fd7500d0822bc81daamtklein
1890e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein        void SetupCrashHandler() { }
19030e6e2af14e84216b1c113fd7500d0822bc81daamtklein
1910e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein    #endif
1920e3fac215d0ee2e2efaca69b7d53f636f4fe5ba7mtklein#endif // SK_CRASH_HANDLER
193