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