Пример #1
0
std::string Base::Name(Phase const& phase) const
{
    INFO0;
    auto name = Base::Name(phase.Stage());
    switch (phase.Tag()) {
    case Tag::signal : return SignalName(name);
    case Tag::background : return BackgroundName(name);
        DEFAULT(boca::Name(phase.Tag()), "");
    }
}
Пример #2
0
std::string Base::SignalFileName(Stage stage) const
{
    INFO0;
//     auto name = SignalName();
    auto name = Name();
    switch (stage) {
    case Stage::trainer : name = TrainerName(name);
        break;
    case Stage::reader : name = ReaderName(name);
        break;
        DEFAULT(boca::Name(stage), "");
    }
    return PathName(SignalName(name));
}
Пример #3
0
std::string Base::SignalName() const
{
    INFO0;
    return SignalName(Name());
}
Пример #4
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
}
static void RunCrashHandler( const CrashData *crash )
{
	if( g_pCrashHandlerArgv0 == NULL )
	{
		safe_print( fileno(stderr), "Crash handler failed: CrashHandlerHandleArgs was not called\n", NULL );
		_exit( 1 );
	}
	
	/* Block SIGPIPE, so we get EPIPE. */
	struct sigaction sa;
	memset( &sa, 0, sizeof(sa) );
	sa.sa_handler = SIG_IGN;
	if( sigaction( SIGPIPE, &sa, NULL ) != 0 )
	{
		safe_print( fileno(stderr), "sigaction() failed: %s", strerror(errno), NULL );
		/* non-fatal */
	}

	static int received = 0;
	static int active = 0;

	if( active )
	{
		/* We've received a second signal.  This may mean that another thread
		 * crashed before we stopped it, or it may mean that the crash handler
		 * crashed. */
		switch( crash->type )
		{
		case CrashData::SIGNAL:
			safe_print( fileno(stderr), "Fatal signal (", SignalName(crash->signal), ")", NULL );
			break;

		case CrashData::FORCE_CRASH:
			safe_print( fileno(stderr), "Crash handler failed: \"", crash->reason, "\"", NULL );
			break;

		default:
			safe_print( fileno(stderr), "Unexpected RunCrashHandler call (", itoa(crash->type), ")", NULL );
			break;
		}

		if( active == 1 )
			safe_print( fileno(stderr), " while still in the crash handler\n", NULL);
		else if( active == 2 )
			safe_print( fileno(stderr), " while in the crash handler child\n", NULL);

		_exit( 1 );
	}
	active = 1;
	received = getpid();

	/* Stop other threads.  XXX: This prints a spurious ptrace error if any threads
	 * are already suspended, which happens in ForceCrashHandlerDeadlock(). */
	RageThread::HaltAllThreads();
	
	/* We need to be very careful, since we're under crash conditions.  Let's fork
	 * a process and exec ourself to get a clean environment to work in. */
	int fds[2];
	if( pipe(fds) != 0 )
	{
		safe_print( fileno(stderr), "Crash handler pipe() failed: ", strerror(errno), "\n", NULL );
		exit( 1 );
	}

	pid_t childpid = fork();
	if( childpid == -1 )
	{
		safe_print( fileno(stderr), "Crash handler fork() failed: ", strerror(errno), "\n", NULL );
		_exit( 1 );
	}

	if( childpid == 0 )
	{
		active = 2;
		close( fds[1] );
		spawn_child_process( fds[0] );
	}
	else
	{
		close( fds[0] );
		parent_process( fds[1], crash );
		close( fds[1] );

		int status = 0;
#if !defined(MACOSX)
		waitpid( childpid, &status, 0 );
#endif

		/* We need to resume threads before continuing, or we may deadlock on _exit(). */
		/* XXX: race condition:  If two threads are deadlocked on a pair of mutexes, there's
		 * a chance that they'll both try to lock the other's mutex at the same time.  If
		 * that happens, then they'll both time out the lock at about the same time.  One
		 * will trigger the deadlock crash first, and the other will be suspended.  However,
		 * once we resume it here, it'll continue, and * trigger the deadlock crash again.
		 * It can result in unrecoverable deadlocks. */
		RageThread::ResumeAllThreads();

		if( WIFSIGNALED(status) )
			safe_print( fileno(stderr), "Crash handler child exited with signal ", itoa(WTERMSIG(status)), "\n", NULL );
	}
}
Пример #6
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 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
}