// // 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 #include #include #include #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(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(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 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