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

This commit is contained in:
Marcelo Fernandez 2017-08-03 21:07:16 -03:00
parent 8be9e8b484
commit 60cf34b968
23 changed files with 782 additions and 13 deletions

View file

@ -285,6 +285,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

@ -64,6 +64,10 @@ Error EditorRun::run(const String &p_scene, const String p_custom_args, const Li
args.push_back("-debugnav");
}
if (OS::get_singleton()->is_disable_crash_handler()) {
args.push_back("--disable-crash-handler");
}
int screen = EditorSettings::get_singleton()->get("game_window_placement/screen");
if (screen == 0) {

View file

@ -945,6 +945,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;
@ -985,6 +989,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

@ -179,6 +179,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print("\t-lang [locale]: Use a specific locale\n");
OS::get_singleton()->print("\t-rfs <host/ip>[:<port>] : Remote FileSystem.\n");
OS::get_singleton()->print("\t-rfs_pass <password> : Password for Remote FileSystem.\n");
OS::get_singleton()->print("\t-dch : Disable crash handler when supported by the platform code.\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print("\t-doctool FILE: Dump the whole engine api to FILE in XML format. If FILE exists, it will be merged.\n");
OS::get_singleton()->print("\t-nodocbase: Disallow dump the base types (used with -doctool).\n");
@ -212,6 +213,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
performance = memnew(Performance);
globals->add_singleton(Globals::Singleton("Performance", performance));
GLOBAL_DEF("application/crash_handler_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 */
@ -536,6 +539,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else {
goto error;
}
} else if (I->get() == "-dch") {
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 = [
'joystick_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,179 @@
/*************************************************************************/
/* 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 <stdlib.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 || Globals::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 = Globals::get_singleton()->get("application/crash_handler_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"
@ -111,6 +112,8 @@ public:
Size2 window_size;
Rect2 restore_rect;
CrashHandler crash_handler;
float _mouse_scale(float p_scale) {
if (display_scale > 1.0)
return p_scale;
@ -214,6 +217,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

@ -842,6 +842,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);
@ -1888,3 +1890,11 @@ OS_OSX::OS_OSX() {
zoomed = false;
display_scale = 1.0;
}
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",

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() || Globals::get_singleton() == NULL || IsDebuggerPresent()) {
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 = Globals::get_singleton()->get("application/crash_handler_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

@ -240,7 +240,7 @@ def configure(env):
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

@ -156,10 +156,7 @@ int widechar_main(int argc, wchar_t **argv) {
return os.get_exit_code();
};
int main(int _argc, char **_argv) {
// _argc and _argv are ignored
// we are going to use the WideChar version of them instead
int _main() {
LPWSTR *wc_argv;
int argc;
int result;
@ -177,6 +174,21 @@ int main(int _argc, char **_argv) {
return result;
}
int main(int _argc, char **_argv) {
// _argc and _argv are ignored
// we are going to use the WideChar version of them instead
#ifdef CRASH_HANDLER_EXCEPTION
__try {
return _main();
} __except (CrashHandlerException(GetExceptionInformation())) {
return 1;
}
#else
return _main();
#endif
}
HINSTANCE godot_hinstance = NULL;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

View file

@ -170,6 +170,8 @@ static MemoryPoolDynamic *mempool_dynamic = NULL;
void OS_Windows::initialize_core() {
crash_handler.initialize();
last_button_state = 0;
//RedirectIOToConsole();
@ -2309,6 +2311,14 @@ bool OS_Windows::is_vsync_enabled() const {
return true;
}
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 "os/input.h"
#include "os/os.h"
#include "servers/physics/physics_server_sw.h"
@ -38,8 +39,8 @@
#include "servers/visual_server.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "servers/audio/audio_server_sw.h"
#include "servers/audio/sample_manager_sw.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
@ -137,6 +138,8 @@ class OS_Windows : public OS {
AudioDriverRtAudio driver_rtaudio;
#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);
@ -277,6 +280,9 @@ public:
virtual void set_use_vsync(bool p_enable);
virtual bool is_vsync_enabled() const;
void disable_crash_handler();
bool is_disable_crash_handler() const;
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
};

View file

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

View file

@ -0,0 +1,136 @@
/*************************************************************************/
/* 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>
#include <stdlib.h>
static void handle_crash(int sig) {
if (OS::get_singleton() == NULL || Globals::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 = Globals::get_singleton()->get("application/crash_handler_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

@ -138,6 +138,7 @@ def configure(env):
elif (env["target"] == "debug"):
env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
env.Append(LINKFLAGS=['-rdynamic'])
env.ParseConfig('pkg-config x11 --cflags --libs')
env.ParseConfig('pkg-config xinerama --cflags --libs')

View file

@ -90,6 +90,13 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
return AudioDriverManagerSW::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) {
last_button_state = 0;
@ -2015,3 +2022,11 @@ OS_X11::OS_X11() {
xim_style = 0L;
mouse_mode = MOUSE_MODE_VISIBLE;
}
void OS_X11::disable_crash_handler() {
crash_handler.disable();
}
bool OS_X11::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}

View file

@ -31,6 +31,7 @@
#define OS_X11_H
#include "context_gl_x11.h"
#include "crash_handler_x11.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
@ -173,6 +174,8 @@ class OS_X11 : public OS_Unix {
Atom net_wm_icon;
CrashHandler crash_handler;
int audio_driver_index;
unsigned int capture_idle;
bool maximized;
@ -194,6 +197,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();
@ -266,6 +270,9 @@ public:
void run();
void disable_crash_handler();
bool is_disable_crash_handler() const;
OS_X11();
};