| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  crash_handler_windows.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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 15:43:54 +01:00
										 |  |  | #include "crash_handler_windows.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 19:33:38 -03:00
										 |  |  | #include "core/config/project_settings.h"
 | 
					
						
							| 
									
										
										
										
											2019-02-20 13:00:19 +01: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"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CRASH_HANDLER_EXCEPTION
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-12 19:05:16 +05:30
										 |  |  | // Backtrace code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <iterator>
 | 
					
						
							| 
									
										
										
										
											2020-04-26 22:27:04 +02:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2019-02-20 13:00:19 +01:00
										 |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-26 22:27:04 +02:00
										 |  |  | #include <psapi.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | // 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; | 
					
						
							| 
									
										
										
										
											2020-11-24 10:12:55 +01:00
										 |  |  | 	void *base_address = nullptr; | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	DWORD load_size; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class symbol { | 
					
						
							|  |  |  | 	typedef IMAGEHLP_SYMBOL64 sym_type; | 
					
						
							|  |  |  | 	sym_type *sym; | 
					
						
							|  |  |  | 	static const int max_name_len = 1024; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2017-12-06 21:36:34 +01:00
										 |  |  | 	symbol(HANDLE process, DWORD64 address) : | 
					
						
							|  |  |  | 			sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		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() { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		if (*sym->Name == '\0') { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 			return "<couldn't map PC to fn name>"; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		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: | 
					
						
							| 
									
										
										
										
											2017-12-06 21:36:34 +01:00
										 |  |  | 	get_mod_info(HANDLE h) : | 
					
						
							|  |  |  | 			process(h) {} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	if (OS::get_singleton() == nullptr || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		return EXCEPTION_CONTINUE_SEARCH; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02: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.
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01: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); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-02 16:18:58 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 	print_error("\n================================================================"); | 
					
						
							|  |  |  | 	print_error(vformat("%s: Program crashed", __FUNCTION__)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Print the engine version just before, so that people are reminded to include the version in backtrace reports.
 | 
					
						
							|  |  |  | 	if (String(VERSION_HASH).is_empty()) { | 
					
						
							|  |  |  | 		print_error(vformat("Engine version: %s", VERSION_FULL_NAME)); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	print_error(vformat("Dumping the backtrace. %s", msg)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	// Load the symbols:
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (!SymInitialize(process, nullptr, false)) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		return EXCEPTION_CONTINUE_SEARCH; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 11:12:54 +02:00
										 |  |  | 	SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_EXACT_SYMBOLS); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 12:55:23 +03:00
										 |  |  | #if defined(_M_X64)
 | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	frame.AddrPC.Offset = context->Rip; | 
					
						
							|  |  |  | 	frame.AddrStack.Offset = context->Rsp; | 
					
						
							|  |  |  | 	frame.AddrFrame.Offset = context->Rbp; | 
					
						
							| 
									
										
										
										
											2022-08-26 12:55:23 +03:00
										 |  |  | #elif defined(_M_ARM64) || defined(_M_ARM64EC)
 | 
					
						
							|  |  |  | 	frame.AddrPC.Offset = context->Pc; | 
					
						
							|  |  |  | 	frame.AddrStack.Offset = context->Sp; | 
					
						
							|  |  |  | 	frame.AddrFrame.Offset = context->Fp; | 
					
						
							|  |  |  | #elif defined(_M_ARM)
 | 
					
						
							|  |  |  | 	frame.AddrPC.Offset = context->Pc; | 
					
						
							|  |  |  | 	frame.AddrStack.Offset = context->Sp; | 
					
						
							|  |  |  | 	frame.AddrFrame.Offset = context->R11; | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | #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; | 
					
						
							| 
									
										
										
										
											2019-05-23 19:57:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int n = 0; | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	do { | 
					
						
							|  |  |  | 		if (skip_first) { | 
					
						
							|  |  |  | 			skip_first = false; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if (frame.AddrPC.Offset != 0) { | 
					
						
							|  |  |  | 				std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 				if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line)) { | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 					print_error(vformat("[%d] %s (%s:%d)", n, fnName.c_str(), (char *)line.FileName, (int)line.LineNumber)); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 					print_error(vformat("[%d] %s", n, fnName.c_str())); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 				print_error(vformat("[%d] ???", n)); | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			n++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		if (!StackWalk64(image_type, process, hThread, &frame, context, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr)) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 	} while (frame.AddrReturn.Offset != 0 && n < 256); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-05 11:45:42 +02:00
										 |  |  | 	print_error("-- END OF BACKTRACE --"); | 
					
						
							|  |  |  | 	print_error("================================================================"); | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	SymCleanup(process); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Pass the exception to the OS
 | 
					
						
							|  |  |  | 	return EXCEPTION_CONTINUE_SEARCH; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CrashHandler::CrashHandler() { | 
					
						
							|  |  |  | 	disabled = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CrashHandler::~CrashHandler() { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CrashHandler::disable() { | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	if (disabled) { | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2022-02-16 13:56:32 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-07 22:01:49 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	disabled = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CrashHandler::initialize() { | 
					
						
							|  |  |  | } |