| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  crash_handler_linuxbsd.cpp                                            */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* 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.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 10:36:29 -03:00
										 |  |  | #include "crash_handler_linuxbsd.h"
 | 
					
						
							| 
									
										
										
										
											2019-02-12 15:43:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 19:33:38 -03:00
										 |  |  | #include "core/config/project_settings.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-11 18:13:45 +02:00
										 |  |  | #include "core/os/os.h"
 | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | #include "core/string/print_string.h"
 | 
					
						
							| 
									
										
										
										
											2021-04-12 16:59:23 +02:00
										 |  |  | #include "core/version.h"
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | #include "main/main.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 15:43:54 +01:00
										 |  |  | #ifdef DEBUG_ENABLED
 | 
					
						
							|  |  |  | #define CRASH_HANDLER_ENABLED 1
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | #ifdef CRASH_HANDLER_ENABLED
 | 
					
						
							|  |  |  | #include <cxxabi.h>
 | 
					
						
							|  |  |  | #include <dlfcn.h>
 | 
					
						
							|  |  |  | #include <execinfo.h>
 | 
					
						
							| 
									
										
										
										
											2023-01-15 01:18:00 +03:00
										 |  |  | #include <link.h>
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | #include <signal.h>
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:21:45 -03:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void handle_crash(int sig) { | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	if (OS::get_singleton() == nullptr) { | 
					
						
							| 
									
										
										
										
											2018-09-24 22:21:05 +01:00
										 |  |  | 		abort(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	void *bt_buffer[256]; | 
					
						
							|  |  |  | 	size_t size = backtrace(bt_buffer, 256); | 
					
						
							|  |  |  | 	String _execpath = OS::get_singleton()->get_executable_path(); | 
					
						
							| 
									
										
										
										
											2019-05-23 19:57:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	String msg; | 
					
						
							|  |  |  | 	const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); | 
					
						
							|  |  |  | 	if (proj_settings) { | 
					
						
							|  |  |  | 		msg = proj_settings->get("debug/settings/crash_handler/message"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 	// Tell MainLoop about the crash. This can be handled by users too in Node.
 | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	if (OS::get_singleton()->get_main_loop()) { | 
					
						
							| 
									
										
										
										
											2018-07-02 16:18:58 -03:00
										 |  |  | 		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-02 16:18:58 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 	// Dump the backtrace to stderr with a message to the user
 | 
					
						
							|  |  |  | 	print_error("\n================================================================"); | 
					
						
							|  |  |  | 	print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, sig)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-12 16:59:23 +02:00
										 |  |  | 	// Print the engine version just before, so that people are reminded to include the version in backtrace reports.
 | 
					
						
							| 
									
										
										
										
											2022-02-08 20:50:37 +01:00
										 |  |  | 	if (String(VERSION_HASH).is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 		print_error(vformat("Engine version: %s", VERSION_FULL_NAME)); | 
					
						
							| 
									
										
										
										
											2021-04-12 16:59:23 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 		print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH)); | 
					
						
							| 
									
										
										
										
											2021-04-12 16:59:23 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 	print_error(vformat("Dumping the backtrace. %s", msg)); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	char **strings = backtrace_symbols(bt_buffer, size); | 
					
						
							| 
									
										
										
										
											2023-01-15 01:18:00 +03:00
										 |  |  | 	// PIE executable relocation, zero for non-PIE executables
 | 
					
						
							| 
									
										
										
										
											2023-01-21 16:14:33 +01:00
										 |  |  | #ifdef __GLIBC__
 | 
					
						
							|  |  |  | 	// This is a glibc only thing apparently.
 | 
					
						
							| 
									
										
										
										
											2023-01-15 01:18:00 +03:00
										 |  |  | 	uintptr_t relocation = _r_debug.r_map->l_addr; | 
					
						
							| 
									
										
										
										
											2023-01-21 16:14:33 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	// Non glibc systems apparently don't give PIE relocation info.
 | 
					
						
							|  |  |  | 	uintptr_t relocation = 0; | 
					
						
							|  |  |  | #endif //__GLIBC__
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	if (strings) { | 
					
						
							| 
									
										
										
										
											2023-01-15 01:18:00 +03:00
										 |  |  | 		List<String> args; | 
					
						
							|  |  |  | 		for (size_t i = 0; i < size; i++) { | 
					
						
							|  |  |  | 			char str[1024]; | 
					
						
							|  |  |  | 			snprintf(str, 1024, "%p", (void *)((uintptr_t)bt_buffer[i] - relocation)); | 
					
						
							|  |  |  | 			args.push_back(str); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		args.push_back("-e"); | 
					
						
							|  |  |  | 		args.push_back(_execpath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Try to get the file/line number using addr2line
 | 
					
						
							|  |  |  | 		int ret; | 
					
						
							|  |  |  | 		String output = ""; | 
					
						
							|  |  |  | 		Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret); | 
					
						
							|  |  |  | 		Vector<String> addr2line_results; | 
					
						
							|  |  |  | 		if (err == OK) { | 
					
						
							|  |  |  | 			addr2line_results = output.substr(0, output.length() - 1).split("\n", false); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		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] == '_') { | 
					
						
							| 
									
										
										
										
											2022-10-01 21:09:22 +02:00
										 |  |  | 					int status = 0; | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 					char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					if (status == 0 && demangled) { | 
					
						
							|  |  |  | 						snprintf(fname, 1024, "%s", demangled); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					if (demangled) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 						free(demangled); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-15 01:18:00 +03:00
										 |  |  | 			print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, err == OK ? addr2line_results[i] : "")); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		free(strings); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 	print_error("-- END OF BACKTRACE --"); | 
					
						
							|  |  |  | 	print_error("================================================================"); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Abort to pass the error to the OS
 | 
					
						
							|  |  |  | 	abort(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CrashHandler::CrashHandler() { | 
					
						
							|  |  |  | 	disabled = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CrashHandler::~CrashHandler() { | 
					
						
							| 
									
										
										
										
											2018-09-24 22:21:05 +01:00
										 |  |  | 	disable(); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CrashHandler::disable() { | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	if (disabled) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef CRASH_HANDLER_ENABLED
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	signal(SIGSEGV, nullptr); | 
					
						
							|  |  |  | 	signal(SIGFPE, nullptr); | 
					
						
							|  |  |  | 	signal(SIGILL, nullptr); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	disabled = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CrashHandler::initialize() { | 
					
						
							|  |  |  | #ifdef CRASH_HANDLER_ENABLED
 | 
					
						
							|  |  |  | 	signal(SIGSEGV, handle_crash); | 
					
						
							|  |  |  | 	signal(SIGFPE, handle_crash); | 
					
						
							|  |  |  | 	signal(SIGILL, handle_crash); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } |