mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-06 02:09:55 +03:00
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>
This commit is contained in:
42
BUILD.gn
42
BUILD.gn
@@ -3,7 +3,6 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
# import the use_x11 variable
|
||||
import("//build/config/dcheck_always_on.gni")
|
||||
import("//build/config/linux/pkg_config.gni")
|
||||
import("//build/config/ui.gni")
|
||||
import("//testing/libfuzzer/fuzzer_test.gni")
|
||||
@@ -145,6 +144,13 @@ config("build_id_config") {
|
||||
ldflags = [ "-Wl,--build-id" ]
|
||||
}
|
||||
|
||||
# Useful for more informative stack traces.
|
||||
config("better_linux_stack_traces") {
|
||||
if (angle_better_stack_traces) {
|
||||
ldflags = [ "-Wl,--export-dynamic" ]
|
||||
}
|
||||
}
|
||||
|
||||
# Windows ARM64 is available since 10.0.16299 so no need to copy
|
||||
# d3dcompiler_47.dll because this file is available as inbox.
|
||||
if (is_win && target_cpu != "arm64") {
|
||||
@@ -210,6 +216,25 @@ config("angle_common_config") {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
angle_source_set("angle_stack_walker") {
|
||||
sources = [
|
||||
"util/windows/third_party/StackWalker/src/StackWalker.cpp",
|
||||
"util/windows/third_party/StackWalker/src/StackWalker.h",
|
||||
]
|
||||
|
||||
if (is_clang) {
|
||||
cflags_cc = [
|
||||
"-Wno-c++98-compat-extra-semi",
|
||||
"-Wno-missing-declarations",
|
||||
"-Wno-switch",
|
||||
]
|
||||
} else {
|
||||
cflags_cc = [ "/wd4740" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angle_source_set("angle_system_utils") {
|
||||
sources = angle_system_utils_sources
|
||||
}
|
||||
@@ -921,12 +946,18 @@ foreach(is_shared_library,
|
||||
|
||||
target(library_type, library_name) {
|
||||
sources = util_sources
|
||||
deps = [
|
||||
":angle_common",
|
||||
":angle_util_loader_headers",
|
||||
]
|
||||
public_deps = []
|
||||
libs = []
|
||||
|
||||
if (is_win) {
|
||||
sources += util_win_sources
|
||||
deps += [ ":angle_stack_walker" ]
|
||||
}
|
||||
|
||||
libs = []
|
||||
if (is_linux) {
|
||||
sources += util_linux_sources
|
||||
libs += [
|
||||
@@ -950,7 +981,6 @@ foreach(is_shared_library,
|
||||
if (is_android) {
|
||||
# To prevent linux sources filtering on android
|
||||
set_sources_assignment_filter([])
|
||||
sources += util_linux_sources
|
||||
sources += util_android_sources
|
||||
libs += [
|
||||
"android",
|
||||
@@ -962,12 +992,6 @@ foreach(is_shared_library,
|
||||
|
||||
public_configs += [ ":angle_util_config" ]
|
||||
|
||||
deps = [
|
||||
":angle_common",
|
||||
":angle_util_loader_headers",
|
||||
]
|
||||
|
||||
public_deps = []
|
||||
if (is_fuchsia) {
|
||||
sources += util_fuchsia_sources
|
||||
public_deps += [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/dcheck_always_on.gni")
|
||||
import("//build/config/sanitizers/sanitizers.gni")
|
||||
import("//build/config/ui.gni") # import the use_x11 variable
|
||||
import("//build_overrides/angle.gni")
|
||||
@@ -95,14 +96,21 @@ if (is_win) {
|
||||
}
|
||||
|
||||
angle_common_configs = [
|
||||
angle_root + ":better_linux_stack_traces",
|
||||
angle_root + ":extra_warnings",
|
||||
angle_root + ":internal_config",
|
||||
]
|
||||
|
||||
angle_remove_configs = [ "//build/config/compiler:default_include_dirs" ]
|
||||
angle_better_stack_traces = (is_debug || dcheck_always_on) && is_linux
|
||||
|
||||
if (is_clang) {
|
||||
angle_remove_configs += [ "//build/config/clang:find_bad_constructs" ]
|
||||
|
||||
# Disabled to enable better stack traces.
|
||||
if (angle_better_stack_traces) {
|
||||
angle_remove_configs += [ "//build/config/gcc:symbol_visibility_hidden" ]
|
||||
}
|
||||
}
|
||||
|
||||
set_defaults("angle_executable") {
|
||||
|
||||
@@ -43,7 +43,8 @@ def write_header(data_source_name,
|
||||
api_lower=api,
|
||||
preamble=preamble,
|
||||
export=export,
|
||||
lib=lib.upper())
|
||||
lib=lib.upper(),
|
||||
load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()))
|
||||
|
||||
out.write(loader_header)
|
||||
out.close()
|
||||
@@ -71,7 +72,8 @@ def write_source(data_source_name, all_cmds, api, path, ns="", prefix=None, expo
|
||||
function_pointers="\n".join(var_defs),
|
||||
set_pointers="\n".join(setters),
|
||||
api_upper=api.upper(),
|
||||
api_lower=api)
|
||||
api_lower=api,
|
||||
load_fn_name="Load%s%s" % (prefix if prefix else "", api.upper()))
|
||||
|
||||
out.write(loader_source)
|
||||
out.close()
|
||||
@@ -266,9 +268,9 @@ namespace angle
|
||||
{{
|
||||
using GenericProc = void (*)();
|
||||
using LoadProc = GenericProc (KHRONOS_APIENTRY *)(const char *);
|
||||
{export}void Load{api_upper}(LoadProc loadProc);
|
||||
{export}void {load_fn_name}(LoadProc loadProc);
|
||||
}} // namespace angle
|
||||
|
||||
|
||||
#endif // {lib}_{api_upper}_LOADER_AUTOGEN_H_
|
||||
"""
|
||||
|
||||
@@ -288,7 +290,7 @@ template_loader_cpp = """// GENERATED FILE - DO NOT EDIT.
|
||||
|
||||
namespace angle
|
||||
{{
|
||||
void Load{api_upper}(LoadProc loadProc)
|
||||
void {load_fn_name}(LoadProc loadProc)
|
||||
{{
|
||||
{set_pointers}
|
||||
}}
|
||||
|
||||
@@ -144,15 +144,15 @@
|
||||
"GL/EGL/WGL loader:scripts/egl_angle_ext.xml":
|
||||
"cc91aa6b14979dc7b3a0b7fee024e59e",
|
||||
"GL/EGL/WGL loader:scripts/generate_loader.py":
|
||||
"b8c0dc876c8122bdc2447de982bcfad6",
|
||||
"5a7cd014230fe04664d9613e65399d42",
|
||||
"GL/EGL/WGL loader:scripts/registry_xml.py":
|
||||
"79d48343cb33f2f534720f84dcba1b4f",
|
||||
"GL/EGL/WGL loader:scripts/wgl.xml":
|
||||
"aa96419c582af2f6673430e2847693f4",
|
||||
"GL/EGL/WGL loader:src/libEGL/egl_loader_autogen.cpp":
|
||||
"07e4ac072bd111f32d0798131e5e2926",
|
||||
"494b0076622c9d7f70b74eeb00fd348c",
|
||||
"GL/EGL/WGL loader:src/libEGL/egl_loader_autogen.h":
|
||||
"5faf638e5f4b23e268193e2cf4a03aae",
|
||||
"8fd78216d48373e776f2f579a58f84c8",
|
||||
"GL/EGL/WGL loader:util/egl_loader_autogen.cpp":
|
||||
"310b388513c03d205c33e84454851ed7",
|
||||
"GL/EGL/WGL loader:util/egl_loader_autogen.h":
|
||||
|
||||
@@ -102,7 +102,7 @@ PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC EGL_StreamConsumerGLTextureEx
|
||||
|
||||
namespace angle
|
||||
{
|
||||
void LoadEGL(LoadProc loadProc)
|
||||
void LoadEGL_EGL(LoadProc loadProc)
|
||||
{
|
||||
EGL_ChooseConfig = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(loadProc("EGL_ChooseConfig"));
|
||||
EGL_CopyBuffers = reinterpret_cast<PFNEGLCOPYBUFFERSPROC>(loadProc("EGL_CopyBuffers"));
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace angle
|
||||
{
|
||||
using GenericProc = void (*)();
|
||||
using LoadProc = GenericProc(KHRONOS_APIENTRY *)(const char *);
|
||||
void LoadEGL(LoadProc loadProc);
|
||||
void LoadEGL_EGL(LoadProc loadProc);
|
||||
} // namespace angle
|
||||
|
||||
#endif // LIBEGL_EGL_LOADER_AUTOGEN_H_
|
||||
|
||||
@@ -34,7 +34,7 @@ void EnsureEGLLoaded()
|
||||
return;
|
||||
|
||||
gEntryPointsLib.reset(angle::OpenSharedLibrary(ANGLE_GLESV2_LIBRARY_NAME));
|
||||
angle::LoadEGL(GlobalLoad);
|
||||
angle::LoadEGL_EGL(GlobalLoad);
|
||||
if (!EGL_GetPlatformDisplay)
|
||||
{
|
||||
fprintf(stderr, "Error loading EGL entry points.\n");
|
||||
|
||||
@@ -55,7 +55,11 @@ void TestPlatform_logError(PlatformMethods *platform, const char *errorMessage)
|
||||
if (testPlatformContext->ignoreMessages)
|
||||
return;
|
||||
|
||||
FAIL() << errorMessage;
|
||||
GTEST_NONFATAL_FAILURE_(errorMessage);
|
||||
|
||||
// Print the stack and stop any crash handling to prevent duplicate reports.
|
||||
PrintStackBacktrace();
|
||||
TerminateCrashHandler();
|
||||
}
|
||||
|
||||
void TestPlatform_logWarning(PlatformMethods *platform, const char *warningMessage)
|
||||
@@ -491,6 +495,8 @@ void ANGLETestBase::ANGLETestSetUp()
|
||||
{
|
||||
mSetUpCalled = true;
|
||||
|
||||
InitCrashHandler();
|
||||
|
||||
gDefaultPlatformMethods.overrideWorkaroundsD3D = TestPlatform_overrideWorkaroundsD3D;
|
||||
gDefaultPlatformMethods.overrideFeaturesVk = TestPlatform_overrideFeaturesVk;
|
||||
gDefaultPlatformMethods.logError = TestPlatform_logError;
|
||||
@@ -616,6 +622,8 @@ void ANGLETestBase::ANGLETestTearDown()
|
||||
mFixture->eglWindow->destroySurface();
|
||||
}
|
||||
|
||||
TerminateCrashHandler();
|
||||
|
||||
// Check for quit message
|
||||
Event myEvent;
|
||||
while (mFixture->osWindow->popEvent(&myEvent))
|
||||
|
||||
167
util/posix/Posix_crash_handler.cpp
Normal file
167
util/posix/Posix_crash_handler.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// system_utils_crash_handler:
|
||||
// ANGLE's crash handling and stack walking code. Modified from Skia's:
|
||||
// https://github.com/google/skia/blob/master/tools/CrashHandler.cpp
|
||||
//
|
||||
|
||||
#include "util/system_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()
|
||||
{
|
||||
// No implementations yet.
|
||||
}
|
||||
|
||||
void TerminateCrashHandler()
|
||||
{
|
||||
// No implementations yet.
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
char demangled[256];
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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
|
||||
@@ -26,6 +26,13 @@ ANGLE_UTIL_EXPORT void WriteDebugMessage(const char *format, ...);
|
||||
|
||||
// Set thread affinity and priority.
|
||||
ANGLE_UTIL_EXPORT bool StabilizeCPUForBenchmarking();
|
||||
|
||||
// Set a crash handler to print stack traces.
|
||||
ANGLE_UTIL_EXPORT void InitCrashHandler();
|
||||
ANGLE_UTIL_EXPORT void TerminateCrashHandler();
|
||||
|
||||
// Print a stack back trace.
|
||||
ANGLE_UTIL_EXPORT void PrintStackBacktrace();
|
||||
} // namespace angle
|
||||
|
||||
#endif // UTIL_SYSTEM_UTILS_H_
|
||||
|
||||
@@ -50,12 +50,15 @@ util_winrt_sources = [
|
||||
"util/windows/WindowsTimer.h",
|
||||
]
|
||||
|
||||
util_linux_sources = [
|
||||
util_posix_sources = [
|
||||
"util/posix/PosixTimer.cpp",
|
||||
"util/posix/PosixTimer.h",
|
||||
"util/posix/Posix_crash_handler.cpp",
|
||||
"util/posix/Posix_system_utils.cpp",
|
||||
]
|
||||
|
||||
util_linux_sources = util_posix_sources
|
||||
|
||||
util_x11_sources = [
|
||||
"util/x11/X11Pixmap.cpp",
|
||||
"util/x11/X11Pixmap.h",
|
||||
@@ -63,13 +66,10 @@ util_x11_sources = [
|
||||
"util/x11/X11Window.h",
|
||||
]
|
||||
|
||||
util_fuchsia_sources = [
|
||||
"util/posix/PosixTimer.cpp",
|
||||
"util/posix/PosixTimer.h",
|
||||
"util/posix/Posix_system_utils.cpp",
|
||||
"util/fuchsia/ScenicWindow.cpp",
|
||||
"util/fuchsia/ScenicWindow.h",
|
||||
]
|
||||
util_fuchsia_sources = util_posix_sources + [
|
||||
"util/fuchsia/ScenicWindow.cpp",
|
||||
"util/fuchsia/ScenicWindow.h",
|
||||
]
|
||||
|
||||
util_ozone_sources = [
|
||||
"util/ozone/OzonePixmap.cpp",
|
||||
@@ -84,13 +84,14 @@ util_osx_sources = [
|
||||
"util/osx/OSXPixmap.h",
|
||||
"util/osx/OSXWindow.mm",
|
||||
"util/osx/OSXWindow.h",
|
||||
"util/posix/Posix_crash_handler.cpp",
|
||||
"util/posix/Posix_system_utils.cpp",
|
||||
]
|
||||
|
||||
util_android_sources = [
|
||||
"util/android/AndroidPixmap.cpp",
|
||||
"util/android/AndroidWindow.cpp",
|
||||
"util/android/AndroidWindow.h",
|
||||
"util/android/third_party/android_native_app_glue.c",
|
||||
"util/android/third_party/android_native_app_glue.h",
|
||||
]
|
||||
util_android_sources = util_posix_sources + [
|
||||
"util/android/AndroidPixmap.cpp",
|
||||
"util/android/AndroidWindow.cpp",
|
||||
"util/android/AndroidWindow.h",
|
||||
"util/android/third_party/android_native_app_glue.c",
|
||||
"util/android/third_party/android_native_app_glue.h",
|
||||
]
|
||||
|
||||
@@ -13,8 +13,99 @@
|
||||
#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)
|
||||
{
|
||||
@@ -36,4 +127,22 @@ void WriteDebugMessage(const char *format, ...)
|
||||
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
|
||||
|
||||
29
util/windows/third_party/StackWalker/LICENSE
vendored
Normal file
29
util/windows/third_party/StackWalker/LICENSE
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2005 - 2017, Jochen Kalmbach
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
12
util/windows/third_party/StackWalker/README.chromium
vendored
Normal file
12
util/windows/third_party/StackWalker/README.chromium
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
Name: StackWalker
|
||||
URL: https://github.com/JochenKalmbach/StackWalker
|
||||
License: BSD
|
||||
License File: LICENSE
|
||||
Security Critical: no
|
||||
|
||||
Description:
|
||||
Walking the callstack in windows applications
|
||||
|
||||
See github page for more info. StackWalker is only used on Windows for
|
||||
walking crash stacks in tests for better logging. It can also be used
|
||||
for local debugging.
|
||||
3
util/windows/third_party/StackWalker/src/.clang-format
vendored
Normal file
3
util/windows/third_party/StackWalker/src/.clang-format
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
DisableFormat: true
|
||||
1469
util/windows/third_party/StackWalker/src/StackWalker.cpp
vendored
Normal file
1469
util/windows/third_party/StackWalker/src/StackWalker.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
255
util/windows/third_party/StackWalker/src/StackWalker.h
vendored
Normal file
255
util/windows/third_party/StackWalker/src/StackWalker.h
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
#ifndef __STACKWALKER_H__
|
||||
#define __STACKWALKER_H__
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* StackWalker.h
|
||||
*
|
||||
*
|
||||
*
|
||||
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Copyright (c) 2005-2009, Jochen Kalmbach
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* **********************************************************************/
|
||||
// #pragma once is supported starting with _MSC_VER 1000,
|
||||
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if _MSC_VER >= 1900
|
||||
#pragma warning(disable : 4091)
|
||||
#endif
|
||||
|
||||
// special defines for VC5/6 (if no actual PSDK is installed):
|
||||
#if _MSC_VER < 1300
|
||||
typedef unsigned __int64 DWORD64, *PDWORD64;
|
||||
#if defined(_WIN64)
|
||||
typedef unsigned __int64 SIZE_T, *PSIZE_T;
|
||||
#else
|
||||
typedef unsigned long SIZE_T, *PSIZE_T;
|
||||
#endif
|
||||
#endif // _MSC_VER < 1300
|
||||
|
||||
class StackWalkerInternal; // forward
|
||||
class StackWalker
|
||||
{
|
||||
public:
|
||||
typedef enum StackWalkOptions
|
||||
{
|
||||
// No addition info will be retrieved
|
||||
// (only the address is available)
|
||||
RetrieveNone = 0,
|
||||
|
||||
// Try to get the symbol-name
|
||||
RetrieveSymbol = 1,
|
||||
|
||||
// Try to get the line for this symbol
|
||||
RetrieveLine = 2,
|
||||
|
||||
// Try to retrieve the module-infos
|
||||
RetrieveModuleInfo = 4,
|
||||
|
||||
// Also retrieve the version for the DLL/EXE
|
||||
RetrieveFileVersion = 8,
|
||||
|
||||
// Contains all the above
|
||||
RetrieveVerbose = 0xF,
|
||||
|
||||
// Generate a "good" symbol-search-path
|
||||
SymBuildPath = 0x10,
|
||||
|
||||
// Also use the public Microsoft-Symbol-Server
|
||||
SymUseSymSrv = 0x20,
|
||||
|
||||
// Contains all the above "Sym"-options
|
||||
SymAll = 0x30,
|
||||
|
||||
// Contains all options (default)
|
||||
OptionsAll = 0x3F
|
||||
} StackWalkOptions;
|
||||
|
||||
StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
|
||||
LPCSTR szSymPath = NULL,
|
||||
DWORD dwProcessId = GetCurrentProcessId(),
|
||||
HANDLE hProcess = GetCurrentProcess());
|
||||
StackWalker(DWORD dwProcessId, HANDLE hProcess);
|
||||
virtual ~StackWalker();
|
||||
|
||||
typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
|
||||
HANDLE hProcess,
|
||||
DWORD64 qwBaseAddress,
|
||||
PVOID lpBuffer,
|
||||
DWORD nSize,
|
||||
LPDWORD lpNumberOfBytesRead,
|
||||
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
|
||||
);
|
||||
|
||||
BOOL LoadModules();
|
||||
|
||||
BOOL ShowCallstack(
|
||||
HANDLE hThread = GetCurrentThread(),
|
||||
const CONTEXT* context = NULL,
|
||||
PReadProcessMemoryRoutine readMemoryFunction = NULL,
|
||||
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
|
||||
);
|
||||
|
||||
BOOL ShowObject(LPVOID pObject);
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
|
||||
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
|
||||
protected:
|
||||
#endif
|
||||
enum
|
||||
{
|
||||
STACKWALK_MAX_NAMELEN = 1024
|
||||
}; // max name length for found symbols
|
||||
|
||||
protected:
|
||||
// Entry for each Callstack-Entry
|
||||
typedef struct CallstackEntry
|
||||
{
|
||||
DWORD64 offset; // if 0, we have no valid entry
|
||||
CHAR name[STACKWALK_MAX_NAMELEN];
|
||||
CHAR undName[STACKWALK_MAX_NAMELEN];
|
||||
CHAR undFullName[STACKWALK_MAX_NAMELEN];
|
||||
DWORD64 offsetFromSmybol;
|
||||
DWORD offsetFromLine;
|
||||
DWORD lineNumber;
|
||||
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
|
||||
DWORD symType;
|
||||
LPCSTR symTypeString;
|
||||
CHAR moduleName[STACKWALK_MAX_NAMELEN];
|
||||
DWORD64 baseOfImage;
|
||||
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
|
||||
} CallstackEntry;
|
||||
|
||||
typedef enum CallstackEntryType
|
||||
{
|
||||
firstEntry,
|
||||
nextEntry,
|
||||
lastEntry
|
||||
} CallstackEntryType;
|
||||
|
||||
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
|
||||
virtual void OnLoadModule(LPCSTR img,
|
||||
LPCSTR mod,
|
||||
DWORD64 baseAddr,
|
||||
DWORD size,
|
||||
DWORD result,
|
||||
LPCSTR symType,
|
||||
LPCSTR pdbName,
|
||||
ULONGLONG fileVersion);
|
||||
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
|
||||
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
|
||||
virtual void OnOutput(LPCSTR szText);
|
||||
|
||||
StackWalkerInternal* m_sw;
|
||||
HANDLE m_hProcess;
|
||||
DWORD m_dwProcessId;
|
||||
BOOL m_modulesLoaded;
|
||||
LPSTR m_szSymPath;
|
||||
|
||||
int m_options;
|
||||
int m_MaxRecursionCount;
|
||||
|
||||
static BOOL __stdcall myReadProcMem(HANDLE hProcess,
|
||||
DWORD64 qwBaseAddress,
|
||||
PVOID lpBuffer,
|
||||
DWORD nSize,
|
||||
LPDWORD lpNumberOfBytesRead);
|
||||
|
||||
friend StackWalkerInternal;
|
||||
}; // class StackWalker
|
||||
|
||||
// The "ugly" assembler-implementation is needed for systems before XP
|
||||
// If you have a new PSDK and you only compile for XP and later, then you can use
|
||||
// the "RtlCaptureContext"
|
||||
// Currently there is no define which determines the PSDK-Version...
|
||||
// So we just use the compiler-version (and assumes that the PSDK is
|
||||
// the one which was installed by the VS-IDE)
|
||||
|
||||
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
|
||||
// But I currently use it in x64/IA64 environments...
|
||||
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#ifdef CURRENT_THREAD_VIA_EXCEPTION
|
||||
// TODO: The following is not a "good" implementation,
|
||||
// because the callstack is only valid in the "__except" block...
|
||||
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
|
||||
do \
|
||||
{ \
|
||||
memset(&c, 0, sizeof(CONTEXT)); \
|
||||
EXCEPTION_POINTERS* pExp = NULL; \
|
||||
__try \
|
||||
{ \
|
||||
throw 0; \
|
||||
} \
|
||||
__except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \
|
||||
: EXCEPTION_EXECUTE_HANDLER)) \
|
||||
{ \
|
||||
} \
|
||||
if (pExp != NULL) \
|
||||
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
|
||||
c.ContextFlags = contextFlags; \
|
||||
} while (0);
|
||||
#else
|
||||
// clang-format off
|
||||
// The following should be enough for walking the callstack...
|
||||
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
|
||||
do \
|
||||
{ \
|
||||
memset(&c, 0, sizeof(CONTEXT)); \
|
||||
c.ContextFlags = contextFlags; \
|
||||
__asm call x \
|
||||
__asm x: pop eax \
|
||||
__asm mov c.Eip, eax \
|
||||
__asm mov c.Ebp, ebp \
|
||||
__asm mov c.Esp, esp \
|
||||
} while (0)
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
// The following is defined for x86 (XP and higher), x64 and IA64:
|
||||
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
|
||||
do \
|
||||
{ \
|
||||
memset(&c, 0, sizeof(CONTEXT)); \
|
||||
c.ContextFlags = contextFlags; \
|
||||
RtlCaptureContext(&c); \
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
#endif //defined(_MSC_VER)
|
||||
|
||||
#endif // __STACKWALKER_H__
|
||||
Reference in New Issue
Block a user