WvStreams
wvcrashbase.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 2005 Net Integration Technologies, Inc.
4 *
5 * Routines to save messages that can be logged when a program crashes.
6 */
7#include "wvcrash.h"
8
9#include <errno.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14IWvStream *WvCrashInfo::in_stream = NULL;
15const char *WvCrashInfo::in_stream_id = NULL;
16enum WvCrashInfo::InStreamState WvCrashInfo::in_stream_state = UNUSED;
17static const int ring_buffer_order = wvcrash_ring_buffer_order;
18static const int ring_buffer_size = wvcrash_ring_buffer_size;
19static const int ring_buffer_mask = ring_buffer_size - 1;
20static char ring_buffer[ring_buffer_size+1];
21static int ring_buffer_start = 0, ring_buffer_used = 0;
22
23void wvcrash_ring_buffer_put(const char *str)
24{
25 wvcrash_ring_buffer_put(str, strlen(str));
26}
27
28
29void wvcrash_ring_buffer_put(const char *str, size_t len)
30{
31 while (len > 0)
32 {
33 int pos = (ring_buffer_start + ring_buffer_used) & ring_buffer_mask;
34 ring_buffer[pos] = *str++;
35 --len;
36 if (ring_buffer_used == ring_buffer_size)
37 ring_buffer_start = (ring_buffer_start + 1) & ring_buffer_mask;
38 else
39 ++ring_buffer_used;
40 }
41}
42
43
44const char *wvcrash_ring_buffer_get()
45{
46 if (ring_buffer_used == 0)
47 return NULL;
48 const char *result;
49 if (ring_buffer_start + ring_buffer_used >= ring_buffer_size)
50 {
51 ring_buffer[ring_buffer_size] = '\0';
52 result = &ring_buffer[ring_buffer_start];
53 ring_buffer_used -= ring_buffer_size - ring_buffer_start;
54 ring_buffer_start = 0;
55 }
56 else
57 {
58 ring_buffer[ring_buffer_start + ring_buffer_used] = '\0';
59 result = &ring_buffer[ring_buffer_start];
60 ring_buffer_start += ring_buffer_used;
61 ring_buffer_used = 0;
62 }
63 return result;
64}
65
66
67
68// FIXME: leaving of a will and catching asserts mostly only works in Linux
69#ifdef __linux
70
71#ifdef __USE_GNU
72static const char *argv0 = program_invocation_short_name;
73#else
74static const char *argv0 = "UNKNOWN";
75#endif // __USE_GNU
76
77// Reserve enough buffer for a screenful of programme.
78static const int buffer_size = 2048;
79static char will_msg[buffer_size];
80static char assert_msg[buffer_size];
81
82
83extern "C"
84{
85 // Support assert().
86 void __assert_fail(const char *__assertion, const char *__file,
87 unsigned int __line, const char *__function)
88 {
89 // Set the assert message that WvCrash will dump.
90 snprintf(assert_msg, buffer_size,
91 "%s: %s:%u: %s: Assertion `%s' failed.\n",
92 argv0, __file, __line, __function, __assertion);
93 assert_msg[buffer_size - 1] = '\0';
94
95 // Emulate the GNU C library's __assert_fail().
96 fprintf(stderr, "%s: %s:%u: %s: Assertion `%s' failed.\n",
97 argv0, __file, __line, __function, __assertion);
98 abort();
99 }
100
101
102 // Wrapper for standards compliance.
103 void __assert(const char *__assertion, const char *__file,
104 unsigned int __line, const char *__function)
105 {
106 __assert_fail(__assertion, __file, __line, __function);
107 }
108
109
110 // Support the GNU assert_perror() extension.
111 void __assert_perror_fail(int __errnum, const char *__file,
112 unsigned int __line, const char *__function)
113 {
114 // Set the assert message that WvCrash will dump.
115 snprintf(assert_msg, buffer_size,
116 "%s: %s:%u: %s: Unexpected error: %s.\n",
117 argv0, __file, __line, __function, strerror(__errnum));
118 assert_msg[buffer_size - 1] = '\0';
119
120 // Emulate the GNU C library's __assert_perror_fail().
121 fprintf(stderr, "%s: %s:%u: %s: Unexpected error: %s.\n",
122 argv0, __file, __line, __function, strerror(__errnum));
123 abort();
124 }
125} // extern "C"
126
127
128// This function is meant to support people who wish to leave a last will
129// and testament in the WvCrash.
130void wvcrash_leave_will(const char *will)
131{
132 if (will)
133 {
134 strncpy(will_msg, will, buffer_size);
135 will_msg[buffer_size - 1] = '\0';
136 }
137 else
138 will_msg[0] = '\0';
139}
140
141
142const char *wvcrash_read_will()
143{
144 return will_msg;
145}
146
147
148const char *wvcrash_read_assert()
149{
150 return assert_msg;
151}
152
153
154void __wvcrash_init_buffers(const char *program_name)
155{
156 if (program_name)
157 argv0 = program_name;
158 will_msg[0] = '\0';
159 assert_msg[0] = '\0';
160}
161
162
163#else // this is NOT __linux
164
165void wvcrash_leave_will(const char *will) {}
166const char *wvcrash_read_will() { return NULL; }
167
168#endif // __linux