Linux: Resolve backtrace symbols directly from .symtab instead of .dynsym (#385)

This commit is contained in:
goeiecool9999 2022-10-20 13:12:16 +02:00 committed by GitHub
parent 271a4e4719
commit 9df1325d14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 182 additions and 16 deletions

View file

@ -2,41 +2,60 @@
#include <execinfo.h>
#include <string.h>
#include <string>
#include "config/CemuConfig.h"
#include "util/helpers/StringHelpers.h"
#if BOOST_OS_LINUX
#include "ELFSymbolTable.h"
#endif
#if BOOST_OS_LINUX
void demangleAndPrintBacktrace(char** backtrace, size_t size)
{
ELFSymbolTable symTable;
for (char** i = backtrace; i < backtrace + size; i++)
{
std::string traceLine{*i};
std::string_view traceLine{*i};
// basic check to see if the backtrace line matches expected format
size_t parenthesesOpen = traceLine.find_last_of('(');
size_t parenthesesClose = traceLine.find_last_of(')');
size_t offsetPlus = traceLine.find_last_of('+');
if (!parenthesesOpen || !parenthesesClose || !offsetPlus ||
offsetPlus < parenthesesOpen || offsetPlus > parenthesesClose)
{
// something unexpected was read. fall back to default string
// fall back to default string
std::cerr << traceLine << std::endl;
continue;
}
std::string symbolName = traceLine.substr(parenthesesOpen+1,offsetPlus-parenthesesOpen-1);
int status = -1;
char* demangled = abi::__cxa_demangle(symbolName.c_str(), nullptr, nullptr, &status);
if (demangled)
// attempt to resolve symbol from regular symbol table if missing from dynamic symbol table
uint64 newOffset = -1;
std::string_view symbolName = traceLine.substr(parenthesesOpen+1, offsetPlus-parenthesesOpen-1);
if (symbolName.empty())
{
std::cerr << traceLine.substr(0, parenthesesOpen+1);
std::cerr << demangled;
std::cerr << traceLine.substr(offsetPlus) << std::endl;
free(demangled);
uint64 symbolOffset = StringHelpers::ToInt64(traceLine.substr(offsetPlus+1,offsetPlus+1-parenthesesClose-1));
symbolName = symTable.OffsetToSymbol(symbolOffset, newOffset);
}
std::cerr << traceLine.substr(0, parenthesesOpen+1);
std::cerr << boost::core::demangle(symbolName.empty() ? "" : symbolName.data());
// print relative or existing symbol offset.
std::cerr << '+';
if (newOffset != -1)
{
std::cerr << std::hex << newOffset;
std::cerr << traceLine.substr(parenthesesClose) << std::endl;
}
else
{
std::cerr << traceLine << std::endl;
std::cerr << traceLine.substr(offsetPlus+1) << std::endl;
}
}
}
#endif
// handle signals that would dump core, print stacktrace and then dump depending on config
void handlerDumpingSignal(int sig)
@ -61,6 +80,7 @@ void handlerDumpingSignal(int sig)
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
#if BOOST_OS_LINUX
char** symbol_trace = backtrace_symbols(array, size);
if (symbol_trace)
@ -72,6 +92,9 @@ void handlerDumpingSignal(int sig)
{
std::cerr << "Failed to read backtrace" << std::endl;
}
#else
backtrace_symbols_fd(array, size, STDERR_FILENO);
#endif
if (GetConfig().crash_dump == CrashDump::Enabled)
{