mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
684 lines
19 KiB
C++
684 lines
19 KiB
C++
#include "ExceptionParser.h"
|
|
|
|
#include "../Program/ProgramConfig.h"
|
|
#include "../logfacility.h"
|
|
#include "../threadhelp.h"
|
|
#include <format/format.h>
|
|
|
|
#ifdef WINDOWS
|
|
#include "../pol_global_config_win.h"
|
|
#else
|
|
#include "pol_global_config.h"
|
|
#endif
|
|
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef WINDOWS
|
|
#include <arpa/inet.h>
|
|
#include <cxxabi.h>
|
|
#include <execinfo.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <unistd.h>
|
|
|
|
#define SOCKET int
|
|
#else
|
|
#include "../Header_Windows.h"
|
|
#endif
|
|
|
|
#define MAX_STACK_TRACE_DEPTH 200
|
|
#define MAX_STACK_TRACE_STEP_LENGTH 512
|
|
|
|
namespace Pol
|
|
{
|
|
namespace Clib
|
|
{
|
|
using namespace std;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ExceptionParser::m_programAbortReporting = false;
|
|
std::string ExceptionParser::m_programAbortReportingServer = "";
|
|
std::string ExceptionParser::m_programAbortReportingUrl = "";
|
|
std::string ExceptionParser::m_programAbortReportingReporter = "";
|
|
std::string ExceptionParser::m_programStart = Pol::Clib::Logging::LogSink::getTimeStamp();
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace
|
|
{
|
|
void getSignalDescription( int signal, string& signalName, string& signalDescription )
|
|
{
|
|
switch ( signal )
|
|
{
|
|
case 1:
|
|
signalName = "SIGHUP";
|
|
signalDescription = "hangup detected on controlling terminal or death of controlling process";
|
|
break;
|
|
case 2:
|
|
signalName = "SIGINT";
|
|
signalDescription = "interrupt from keyboard";
|
|
break;
|
|
case 3:
|
|
signalName = "SIGQUIT";
|
|
signalDescription = "quit from keyboard";
|
|
break;
|
|
case 4:
|
|
signalName = "SIGILL";
|
|
signalDescription = "illegal Instruction";
|
|
break;
|
|
case 6:
|
|
signalName = "SIGABRT";
|
|
signalDescription = "abort signal from abort()";
|
|
break;
|
|
case 8:
|
|
signalName = "SIGFPE";
|
|
signalDescription = "floating point exception";
|
|
break;
|
|
case 9:
|
|
signalName = "SIGKILL";
|
|
signalDescription = "kill signal";
|
|
break;
|
|
case 10:
|
|
signalName = "SIGBUS";
|
|
signalDescription = "bus error";
|
|
break;
|
|
case 11:
|
|
signalName = "SIGSEGV";
|
|
signalDescription = "invalid memory reference";
|
|
break;
|
|
case 12:
|
|
signalName = "SIGSYS";
|
|
signalDescription = "bad argument to system call";
|
|
break;
|
|
case 13:
|
|
signalName = "SIGPIPE";
|
|
signalDescription = "broken pipe: write to pipe with no readers";
|
|
break;
|
|
case 14:
|
|
signalName = "SIGALRM";
|
|
signalDescription = "timer signal from alarm()";
|
|
break;
|
|
case 15:
|
|
signalName = "SIGTERM";
|
|
signalDescription = "termination signal";
|
|
break;
|
|
case 18:
|
|
signalName = "SIGCONT";
|
|
signalDescription = "continue signal from tty";
|
|
break;
|
|
case 19:
|
|
signalName = "SIGSTOP";
|
|
signalDescription = "stop signal from tty";
|
|
break;
|
|
case 20:
|
|
signalName = "SIGTSTP";
|
|
signalDescription = "stop signal from user (keyboard)";
|
|
break;
|
|
case 16:
|
|
case 30:
|
|
signalName = "SIGUSR1";
|
|
signalDescription = "user-defined signal 1";
|
|
break;
|
|
case 17:
|
|
case 31:
|
|
signalName = "SIGUSR2";
|
|
signalDescription = "user-defined signal 2";
|
|
break;
|
|
default:
|
|
signalName = "unsupported signal";
|
|
signalDescription = "unsupported signal occurred";
|
|
break;
|
|
}
|
|
}
|
|
|
|
void logExceptionSignal( int signal )
|
|
{
|
|
string signalName;
|
|
string signalDescription;
|
|
|
|
getSignalDescription( signal, signalName, signalDescription );
|
|
printf( "Signal \"%s\"(%d: %s) detected.\n", signalName.c_str(), signal,
|
|
signalDescription.c_str() );
|
|
}
|
|
|
|
string getCompilerVersion()
|
|
{
|
|
#ifdef LINUX
|
|
char result[256];
|
|
#ifdef __clang__
|
|
sprintf( result, "clang %d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__ );
|
|
#else
|
|
sprintf( result, "gcc %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ );
|
|
#endif
|
|
#endif
|
|
#ifdef WINDOWS
|
|
string result;
|
|
switch ( _MSC_VER )
|
|
{
|
|
case 1900:
|
|
result = "MSVC++ 14.0 (Visual Studio 2015)";
|
|
break;
|
|
case 1800:
|
|
result = "MSVC++ 12.0 (Visual Studio 2013)";
|
|
break;
|
|
case 1700:
|
|
result = "MSVC++ 11.0 (Visual Studio 2012)";
|
|
break;
|
|
case 1600:
|
|
result = "MSVC++ 10.0 (Visual Studio 2010)";
|
|
break;
|
|
case 1500:
|
|
result = "MSVC++ 9.0 (Visual Studio 2008)";
|
|
break;
|
|
case 1400:
|
|
result = "MSVC++ 8.0 (Visual Studio 2005)";
|
|
break;
|
|
case 1310:
|
|
result = "MSVC++ 7.1 (Visual Studio 2003)";
|
|
break;
|
|
case 1300:
|
|
result = "MSVC++ 7.0";
|
|
break;
|
|
case 1200:
|
|
result = "MSVC++ 6.0";
|
|
break;
|
|
case 1100:
|
|
result = "MSVC++ 5.0";
|
|
break;
|
|
default:
|
|
#if ( _MSC_VER > 1800 )
|
|
result = "MSVC++ newer than version 12.0";
|
|
#elif ( _MSC_VER < 1100 )
|
|
result = "MSVC++ older than version 5.0";
|
|
#else
|
|
result = "MSVC++ (some unsupported version)";
|
|
#endif
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
void doHttpPOST( const string& host, const string& url, const string& content )
|
|
{
|
|
#define MAXLINE 4096
|
|
char request[MAXLINE + 1];
|
|
SOCKET socketFD;
|
|
char targetIP[INET6_ADDRSTRLEN];
|
|
|
|
/**
|
|
* prepare the request
|
|
*/
|
|
#ifdef _MSC_VER
|
|
_snprintf(
|
|
#else
|
|
snprintf(
|
|
#endif
|
|
request, MAXLINE,
|
|
"POST %s HTTP/1.0\r\n"
|
|
"Host: %s\r\n"
|
|
"Content-Type: application/x-www-form-urlencoded\r\n"
|
|
"User-Agent: POL in-app abort reporting system, %s\r\n"
|
|
"Content-length: %d\r\n\r\n"
|
|
"%s",
|
|
url.c_str(), host.c_str(), POL_VERSION_ID, (int)content.size(), content.c_str() );
|
|
|
|
/**
|
|
* DNS lookup if needed
|
|
*/
|
|
struct addrinfo* serverAddr;
|
|
struct addrinfo hints;
|
|
memset( &hints, 0, sizeof hints );
|
|
hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
|
|
hints.ai_flags = AI_ADDRCONFIG;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
int res = getaddrinfo( host.c_str(), "http", &hints, &serverAddr );
|
|
if ( res != 0 )
|
|
{
|
|
fprintf( stderr, "getaddrinfo() failed for \"%s\" due to \"%s\"(code: %d)\n", host.c_str(),
|
|
gai_strerror( res ), res );
|
|
exit( 1 );
|
|
}
|
|
|
|
switch ( serverAddr->ai_addr->sa_family )
|
|
{
|
|
case AF_INET:
|
|
if ( inet_ntop( AF_INET, &( (struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
|
|
INET_ADDRSTRLEN ) == NULL )
|
|
exit( 1 );
|
|
break;
|
|
|
|
case AF_INET6:
|
|
if ( inet_ntop( AF_INET6, &( (struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
|
|
INET6_ADDRSTRLEN ) == NULL )
|
|
exit( 1 );
|
|
break;
|
|
|
|
default:
|
|
fprintf( stderr, "Unknown address family found for %s\n", host.c_str() );
|
|
exit( 1 );
|
|
}
|
|
|
|
// create the socket
|
|
socketFD = socket( serverAddr->ai_family, serverAddr->ai_socktype, serverAddr->ai_protocol );
|
|
|
|
/**
|
|
* connect to the bug tracking server
|
|
*/
|
|
if ( ( res = connect( socketFD, serverAddr->ai_addr, (int)serverAddr->ai_addrlen ) ) != 0 )
|
|
{
|
|
fprintf( stderr, "connect() failed for server \"%s\"(IP: %s) due \"%s\"(%d)\n", host.c_str(),
|
|
targetIP, strerror( errno ), errno );
|
|
exit( 1 );
|
|
}
|
|
|
|
freeaddrinfo( serverAddr ); // not needed anymore
|
|
|
|
/**
|
|
* send the request
|
|
*/
|
|
#ifndef _WIN32
|
|
send( socketFD, request, strlen( request ), MSG_NOSIGNAL );
|
|
#else
|
|
send( socketFD, request, (int)strlen( request ), 0 );
|
|
#endif
|
|
printf( "Abort report was sent to %s%s (IP: %s)\n", host.c_str(), url.c_str(), targetIP );
|
|
|
|
/**
|
|
* wait for some answers and print them on the screen
|
|
*/
|
|
ssize_t readBytes;
|
|
char answer[MAXLINE + 1];
|
|
|
|
#ifndef _WIN32
|
|
while ( ( readBytes = recv( socketFD, answer, MAXLINE, MSG_NOSIGNAL ) ) > 0 )
|
|
{
|
|
#else
|
|
while ( ( readBytes = recv( socketFD, answer, MAXLINE, 0 ) ) > 0 )
|
|
{
|
|
#endif
|
|
answer[readBytes] = '\0';
|
|
printf( "Answer from bug tracking server:\n%s\n", answer );
|
|
// skip the received answer and proceed
|
|
}
|
|
|
|
// close the socket to the bug tracking server
|
|
#ifndef _WIN32
|
|
close( socketFD );
|
|
#else
|
|
closesocket( socketFD );
|
|
#endif
|
|
}
|
|
} // namespace
|
|
|
|
void ExceptionParser::reportProgramAbort( const string& stackTrace, const string& reason )
|
|
{
|
|
/**
|
|
* set some default values if the abort occurs too early and pol.cfg wasn't parsed yet
|
|
*/
|
|
string host = "polserver.com";
|
|
string url = "/pol/report_program_abort.php";
|
|
if ( ( m_programAbortReportingServer.c_str() != NULL ) &&
|
|
( m_programAbortReportingServer != "" ) )
|
|
{
|
|
host = m_programAbortReportingServer;
|
|
if ( m_programAbortReportingUrl.c_str() != NULL )
|
|
url = m_programAbortReportingUrl;
|
|
}
|
|
|
|
// create the abort description for the subsequent POST request
|
|
string content = "email=" + m_programAbortReportingReporter +
|
|
"&"
|
|
"bin=" +
|
|
PROG_CONFIG::programName() +
|
|
"&"
|
|
"start_time=" +
|
|
m_programStart +
|
|
"&"
|
|
"abort_time=" +
|
|
Pol::Clib::Logging::LogSink::getTimeStamp() +
|
|
"&"
|
|
"reason=" +
|
|
reason +
|
|
"&"
|
|
"trace=" +
|
|
stackTrace +
|
|
"&"
|
|
"comp=" +
|
|
getCompilerVersion() +
|
|
"&"
|
|
"comp_time=" POL_BUILD_DATETIME
|
|
"&"
|
|
"build_target=" +
|
|
POL_BUILD_TARGET +
|
|
"&"
|
|
"build_revision=" POL_VERSION_ID
|
|
"&"
|
|
"misc=";
|
|
|
|
// execute the POST request
|
|
doHttpPOST( host, url, content );
|
|
}
|
|
|
|
void ExceptionParser::handleExceptionSignal( int signal )
|
|
{
|
|
switch ( signal )
|
|
{
|
|
case SIGILL:
|
|
case SIGFPE:
|
|
case SIGSEGV:
|
|
case SIGTERM:
|
|
case SIGABRT:
|
|
{
|
|
/**
|
|
* inform the user about the program abort
|
|
*/
|
|
printf(
|
|
"########################################################################################"
|
|
"\n" );
|
|
if ( m_programAbortReporting )
|
|
printf( "POL will exit now. The following will be sent to the POL developers:\n\n" );
|
|
else
|
|
printf(
|
|
"POL will exit now. Please, post the following to the forum: "
|
|
"http://forums.polserver.com/.\n" );
|
|
string tStackTrace = ExceptionParser::getTrace();
|
|
printf( tStackTrace.c_str() );
|
|
printf( "Admin contact: %s\n", m_programAbortReportingReporter.c_str() );
|
|
printf( "Executable: %s\n", PROG_CONFIG::programName().c_str() );
|
|
printf( "Start time: %s\n", m_programStart.c_str() );
|
|
printf( "Current time: %s\n", Pol::Clib::Logging::LogSink::getTimeStamp().c_str() );
|
|
printf( "\n" );
|
|
printf( "Stack trace:\n%s", tStackTrace.c_str() );
|
|
printf( "\n" );
|
|
printf( "Compiler: %s\n", getCompilerVersion().c_str() );
|
|
printf( "Compile time: %s\n", POL_BUILD_DATETIME );
|
|
printf( "Build target: %s\n", POL_BUILD_TARGET );
|
|
printf( "Build revision: %s\n", POL_VERSION_ID );
|
|
#ifndef _WIN32
|
|
printf( "GNU C library (compile time): %d.%d\n", __GLIBC__, __GLIBC_MINOR__ );
|
|
#endif
|
|
printf( "\n" );
|
|
printf(
|
|
"########################################################################################"
|
|
"\n" );
|
|
fflush( stdout );
|
|
|
|
/**
|
|
* use the program abort reporting system
|
|
*/
|
|
if ( m_programAbortReporting )
|
|
{
|
|
string signalName;
|
|
string signalDescription;
|
|
|
|
getSignalDescription( signal, signalName, signalDescription );
|
|
ExceptionParser::reportProgramAbort(
|
|
tStackTrace, "CRASH caused by signal " + signalName + " (" + signalDescription + ")" );
|
|
}
|
|
|
|
// finally, go to hell
|
|
exit( 1 );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
ExceptionParser::ExceptionParser() {}
|
|
|
|
ExceptionParser::~ExceptionParser() {}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef _WIN32
|
|
string ExceptionParser::getTrace()
|
|
{
|
|
string result;
|
|
|
|
void* stackTrace[MAX_STACK_TRACE_DEPTH];
|
|
int stackTraceSize;
|
|
char** stackTraceList;
|
|
int stackTraceStep = 0;
|
|
char* stringBuf = (char*)malloc( MAX_STACK_TRACE_STEP_LENGTH );
|
|
|
|
stackTraceSize = backtrace( stackTrace, MAX_STACK_TRACE_DEPTH );
|
|
stackTraceList = backtrace_symbols( stackTrace, stackTraceSize );
|
|
|
|
size_t funcNameSize = 256;
|
|
char* funcnName = (char*)malloc( funcNameSize );
|
|
|
|
// iterate over all entries and do the demangling
|
|
for ( int i = 0; i < stackTraceSize; i++ )
|
|
{
|
|
// get the pointers to the name, offset and end of offset
|
|
char* beginFuncName = nullptr;
|
|
char* beginFuncOffset = nullptr;
|
|
char* endFuncOffset = nullptr;
|
|
char* beginBinaryName = stackTraceList[i];
|
|
char* beginBinaryOffset = nullptr;
|
|
char* endBinaryOffset = nullptr;
|
|
for ( char* entryPointer = stackTraceList[i]; *entryPointer; ++entryPointer )
|
|
{
|
|
if ( *entryPointer == '(' )
|
|
{
|
|
beginFuncName = entryPointer;
|
|
}
|
|
else if ( *entryPointer == '+' )
|
|
{
|
|
beginFuncOffset = entryPointer;
|
|
}
|
|
else if ( *entryPointer == ')' && beginFuncOffset )
|
|
{
|
|
endFuncOffset = entryPointer;
|
|
}
|
|
else if ( *entryPointer == '[' )
|
|
{
|
|
beginBinaryOffset = entryPointer;
|
|
}
|
|
else if ( *entryPointer == ']' && beginBinaryOffset )
|
|
{
|
|
endBinaryOffset = entryPointer;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set the default value for the output line
|
|
sprintf( stringBuf, "\n" );
|
|
|
|
bool parse_succeeded = beginFuncName && beginFuncOffset && endFuncOffset && beginBinaryOffset &&
|
|
endBinaryOffset && beginFuncName < beginFuncOffset;
|
|
|
|
// get the detailed values for the output line if available
|
|
if ( parse_succeeded )
|
|
{
|
|
// terminate the C strings
|
|
*beginFuncName++ = '\0';
|
|
*beginFuncOffset++ = '\0';
|
|
*endFuncOffset = '\0';
|
|
*beginBinaryOffset++ = '\0';
|
|
*endBinaryOffset = '\0';
|
|
|
|
int res;
|
|
funcnName = abi::__cxa_demangle( beginFuncName, funcnName, &funcNameSize, &res );
|
|
unsigned int binaryOffset = strtoul( beginBinaryOffset, NULL, 16 );
|
|
if ( res == 0 )
|
|
{
|
|
string funcnNameStr = ( funcnName ? funcnName : "" );
|
|
if ( funcnName && strncmp( funcnName, "Pol::", 5 ) == 0 )
|
|
funcnNameStr = ">> " + funcnNameStr;
|
|
|
|
if ( beginBinaryName && strlen( beginBinaryName ) )
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s:[%s] from %s\n", stackTraceStep, binaryOffset,
|
|
funcnNameStr.c_str(), beginFuncOffset, beginBinaryName );
|
|
else
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s from %s\n", stackTraceStep, binaryOffset,
|
|
funcnNameStr.c_str(), beginFuncOffset );
|
|
stackTraceStep++;
|
|
}
|
|
else
|
|
{
|
|
if ( beginBinaryName && strlen( beginBinaryName ) )
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s:[%s] from %s\n", stackTraceStep, binaryOffset,
|
|
beginFuncName, beginFuncOffset, beginBinaryName );
|
|
else
|
|
sprintf( stringBuf, "#%02d 0x%016x in %s:[%s]\n", stackTraceStep, binaryOffset,
|
|
beginFuncName, beginFuncOffset );
|
|
stackTraceStep++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// print the raw trace, as it is better than nothing
|
|
sprintf( stringBuf, "#%02d %s\n", stackTraceStep, stackTraceList[i] );
|
|
stackTraceStep++;
|
|
}
|
|
|
|
// append the line to the result
|
|
result += string( stringBuf );
|
|
}
|
|
|
|
// memory cleanup
|
|
free( funcnName );
|
|
free( stackTraceList );
|
|
free( stringBuf );
|
|
|
|
return result;
|
|
}
|
|
|
|
static void handleSignalLinux( int signal, siginfo_t* signalInfo, void* arg )
|
|
{
|
|
(void)arg;
|
|
logExceptionSignal( signal );
|
|
if ( signalInfo != NULL )
|
|
{
|
|
if ( signal == SIGSEGV )
|
|
{
|
|
if ( signalInfo->si_addr != NULL )
|
|
printf( "Segmentation fault detected - faulty memory reference at location: %p\n",
|
|
signalInfo->si_addr );
|
|
else
|
|
printf( "Segmentation fault detected - null pointer reference\n" );
|
|
}
|
|
if ( signalInfo->si_errno != 0 )
|
|
printf( "This signal occurred because \"%s\"(%d)\n", strerror( signalInfo->si_errno ),
|
|
signalInfo->si_errno );
|
|
if ( signalInfo->si_code != 0 )
|
|
printf( "Signal code is %d\n", signalInfo->si_code );
|
|
}
|
|
ExceptionParser::handleExceptionSignal( signal );
|
|
}
|
|
|
|
static void handleStackTraceRequestLinux( int signal, siginfo_t* signalInfo, void* arg )
|
|
{
|
|
(void)signal;
|
|
(void)signalInfo;
|
|
(void)arg;
|
|
threadhelp::ThreadMap::Contents threadDesc;
|
|
threadhelp::threadmap.CopyContents( threadDesc );
|
|
|
|
fmt::Writer output;
|
|
output << "STACK TRACE for thread \"" << threadDesc[pthread_self()] << "\"(" << pthread_self()
|
|
<< "):\n";
|
|
output << ExceptionParser::getTrace() << "\n";
|
|
|
|
// print to stdout
|
|
printf( "%s", output.c_str() );
|
|
|
|
// print to error output
|
|
POLLOG_ERROR << output.str();
|
|
|
|
// wait here for logging facility to make sure everything was processed
|
|
if ( Clib::Logging::global_logger )
|
|
Clib::Logging::global_logger->wait_for_empty_queue();
|
|
}
|
|
|
|
void ExceptionParser::logAllStackTraces()
|
|
{
|
|
threadhelp::ThreadMap::Contents threadsDesc;
|
|
threadhelp::threadmap.CopyContents( threadsDesc );
|
|
for ( const auto& threadDesc : threadsDesc )
|
|
{
|
|
pthread_t threadID = (pthread_t)threadDesc.first;
|
|
|
|
if ( pthread_kill( threadID, SIGUSR1 ) != 0 )
|
|
{
|
|
fmt::Writer output;
|
|
output << "pthread_kill() failed to send SIGUSR1 to thread " << threadsDesc[threadID] << "("
|
|
<< threadID << ")\n";
|
|
fprintf( stderr, "%s", output.c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExceptionParser::initGlobalExceptionCatching()
|
|
{
|
|
struct sigaction sigAction;
|
|
|
|
memset( &sigAction, 0, sizeof( sigAction ) );
|
|
sigemptyset( &sigAction.sa_mask );
|
|
sigAction.sa_sigaction = handleSignalLinux;
|
|
sigAction.sa_flags = SA_SIGINFO;
|
|
sigaction( SIGINT, &sigAction, NULL );
|
|
sigaction( SIGTERM, &sigAction, NULL );
|
|
sigaction( SIGSEGV, &sigAction, NULL );
|
|
sigaction( SIGABRT, &sigAction, NULL );
|
|
sigAction.sa_sigaction = handleStackTraceRequestLinux;
|
|
sigaction( SIGUSR1, &sigAction, NULL );
|
|
|
|
// set handler stack
|
|
stack_t tStack;
|
|
tStack.ss_sp = malloc( SIGSTKSZ );
|
|
if ( tStack.ss_sp == NULL )
|
|
{
|
|
printf( "Could not allocate signal handler stack\n" );
|
|
exit( 1 );
|
|
}
|
|
tStack.ss_size = SIGSTKSZ;
|
|
tStack.ss_flags = 0;
|
|
if ( sigaltstack( &tStack, NULL ) == -1 )
|
|
{
|
|
printf( "Could not set signal handler stack\n" );
|
|
exit( 1 );
|
|
}
|
|
}
|
|
#else // _WIN32
|
|
string ExceptionParser::getTrace()
|
|
{
|
|
string result;
|
|
|
|
return result;
|
|
}
|
|
|
|
void ExceptionParser::logAllStackTraces() {}
|
|
|
|
void ExceptionParser::initGlobalExceptionCatching() {}
|
|
#endif // _WIN32
|
|
|
|
void ExceptionParser::configureProgramAbortReportingSystem( bool active, std::string server,
|
|
std::string url, std::string reporter )
|
|
{
|
|
m_programAbortReporting = active;
|
|
m_programAbortReportingServer = std::move( server );
|
|
m_programAbortReportingUrl = std::move( url );
|
|
m_programAbortReportingReporter = std::move( reporter );
|
|
}
|
|
|
|
bool ExceptionParser::programAbortReporting()
|
|
{
|
|
return m_programAbortReporting;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
} // namespaces
|