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 Sat Feb 21 21:05:26 2004 for WvStreams by doxygen 1.3.5