00001
00002
00003
00004
00005
00006
00007
00008 #include "wvcrash.h"
00009 #include <signal.h>
00010 #include <fcntl.h>
00011 #include <string.h>
00012
00013
00014 #ifdef __linux
00015
00016 # include <execinfo.h>
00017 #include <unistd.h>
00018
00019 static const char *argv0 = "UNKNOWN";
00020
00021
00022 static void wr(int fd, const char *str)
00023 {
00024 write(fd, str, strlen(str));
00025 }
00026
00027
00028
00029 static void wrn(int fd, int num)
00030 {
00031 int tmp;
00032 char c;
00033
00034 if (num < 0)
00035 {
00036 wr(fd, "-");
00037 num = -num;
00038 }
00039 else if (num == 0)
00040 {
00041 wr(fd, "0");
00042 return;
00043 }
00044
00045 tmp = 0;
00046 while (num > 0)
00047 {
00048 tmp *= 10;
00049 tmp += num%10;
00050 num /= 10;
00051 }
00052
00053 while (tmp > 0)
00054 {
00055 c = '0' + (tmp%10);
00056 write(fd, &c, 1);
00057 tmp /= 10;
00058 }
00059 }
00060
00061
00062 void wvcrash_real(int sig, int fd)
00063 {
00064 static void *trace[64];
00065 static char *signame = strsignal(sig);
00066
00067 wr(fd, argv0);
00068 wr(fd, " dying on signal ");
00069 wrn(fd, sig);
00070 if (signame)
00071 {
00072 wr(fd, " (");
00073 wr(fd, signame);
00074 wr(fd, ")");
00075 }
00076 wr(fd, "\n\nBacktrace:\n");
00077 backtrace_symbols_fd(trace,
00078 backtrace(trace, sizeof(trace)/sizeof(trace[0])), fd);
00079
00080
00081
00082
00083 if (sig == SIGABRT)
00084 sig = SIGBUS;
00085 else if (sig != 0)
00086 sig = SIGABRT;
00087
00088 signal(sig, SIG_DFL);
00089 raise(sig);
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 void wvcrash(int sig)
00101 {
00102 int fds[2];
00103 pid_t pid;
00104
00105 signal(sig, SIG_DFL);
00106 wr(2, "\n\nwvcrash: crashing!\n");
00107
00108 if (pipe(fds))
00109 wvcrash_real(sig, 2);
00110 else
00111 {
00112 pid = fork();
00113 if (pid < 0)
00114 wvcrash_real(sig, 2);
00115 else if (pid == 0)
00116 {
00117 close(fds[1]);
00118 dup2(fds[0], 0);
00119 fcntl(0, F_SETFD, 0);
00120
00121 execlp("wvcrash", "wvcrash", NULL);
00122
00123
00124 wr(2, "wvcrash: can't exec wvcrash binary "
00125 "- writing to wvcrash.txt!\n");
00126 execlp("dd", "dd", "of=wvcrash.txt", NULL);
00127
00128 wr(2, "wvcrash: can't exec dd to write to wvcrash.txt!\n");
00129 _exit(127);
00130 }
00131 else if (pid > 0)
00132 {
00133 close(fds[0]);
00134 wvcrash_real(sig, fds[1]);
00135 }
00136 }
00137
00138
00139 _exit(126);
00140 }
00141
00142
00143 void wvcrash_setup(const char *_argv0)
00144 {
00145 argv0 = _argv0;
00146 signal(SIGSEGV, wvcrash);
00147 signal(SIGBUS, wvcrash);
00148 signal(SIGABRT, wvcrash);
00149 signal(SIGFPE, wvcrash);
00150 signal(SIGILL, wvcrash);
00151 }
00152
00153 #else // Not Linux
00154
00155 void wvcrash(int sig) {}
00156 void wvcrash_setup(const char *_argv0) {}
00157
00158 #endif // Not Linux