WvStreams
wvcrashbase.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2005 Net Integration Technologies, Inc.
00004  *
00005  * Routines to save messages that can be logged when a program crashes.
00006  */
00007 #include "wvcrash.h"
00008 
00009 #include <errno.h>
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <string.h>
00013 
00014 IWvStream *WvCrashInfo::in_stream = NULL;
00015 const char *WvCrashInfo::in_stream_id = NULL;
00016 enum WvCrashInfo::InStreamState WvCrashInfo::in_stream_state = UNUSED;
00017 static const int ring_buffer_order = wvcrash_ring_buffer_order;
00018 static const int ring_buffer_size = wvcrash_ring_buffer_size;
00019 static const int ring_buffer_mask = ring_buffer_size - 1;
00020 static char ring_buffer[ring_buffer_size+1];
00021 static int ring_buffer_start = 0, ring_buffer_used = 0;
00022 
00023 void wvcrash_ring_buffer_put(const char *str)
00024 {
00025     wvcrash_ring_buffer_put(str, strlen(str));
00026 }
00027 
00028 
00029 void wvcrash_ring_buffer_put(const char *str, size_t len)
00030 {
00031     while (len > 0)
00032     {
00033         int pos = (ring_buffer_start + ring_buffer_used) & ring_buffer_mask;
00034         ring_buffer[pos] = *str++;
00035         --len;
00036         if (ring_buffer_used == ring_buffer_size)
00037             ring_buffer_start = (ring_buffer_start + 1) & ring_buffer_mask;
00038         else
00039             ++ring_buffer_used;
00040     }
00041 }
00042 
00043 
00044 const char *wvcrash_ring_buffer_get()
00045 {
00046     if (ring_buffer_used == 0)
00047         return NULL;
00048     const char *result;
00049     if (ring_buffer_start + ring_buffer_used >= ring_buffer_size)
00050     {
00051         ring_buffer[ring_buffer_size] = '\0';
00052         result = &ring_buffer[ring_buffer_start];
00053         ring_buffer_used -= ring_buffer_size - ring_buffer_start;
00054         ring_buffer_start = 0;
00055     }
00056     else
00057     {
00058         ring_buffer[ring_buffer_start + ring_buffer_used] = '\0';
00059         result = &ring_buffer[ring_buffer_start];
00060         ring_buffer_start += ring_buffer_used;
00061         ring_buffer_used = 0;
00062     }
00063     return result;
00064 }
00065 
00066 
00067 
00068 // FIXME: leaving of a will and catching asserts mostly only works in Linux
00069 #if 1
00070 
00071 #ifdef __USE_GNU
00072 static const char *argv0 = program_invocation_short_name;
00073 #else
00074 static const char *argv0 = "UNKNOWN";
00075 #endif // __USE_GNU
00076 
00077 // Reserve enough buffer for a screenful of programme.
00078 static const int buffer_size = 2048;
00079 static char will_msg[buffer_size];
00080 static char assert_msg[buffer_size];
00081 
00082 
00083 extern "C"
00084 {
00085     // Support assert().
00086     void __assert_fail(const char *__assertion, const char *__file,
00087                        unsigned int __line, const char *__function)
00088     {
00089         // Set the assert message that WvCrash will dump.
00090         snprintf(assert_msg, buffer_size,
00091                  "%s: %s:%u: %s: Assertion `%s' failed.\n",
00092                  argv0, __file, __line, __function, __assertion);
00093         assert_msg[buffer_size - 1] = '\0';
00094 
00095         // Emulate the GNU C library's __assert_fail().
00096         fprintf(stderr, "%s: %s:%u: %s: Assertion `%s' failed.\n",
00097                 argv0, __file, __line, __function, __assertion);
00098         abort();
00099     }
00100 
00101 
00102     // Wrapper for standards compliance.
00103     void __assert(const char *__assertion, const char *__file,
00104                   unsigned int __line, const char *__function)
00105     {
00106         __assert_fail(__assertion, __file, __line, __function);
00107     }
00108 
00109 
00110     // Support the GNU assert_perror() extension.
00111     void __assert_perror_fail(int __errnum, const char *__file,
00112                               unsigned int __line, const char *__function)
00113     {
00114         // Set the assert message that WvCrash will dump.
00115         snprintf(assert_msg, buffer_size,
00116                  "%s: %s:%u: %s: Unexpected error: %s.\n",
00117                  argv0, __file, __line, __function, strerror(__errnum));
00118         assert_msg[buffer_size - 1] = '\0';
00119 
00120         // Emulate the GNU C library's __assert_perror_fail().
00121         fprintf(stderr, "%s: %s:%u: %s: Unexpected error: %s.\n",
00122                 argv0, __file, __line, __function, strerror(__errnum));
00123         abort();
00124     }
00125 } // extern "C"
00126 
00127 
00128 // This function is meant to support people who wish to leave a last will
00129 // and testament in the WvCrash.
00130 void wvcrash_leave_will(const char *will)
00131 {
00132     if (will)
00133     {
00134         strncpy(will_msg, will, buffer_size);
00135         will_msg[buffer_size - 1] = '\0';
00136     }
00137     else
00138         will_msg[0] = '\0';
00139 }
00140 
00141 
00142 const char *wvcrash_read_will()
00143 {
00144     return will_msg;
00145 }
00146 
00147 
00148 const char *wvcrash_read_assert()
00149 {
00150     return assert_msg;
00151 }
00152 
00153 
00154 void __wvcrash_init_buffers(const char *program_name)
00155 {
00156     if (program_name)
00157         argv0 = program_name;
00158     will_msg[0] = '\0';
00159     assert_msg[0] = '\0';
00160 }
00161 
00162 
00163 #else // this is NOT __linux
00164 
00165 void wvcrash_leave_will(const char *will) {}
00166 const char *wvcrash_read_will() { return NULL; }
00167 
00168 #endif // __linux