// // Copyright 2019 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // crash_handler_posix: // ANGLE's crash handling and stack walking code. Modified from Skia's: // https://github.com/google/skia/blob/master/tools/CrashHandler.cpp // #include "util/test_utils.h" #include "common/angleutils.h" #include #include #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) # if defined(ANGLE_PLATFORM_APPLE) // We only use local unwinding, so we can define this to select a faster implementation. # define UNW_LOCAL_ONLY # include # include # include # elif defined(ANGLE_PLATFORM_POSIX) // We'd use libunwind here too, but it's a pain to get installed for // both 32 and 64 bit on bots. Doesn't matter much: catchsegv is best anyway. # include # include # include # include # include # endif // defined(ANGLE_PLATFORM_APPLE) #endif // !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) namespace angle { #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA) void PrintStackBacktrace() { // No implementations yet. } void InitCrashHandler(CrashCallback *callback) { // No implementations yet. } void TerminateCrashHandler() { // No implementations yet. } #else namespace { CrashCallback *gCrashHandlerCallback; } // namespace # if defined(ANGLE_PLATFORM_APPLE) void PrintStackBacktrace() { printf("Backtrace:\n"); unw_context_t context; unw_getcontext(&context); unw_cursor_t cursor; unw_init_local(&cursor, &context); while (unw_step(&cursor) > 0) { static const size_t kMax = 256; char mangled[kMax], demangled[kMax]; unw_word_t offset; unw_get_proc_name(&cursor, mangled, kMax, &offset); int ok; size_t len = kMax; abi::__cxa_demangle(mangled, demangled, &len, &ok); printf(" %s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset); } printf("\n"); } static void Handler(int sig) { if (gCrashHandlerCallback) { (*gCrashHandlerCallback)(); } printf("\nSignal %d:\n", sig); PrintStackBacktrace(); // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). _Exit(sig); } # elif defined(ANGLE_PLATFORM_POSIX) void PrintStackBacktrace() { printf("Backtrace:\n"); void *stack[64]; const int count = backtrace(stack, ArraySize(stack)); char **symbols = backtrace_symbols(stack, count); for (int i = 0; i < count; i++) { Dl_info info; if (dladdr(stack[i], &info) && info.dli_sname) { // Make sure this is large enough to hold the fully demangled names, otherwise we could // segault/hang here. For example, Vulkan validation layer errors can be deep enough // into the stack that very large symbol names are generated. char demangled[4096]; size_t len = ArraySize(demangled); int ok; abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok); if (ok == 0) { printf(" %s\n", demangled); continue; } } printf(" %s\n", symbols[i]); } } static void Handler(int sig) { if (gCrashHandlerCallback) { (*gCrashHandlerCallback)(); } printf("\nSignal %d [%s]:\n", sig, strsignal(sig)); PrintStackBacktrace(); // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). _Exit(sig); } # endif // defined(ANGLE_PLATFORM_APPLE) static constexpr int kSignals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP, }; void InitCrashHandler(CrashCallback *callback) { gCrashHandlerCallback = callback; for (int sig : kSignals) { // Register our signal handler unless something's already done so (e.g. catchsegv). void (*prev)(int) = signal(sig, Handler); if (prev != SIG_DFL) { signal(sig, prev); } } } void TerminateCrashHandler() { gCrashHandlerCallback = nullptr; for (int sig : kSignals) { void (*prev)(int) = signal(sig, SIG_DFL); if (prev != Handler && prev != SIG_DFL) { signal(sig, prev); } } } #endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_FUCHSIA) } // namespace angle