Edit

kc3-lang/angle/util/windows/Windows_system_utils.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-06-03 15:21:47
    Hash : 20d380fa
    Message : Print stack backtrace on critical failure. We reuse code from Skia to walk the stack on Posix platforms. See: https://github.com/google/skia/blob/master/tools/CrashHandler.cpp On Windows we use a BSD-licensed tool called StackWalker. See: https://github.com/JochenKalmbach/StackWalker This allows us to get high quality stack traces on Win/Linux/Mac. Bug: angleproject:3162 Change-Id: I9c50ede2c6a41ed0ee85a0507372df42a487bcef Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1632950 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Yuly Novikov <ynovikov@chromium.org>

  • util/windows/Windows_system_utils.cpp
  • //
    // Copyright (c) 2014 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.
    //
    
    // Windows_system_utils.cpp: Implementation of OS-specific functions for Windows
    
    #include "util/system_utils.h"
    
    #include <stdarg.h>
    #include <windows.h>
    #include <array>
    #include <vector>
    
    #include "util/windows/third_party/StackWalker/src/StackWalker.h"
    
    namespace angle
    {
    namespace
    {
    static const struct
    {
        const char *name;
        const DWORD code;
    } kExceptions[] = {
    #define _(E)  \
        {         \
    #        E, E \
        }
        _(EXCEPTION_ACCESS_VIOLATION),
        _(EXCEPTION_BREAKPOINT),
        _(EXCEPTION_INT_DIVIDE_BY_ZERO),
        _(EXCEPTION_STACK_OVERFLOW),
    #undef _
    };
    
    class CustomStackWalker : public StackWalker
    {
      public:
        CustomStackWalker() {}
        ~CustomStackWalker() {}
    
        void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) override
        {
            char buffer[STACKWALK_MAX_NAMELEN];
            size_t maxLen = _TRUNCATE;
            if ((eType != lastEntry) && (entry.offset != 0))
            {
                if (entry.name[0] == 0)
                    strncpy_s(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)",
                              _TRUNCATE);
                if (entry.undName[0] != 0)
                    strncpy_s(entry.name, STACKWALK_MAX_NAMELEN, entry.undName, _TRUNCATE);
                if (entry.undFullName[0] != 0)
                    strncpy_s(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName, _TRUNCATE);
                if (entry.lineFileName[0] == 0)
                {
                    strncpy_s(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)",
                              _TRUNCATE);
                    if (entry.moduleName[0] == 0)
                        strncpy_s(entry.moduleName, STACKWALK_MAX_NAMELEN,
                                  "(module-name not available)", _TRUNCATE);
                    _snprintf_s(buffer, maxLen, "    %s - %p (%s): %s\n", entry.name,
                                reinterpret_cast<void *>(entry.offset), entry.moduleName,
                                entry.lineFileName);
                }
                else
                    _snprintf_s(buffer, maxLen, "    %s (%s:%d)\n", entry.name, entry.lineFileName,
                                entry.lineNumber);
                buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
                printf("%s", buffer);
                OutputDebugStringA(buffer);
            }
        }
    };
    
    void PrintBacktrace(CONTEXT *c)
    {
        printf("Backtrace:\n");
        OutputDebugStringA("Backtrace:\n");
    
        CustomStackWalker sw;
        sw.ShowCallstack(GetCurrentThread(), c);
    }
    
    LONG WINAPI StackTraceCrashHandler(EXCEPTION_POINTERS *e)
    {
        const DWORD code = e->ExceptionRecord->ExceptionCode;
        printf("\nCaught exception %lu", code);
        for (size_t i = 0; i < ArraySize(kExceptions); i++)
        {
            if (kExceptions[i].code == code)
            {
                printf(" %s", kExceptions[i].name);
            }
        }
        printf("\n");
    
        PrintBacktrace(e->ContextRecord);
    
        // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
        _exit(1);
    
        // The compiler wants us to return something.  This is what we'd do if we didn't _exit().
        return EXCEPTION_EXECUTE_HANDLER;
    }
    }  // anonymous namespace
    
    void Sleep(unsigned int milliseconds)
    {
        ::Sleep(static_cast<DWORD>(milliseconds));
    }
    
    void WriteDebugMessage(const char *format, ...)
    {
        va_list args;
        va_start(args, format);
        int size = vsnprintf(nullptr, 0, format, args);
        va_end(args);
    
        std::vector<char> buffer(size + 2);
        va_start(args, format);
        vsnprintf(buffer.data(), size + 1, format, args);
        va_end(args);
    
        OutputDebugStringA(buffer.data());
    }
    
    void InitCrashHandler()
    {
        SetUnhandledExceptionFilter(StackTraceCrashHandler);
    }
    
    void TerminateCrashHandler()
    {
        SetUnhandledExceptionFilter(nullptr);
    }
    
    void PrintStackBacktrace()
    {
        CONTEXT context;
        ZeroMemory(&context, sizeof(CONTEXT));
        RtlCaptureContext(&context);
        PrintBacktrace(&context);
    }
    
    }  // namespace angle