diff --git a/stepmania/src/archutils/Unix/CrashHandler.cc b/stepmania/src/archutils/Unix/CrashHandler.cpp similarity index 94% rename from stepmania/src/archutils/Unix/CrashHandler.cc rename to stepmania/src/archutils/Unix/CrashHandler.cpp index eda0a55933..d58f972860 100644 --- a/stepmania/src/archutils/Unix/CrashHandler.cc +++ b/stepmania/src/archutils/Unix/CrashHandler.cpp @@ -1,6 +1,5 @@ #include "global.h" -#include #include #include #include @@ -46,7 +45,7 @@ static void spawn_child_process(int from_parent) if(from_parent != 3) { - int ret = dup2(from_parent, 3); + dup2(from_parent, 3); close(from_parent); } @@ -60,7 +59,7 @@ static void spawn_child_process(int from_parent) static void parent_write(int to_child, const void *p, size_t size) { - int ret = write(to_child, p, size); + size_t ret = write(to_child, p, size); if(ret != size) { safe_print(fileno(stderr), "Unexpected write() result (", strerror(errno), ")\n", NULL); @@ -124,7 +123,7 @@ static void parent_process( int to_child, void **BacktracePointers, int SignalRe * XXX: make sure the parent dying doesn't take out the child */ -#if BACKTRACE_METHOD == X86_LINUX +#if defined(BACKTRACE_METHOD_X86_LINUX) /* The x86 backtrace() in glibc doesn't make any effort at all to decode * signal trampolines. The result is that it doesn't properly show the * function that actually caused the signal--which is the most important @@ -345,7 +344,7 @@ static void do_backtrace( void **buf, size_t size, bool ignore_before_sig = true buf[i] = NULL; } -#elif BACKTRACE_METHOD == BACKTRACE +#elif defined(BACKTRACE_METHOD_BACKTRACE) static void do_backtrace(void **buf, size_t size) { int retsize = backtrace( buf, size-1 ); @@ -361,8 +360,24 @@ static void do_backtrace(void **buf, size_t size) buf[retsize] = NULL; } +#elif defined(BACKTRACE_METHOD_POWERPC_DARWIN) +#include "archutils/Darwin/Crash.h" +typedef struct Frame { + Frame *stackPointer; + long conditionReg; + void *linkReg; +} *FramePtr; + +static void do_backtrace(void **buf, size_t size) +{ + FramePtr frame = FramePtr(GetCrashedFramePtr()); + unsigned i; + for (i=0; frame && frame->linkReg && istackPointer) + buf[i] = frame->linkReg; + buf[i] = NULL; +} #else -#error BACKTRACE_METHOD required +#error BACKTRACE_METHOD_* required #endif @@ -393,7 +408,7 @@ void CrashSignalHandler( int signal ) /* 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. */ - const char *my_fn = g_argv[0]; + //const char *my_fn = g_argv[0]; int fds[2]; if(pipe(fds) != 0) diff --git a/stepmania/src/archutils/Unix/CrashHandlerChild.cc b/stepmania/src/archutils/Unix/CrashHandlerChild.cc deleted file mode 100644 index a701bbcef7..0000000000 --- a/stepmania/src/archutils/Unix/CrashHandlerChild.cc +++ /dev/null @@ -1,286 +0,0 @@ -/* for dladdr: */ -#define __USE_GNU -#include "global.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "StepMania.h" /* for g_argv */ -#include "RageUtil.h" -#include "CrashHandler.h" -#include "CrashHandlerInternal.h" -#include "RageLog.h" /* for RageLog::GetAdditionalLog, etc. only */ - -struct BacktraceNames -{ - CString Symbol, File; - int Address; - int Offset; - void FromAddr( void *p ); - void FromString( CString str ); - void Demangle(); - CString Format() const; -}; - -#if defined(HAVE_LIBIBERTY) -#include "libiberty.h" - -/* This is in libiberty. Where is it declared? */ -extern "C" { -char *cplus_demangle (const char *mangled, int options); -} - -void BacktraceNames::Demangle() -{ - char *f = cplus_demangle(Symbol, 0); - if(!f) - return; - Symbol = f; - free(f); -} -#else -void BacktraceNames::Demangle() { } -#endif - - -CString BacktraceNames::Format() const -{ - CString ShortenedPath = File; - if( Symbol != "" ) - { - /* We have some sort of symbol name, so abbreviate or elide the module name. */ - if( ShortenedPath == g_argv[0] ) - ShortenedPath = ""; - else - { - unsigned slash = ShortenedPath.rfind('/'); - if( slash != ShortenedPath.npos ) - ShortenedPath = ShortenedPath.substr(slash+1); - ShortenedPath = CString("(") + ShortenedPath + ")"; - } - } - - CString ret = ssprintf( "%08x: ", Address ); - if( Symbol != "" ) - ret += Symbol + " "; - ret += ShortenedPath; - - return ret; -} - - -#if BACKTRACE_LOOKUP_METHOD == DLADDR -/* This version simply asks libdl, which is more robust. */ -#include -void BacktraceNames::FromAddr( void *p ) -{ - Dl_info di; - if( !dladdr(p, &di) ) - return; - - Symbol = di.dli_sname; - File = di.dli_fname; - Address = (int) p; - Offset = (char*)(p)-(char*)di.dli_saddr; -} - -#elif BACKTRACE_LOOKUP_METHOD == BACKTRACE_SYMBOLS -/* This version parses backtrace_symbols(), an doesn't need libdl. */ -#include -void BacktraceNames::FromAddr( void *p ) -{ - char **foo = backtrace_symbols(&p, 1); - if( foo == NULL ) - return; - FromString( foo[0] ); - Address = (int) p; - free(foo); -} - -/* "path(mangled name+offset) [address]" */ -void BacktraceNames::FromString( CString s ) -{ - /* Hacky parser. I don't want to use regexes in the crash handler. */ - CString MangledAndOffset, sAddress; - unsigned pos = 0; - while( pos < s.size() && s[pos] != '(' && s[pos] != '[' ) - File += s[pos++]; - TrimRight( File ); - TrimLeft( File ); - - if( pos < s.size() && s[pos] == '(' ) - { - pos++; - while( pos < s.size() && s[pos] != ')' ) - MangledAndOffset += s[pos++]; - } - - if( MangledAndOffset != "" ) - { - unsigned plus = MangledAndOffset.rfind('+'); - - if(plus == MangledAndOffset.npos) - { - Symbol = MangledAndOffset; - Offset = 0; - } - else - { - Symbol = MangledAndOffset.substr(0, plus); - CString str = MangledAndOffset.substr(plus); - if( sscanf(str, "%i", &Offset) != 1 ) - Offset=0; - } - } -} -#else -#error BACKTRACE_LOOKUP_METHOD required -#endif - - -static void output_stack_trace( FILE *out, void **BacktracePointers ) -{ - for( int i = 0; BacktracePointers[i]; ++i) - { - BacktraceNames bn; - bn.FromAddr( BacktracePointers[i] ); - bn.Demangle(); - - if( bn.Symbol == "__libc_start_main" ) - break; - - fprintf( out, "%s\n", bn.Format().c_str() ); - } -} - -/* 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() -{ - int ret; - - /* 1. Read the backtrace pointers. */ - void *BacktracePointers[BACKTRACE_MAX_SIZE]; - ret = read(3, BacktracePointers, sizeof(void *)*BACKTRACE_MAX_SIZE); - - /* 2. Read the signal. */ - int SignalReceived; - ret = read(3, &SignalReceived, sizeof(SignalReceived)); - - /* 3. Read info. */ - int size; - ret = read(3, &size, sizeof(size)); - char *Info = new char [size]; - ret = read(3, Info, size); - - /* 4. Read AdditionalLog. */ - ret = read(3, &size, sizeof(size)); - char *AdditionalLog = new char [size]; - ret = read(3, AdditionalLog, size); - - /* 5. Read RecentLogs. */ - int cnt = 0; - ret = read(3, &cnt, sizeof(cnt)); - char *Recent[1024]; - for( int i = 0; i < cnt; ++i ) - { - ret = read(3, &size, sizeof(size)); - Recent[i] = new char [size]; - ret = read(3, Recent[i], size); - } - - /* Wait for the child to either finish cleaning up or die. XXX: - * This should time out, in case something deadlocks. */ - - char x; - ret = read(3, &x, sizeof(x)); - 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 */ - } - - FILE *CrashDump = fopen("/tmp/crashinfo.txt", "w+"); - if(CrashDump == NULL) - { - fprintf(stderr, "Couldn't open crashinfo.txt: %s", strerror(errno)); - exit(1); - } - - fprintf(CrashDump, "StepMania crash report\n"); - fprintf(CrashDump, "--------------------------------------\n"); - fprintf(CrashDump, "\n"); - - CString Signal; - -#define X(a) case a: Signal = #a; break; - switch(SignalReceived) - { - case SIGALRM: Signal = "Alarm"; break; - case SIGBUS: Signal = "Bus error"; break; - case SIGFPE: Signal = "Floating point exception"; break; - X(SIGHUP) - case SIGILL: Signal = "Illegal instruction"; break; - X(SIGINT) X(SIGIOT) - case SIGPIPE: Signal = "Broken pipe"; break; - X(SIGQUIT) - case SIGSEGV: Signal = "Segmentation fault"; break; - X(SIGTRAP) X(SIGTERM) X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ) -#if defined(HAVE_DECL_SIGPWR) && HAVE_DECL_SIGPWR - X(SIGPWR) -#endif - default: Signal = ssprintf("Unknown signal %i", SignalReceived); break; - } - - fprintf( CrashDump, "Crash reason: %s\n\n", Signal.c_str() ); - - output_stack_trace( CrashDump, BacktracePointers ); - 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); - - fprintf(stderr, - "\n" - "StepMania has crashed. Debug information has been output to\n" - "\n" - " /tmp/crashinfo.txt\n" - "\n" - "Please report a bug at:\n" - "\n" - " http://sourceforge.net/tracker/?func=add&group_id=37892&atid=421366\n" - "\n" - ); - - - /* Forcibly kill our parent. */ -// kill( getppid(), SIGKILL ); -} - - -void CrashHandlerHandleArgs() -{ - if(g_argc == 2 && !strcmp(g_argv[1], CHILD_MAGIC_PARAMETER)) - { - child_process(); - exit(0); - } -} - - diff --git a/stepmania/src/archutils/Unix/CrashHandlerChild.cpp b/stepmania/src/archutils/Unix/CrashHandlerChild.cpp new file mode 100644 index 0000000000..d4ee732c73 --- /dev/null +++ b/stepmania/src/archutils/Unix/CrashHandlerChild.cpp @@ -0,0 +1,396 @@ +/* for dladdr: */ +#define __USE_GNU +#include "global.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "StepMania.h" /* for g_argv */ +#include "RageUtil.h" +#include "CrashHandler.h" +#include "CrashHandlerInternal.h" +#include "RageLog.h" /* for RageLog::GetAdditionalLog, etc. only */ + +#if defined(DARWIN) +#include "archutils/Darwin/Crash.h" +#endif + +struct BacktraceNames +{ + CString Symbol, File; + int Address; + int Offset; + void FromAddr( void *p ); + void FromString( CString str ); + void Demangle(); + CString Format() const; +}; + +#if defined(HAVE_LIBIBERTY) +#include "libiberty.h" + +/* This is in libiberty. Where is it declared? */ +extern "C" { + char *cplus_demangle (const char *mangled, int options); +} + +void BacktraceNames::Demangle() +{ + char *f = cplus_demangle(Symbol, 0); + if(!f) + return; + Symbol = f; + free(f); +} +#else +void BacktraceNames::Demangle() { } +#endif + + +CString BacktraceNames::Format() const +{ + CString ShortenedPath = File; + if( Symbol != "" ) + { + /* We have some sort of symbol name, so abbreviate or elide the module name. */ + if( ShortenedPath == g_argv[0] ) + ShortenedPath = ""; + else + { + unsigned slash = ShortenedPath.rfind('/'); + if( slash != ShortenedPath.npos ) + ShortenedPath = ShortenedPath.substr(slash+1); + ShortenedPath = CString("(") + ShortenedPath + ")"; + } + } + + CString ret = ssprintf( "%08x: ", Address ); + if( Symbol != "" ) + ret += Symbol + " "; + ret += ShortenedPath; + + return ret; +} + + +#if defined(BACKTRACE_LOOKUP_METHOD_DLADDR) +/* This version simply asks libdl, which is more robust. */ +#include +void BacktraceNames::FromAddr( void *p ) +{ + Dl_info di; + if( !dladdr(p, &di) ) + return; + + Symbol = di.dli_sname; + File = di.dli_fname; + Address = (int) p; + Offset = (char*)(p)-(char*)di.dli_saddr; +} + +#elif defined(BACKTRACE_LOOKUP_METHOD_BACKTRACE_SYMBOLS) +/* This version parses backtrace_symbols(), an doesn't need libdl. */ +#include +void BacktraceNames::FromAddr( void *p ) +{ + char **foo = backtrace_symbols(&p, 1); + if( foo == NULL ) + return; + FromString( foo[0] ); + Address = (int) p; + free(foo); +} + +/* "path(mangled name+offset) [address]" */ +void BacktraceNames::FromString( CString s ) +{ + /* Hacky parser. I don't want to use regexes in the crash handler. */ + CString MangledAndOffset, sAddress; + unsigned pos = 0; + while( pos < s.size() && s[pos] != '(' && s[pos] != '[' ) + File += s[pos++]; + TrimRight( File ); + TrimLeft( File ); + + if( pos < s.size() && s[pos] == '(' ) + { + pos++; + while( pos < s.size() && s[pos] != ')' ) + MangledAndOffset += s[pos++]; + } + + if( MangledAndOffset != "" ) + { + unsigned plus = MangledAndOffset.rfind('+'); + + if(plus == MangledAndOffset.npos) + { + Symbol = MangledAndOffset; + Offset = 0; + } + else + { + Symbol = MangledAndOffset.substr(0, plus); + CString str = MangledAndOffset.substr(plus); + if( sscanf(str, "%i", &Offset) != 1 ) + Offset=0; + } + } +} +#elif defined(BACKTRACE_LOOKUP_METHOD_ATOS) +void BacktraceNames::FromAddr( void *p ) +{ + int fds[2]; + int out = fileno(stdout); + pid_t pid; + pid_t ppid = getppid(); /* Do this before fork()ing! */ + + Offset = 0; + Address = long(p); + + if (pipe(fds) != 0) + { + fprintf(stderr, "FromAddr pipe() failed: %s\n", strerror(errno)); + exit(1); + } + + pid = fork(); + if (pid == -1) + { + fprintf(stderr, "FromAddr fork() failed: %s\n", strerror(errno)); + exit(1); + } + + if (pid == 0) + { + close(fds[0]); + for (int fd = 3; fd < 1024; ++fd) + if (fd != fds[1]) + close(fd); + dup2(fds[1], out); + close(fds[1]); + + char *addy; + asprintf(&addy, "0x%x", long(p)); + const char *p = ssprintf("%d", ppid); + + fprintf(stderr, "%s\n", p); + if (execl("/usr/bin/atos", "/usr/bin/atos", "-p", p, addy, NULL)) + fprintf(stderr, "atos failed: %s\n", strerror(errno)); + free(addy); + close(out); + exit(0); + } + + close(fds[1]); + char f[BACKTRACE_MAX_SIZE]; + bzero(f, BACKTRACE_MAX_SIZE); + int len = read(fds[0], f, BACKTRACE_MAX_SIZE); + if (len == -1) + { + fprintf(stderr, "FromAddr read() failed: %s\n", strerror(errno)); + Symbol = ""; + File = ""; + } + else + { +#if 0 + CStringArray mangledAndFile; + + split(f, " ", mangledAndFile); + if (mangledAndFile.size() > 0) + { + Symbol = mangledAndFile[0]; + if (mangledAndFile.size() > 2) + { + File = mangledAndFile[3]; + File = File.substr(0, File.rfind(")")); + } + else + File = ""; + } + else + { + Symbol = ""; + File = ""; + } +#else + Symbol = f; + File = ""; +#endif + } +} +#else +#error BACKTRACE_LOOKUP_METHOD_* required +#endif + + +static void output_stack_trace( FILE *out, void **BacktracePointers ) +{ + for( int i = 0; BacktracePointers[i]; ++i) + { + BacktraceNames bn; + bn.FromAddr( BacktracePointers[i] ); + bn.Demangle(); + + if( bn.Symbol == "__libc_start_main" ) + break; + + fprintf( out, "%s\n", bn.Format().c_str() ); + } +} + +/* 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() +{ + int ret; + + /* 1. Read the backtrace pointers. */ + void *BacktracePointers[BACKTRACE_MAX_SIZE]; + ret = read(3, BacktracePointers, sizeof(void *)*BACKTRACE_MAX_SIZE); + + /* 2. Read the signal. */ + int SignalReceived; + ret = read(3, &SignalReceived, sizeof(SignalReceived)); + + /* 3. Read info. */ + int size; + ret = read(3, &size, sizeof(size)); + char *Info = new char [size]; + ret = read(3, Info, size); + + /* 4. Read AdditionalLog. */ + ret = read(3, &size, sizeof(size)); + char *AdditionalLog = new char [size]; + ret = read(3, AdditionalLog, size); + + /* 5. Read RecentLogs. */ + int cnt = 0; + ret = read(3, &cnt, sizeof(cnt)); + char *Recent[1024]; + for( int i = 0; i < cnt; ++i ) + { + ret = read(3, &size, sizeof(size)); + Recent[i] = new char [size]; + ret = read(3, Recent[i], size); + } + + /* Wait for the child to either finish cleaning up or die. XXX: + * This should time out, in case something deadlocks. */ + + char x; + ret = read(3, &x, sizeof(x)); + 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 */ + } + + FILE *CrashDump = fopen("/tmp/crashinfo.txt", "w+"); + if(CrashDump == NULL) + { + fprintf(stderr, "Couldn't open crashinfo.txt: %s", strerror(errno)); + exit(1); + } + + fprintf(CrashDump, "StepMania crash report\n"); + fprintf(CrashDump, "--------------------------------------\n"); + fprintf(CrashDump, "\n"); + + CString Signal; +#if !defined(BACKTRACE_METHOD_POWERPC_DARWIN) +#define X(a) case a: Signal = #a; break; + switch(SignalReceived) + { + case SIGALRM: Signal = "Alarm"; break; + case SIGBUS: Signal = "Bus error"; break; + case SIGFPE: Signal = "Floating point exception"; break; + X(SIGHUP) + case SIGILL: Signal = "Illegal instruction"; break; + X(SIGINT) X(SIGIOT) + case SIGPIPE: Signal = "Broken pipe"; break; + X(SIGQUIT) + case SIGSEGV: Signal = "Segmentation fault"; break; + X(SIGTRAP) X(SIGTERM) X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ) +#if defined(HAVE_DECL_SIGPWR) && HAVE_DECL_SIGPWR + X(SIGPWR) +#endif + default: Signal = ssprintf("Unknown signal %i", SignalReceived); break; + } +#else +#define X(code) case k##code: Signal = #code; break; + switch (SignalReceived) + { + X(UnknownException) + X(IllegalInstructionException) + X(TrapException) + X(AccessException) + X(UnmappedMemoryException) + X(ExcludedMemoryException) + X(ReadOnlyMemoryException) + X(UnresolvablePageFaultException) + X(PrivilegeViolationException) + X(TraceException) + X(InstructionBreakpointException) + X(DataBreakpointException) + X(FloatingPointException) + X(StackOverflowException) + default: Signal = ssprintf("Unknown Exception %i", SignalReceived); break; + } +#endif + + fprintf( CrashDump, "Crash reason: %s\n\n", Signal.c_str() ); + + output_stack_trace( CrashDump, BacktracePointers ); + 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(); +#else + fprintf(stderr, + "\n" + "StepMania has crashed. Debug information has been output to\n" + "\n" + " /tmp/crashinfo.txt\n" + "\n" + "Please report a bug at:\n" + "\n" + " http://sourceforge.net/tracker/?func=add&group_id=37892&atid=421366\n" + "\n" + ); +#endif + + /* Forcibly kill our parent. */ + // kill( getppid(), SIGKILL ); +} + + +void CrashHandlerHandleArgs() +{ + if(g_argc == 2 && !strcmp(g_argv[1], CHILD_MAGIC_PARAMETER)) + { + child_process(); + exit(0); + } +} + +