WvStreams
|
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