[macOS/Linux] Add module information to the crash handler.
This commit is contained in:
@@ -105,7 +105,15 @@ static void handle_crash(int sig) {
|
||||
uintptr_t relocation = 0;
|
||||
#endif //__GLIBC__
|
||||
|
||||
print_error(vformat("Load address: %x\n", (uint64_t)relocation));
|
||||
void *load_addr = nullptr;
|
||||
{
|
||||
Dl_info info;
|
||||
if (dladdr(bt_buffer[size - 1], &info)) {
|
||||
load_addr = info.dli_fbase;
|
||||
}
|
||||
}
|
||||
|
||||
print_error(vformat("Load address: %x\n", (uint64_t)load_addr));
|
||||
|
||||
if (strings) {
|
||||
int ret;
|
||||
@@ -146,40 +154,76 @@ static void handle_crash(int sig) {
|
||||
args.push_back("-C");
|
||||
|
||||
// Try to get the file/line number using addr2line
|
||||
String output;
|
||||
Error err = OS::get_singleton()->execute(exe_name, args, &output, &ret);
|
||||
String addr2line_output;
|
||||
Error err = OS::get_singleton()->execute(exe_name, args, &addr2line_output, &ret);
|
||||
if (err == OK) {
|
||||
Vector<String> addr2line_results = output.substr(0, output.length() - 1).split("\n", false);
|
||||
Vector<String> addr2line_results = addr2line_output.substr(0, addr2line_output.length() - 1).split("\n", false);
|
||||
|
||||
for (size_t i = 1; i < size; i++) {
|
||||
// Simplify printed file paths to remove redundant `/./` sections (e.g. `/opt/godot/./core` -> `/opt/godot/core`).
|
||||
print_error(vformat("[%d] %x - %s", (int64_t)i, (uint64_t)bt_buffer[i], addr2line_results[i].replace("/./", "/")));
|
||||
}
|
||||
} else {
|
||||
// Otherwise fall back to trace symbols.
|
||||
for (size_t i = 1; i < size; i++) {
|
||||
char fname[1024];
|
||||
String output = addr2line_results[i].replace("/./", "/");
|
||||
String mod_name = "main";
|
||||
uint64_t mod_off = (uint64_t)load_addr;
|
||||
bool addr2line_fail = output.strip_edges().ends_with("??:0");
|
||||
if (addr2line_fail) {
|
||||
output = String(strings[i]);
|
||||
}
|
||||
|
||||
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] == '_') {
|
||||
if (dladdr(bt_buffer[i], &info)) {
|
||||
mod_off = (uint64_t)info.dli_fbase;
|
||||
if (mod_off != (uint64_t)load_addr) {
|
||||
mod_name = String(info.dli_fname).get_file();
|
||||
}
|
||||
if (addr2line_fail && info.dli_sname && info.dli_sname[0] == '_') {
|
||||
int status = 0;
|
||||
char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
|
||||
|
||||
if (status == 0 && demangled) {
|
||||
snprintf(fname, 1024, "%s", demangled);
|
||||
output = String(demangled);
|
||||
}
|
||||
|
||||
if (demangled) {
|
||||
free(demangled);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mod_name = "<unknown module>";
|
||||
}
|
||||
|
||||
print_error(vformat("[%d] %x - %s", (int64_t)i, (uint64_t)bt_buffer[i], fname));
|
||||
// Simplify printed file paths to remove redundant `/./` sections (e.g. `/opt/godot/./core` -> `/opt/godot/core`).
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s", (int64_t)i, (uint64_t)bt_buffer[i], mod_name, (uint64_t)bt_buffer[i] - mod_off, output));
|
||||
}
|
||||
} else {
|
||||
// Otherwise fall back to trace symbols.
|
||||
for (size_t i = 1; i < size; i++) {
|
||||
String output = String(strings[i]);
|
||||
String mod_name = "main";
|
||||
uint64_t mod_off = (uint64_t)load_addr;
|
||||
|
||||
Dl_info info;
|
||||
// Try to demangle the function name to provide a more readable one.
|
||||
if (dladdr(bt_buffer[i], &info)) {
|
||||
mod_off = (uint64_t)info.dli_fbase;
|
||||
if (mod_off != (uint64_t)load_addr) {
|
||||
mod_name = String(info.dli_fname).get_file();
|
||||
}
|
||||
if (info.dli_sname && info.dli_sname[0] == '_') {
|
||||
int status = 0;
|
||||
char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
|
||||
|
||||
if (status == 0 && demangled) {
|
||||
output = String(demangled);
|
||||
}
|
||||
|
||||
if (demangled) {
|
||||
free(demangled);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mod_name = "<unknown module>";
|
||||
}
|
||||
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s", (int64_t)i, (uint64_t)bt_buffer[i], mod_name, (uint64_t)bt_buffer[i] - mod_off, output));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,32 +153,41 @@ static void handle_crash(int sig) {
|
||||
|
||||
for (int i = 1; i < lines.size() && i < (int)size; i++) {
|
||||
String output = lines[i];
|
||||
String mod_name = "main";
|
||||
uint64_t mod_off = (uint64_t)load_addr;
|
||||
|
||||
// If atos failed for this address, fall back to dladdr.
|
||||
if (output.substr(0, 2) == "0x" && strings) {
|
||||
char fname[1024];
|
||||
if (strings) {
|
||||
bool atos_fail = output.substr(0, 2) == "0x";
|
||||
if (atos_fail) {
|
||||
Vector<String> fname_spl = String(strings[i]).split(" ", false, 3);
|
||||
output = fname_spl[fname_spl.size() - 1];
|
||||
}
|
||||
|
||||
Dl_info info;
|
||||
|
||||
snprintf(fname, 1024, "%s", strings[i]);
|
||||
|
||||
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
|
||||
if (info.dli_sname[0] == '_') {
|
||||
if (dladdr(bt_buffer[i], &info)) {
|
||||
mod_off = (uint64_t)info.dli_fbase;
|
||||
if (mod_off != (uint64_t)load_addr) {
|
||||
mod_name = String(info.dli_fname).get_file();
|
||||
}
|
||||
if (atos_fail && info.dli_sname && info.dli_sname[0] == '_') {
|
||||
int status;
|
||||
char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
|
||||
|
||||
if (status == 0 && demangled) {
|
||||
snprintf(fname, 1024, "%s", demangled);
|
||||
output = String(demangled);
|
||||
}
|
||||
|
||||
if (demangled) {
|
||||
free(demangled);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mod_name = "<unknown module>";
|
||||
}
|
||||
output = fname;
|
||||
}
|
||||
|
||||
print_error(vformat("[%d] %x - %s", (int64_t)i, (uint64_t)bt_buffer[i], output));
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s", (int64_t)i, (uint64_t)bt_buffer[i], mod_name, (uint64_t)bt_buffer[i] - mod_off, output));
|
||||
}
|
||||
|
||||
if (strings) {
|
||||
@@ -189,7 +198,35 @@ static void handle_crash(int sig) {
|
||||
char **strings = backtrace_symbols(bt_buffer, size);
|
||||
if (strings) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
print_error(vformat("[%d] %x - %s", (int64_t)i, (uint64_t)bt_buffer[i], strings[i]));
|
||||
Vector<String> fname_spl = String(strings[i]).split(" ", false, 3);
|
||||
String output = fname_spl[fname_spl.size() - 1];
|
||||
|
||||
String mod_name = "main";
|
||||
uint64_t mod_off = (uint64_t)load_addr;
|
||||
|
||||
Dl_info info;
|
||||
if (dladdr(bt_buffer[i], &info)) {
|
||||
mod_off = (uint64_t)info.dli_fbase;
|
||||
if (mod_off != (uint64_t)load_addr) {
|
||||
mod_name = String(info.dli_fname).get_file();
|
||||
}
|
||||
if (info.dli_sname && info.dli_sname[0] == '_') {
|
||||
int status;
|
||||
char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
|
||||
|
||||
if (status == 0 && demangled) {
|
||||
output = String(demangled);
|
||||
}
|
||||
|
||||
if (demangled) {
|
||||
free(demangled);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mod_name = "<unknown module>";
|
||||
}
|
||||
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s", (int64_t)i, (uint64_t)bt_buffer[i], mod_name, (uint64_t)bt_buffer[i] - mod_off, output));
|
||||
}
|
||||
free(strings);
|
||||
}
|
||||
|
||||
@@ -109,9 +109,7 @@ public:
|
||||
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, nullptr, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
|
||||
SymLoadModule64(process, nullptr, ret.image_name.c_str(), ret.module_name.c_str(), (DWORD64)ret.base_address, ret.load_size);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@@ -229,11 +227,11 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
|
||||
}
|
||||
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line)) {
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s (%s:%d)", n, (uint64_t)frame.AddrPC.Offset, mod_name, (uint64_t)frame.AddrPC.Offset - offset, fnName.c_str(), (char *)line.FileName, (int)line.LineNumber));
|
||||
} else {
|
||||
} else if (!fnName.empty()) {
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s", n, (uint64_t)frame.AddrPC.Offset, mod_name, (uint64_t)frame.AddrPC.Offset - offset, fnName.c_str()));
|
||||
} else {
|
||||
print_error(vformat("[%d] %x (%s+%x) - ???", n, (uint64_t)frame.AddrPC.Offset, mod_name, (uint64_t)frame.AddrPC.Offset - offset));
|
||||
}
|
||||
} else {
|
||||
print_error(vformat("[%d] ???", n));
|
||||
}
|
||||
|
||||
n++;
|
||||
|
||||
@@ -94,9 +94,7 @@ public:
|
||||
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, nullptr, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
|
||||
SymLoadModule64(process, nullptr, ret.image_name.c_str(), ret.module_name.c_str(), (DWORD64)ret.base_address, ret.load_size);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@@ -141,9 +139,7 @@ int symbol_callback(void *data, uintptr_t pc, const char *filename, int lineno,
|
||||
}
|
||||
print_error(vformat("[%d] %x (%s+%x) - %s (%s:%d)", ch_data->index++, ch_data->pc, mod_name, ch_data->pc - offset, String::utf8(fname), String::utf8(filename), lineno));
|
||||
} else if ((int64_t)ch_data->pc > 0) {
|
||||
print_error(vformat("[%d] %x (%s+%x) - <couldn't map PC to fn name>", ch_data->index++, ch_data->pc, mod_name, ch_data->pc - offset));
|
||||
} else {
|
||||
print_error(vformat("[%d] ???", ch_data->index++));
|
||||
print_error(vformat("[%d] %x (%s+%x) - ???", ch_data->index++, ch_data->pc, mod_name, ch_data->pc - offset));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -287,6 +283,10 @@ extern void CrashHandlerException(int signal) {
|
||||
print_error("-- END OF C++ BACKTRACE --");
|
||||
print_error("================================================================");
|
||||
|
||||
if (data.sym_ok) {
|
||||
SymCleanup(data.process);
|
||||
}
|
||||
|
||||
for (const Ref<ScriptBacktrace> &backtrace : ScriptServer::capture_script_backtraces(false)) {
|
||||
if (!backtrace->is_empty()) {
|
||||
print_error(backtrace->format());
|
||||
|
||||
Reference in New Issue
Block a user