Files
itgmania212121/stepmania/src/archutils/Unix/CrashHandlerChild.cpp
T

332 lines
8.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define __USE_GNU
#include "global.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Backtrace.h"
#include "BacktraceNames.h"
#include "RageUtil.h"
#include "CrashHandler.h"
#include "CrashHandlerInternal.h"
#include "RageLog.h" /* for RageLog::GetAdditionalLog, etc. only */
#include "ProductInfo.h"
#if defined(DARWIN)
#include "archutils/Darwin/Crash.h"
#endif
#if defined(HAVE_VERSION_INFO)
extern const unsigned version_num;
#endif
const char *g_pCrashHandlerArgv0 = NULL;
static void output_stack_trace( FILE *out, void **BacktracePointers )
{
if( BacktracePointers[0] == BACKTRACE_METHOD_NOT_AVAILABLE )
{
fprintf( out, "No backtrace method available.\n");
return;
}
if( !BacktracePointers[0] )
{
fprintf( out, "Backtrace was empty.\n");
return;
}
for( int i = 0; BacktracePointers[i]; ++i)
{
BacktraceNames bn;
bn.FromAddr( BacktracePointers[i] );
bn.Demangle();
/* Don't show the main module name. */
if( bn.File == g_pCrashHandlerArgv0 )
bn.File = "";
if( bn.Symbol == "__libc_start_main" )
break;
fprintf( out, "%s\n", bn.Format().c_str() );
}
}
#if !defined(DARWIN)
const char *SignalCodeName( int signo, int code )
{
switch( code )
{
case SI_USER: return "user signal";
case SI_KERNEL: return "kernel signal";
case SI_QUEUE: return "sigqueue signal";
case SI_TIMER: return "timer expired";
case SI_MESGQ: return "mesgq state changed";
case SI_ASYNCIO: return "async I/O completed";
case SI_SIGIO: return "queued SIGIO";
}
switch( signo )
{
case SIGILL:
switch( code )
{
case ILL_ILLOPC: return "illegal opcode";
case ILL_ILLOPN: return "illegal operand";
case ILL_ILLADR: return "illegal addressing mode";
case ILL_ILLTRP: return "illegal trap";
case ILL_PRVOPC: return "privileged opcode";
case ILL_PRVREG: return "privileged register";
case ILL_COPROC: return "coprocessor error";
case ILL_BADSTK: return "internal stack error";
}
break;
case SIGFPE:
switch( code )
{
case FPE_INTDIV: return "integer divide by zero";
case FPE_INTOVF: return "integer overflow";
case FPE_FLTDIV: return "floating point divide by zero";
case FPE_FLTOVF: return "floating point overflow";
case FPE_FLTUND: return "floating point underflow";
case FPE_FLTRES: return "floating point inexact result";
case FPE_FLTINV: return "floating point invalid operation";
case FPE_FLTSUB: return "subscript out of range";
}
break;
case SIGSEGV:
switch( code )
{
case SEGV_MAPERR: return "address not mapped";
case SEGV_ACCERR: return "invalid permissions";
}
break;
case SIGBUS:
switch( code )
{
case BUS_ADRALN: return "invalid address alignment";
case BUS_ADRERR: return "nonexistent physical address";
case BUS_OBJERR: return "object specific hardware error";
}
break;
case SIGTRAP:
switch( code )
{
case TRAP_BRKPT: return "process breakpoint";
case TRAP_TRACE: return "process trace trap";
}
break;
case SIGCHLD:
switch( code )
{
case CLD_EXITED: return "child has exited";
case CLD_KILLED: return "child was killed";
case CLD_DUMPED: return "child terminated abnormally";
case CLD_TRAPPED: return "traced child has trapped";
case CLD_STOPPED: return "child has stopped";
case CLD_CONTINUED: return "stopped child has continued";
}
break;
case SIGPOLL:
switch( code )
{
case POLL_IN: return "data input available";
case POLL_OUT: return "output buffers available";
case POLL_MSG: return "input message available";
case POLL_ERR: return "i/o error";
case POLL_PRI: return "high priority input available";
case POLL_HUP: return "device disconnected";
}
break;
}
static char buf[128];
strcpy( buf, "Unknown code " );
strcat( buf, itoa(code) );
return buf;
}
#endif
/* Once we get here, we should be * safe to do whatever we want;
* heavyweights like malloc and CString are OK. (Don't crash!) */
static void child_process()
{
int ret;
/* 1. Read the backtrace pointers. */
void *BacktracePointers[BACKTRACE_MAX_SIZE];
ret = read(3, BacktracePointers, sizeof(void *)*BACKTRACE_MAX_SIZE);
/* 2. Read the CrashData. */
CrashData crash;
ret = read(3, &crash, sizeof(CrashData));
/* 3. Read info. */
int size;
ret = read(3, &size, sizeof(size));
char *Info = new char [size];
ret = read(3, Info, size);
/* 4. Read AdditionalLog. */
ret = read(3, &size, sizeof(size));
char *AdditionalLog = new char [size];
ret = read(3, AdditionalLog, size);
/* 5. Read RecentLogs. */
int cnt = 0;
ret = read(3, &cnt, sizeof(cnt));
char *Recent[1024];
for( int i = 0; i < cnt; ++i )
{
ret = read(3, &size, sizeof(size));
Recent[i] = new char [size];
ret = read(3, Recent[i], size);
}
/* 6. Read CHECKPOINTs. */
ret = read(3, &size, sizeof(size));
char *temp = new char [size];
ret = read(3, temp, size);
CStringArray Checkpoints;
split(temp, "$$", Checkpoints);
delete [] temp;
/* 7. Read the crashed thread's name. */
ret = read(3, &size, sizeof(size));
temp = new char [size];
ret = read(3, temp, size);
const CString CrashedThread(temp);
delete[] temp;
/* Wait for the child to either finish cleaning up or die. XXX:
* This should time out, in case something deadlocks. */
char x;
ret = read(3, &x, sizeof(x));
if( (ret == -1 && errno != EPIPE) || ret != 0 )
{
/* We expect an EOF or EPIPE. What happened? */
fprintf(stderr, "Unexpected child read() result: %i (%s)\n", ret, strerror(errno));
/* keep going */
}
const char *home = getenv( "HOME" );
CString sCrashInfoPath = "/tmp";
if( home )
sCrashInfoPath = home;
sCrashInfoPath += "/crashinfo.txt";
FILE *CrashDump = fopen( sCrashInfoPath, "w+" );
if(CrashDump == NULL)
{
fprintf( stderr, "Couldn't open " + sCrashInfoPath + ": %s\n", strerror(errno) );
exit(1);
}
fprintf(CrashDump, "%s crash report", PRODUCT_NAME_VER );
#if defined(HAVE_VERSION_INFO)
fprintf(CrashDump, " (build %u)", version_num);
#endif
fprintf(CrashDump, "\n");
fprintf(CrashDump, "--------------------------------------\n");
fprintf(CrashDump, "\n");
CString reason;
switch( crash.type )
{
#if !defined(DARWIN)
case CrashData::SIGNAL:
{
CString Signal = SignalName( crash.signal );
reason = ssprintf( "%s - %s", Signal.c_str(), SignalCodeName(crash.signal, crash.si.si_code) );
switch( crash.signal )
{
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
reason += ssprintf( " at 0x%08x", (unsigned int) crash.si.si_addr );
}
break;
}
#endif
#if defined(DARWIN)
case CrashData::OSX_EXCEPTION:
reason = ExceptionName( crash.kind );
break;
#endif
case CrashData::FORCE_CRASH_THIS_THREAD:
crash.reason[ sizeof(crash.reason)-1] = 0;
reason = crash.reason;
break;
}
fprintf( CrashDump, "Crash reason: %s\n", reason.c_str() );
fprintf( CrashDump, "Crashed thread: %s\n\n", CrashedThread.c_str() );
fprintf(CrashDump, "Checkpoints:\n");
for (unsigned i=0; i<Checkpoints.size(); ++i)
fprintf(CrashDump, Checkpoints[i]);
fprintf(CrashDump, "\n");
output_stack_trace( CrashDump, BacktracePointers );
fprintf(CrashDump, "\n");
fprintf(CrashDump, "Static log:\n");
fprintf(CrashDump, "%s", Info);
fprintf(CrashDump, "%s", AdditionalLog);
fprintf(CrashDump, "\nPartial log:\n");
for( int i = 0; i < cnt; ++i )
fprintf(CrashDump, "%s\n", Recent[i] );
fprintf(CrashDump, "\n");
fprintf(CrashDump, "-- End of report\n");
fclose(CrashDump);
#if defined(DARWIN)
InformUserOfCrash( sCrashInfoPath );
#else
fprintf(stderr,
"\n"
PRODUCT_NAME " has crashed. Debug information has been output to\n"
"\n"
" " + sCrashInfoPath + "\n"
"\n"
"Please report a bug at:\n"
"\n"
" http://sourceforge.net/tracker/?func=add&group_id=37892&atid=421366\n"
"\n"
);
#endif
/* Forcibly kill our parent. */
// kill( getppid(), SIGKILL );
}
void CrashHandlerHandleArgs( int argc, char* argv[] )
{
g_pCrashHandlerArgv0 = argv[0];
if( argc == 2 && !strcmp(argv[1], CHILD_MAGIC_PARAMETER) )
{
child_process();
exit(0);
}
}