Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvcrash.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Routines to generate a stack backtrace automatically when a program 00006 * crashes. 00007 */ 00008 #include "wvcrash.h" 00009 #include <signal.h> 00010 #include <fcntl.h> 00011 #include <string.h> 00012 00013 // FIXME: this file mostly only works in Linux 00014 #ifdef __linux 00015 00016 # include <execinfo.h> 00017 #include <unistd.h> 00018 00019 static const char *argv0 = "UNKNOWN"; 00020 00021 // write a string 'str' to fd 00022 static void wr(int fd, const char *str) 00023 { 00024 write(fd, str, strlen(str)); 00025 } 00026 00027 00028 // convert 'num' to a string and write it to fd. 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 // we want to create a coredump, and the kernel seems to not want to do 00081 // that if we send ourselves the same signal that we're already in. 00082 // Whatever... just send a different one :) 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 // Hint: we can't do anything really difficult here, because the program is 00094 // probably really confused. So we should try to limit this to straight 00095 // kernel syscalls (ie. don't fiddle with FILE* or streams or lists, just 00096 // use straight file descriptors.) 00097 // 00098 // We fork a subprogram to do the fancy stuff like sending email. 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); // just use stderr instead 00110 else 00111 { 00112 pid = fork(); 00113 if (pid < 0) 00114 wvcrash_real(sig, 2); // just use stderr instead 00115 else if (pid == 0) // child 00116 { 00117 close(fds[1]); 00118 dup2(fds[0], 0); // make stdin read from pipe 00119 fcntl(0, F_SETFD, 0); 00120 00121 execlp("wvcrash", "wvcrash", NULL); 00122 00123 // if we get here, we couldn't exec wvcrash 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) // parent 00132 { 00133 close(fds[0]); 00134 wvcrash_real(sig, fds[1]); 00135 } 00136 } 00137 00138 // child (usually) 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

Generated on Tue Oct 5 01:09:20 2004 for WvStreams by doxygen 1.3.7