| // |
| // 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 <stdio.h> |
| #include <stdlib.h> |
| |
| #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 <cxxabi.h> |
| # include <libunwind.h> |
| # include <signal.h> |
| # 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 <cxxabi.h> |
| # include <dlfcn.h> |
| # include <execinfo.h> |
| # include <signal.h> |
| # include <string.h> |
| # 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 |