Added a crash handler to dump the backtrace on Windows, Linux and OS X

This commit is contained in:
Marcelo Fernandez 2017-09-07 22:01:49 -03:00
parent 06138bf18c
commit 83fe937362
23 changed files with 787 additions and 24 deletions

View File

@ -279,6 +279,9 @@ public:
bool is_stdout_verbose() const;
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
enum CursorShape {
CURSOR_ARROW,
CURSOR_IBEAM,

View File

@ -72,6 +72,10 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li
screen--;
}
if (OS::get_singleton()->is_disable_crash_handler()) {
args.push_back("--disable-crash-handler");
}
Rect2 screen_rect;
screen_rect.position = OS::get_singleton()->get_screen_position(screen);
screen_rect.size = OS::get_singleton()->get_screen_size(screen);

View File

@ -948,6 +948,10 @@ void ProjectManager::_open_project_confirm() {
args.push_back("--editor");
if (OS::get_singleton()->is_disable_crash_handler()) {
args.push_back("--disable-crash-handler");
}
String exec = OS::get_singleton()->get_executable_path();
OS::ProcessID pid = 0;
@ -999,6 +1003,10 @@ void ProjectManager::_run_project_confirm() {
args.push_back("--path");
args.push_back(path);
if (OS::get_singleton()->is_disable_crash_handler()) {
args.push_back("--disable-crash-handler");
}
String exec = OS::get_singleton()->get_executable_path();
OS::ProcessID pid = 0;

View File

@ -194,6 +194,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n");
OS::get_singleton()->print(" --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n");
OS::get_singleton()->print(" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n");
OS::get_singleton()->print(" --disable-crash-handler Disable crash handler when supported by the platform code.\n");
OS::get_singleton()->print(" --fixed-fps <fps> Forces a fixed ratio between process and fixed_process timing, for use when precision is required, or when rendering to video files. Setting this will disable real-time syncronization, so that run speed is only capped by performance\n");
OS::get_singleton()->print("\n");
@ -247,6 +248,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
performance = memnew(Performance);
globals->add_singleton(ProjectSettings::Singleton("Performance", performance));
GLOBAL_DEF("debug/settings/backtrace/message", String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
MAIN_PRINT("Main: Parse CMDLine");
/* argument parsing and main creation */
@ -582,6 +585,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing fixed-fps argument, aborting.\n");
goto error;
}
} else if (I->get() == "--disable-crash-handler") {
OS::get_singleton()->disable_crash_handler();
} else {
//test for game path

View File

@ -3,6 +3,7 @@
Import('env')
files = [
'crash_handler_osx.mm',
'os_osx.mm',
'godot_main_osx.mm',
'audio_driver_osx.cpp',
@ -12,4 +13,8 @@ files = [
'power_osx.cpp',
]
env.Program('#bin/godot', files)
prog = env.Program('#bin/godot', files)
if (env['target'] == "debug" or env['target'] == "release_debug"):
# Build the .dSYM file for atos
action = "dsymutil " + File(prog)[0].path + " -o " + File(prog)[0].path + ".dSYM"
env.AddPostAction(prog, action)

View File

@ -0,0 +1,47 @@
/*************************************************************************/
/* crash_handler_osx.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef CRASH_HANDLER_OSX_H
#define CRASH_HANDLER_OSX_H
class CrashHandler {
bool disabled;
public:
void initialize();
void disable();
bool is_disabled() const { return disabled; };
CrashHandler();
~CrashHandler();
};
#endif

View File

@ -0,0 +1,178 @@
/*************************************************************************/
/* crash_handler_osx.mm */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "main/main.h"
#include "os_osx.h"
#include <string.h>
#include <unistd.h>
// Note: Dump backtrace in 32bit mode is getting a bus error on the fgets by the ->execute, so enable only on 64bit
#if defined(DEBUG_ENABLED) && defined(__x86_64__)
#define CRASH_HANDLER_ENABLED 1
#endif
#ifdef CRASH_HANDLER_ENABLED
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <signal.h>
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
#ifdef __x86_64__
static uint64_t load_address() {
const struct segment_command_64 *cmd = getsegbyname("__TEXT");
#else
static uint32_t load_address() {
const struct segment_command *cmd = getsegbyname("__TEXT");
#endif
char full_path[1024];
uint32_t size = sizeof(full_path);
if (cmd && !_NSGetExecutablePath(full_path, &size)) {
uint32_t dyld_count = _dyld_image_count();
for (uint32_t i = 0; i < dyld_count; i++) {
const char *image_name = _dyld_get_image_name(i);
if (image_name && strncmp(image_name, full_path, 1024) == 0) {
return cmd->vmaddr + _dyld_get_image_vmaddr_slide(i);
}
}
}
return 0;
}
static void handle_crash(int sig) {
if (OS::get_singleton() == NULL)
return;
void *bt_buffer[256];
size_t size = backtrace(bt_buffer, 256);
String _execpath = OS::get_singleton()->get_executable_path();
String msg = GLOBAL_GET("debug/settings/backtrace/message");
// Dump the backtrace to stderr with a message to the user
fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
void *load_addr = (void *)load_address();
for (int i = 1; i < size; i++) {
char fname[1024];
Dl_info info;
snprintf(fname, 1024, "%s", strings[i]);
// Try to demangle the function name to provide a more readable one
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
int status;
char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
if (status == 0 && demangled) {
snprintf(fname, 1024, "%s", demangled);
}
if (demangled)
free(demangled);
}
}
String output = fname;
// Try to get the file/line number using atos
if (bt_buffer[i] > (void *)0x0 && OS::get_singleton()) {
List<String> args;
char str[1024];
args.push_back("-o");
args.push_back(_execpath);
args.push_back("-arch");
#ifdef __x86_64__
args.push_back("x86_64");
#else
args.push_back("i386");
#endif
args.push_back("-l");
snprintf(str, 1024, "%p", load_addr);
args.push_back(str);
snprintf(str, 1024, "%p", bt_buffer[i]);
args.push_back(str);
int ret;
String out = "";
Error err = OS::get_singleton()->execute(String("atos"), args, true, NULL, &out, &ret);
if (err == OK && out.substr(0, 2) != "0x") {
out.erase(out.length() - 1, 1);
output = out;
}
}
fprintf(stderr, "[%d] %ls\n", i, output.c_str());
}
free(strings);
}
fprintf(stderr, "-- END OF BACKTRACE --\n");
// Abort to pass the error to the OS
abort();
}
#endif
CrashHandler::CrashHandler() {
disabled = false;
}
CrashHandler::~CrashHandler() {
}
void CrashHandler::disable() {
if (disabled)
return;
#ifdef CRASH_HANDLER_ENABLED
signal(SIGSEGV, NULL);
signal(SIGFPE, NULL);
signal(SIGILL, NULL);
#endif
disabled = true;
}
void CrashHandler::initialize() {
#ifdef CRASH_HANDLER_ENABLED
signal(SIGSEGV, handle_crash);
signal(SIGFPE, handle_crash);
signal(SIGILL, handle_crash);
#endif
}

View File

@ -35,7 +35,6 @@
#include <unistd.h>
int main(int argc, char **argv) {
int first_arg = 1;
const char *dbg_arg = "-NSDocumentRevisionsDebugMode";
printf("arguments\n");

View File

@ -30,6 +30,7 @@
#ifndef OS_OSX_H
#define OS_OSX_H
#include "crash_handler_osx.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/unix/os_unix.h"
@ -110,6 +111,8 @@ public:
power_osx *power_manager;
CrashHandler crash_handler;
float _mouse_scale(float p_scale) {
if (display_scale > 1.0)
return p_scale;
@ -224,6 +227,9 @@ public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
void disable_crash_handler();
bool is_disable_crash_handler() const;
OS_OSX();
};

View File

@ -910,6 +910,8 @@ OS::VideoMode OS_OSX::get_default_video_mode() const {
void OS_OSX::initialize_core() {
crash_handler.initialize();
OS_Unix::initialize_core();
DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES);
@ -2022,3 +2024,11 @@ OS_OSX::OS_OSX() {
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
void OS_OSX::disable_crash_handler() {
crash_handler.disable();
}
bool OS_OSX::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}

View File

@ -5,6 +5,7 @@ Import('env')
common_win = [
"context_gl_win.cpp",
"crash_handler_win.cpp",
"os_windows.cpp",
"ctxgl_procaddr.cpp",
"key_mapping_win.cpp",
@ -12,7 +13,7 @@ common_win = [
"packet_peer_udp_winsock.cpp",
"stream_peer_winsock.cpp",
"joypad.cpp",
"power_windows.cpp",
"power_windows.cpp",
]
restarget = "godot_res" + env["OBJSUFFIX"]

View File

@ -0,0 +1,211 @@
/*************************************************************************/
/* crash_handler_win.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "main/main.h"
#include "os_windows.h"
#ifdef CRASH_HANDLER_EXCEPTION
// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
#include <psapi.h>
#include <algorithm>
#include <iterator>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
// Some versions of imagehlp.dll lack the proper packing directives themselves
// so we need to do it.
#pragma pack(push, before_imagehlp, 8)
#include <imagehlp.h>
#pragma pack(pop, before_imagehlp)
struct module_data {
std::string image_name;
std::string module_name;
void *base_address;
DWORD load_size;
};
class symbol {
typedef IMAGEHLP_SYMBOL64 sym_type;
sym_type *sym;
static const int max_name_len = 1024;
public:
symbol(HANDLE process, DWORD64 address)
: sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) {
memset(sym, '\0', sizeof(*sym) + max_name_len);
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLength = max_name_len;
DWORD64 displacement;
SymGetSymFromAddr64(process, address, &displacement, sym);
}
std::string name() { return std::string(sym->Name); }
std::string undecorated_name() {
if (*sym->Name == '\0')
return "<couldn't map PC to fn name>";
std::vector<char> und_name(max_name_len);
UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE);
return std::string(&und_name[0], strlen(&und_name[0]));
}
};
class get_mod_info {
HANDLE process;
public:
get_mod_info(HANDLE h)
: process(h) {}
module_data operator()(HMODULE module) {
module_data ret;
char temp[4096];
MODULEINFO mi;
GetModuleInformation(process, module, &mi, sizeof(mi));
ret.base_address = mi.lpBaseOfDll;
ret.load_size = mi.SizeOfImage;
GetModuleFileNameEx(process, module, temp, sizeof(temp));
ret.image_name = temp;
GetModuleBaseName(process, module, temp, sizeof(temp));
ret.module_name = temp;
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
return ret;
}
};
DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
HANDLE process = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
DWORD offset_from_symbol = 0;
IMAGEHLP_LINE64 line = { 0 };
std::vector<module_data> modules;
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);
if (OS::get_singleton() == NULL || OS::get_singleton()->is_disable_crash_handler()) {
return EXCEPTION_CONTINUE_SEARCH;
}
fprintf(stderr, "%s: Program crashed\n", __FUNCTION__);
// Load the symbols:
if (!SymInitialize(process, NULL, false))
return EXCEPTION_CONTINUE_SEARCH;
SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
module_handles.resize(cbNeeded / sizeof(HMODULE));
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process));
void *base = modules[0].base_address;
// Setup stuff:
CONTEXT *context = ep->ContextRecord;
STACKFRAME64 frame;
bool skip_first = false;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
#ifdef _M_X64
frame.AddrPC.Offset = context->Rip;
frame.AddrStack.Offset = context->Rsp;
frame.AddrFrame.Offset = context->Rbp;
#else
frame.AddrPC.Offset = context->Eip;
frame.AddrStack.Offset = context->Esp;
frame.AddrFrame.Offset = context->Ebp;
// Skip the first one to avoid a duplicate on 32-bit mode
skip_first = true;
#endif
line.SizeOfStruct = sizeof(line);
IMAGE_NT_HEADERS *h = ImageNtHeader(base);
DWORD image_type = h->FileHeader.Machine;
int n = 0;
String msg = GLOBAL_GET("debug/settings/backtrace/message");
fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
do {
if (skip_first) {
skip_first = false;
} else {
if (frame.AddrPC.Offset != 0) {
std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name();
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line))
fprintf(stderr, "[%d] %s (%s:%d)\n", n, fnName.c_str(), line.FileName, line.LineNumber);
else
fprintf(stderr, "[%d] %s\n", n, fnName.c_str());
} else
fprintf(stderr, "[%d] ???\n", n);
n++;
}
if (!StackWalk64(image_type, process, hThread, &frame, context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
break;
} while (frame.AddrReturn.Offset != 0 && n < 256);
fprintf(stderr, "-- END OF BACKTRACE --\n");
SymCleanup(process);
// Pass the exception to the OS
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
CrashHandler::CrashHandler() {
disabled = false;
}
CrashHandler::~CrashHandler() {
}
void CrashHandler::disable() {
if (disabled)
return;
disabled = true;
}
void CrashHandler::initialize() {
}

View File

@ -0,0 +1,56 @@
/*************************************************************************/
/* crash_handler_win.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef CRASH_HANDLER_WIN_H
#define CRASH_HANDLER_WIN_H
#include <windows.h>
// Crash handler exception only enabled with MSVC
#if defined(DEBUG_ENABLED) && defined(MSVC)
#define CRASH_HANDLER_EXCEPTION 1
extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep);
#endif
class CrashHandler {
bool disabled;
public:
void initialize();
void disable();
bool is_disabled() const { return disabled; };
CrashHandler();
~CrashHandler();
};
#endif

View File

@ -123,7 +123,7 @@ def configure(env):
env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
elif (env["target"] == "debug"):
env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od'])
env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od', '/EHsc'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
env.Append(LINKFLAGS=['/DEBUG'])

View File

@ -157,24 +157,32 @@ int widechar_main(int argc, wchar_t **argv) {
};
int main(int _argc, char **_argv) {
// _argc and _argv are ignored
// we are going to use the WideChar version of them instead
// _argc and _argv are ignored
// we are going to use the WideChar version of them instead
LPWSTR *wc_argv;
int argc;
int result;
#ifdef CRASH_HANDLER_EXCEPTION
__try {
#endif
LPWSTR *wc_argv;
int argc;
int result;
wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (NULL == wc_argv) {
wprintf(L"CommandLineToArgvW failed\n");
return 0;
if (NULL == wc_argv) {
wprintf(L"CommandLineToArgvW failed\n");
return 0;
}
result = widechar_main(argc, wc_argv);
LocalFree(wc_argv);
return result;
#ifdef CRASH_HANDLER_EXCEPTION
} __except (CrashHandlerException(GetExceptionInformation())) {
return 1;
}
result = widechar_main(argc, wc_argv);
LocalFree(wc_argv);
return result;
#endif
}
HINSTANCE godot_hinstance = NULL;

View File

@ -164,6 +164,8 @@ const char *OS_Windows::get_audio_driver_name(int p_driver) const {
void OS_Windows::initialize_core() {
crash_handler.initialize();
last_button_state = 0;
//RedirectIOToConsole();
@ -2368,6 +2370,14 @@ bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
void OS_Windows::disable_crash_handler() {
crash_handler.disable();
}
bool OS_Windows::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
key_event_pos = 0;

View File

@ -31,6 +31,7 @@
#define OS_WINDOWS_H
#include "context_gl_win.h"
#include "crash_handler_win.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "os/input.h"
@ -134,6 +135,8 @@ class OS_Windows : public OS {
AudioDriverXAudio2 driver_xaudio2;
#endif
CrashHandler crash_handler;
void _drag_event(int p_x, int p_y, int idx);
void _touch_event(bool p_pressed, int p_x, int p_y, int idx);
@ -284,6 +287,9 @@ public:
virtual bool _check_internal_feature_support(const String &p_feature);
void disable_crash_handler();
bool is_disable_crash_handler() const;
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
};

View File

@ -3,12 +3,13 @@
Import('env')
common_x11 = [\
"context_gl_x11.cpp",\
"os_x11.cpp",\
"key_mapping_x11.cpp",\
"joypad_linux.cpp",\
"power_x11.cpp",\
common_x11 = [
"context_gl_x11.cpp",
"crash_handler_x11.cpp",
"os_x11.cpp",
"key_mapping_x11.cpp",
"joypad_linux.cpp",
"power_x11.cpp",
]
env.Program('#bin/godot', ['godot_x11.cpp'] + common_x11)

View File

@ -0,0 +1,135 @@
/*************************************************************************/
/* crash_handler_x11.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef DEBUG_ENABLED
#define CRASH_HANDLER_ENABLED 1
#endif
#include "main/main.h"
#include "os_x11.h"
#ifdef CRASH_HANDLER_ENABLED
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <signal.h>
static void handle_crash(int sig) {
if (OS::get_singleton() == NULL)
return;
void *bt_buffer[256];
size_t size = backtrace(bt_buffer, 256);
String _execpath = OS::get_singleton()->get_executable_path();
String msg = GLOBAL_GET("debug/settings/backtrace/message");
// Dump the backtrace to stderr with a message to the user
fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
for (size_t i = 1; i < size; i++) {
char fname[1024];
Dl_info info;
snprintf(fname, 1024, "%s", strings[i]);
// Try to demangle the function name to provide a more readable one
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
int status;
char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
if (status == 0 && demangled) {
snprintf(fname, 1024, "%s", demangled);
}
if (demangled)
free(demangled);
}
}
List<String> args;
char str[1024];
snprintf(str, 1024, "%p", bt_buffer[i]);
args.push_back(str);
args.push_back("-e");
args.push_back(_execpath);
String output = "";
// Try to get the file/line number using addr2line
if (OS::get_singleton()) {
int ret;
Error err = OS::get_singleton()->execute(String("addr2line"), args, true, NULL, &output, &ret);
if (err == OK) {
output.erase(output.length() - 1, 1);
}
}
fprintf(stderr, "[%ld] %s (%ls)\n", i, fname, output.c_str());
}
free(strings);
}
fprintf(stderr, "-- END OF BACKTRACE --\n");
// Abort to pass the error to the OS
abort();
}
#endif
CrashHandler::CrashHandler() {
disabled = false;
}
CrashHandler::~CrashHandler() {
}
void CrashHandler::disable() {
if (disabled)
return;
#ifdef CRASH_HANDLER_ENABLED
signal(SIGSEGV, NULL);
signal(SIGFPE, NULL);
signal(SIGILL, NULL);
#endif
disabled = true;
}
void CrashHandler::initialize() {
#ifdef CRASH_HANDLER_ENABLED
signal(SIGSEGV, handle_crash);
signal(SIGFPE, handle_crash);
signal(SIGILL, handle_crash);
#endif
}

View File

@ -0,0 +1,47 @@
/*************************************************************************/
/* crash_handler_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef CRASH_HANDLER_X11_H
#define CRASH_HANDLER_X11_H
class CrashHandler {
bool disabled;
public:
void initialize();
void disable();
bool is_disabled() const { return disabled; };
CrashHandler();
~CrashHandler();
};
#endif

View File

@ -87,6 +87,7 @@ def configure(env):
elif (env["target"] == "debug"):
env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
env.Append(LINKFLAGS=['-rdynamic'])
## Architecture

View File

@ -93,6 +93,13 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
return AudioDriverManager::get_driver(p_driver)->get_name();
}
void OS_X11::initialize_core() {
crash_handler.initialize();
OS_Unix::initialize_core();
}
void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
long im_event_mask = 0;
@ -2172,6 +2179,14 @@ int OS_X11::get_power_percent_left() {
return power_manager->get_power_percent_left();
}
void OS_X11::disable_crash_handler() {
crash_handler.disable();
}
bool OS_X11::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}
OS_X11::OS_X11() {
#ifdef RTAUDIO_ENABLED

View File

@ -31,6 +31,7 @@
#define OS_X11_H
#include "context_gl_x11.h"
#include "crash_handler_x11.h"
#include "drivers/unix/os_unix.h"
#include "os/input.h"
#include "servers/visual_server.h"
@ -170,6 +171,8 @@ class OS_X11 : public OS_Unix {
PowerX11 *power_manager;
CrashHandler crash_handler;
int audio_driver_index;
unsigned int capture_idle;
bool maximized;
@ -191,6 +194,7 @@ protected:
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
@ -273,6 +277,9 @@ public:
void run();
void disable_crash_handler();
bool is_disable_crash_handler() const;
OS_X11();
};