Ejemplo n.º 1
0
/* 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
	/* Linux puts the PID that sent the signal in si_addr for SI_USER. */
	if( crash.si.si_code == SI_USER )
		reason += ssprintf( " from pid %li", (long) crash.si.si_addr );
	else switch( crash.signal )
	{
	case SIGILL:
	case SIGFPE:
	case SIGSEGV:
	case SIGBUS:
		reason += ssprintf( " at 0x%0*lx", int(sizeof(void*)*2), (unsigned long) crash.si.si_addr );
	}
	break;
    }
    case CrashData::FORCE_CRASH:
	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");

    for( int i = 0; i < CrashData::MAX_BACKTRACE_THREADS; ++i )
    {
	    if( !crash.BacktracePointers[i][0] )
		    break;
	    fprintf( CrashDump, "Thread: %s\n", crash.m_ThreadName[i] );
	    output_stack_trace( CrashDump, crash.BacktracePointers[i] );
	    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 = stderr;

    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
}
Ejemplo n.º 2
0
/* 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 */
    }

	// We don't need the file/ext, but they're required args.
	CString sPath, sDir, sFile, sExt;

	sPath = g_pCrashHandlerArgv0;
	splitpath( sPath, sDir, sFile, sExt );

	CString sCrashInfoPath = sDir + "stats";
	
	time_t seconds;
	seconds = time( NULL );

#ifdef ITG_ARCADE	
	sCrashInfoPath = ssprintf( "/stats/crashinfo-%ld.txt" , seconds ); // Timestamped!
#else
	sCrashInfoPath = ssprintf( "Data/crashinfo-%ld.txt" , seconds );
#endif

	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", ProductInfo::GetFullVersion().c_str() );
#if defined(HAVE_VERSION_INFO)
    fprintf(CrashDump, " (build %u)", ProductInfo::GetBuildRevision().c_str() );
#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
	/* Linux puts the PID that sent the signal in si_addr for SI_USER. */
	if( crash.si.si_code == SI_USER )
		reason += ssprintf( " from pid %li", (long) crash.si.si_addr );
	else switch( crash.signal )
	{
	case SIGILL:
	case SIGFPE:
	case SIGSEGV:
	case SIGBUS:
		reason += ssprintf( " at 0x%0*lx", int(sizeof(void*)*2), (unsigned long) crash.si.si_addr );
	}
	break;
    }
    case CrashData::FORCE_CRASH:
	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");

    for( int i = 0; i < CrashData::MAX_BACKTRACE_THREADS; ++i )
    {
	    if( !crash.BacktracePointers[i][0] )
		    break;
	    fprintf( CrashDump, "Thread: %s\n", crash.m_ThreadName[i] );
	    output_stack_trace( CrashDump, crash.BacktracePointers[i] );
	    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 = stderr;

	fprintf(tty,
		"\n"
		+ ProductInfo::GetName()
		+ " has crashed.  Debug information has been output to\n"
		"\n"
		"    " + sCrashInfoPath + "\n"
		"\n"
		"Please report a bug at:\n"
		"\n"
		"    " + ProductInfo::GetCrashReportURL() + "\n"
		"\n"
	);

#endif

#ifdef ITG_ARCADE
	struct stat ncr;
	if ( stat("/tmp/no-crash-reboot", &ncr) != 0 )
	{
		sync();
		sleep(5);
		reboot(RB_AUTOBOOT);
	}
#endif
}