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