Edit

kc3-lang/angle/util/posix/crash_handler_posix.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-12-16 15:50:12
    Hash : 5407aaa0
    Message : Re-land "Add new test runner harness." (#2) Re-land #2 changes: * export labels are fixed for the CFI build * crash test disabled because of flakiness and issues with asan Re-land changes: * Unit test is suppressed in ASAN * --deqp-case is fixed * Debug layer errors should correctly work with failure expectations Original message: The ANGLE test harness is a harness around GoogleTest that provides functionality similar to the Chromium test harness. It supports: * splitting a test set into shards * catching and reporting crashes and timeouts * outputting to the Chromium JSON test results format * multi-process execution Unit tests are added in test_utils_unittest.cpp. Bug: angleproject:3162 Bug: chromium:1030192 Change-Id: I71d66a407ea0e53d73cbe75b5b4bfb9e73791534 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1965091 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>

  • util/posix/crash_handler_posix.cpp
  • //
    // 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