diff --git a/src/common/Util/CrashHandler.cpp b/src/common/Util/CrashHandler.cpp new file mode 100644 index 00000000..7bec23f2 --- /dev/null +++ b/src/common/Util/CrashHandler.cpp @@ -0,0 +1,140 @@ +#include "CrashHandler.h" + +#include +#include + +#ifndef _WIN32 +#include +#include +#else + +#endif + +using namespace Sapphire::Common; + +Util::CrashHandler::CrashHandler() +{ + signal( SIGABRT, signalHandler ); + signal( SIGSEGV, signalHandler ); + signal( SIGILL, signalHandler ); + signal( SIGFPE, signalHandler ); + +#ifndef _WIN32 + // SIGBUS not supported on windows + signal( SIGBUS, signalHandler ); +#endif + +#undef REGISTER_SIGNAL +} + +void Util::CrashHandler::signalHandler( int sigNum ) +{ +#define ADD_SIGNAL_MAP( x ) case x: name = #x; break; + const char* name = nullptr; + switch( sigNum ) + { + ADD_SIGNAL_MAP( SIGABRT ); + ADD_SIGNAL_MAP( SIGSEGV ); + ADD_SIGNAL_MAP( SIGILL ); + ADD_SIGNAL_MAP( SIGFPE ); +#ifndef _WIN32 + // SIGBUS not supported on windows + ADD_SIGNAL_MAP( SIGBUS ); +#endif + } +#undef ADD_SIGNAL_MAP + + if( name ) + { + Logger::fatal( "Caught signal {} ({})", sigNum, name ); + } + else + { + Logger::fatal( "Caught signal {}", sigNum ); + } + + printStackTrace(); + + exit( sigNum ); +} + + +void Util::CrashHandler::printStackTrace( unsigned int max_frames ) +{ + Logger::fatal( "Stack trace:" ); + +#ifndef _WIN32 + + void* addrlist[ max_frames + 1 ]; + + int addrlen = backtrace( addrlist, sizeof( addrlist ) / sizeof( void* ) ); + + if ( addrlen == 0 ) + { + Logger::fatal( "No stack addresses available." ); + return; + } + + char** symbollist = backtrace_symbols( addrlist, addrlen ); + + size_t funcnamesize = 1024; + char funcname[1024]; + + // iterate over the returned symbol lines. skip the first, it is the + // address of this function. + for ( unsigned int i = 0; i < addrlen; i++ ) + { + char* begin_name = NULL; + char* begin_offset = NULL; + char* end_offset = NULL; + + // find parentheses and +address offset surrounding the mangled name + for ( char *p = symbollist[i]; *p; ++p ) + { + if ( *p == '(' ) + begin_name = p; + else if ( *p == '+' ) + begin_offset = p; + else if ( *p == ')' && ( begin_offset || begin_name )) + end_offset = p; + } + + if ( begin_name && end_offset && ( begin_name < end_offset )) + { + *begin_name++ = '\0'; + *end_offset++ = '\0'; + if( begin_offset ) + *begin_offset++ = '\0'; + + // mangled name is now in [begin_name, begin_offset) and caller + // offset in [begin_offset, end_offset). now apply + // __cxa_demangle(): + + int status = 0; + char* ret = abi::__cxa_demangle( begin_name, funcname, + &funcnamesize, &status ); + char* fname = begin_name; + if( status == 0 ) + fname = ret; + + const char* format = " {} {:40} {} + {}"; + + if( begin_offset ) + { + Logger::fatal( format, end_offset, symbollist[ i ], fname, begin_offset ); + } + else + { + Logger::fatal( format, end_offset, symbollist[ i ], fname, "" ); + } + } + } + + free( symbollist ); + +#else + +#warning Crash handling isn''t supported on Windows yet. + +#endif +} \ No newline at end of file diff --git a/src/common/Util/CrashHandler.h b/src/common/Util/CrashHandler.h new file mode 100644 index 00000000..4745857c --- /dev/null +++ b/src/common/Util/CrashHandler.h @@ -0,0 +1,28 @@ +#ifndef SAPPHIRE_SIGNALHANDLER_H +#define SAPPHIRE_SIGNALHANDLER_H + + +// based on: https://oroboro.com/stack-trace-on-crash/ + +namespace Sapphire::Common::Util +{ + + /*! + * @brief Provides cross platform stack trace dumping. + * + * Statically init it somewhere so it registers the signal handlers before main runs and you're good to go. + */ + class CrashHandler + { + public: + CrashHandler(); + virtual ~CrashHandler() = default; + + private: + static void signalHandler( int sigNum ); + + static void printStackTrace( unsigned int max_frames = 63 ); + }; +} + +#endif //SAPPHIRE_CRASHHANDLER_H diff --git a/src/tools/exd_struct_test/main.cpp b/src/tools/exd_struct_test/main.cpp index 21c07566..218f89af 100644 --- a/src/tools/exd_struct_test/main.cpp +++ b/src/tools/exd_struct_test/main.cpp @@ -16,6 +16,10 @@ #include #include +#include + +Sapphire::Common::Util::CrashHandler crashHandler; + Sapphire::Data::ExdDataGenerated g_exdData; using namespace Sapphire; @@ -23,12 +27,21 @@ using namespace Sapphire; //const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" ); const std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" ); +int shit() +{ + int* ptr = nullptr; + + *ptr = 1; +} + int main() { Logger::init( "struct_test" ); + shit(); + Logger::info( "Setting up EXD data" ); if( !g_exdData.init( datLocation ) ) {