Beispiel #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 */
    }

	// 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
}
/* 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
}
/* Once we get here, we should be * safe to do whatever we want;
* heavyweights like malloc and RString 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;

    vector<RString> 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 RString CrashedThread(temp);
    delete[] temp;

    /* Wait for the child to either finish cleaning up or die. */
    fd_set rs;
    struct timeval timeout = { 5, 0 }; // 5 seconds

    FD_ZERO( &rs );
    FD_SET( 3, &rs );
    int ret = select( 4, &rs, NULL, NULL, &timeout );

    if( ret == 0 )
    {
        fputs( "Timeout exceeded.\n", stderr );
    }
    else if( (ret == -1 && errno != EPIPE) || ret != 1 )
    {
        fprintf( stderr, "Unexpected return from select() result: %d (%s)\n", ret, strerror(errno) );
        // Keep going.
    }
    else
    {
        char x;

        // No need to check FD_ISSET( 3, &rs ) because it was the only descriptor in the set.
        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 */
        }
    }

    RString sCrashInfoPath = "/tmp";
#if defined(MACOSX)
    sCrashInfoPath = CrashHandler::GetLogsDirectory();
#else
    const char *home = getenv( "HOME" );
    if( home )
        sCrashInfoPath = home;
#endif
    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%s crash report", PRODUCT_FAMILY, product_version );
    fprintf( CrashDump, " (build %s, %s @ %s)", ::sm_version_git_hash, version_date, version_time );
    fprintf( CrashDump, "\n" );
    fprintf( CrashDump, "--------------------------------------\n" );
    fprintf( CrashDump, "\n" );

    RString reason;
    switch( crash.type )
    {
    case CrashData::SIGNAL:
    {
        reason = ssprintf( "%s - %s", SignalName(crash.signal), SignalCodeName(crash.signal, crash.si.si_code) );

        /* 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, "Architecture:   %s\n", HOOKS->GetArchName().c_str() );
    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 )
        fputs( Checkpoints[i], CrashDump );
    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(MACOSX)
    CrashHandler::InformUserOfCrash( sCrashInfoPath );
#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;

    fputs( 	"\n"
            PRODUCT_ID " has crashed.  Debug information has been output to\n"
            "\n"
            "    " + sCrashInfoPath + "\n"
            "\n"
            "Please report a bug at:\n"
            "\n"
            "    " REPORT_BUG_URL "\n"
            "\n", tty );
#endif
}