3 #include "../Program/ProgramConfig.h" 4 #include "../logfacility.h" 5 #include "../threadhelp.h" 6 #include "pol_global_config.h" 7 #include <format/format.h> 17 #include <arpa/inet.h> 21 #include <netinet/in.h> 27 #include "../Header_Windows.h" 30 #define MAX_STACK_TRACE_DEPTH 200 31 #define MAX_STACK_TRACE_STEP_LENGTH 512 51 void getSignalDescription(
int signal,
string& signalName,
string& signalDescription )
56 signalName =
"SIGHUP";
57 signalDescription =
"hangup detected on controlling terminal or death of controlling process";
60 signalName =
"SIGINT";
61 signalDescription =
"interrupt from keyboard";
64 signalName =
"SIGQUIT";
65 signalDescription =
"quit from keyboard";
68 signalName =
"SIGILL";
69 signalDescription =
"illegal Instruction";
72 signalName =
"SIGABRT";
73 signalDescription =
"abort signal from abort()";
76 signalName =
"SIGFPE";
77 signalDescription =
"floating point exception";
80 signalName =
"SIGKILL";
81 signalDescription =
"kill signal";
84 signalName =
"SIGBUS";
85 signalDescription =
"bus error";
88 signalName =
"SIGSEGV";
89 signalDescription =
"invalid memory reference";
92 signalName =
"SIGSYS";
93 signalDescription =
"bad argument to system call";
96 signalName =
"SIGPIPE";
97 signalDescription =
"broken pipe: write to pipe with no readers";
100 signalName =
"SIGALRM";
101 signalDescription =
"timer signal from alarm()";
104 signalName =
"SIGTERM";
105 signalDescription =
"termination signal";
108 signalName =
"SIGCONT";
109 signalDescription =
"continue signal from tty";
112 signalName =
"SIGSTOP";
113 signalDescription =
"stop signal from tty";
116 signalName =
"SIGTSTP";
117 signalDescription =
"stop signal from user (keyboard)";
121 signalName =
"SIGUSR1";
122 signalDescription =
"user-defined signal 1";
126 signalName =
"SIGUSR2";
127 signalDescription =
"user-defined signal 2";
130 signalName =
"unsupported signal";
131 signalDescription =
"unsupported signal occurred";
136 void logExceptionSignal(
int signal )
139 string signalDescription;
141 getSignalDescription( signal, signalName, signalDescription );
142 printf(
"Signal \"%s\"(%d: %s) detected.\n", signalName.c_str(), signal,
143 signalDescription.c_str() );
146 string getCompilerVersion()
151 sprintf( result,
"clang %d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__ );
153 sprintf( result,
"gcc %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ );
161 result =
"MSVC++ 14.0 (Visual Studio 2015)";
164 result =
"MSVC++ 12.0 (Visual Studio 2013)";
167 result =
"MSVC++ 11.0 (Visual Studio 2012)";
170 result =
"MSVC++ 10.0 (Visual Studio 2010)";
173 result =
"MSVC++ 9.0 (Visual Studio 2008)";
176 result =
"MSVC++ 8.0 (Visual Studio 2005)";
179 result =
"MSVC++ 7.1 (Visual Studio 2003)";
182 result =
"MSVC++ 7.0";
185 result =
"MSVC++ 6.0";
188 result =
"MSVC++ 5.0";
191 #if ( _MSC_VER > 1800 ) 192 result =
"MSVC++ newer than version 12.0";
193 #elif ( _MSC_VER < 1100 ) 194 result =
"MSVC++ older than version 5.0";
196 result =
"MSVC++ (some unsupported version)";
205 void doHttpPOST(
const string& host,
const string& url,
const string& content )
210 char targetIP[INET6_ADDRSTRLEN];
221 "POST %s HTTP/1.0\r\n" 223 "Content-Type: application/x-www-form-urlencoded\r\n" 224 "User-Agent: POL in-app abort reporting system, %s\r\n" 225 "Content-length: %d\r\n\r\n" 227 url.c_str(), host.c_str(), POL_VERSION_ID, (int)content.size(), content.c_str() );
232 struct addrinfo* serverAddr;
233 struct addrinfo hints;
234 memset( &hints, 0,
sizeof hints );
235 hints.ai_family = AF_UNSPEC;
236 hints.ai_flags = AI_ADDRCONFIG;
237 hints.ai_socktype = SOCK_STREAM;
238 int res = getaddrinfo( host.c_str(),
"http", &hints, &serverAddr );
241 fprintf( stderr,
"getaddrinfo() failed for \"%s\" due to \"%s\"(code: %d)\n", host.c_str(),
242 gai_strerror( res ), res );
246 switch ( serverAddr->ai_addr->sa_family )
249 if ( inet_ntop( AF_INET, &( (
struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
250 INET_ADDRSTRLEN ) == NULL )
255 if ( inet_ntop( AF_INET6, &( (
struct sockaddr_in*)serverAddr->ai_addr )->sin_addr, targetIP,
256 INET6_ADDRSTRLEN ) == NULL )
261 fprintf( stderr,
"Unknown address family found for %s\n", host.c_str() );
266 socketFD = socket( serverAddr->ai_family, serverAddr->ai_socktype, serverAddr->ai_protocol );
271 if ( ( res = connect( socketFD, serverAddr->ai_addr, (
int)serverAddr->ai_addrlen ) ) != 0 )
273 fprintf( stderr,
"connect() failed for server \"%s\"(IP: %s) due \"%s\"(%d)\n", host.c_str(),
274 targetIP, strerror( errno ), errno );
278 freeaddrinfo( serverAddr );
284 send( socketFD, request, strlen( request ), MSG_NOSIGNAL );
286 send( socketFD, request, (
int)strlen( request ), 0 );
288 printf(
"Abort report was sent to %s%s (IP: %s)\n", host.c_str(), url.c_str(), targetIP );
297 while ( ( readBytes = recv( socketFD, answer,
MAXLINE, MSG_NOSIGNAL ) ) > 0 )
300 while ( ( readBytes = recv( socketFD, answer,
MAXLINE, 0 ) ) > 0 )
303 answer[readBytes] =
'\0';
304 printf(
"Answer from bug tracking server:\n%s\n", answer );
312 closesocket( socketFD );
322 string host =
"polserver.com";
323 string url =
"/pol/report_program_abort.php";
324 if ( ( m_programAbortReportingServer.c_str() != NULL ) &&
325 ( m_programAbortReportingServer !=
"" ) )
327 host = m_programAbortReportingServer;
328 if ( m_programAbortReportingUrl.c_str() != NULL )
329 url = m_programAbortReportingUrl;
333 string content =
"email=" + m_programAbortReportingReporter +
336 PROG_CONFIG::programName() +
351 getCompilerVersion() +
359 "build_revision=" POL_VERSION_ID
364 doHttpPOST( host, url, content );
381 "########################################################################################" 383 if ( m_programAbortReporting )
384 printf(
"POL will exit now. The following will be sent to the POL developers:\n\n" );
387 "POL will exit now. Please, post the following to the forum: " 388 "http://forums.polserver.com/.\n" );
390 printf( tStackTrace.c_str() );
391 printf(
"Admin contact: %s\n", m_programAbortReportingReporter.c_str() );
392 printf(
"Executable: %s\n", PROG_CONFIG::programName().c_str() );
393 printf(
"Start time: %s\n", m_programStart.c_str() );
396 printf(
"Stack trace:\n%s", tStackTrace.c_str() );
398 printf(
"Compiler: %s\n", getCompilerVersion().c_str() );
401 printf(
"Build revision: %s\n", POL_VERSION_ID );
403 printf(
"GNU C library (compile time): %d.%d\n", __GLIBC__, __GLIBC_MINOR__ );
407 "########################################################################################" 414 if ( m_programAbortReporting )
417 string signalDescription;
419 getSignalDescription( signal, signalName, signalDescription );
421 tStackTrace,
"CRASH caused by signal " + signalName +
" (" + signalDescription +
")" );
448 char** stackTraceList;
449 int stackTraceStep = 0;
453 stackTraceList = backtrace_symbols( stackTrace, stackTraceSize );
455 size_t funcNameSize = 256;
456 char* funcnName = (
char*)malloc( funcNameSize );
459 for (
int i = 0; i < stackTraceSize; i++ )
462 char* beginFuncName =
nullptr;
463 char* beginFuncOffset =
nullptr;
464 char* endFuncOffset =
nullptr;
465 char* beginBinaryName = stackTraceList[i];
466 char* beginBinaryOffset =
nullptr;
467 char* endBinaryOffset =
nullptr;
468 for (
char* entryPointer = stackTraceList[i]; *entryPointer; ++entryPointer )
470 if ( *entryPointer ==
'(' )
472 beginFuncName = entryPointer;
474 else if ( *entryPointer ==
'+' )
476 beginFuncOffset = entryPointer;
478 else if ( *entryPointer ==
')' && beginFuncOffset )
480 endFuncOffset = entryPointer;
482 else if ( *entryPointer ==
'[' )
484 beginBinaryOffset = entryPointer;
486 else if ( *entryPointer ==
']' && beginBinaryOffset )
488 endBinaryOffset = entryPointer;
494 sprintf( stringBuf,
"\n" );
496 bool parse_succeeded = beginFuncName && beginFuncOffset && endFuncOffset && beginBinaryOffset &&
497 endBinaryOffset && beginFuncName < beginFuncOffset;
500 if ( parse_succeeded )
503 *beginFuncName++ =
'\0';
504 *beginFuncOffset++ =
'\0';
505 *endFuncOffset =
'\0';
506 *beginBinaryOffset++ =
'\0';
507 *endBinaryOffset =
'\0';
510 funcnName = abi::__cxa_demangle( beginFuncName, funcnName, &funcNameSize, &res );
511 unsigned int binaryOffset = strtoul( beginBinaryOffset, NULL, 16 );
514 string funcnNameStr = ( funcnName ? funcnName :
"" );
515 if ( funcnName && strncmp( funcnName,
"Pol::", 5 ) == 0 )
516 funcnNameStr =
">> " + funcnNameStr;
518 if ( beginBinaryName && strlen( beginBinaryName ) )
519 sprintf( stringBuf,
"#%02d 0x%016x in %s:[%s] from %s\n", stackTraceStep, binaryOffset,
520 funcnNameStr.c_str(), beginFuncOffset, beginBinaryName );
522 sprintf( stringBuf,
"#%02d 0x%016x in %s from %s\n", stackTraceStep, binaryOffset,
523 funcnNameStr.c_str(), beginFuncOffset );
528 if ( beginBinaryName && strlen( beginBinaryName ) )
529 sprintf( stringBuf,
"#%02d 0x%016x in %s:[%s] from %s\n", stackTraceStep, binaryOffset,
530 beginFuncName, beginFuncOffset, beginBinaryName );
532 sprintf( stringBuf,
"#%02d 0x%016x in %s:[%s]\n", stackTraceStep, binaryOffset,
533 beginFuncName, beginFuncOffset );
540 sprintf( stringBuf,
"#%02d %s\n", stackTraceStep, stackTraceList[i] );
545 result += string( stringBuf );
550 free( stackTraceList );
559 logExceptionSignal( signal );
560 if ( signalInfo != NULL )
562 if ( signal == SIGSEGV )
564 if ( signalInfo->si_addr != NULL )
565 printf(
"Segmentation fault detected - faulty memory reference at location: %p\n",
566 signalInfo->si_addr );
568 printf(
"Segmentation fault detected - null pointer reference\n" );
570 if ( signalInfo->si_errno != 0 )
571 printf(
"This signal occurred because \"%s\"(%d)\n", strerror( signalInfo->si_errno ),
572 signalInfo->si_errno );
573 if ( signalInfo->si_code != 0 )
574 printf(
"Signal code is %d\n", signalInfo->si_code );
588 output <<
"STACK TRACE for thread \"" << threadDesc[pthread_self()] <<
"\"(" << pthread_self()
593 printf(
"%s", output.c_str() );
607 for (
const auto& threadDesc : threadsDesc )
609 pthread_t threadID = (pthread_t)threadDesc.first;
611 if ( pthread_kill( threadID, SIGUSR1 ) != 0 )
614 output <<
"pthread_kill() failed to send SIGUSR1 to thread " << threadsDesc[threadID] <<
"(" 615 << threadID <<
")\n";
616 fprintf( stderr,
"%s", output.c_str() );
623 struct sigaction sigAction;
625 memset( &sigAction, 0,
sizeof( sigAction ) );
626 sigemptyset( &sigAction.sa_mask );
628 sigAction.sa_flags = SA_SIGINFO;
629 sigaction( SIGINT, &sigAction, NULL );
630 sigaction( SIGTERM, &sigAction, NULL );
631 sigaction( SIGSEGV, &sigAction, NULL );
632 sigaction( SIGABRT, &sigAction, NULL );
634 sigaction( SIGUSR1, &sigAction, NULL );
639 char* mem =
static_cast<char*
>( mmap( NULL, SIGSTKSZ + 2 * getpagesize(), PROT_READ | PROT_WRITE,
640 MAP_PRIVATE | MAP_ANON, -1, 0 ) );
641 mprotect( mem, getpagesize(), PROT_NONE );
642 mprotect( mem + getpagesize() + SIGSTKSZ, getpagesize(), PROT_NONE );
643 tStack.ss_sp = mem + getpagesize();
644 tStack.ss_size = SIGSTKSZ;
646 if ( sigaltstack( &tStack, NULL ) == -1 )
648 printf(
"Could not set signal handler stack\n" );
666 std::string url, std::string reporter )
668 m_programAbortReporting = active;
669 m_programAbortReportingServer = std::move( server );
670 m_programAbortReportingUrl = std::move( url );
671 m_programAbortReportingReporter = std::move( reporter );
676 return m_programAbortReporting;
static std::string m_programStart
static std::string m_programAbortReportingServer
static void configureProgramAbortReportingSystem(bool active, std::string server, std::string url, std::string reporter)
Configures the bug reporting system.
static std::string getTrace()
Returns a string containing the current stack trace.
static std::string m_programAbortReportingUrl
#define MAX_STACK_TRACE_STEP_LENGTH
static void handleExceptionSignal(int signal)
Handles exceptions.
void CopyContents(Contents &out) const
void wait_for_empty_queue()
static std::string getTimeStamp()
#define MAX_STACK_TRACE_DEPTH
static void initGlobalExceptionCatching()
Initiates globally the exception catching (signal handlers for Linux)
static void handleSignalLinux(int signal, siginfo_t *signalInfo, void *arg)
virtual ~ExceptionParser()
static bool m_programAbortReporting
std::map< size_t, std::string > Contents
static bool programAbortReporting()
Returns true if the bug reporting is active.
static void reportProgramAbort(const std::string &stackTrace, const std::string &reason)
Reports a program abort to the program devs.
static std::string m_programAbortReportingReporter
static void logAllStackTraces()
Logs stack traces of all threads to stdout and error output.
static void handleStackTraceRequestLinux(int signal, siginfo_t *signalInfo, void *arg)
LogFacility * global_logger
static std::string build_target()
static std::string build_datetime()