From a3b322075719280a3b5142ba24c1472ea70cd7cb Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Thu, 7 May 2026 01:25:07 -0700 Subject: [PATCH] macOS crash handler: Move symbolize with atos to its own function --- platform/linuxbsd/crash_handler_linuxbsd.cpp | 8 +- platform/macos/crash_handler_macos.mm | 62 ++------------ platform/macos/stack_trace_macos.h | 85 +++++++++++++++++++ .../windows/crash_handler_windows_signal.cpp | 12 +-- 4 files changed, 101 insertions(+), 66 deletions(-) create mode 100644 platform/macos/stack_trace_macos.h diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index 4a151b6a62..4910c0c3e1 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -93,10 +93,10 @@ static void handle_crash(int sig) { void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); - String _execpath = OS::get_singleton()->get_executable_path(); + String exec_path = OS::get_singleton()->get_executable_path(); - if (FileAccess::exists(_execpath + ".debugsymbols")) { - _execpath = _execpath + ".debugsymbols"; + if (FileAccess::exists(exec_path + ".debugsymbols")) { + exec_path = exec_path + ".debugsymbols"; } String msg; @@ -151,7 +151,7 @@ static void handle_crash(int sig) { args.push_back(str); } args.push_back("-e"); - args.push_back(_execpath); + args.push_back(exec_path); args.push_back("-f"); args.push_back("-p"); args.push_back("-C"); diff --git a/platform/macos/crash_handler_macos.mm b/platform/macos/crash_handler_macos.mm index 9fa88d7bc6..ee303bc8e9 100644 --- a/platform/macos/crash_handler_macos.mm +++ b/platform/macos/crash_handler_macos.mm @@ -47,30 +47,10 @@ #endif #ifdef CRASH_HANDLER_ENABLED +#include "stack_trace_macos.h" + #include -#include #include -#import -#import - -#include -#include - -static uint64_t load_address() { - char full_path[1024]; - uint32_t size = sizeof(full_path); - - if (!_NSGetExecutablePath(full_path, &size)) { - void *handle = dlopen(full_path, RTLD_LAZY | RTLD_NOLOAD); - void *addr = dlsym(handle, "main"); - Dl_info info; - if (dladdr(addr, &info)) { - return (uint64_t)info.dli_fbase; - } - } - - return 0; -} static void handle_crash(int sig) { signal(SIGSEGV, SIG_DFL); @@ -88,7 +68,7 @@ static void handle_crash(int sig) { void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); - String _execpath = OS::get_singleton()->get_executable_path(); + String exec_path = OS::get_singleton()->get_executable_path(); String msg; if (ProjectSettings::get_singleton()) { @@ -112,42 +92,12 @@ static void handle_crash(int sig) { } print_error(vformat("Dumping the backtrace. %s", msg)); - List args; - args.push_back("-o"); - args.push_back(_execpath); - -#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) - args.push_back("-arch"); - args.push_back("x86_64"); -#elif defined(__aarch64__) - args.push_back("-arch"); - args.push_back("arm64"); -#endif - - args.push_back("--fullPath"); - args.push_back("-l"); - - char str[1024]; - void *load_addr = (void *)load_address(); - snprintf(str, 1024, "%p", load_addr); - args.push_back(str); - - for (size_t i = 0; i < size; i++) { - snprintf(str, 1024, "%p", bt_buffer[i]); - args.push_back(str); - } - + const void *load_addr = StackTraceMacOS::find_executable_load_address(); print_error(vformat("Load address: %x\n", (uint64_t)load_addr)); - // Single execution of atos with all addresses. - String out; - int ret; - Error err = OS::get_singleton()->execute(String("atos"), args, &out, &ret); - - if (err == OK) { - // Parse the multi-line output - Vector lines = out.split("\n"); + const Vector lines = StackTraceMacOS::symbolize_with_atos(exec_path, load_addr, bt_buffer, size); + if (!lines.is_empty()) { // Get demangled names from dladdr for fallback. char **strings = backtrace_symbols(bt_buffer, size); diff --git a/platform/macos/stack_trace_macos.h b/platform/macos/stack_trace_macos.h new file mode 100644 index 0000000000..e84a958362 --- /dev/null +++ b/platform/macos/stack_trace_macos.h @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* stack_trace_macos.h */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#pragma once + +#include "core/os/os.h" + +#include +#include + +namespace StackTraceMacOS { + +static void *find_executable_load_address() { + char full_path[1024]; + uint32_t size = sizeof(full_path); + if (!_NSGetExecutablePath(full_path, &size)) { + void *handle = dlopen(full_path, RTLD_LAZY | RTLD_NOLOAD); + void *addr = dlsym(handle, "main"); + Dl_info info; + if (dladdr(addr, &info)) { + return info.dli_fbase; + } + } + return nullptr; +} + +static Vector symbolize_with_atos(const String &p_exec_path, const void *p_load_addr, const void *const *p_backtrace_addresses, size_t p_backtrace_size) { + List args; + args.push_back("-o"); + args.push_back(p_exec_path); +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) + args.push_back("-arch"); + args.push_back("x86_64"); +#elif defined(__aarch64__) || defined(__arm64__) + args.push_back("-arch"); + args.push_back("arm64"); +#endif + args.push_back("--fullPath"); + args.push_back("-l"); + // Add load address first, then the backtrace addresses. + char str[1024]; + snprintf(str, sizeof(str), "%p", p_load_addr); + args.push_back(String(str)); + for (size_t i = 0; i < p_backtrace_size; i++) { + snprintf(str, sizeof(str), "%p", p_backtrace_addresses[i]); + args.push_back(String(str)); + } + // Execute atos with the arguments and capture the output. + String atos_output; + int ret = 0; + const Error err = OS::get_singleton()->execute("atos", args, &atos_output, &ret); + if (err == OK && ret == 0 && !atos_output.is_empty()) { + return atos_output.split("\n", false); + } + return Vector(); +} + +} // namespace StackTraceMacOS diff --git a/platform/windows/crash_handler_windows_signal.cpp b/platform/windows/crash_handler_windows_signal.cpp index d0f6231411..15fad835bc 100644 --- a/platform/windows/crash_handler_windows_signal.cpp +++ b/platform/windows/crash_handler_windows_signal.cpp @@ -241,13 +241,13 @@ extern void CrashHandlerException(int signal) { } print_error(vformat("Dumping the backtrace. %s", msg)); - String _execpath = OS::get_singleton()->get_executable_path(); + String exec_path = OS::get_singleton()->get_executable_path(); // Load process and image info to determine ASLR addresses offset. MODULEINFO mi; GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &mi, sizeof(mi)); int64_t image_mem_base = reinterpret_cast(mi.lpBaseOfDll); - int64_t image_file_base = get_image_base(_execpath); + int64_t image_file_base = get_image_base(exec_path); data.offset = image_mem_base - image_file_base; std::vector modules; @@ -268,12 +268,12 @@ extern void CrashHandlerException(int signal) { print_error(vformat("Load address: %x\n", (uint64_t)data.offset)); - if (FileAccess::exists(_execpath + ".debugsymbols")) { - _execpath = _execpath + ".debugsymbols"; + if (FileAccess::exists(exec_path + ".debugsymbols")) { + exec_path = exec_path + ".debugsymbols"; } - _execpath = _execpath.replace_char('/', '\\'); + exec_path = exec_path.replace_char('/', '\\'); - CharString cs = _execpath.utf8(); // Note: should remain in scope during backtrace_simple call. + CharString cs = exec_path.utf8(); // Note: should remain in scope during backtrace_simple call. data.state = backtrace_create_state(cs.get_data(), 0, &error_callback, reinterpret_cast(&data)); if (data.state != nullptr) { data.index = 1;