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()), ""); } }
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)); }
std::string Base::SignalName() const { INFO0; return SignalName(Name()); }
/* 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 ); } }
/* 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 }