Files
itgmania212121/stepmania/src/archutils/Unix/CrashHandlerChild.cpp
T
2004-05-15 08:23:53 +00:00

409 lines
11 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 <cstdio>
#include <cstring>
#include <cerrno>
#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, const 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];
sprintf( buf, "Unknown code %i", code );
return buf;
}
#endif
bool child_read( int fd, void *p, int size )
{
char *buf = (char *) p;
int got = 0;
while( got < size )
{
int ret = read( fd, buf+got, size-got );
if( ret == -1 )
{
if( errno == EINTR )
continue;
fprintf( stderr, "Crash handler: error communicating with parent: %s\n", strerror(errno) );
return false;
}
if( ret == 0 )
{
fprintf( stderr, "Crash handler: EOF communicating with parent\n", strerror(errno) );
return false;
}
got += ret;
}
return true;
}
/* 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()
{
/* 1. Read the CrashData. */
CrashData crash;
if( !child_read(3, &crash, sizeof(CrashData)) )
return;
/* 2. Read info. */
int size;
if( !child_read(3, &size, sizeof(size)) )
return;
char *Info = new char [size];
if( !child_read(3, Info, size) )
return;
/* 3. Read AdditionalLog. */
if( !child_read(3, &size, sizeof(size)) )
return;
char *AdditionalLog = new char [size];
if( !child_read(3, AdditionalLog, size) )
return;
/* 4. Read RecentLogs. */
int cnt = 0;
if( !child_read(3, &cnt, sizeof(cnt)) )
return;
char *Recent[1024];
for( int i = 0; i < cnt; ++i )
{
if( !child_read(3, &size, sizeof(size)) )
return;
Recent[i] = new char [size];
if( !child_read(3, Recent[i], size) )
return;
}
/* 5. Read CHECKPOINTs. */
if( !child_read(3, &size, sizeof(size)) )
return;
char *temp = new char [size];
if( !child_read(3, temp, size) )
return;
CStringArray Checkpoints;
split(temp, "$$", Checkpoints);
delete [] temp;
/* 6. Read the crashed thread's name. */
if( !child_read(3, &size, sizeof(size)) )
return;
temp = new char [size];
if( !child_read(3, temp, size) )
return;
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;
int ret = read(3, &x, sizeof(x));
if( ret > 0 )
{
fprintf( stderr, "Unexpected child read() result: %i\n", ret );
/* keep going */
} else 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 )
{
case CrashData::SIGNAL:
{
CString Signal = SignalName( crash.signal );
#if !defined(DARWIN)
reason = ssprintf( "%s - %s", Signal.c_str(), SignalCodeName(crash.signal, crash.si.si_code) );
#else
reason = Signal;
#endif
switch( crash.signal )
{
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
reason += ssprintf( " at 0x%08x", (unsigned int) crash.si.si_addr );
}
break;
}
#if defined(DARWIN)
case CrashData::OSX_EXCEPTION:
reason = ExceptionName( crash.kind );
break;
#endif
case CrashData::FORCE_CRASH_THIS_THREAD:
case CrashData::FORCE_CRASH_DEADLOCK:
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, crash.BacktracePointers );
fprintf(CrashDump, "\n");
if( crash.type == CrashData::FORCE_CRASH_DEADLOCK )
{
fprintf(CrashDump, "Deadlocked with:\n");
output_stack_trace( CrashDump, crash.BacktracePointers2 );
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 );
/* Forcibly kill our parent. */
kill( getppid(), SIGKILL );
#else
/* stdout may have been inadvertently closed by the crash in the parent;
* write to /dev/tty instead. */
FILE *tty = fopen( "/dev/tty", "w" );
if( tty == NULL )
tty = stdin;
fprintf(tty,
"\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
}
void CrashHandlerHandleArgs( int argc, char* argv[] )
{
g_pCrashHandlerArgv0 = argv[0];
if( argc == 2 && !strcmp(argv[1], CHILD_MAGIC_PARAMETER) )
{
child_process();
exit(0);
}
}
/*
* (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/