Path: blob/master/platform/windows/crash_handler_windows_signal.cpp
10277 views
/**************************************************************************/1/* crash_handler_windows_signal.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "crash_handler_windows.h"3132#include "core/config/project_settings.h"33#include "core/object/script_language.h"34#include "core/os/os.h"35#include "core/string/print_string.h"36#include "core/version.h"37#include "main/main.h"3839#ifdef CRASH_HANDLER_EXCEPTION4041#include <cxxabi.h>42#include <algorithm>43#include <csignal>44#include <cstdlib>45#include <iterator>46#include <string>47#include <vector>4849#include <psapi.h>5051#include "thirdparty/libbacktrace/backtrace.h"5253struct CrashHandlerData {54int64_t index = 0;55backtrace_state *state = nullptr;56int64_t offset = 0;57};5859int symbol_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {60CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);61if (!function) {62return 0;63}6465char fname[1024];66snprintf(fname, 1024, "%s", function);6768if (function[0] == '_') {69int status;70char *demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status);7172if (status == 0 && demangled) {73snprintf(fname, 1024, "%s", demangled);74}7576if (demangled) {77free(demangled);78}79}8081print_error(vformat("[%d] %s (%s:%d)", ch_data->index++, String::utf8(fname), String::utf8(filename), lineno));82return 0;83}8485void error_callback(void *data, const char *msg, int errnum) {86CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);87if (ch_data->index == 0) {88print_error(vformat("Error(%d): %s", errnum, String::utf8(msg)));89} else {90print_error(vformat("[%d] error(%d): %s", ch_data->index++, errnum, String::utf8(msg)));91}92}9394int trace_callback(void *data, uintptr_t pc) {95CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);96backtrace_pcinfo(ch_data->state, pc - ch_data->offset, &symbol_callback, &error_callback, data);97return 0;98}99100int64_t get_image_base(const String &p_path) {101Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);102if (f.is_null()) {103return 0;104}105{106f->seek(0x3c);107uint32_t pe_pos = f->get_32();108109f->seek(pe_pos);110uint32_t magic = f->get_32();111if (magic != 0x00004550) {112return 0;113}114}115int64_t opt_header_pos = f->get_position() + 0x14;116f->seek(opt_header_pos);117118uint16_t opt_header_magic = f->get_16();119if (opt_header_magic == 0x10B) {120f->seek(opt_header_pos + 0x1C);121return f->get_32();122} else if (opt_header_magic == 0x20B) {123f->seek(opt_header_pos + 0x18);124return f->get_64();125} else {126return 0;127}128}129130extern void CrashHandlerException(int signal) {131CrashHandlerData data;132133if (OS::get_singleton() == nullptr || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) {134return;135}136137if (OS::get_singleton()->is_crash_handler_silent()) {138std::_Exit(0);139}140141String msg;142if (ProjectSettings::get_singleton()) {143msg = GLOBAL_GET("debug/settings/crash_handler/message");144}145146// Tell MainLoop about the crash. This can be handled by users too in Node.147if (OS::get_singleton()->get_main_loop()) {148OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);149}150151print_error("\n================================================================");152print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, signal));153154// Print the engine version just before, so that people are reminded to include the version in backtrace reports.155if (String(GODOT_VERSION_HASH).is_empty()) {156print_error(vformat("Engine version: %s", GODOT_VERSION_FULL_NAME));157} else {158print_error(vformat("Engine version: %s (%s)", GODOT_VERSION_FULL_NAME, GODOT_VERSION_HASH));159}160print_error(vformat("Dumping the backtrace. %s", msg));161162String _execpath = OS::get_singleton()->get_executable_path();163164// Load process and image info to determine ASLR addresses offset.165MODULEINFO mi;166GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &mi, sizeof(mi));167int64_t image_mem_base = reinterpret_cast<int64_t>(mi.lpBaseOfDll);168int64_t image_file_base = get_image_base(_execpath);169data.offset = image_mem_base - image_file_base;170171if (FileAccess::exists(_execpath + ".debugsymbols")) {172_execpath = _execpath + ".debugsymbols";173}174_execpath = _execpath.replace_char('/', '\\');175176CharString cs = _execpath.utf8(); // Note: should remain in scope during backtrace_simple call.177data.state = backtrace_create_state(cs.get_data(), 0, &error_callback, reinterpret_cast<void *>(&data));178if (data.state != nullptr) {179data.index = 1;180backtrace_simple(data.state, 1, &trace_callback, &error_callback, reinterpret_cast<void *>(&data));181}182183print_error("-- END OF C++ BACKTRACE --");184print_error("================================================================");185186for (const Ref<ScriptBacktrace> &backtrace : ScriptServer::capture_script_backtraces(false)) {187if (!backtrace->is_empty()) {188print_error(backtrace->format());189print_error(vformat("-- END OF %s BACKTRACE --", backtrace->get_language_name().to_upper()));190print_error("================================================================");191}192}193}194#endif195196CrashHandler::CrashHandler() {197disabled = false;198}199200CrashHandler::~CrashHandler() {201}202203void CrashHandler::disable() {204if (disabled) {205return;206}207208#if defined(CRASH_HANDLER_EXCEPTION)209signal(SIGSEGV, nullptr);210signal(SIGFPE, nullptr);211signal(SIGILL, nullptr);212#endif213214disabled = true;215}216217void CrashHandler::initialize() {218#if defined(CRASH_HANDLER_EXCEPTION)219signal(SIGSEGV, CrashHandlerException);220signal(SIGFPE, CrashHandlerException);221signal(SIGILL, CrashHandlerException);222#endif223}224225226