fix text also in translations
[enigma2.git] / main / bsod.cpp
1 #include <string.h>
2 #include <signal.h>
3 #include <asm/ptrace.h>
4
5 #include <lib/base/eerror.h>
6 #include <lib/base/smartptr.h>
7 #include <lib/gdi/grc.h>
8 #include <lib/gdi/gfbdc.h>
9 #ifdef WITH_SDL
10 #include <lib/gdi/sdl.h>
11 #endif
12
13 #include "version.h"
14
15 /************************************************/
16
17 #define CRASH_EMAILADDR "crashlog@dream-multimedia-tv.de"
18
19 #define RINGBUFFER_SIZE 16384
20 static char ringbuffer[RINGBUFFER_SIZE];
21 static int ringbuffer_head;
22
23 static void addToLogbuffer(const char *data, int len)
24 {
25         while (len)
26         {
27                 int remaining = RINGBUFFER_SIZE - ringbuffer_head;
28         
29                 if (remaining > len)
30                         remaining = len;
31         
32                 memcpy(ringbuffer + ringbuffer_head, data, remaining);
33                 len -= remaining;
34                 data += remaining;
35                 ringbuffer_head += remaining;
36                 if (ringbuffer_head >= RINGBUFFER_SIZE)
37                         ringbuffer_head = 0;
38         }
39 }
40
41 static std::string getLogBuffer()
42 {
43         int begin = ringbuffer_head;
44         while (ringbuffer[begin] == 0)
45         {
46                 ++begin;
47                 if (begin == RINGBUFFER_SIZE)
48                         begin = 0;
49                 if (begin == ringbuffer_head)
50                         return "";
51         }
52         if (begin < ringbuffer_head)
53                 return std::string(ringbuffer + begin, ringbuffer_head - begin);
54         else
55         {
56                 return std::string(ringbuffer + begin, RINGBUFFER_SIZE - begin) + std::string(ringbuffer, ringbuffer_head);
57         }
58 }
59
60 static void addToLogbuffer(int level, const std::string &log)
61 {
62         addToLogbuffer(log.c_str(), log.size());
63 }
64
65
66 extern std::string getLogBuffer();
67
68 void bsodFatal()
69 {
70         char logfile[128];
71         sprintf(logfile, "/media/hdd/enigma2_crash_%u.log", (unsigned int)time(0));
72         FILE *f = fopen(logfile, "wb");
73         
74         std::string lines = getLogBuffer();
75
76         if (f)
77         {
78                 time_t t = time(0);
79                 fprintf(f, "enigma2 crashed on %s", ctime(&t));
80 #ifdef ENIGMA2_CHECKOUT_TAG
81                 fprintf(f, "enigma2 CVS TAG: " ENIGMA2_CHECKOUT_TAG "\n");
82 #else
83                 fprintf(f, "enigma2 compiled on " __DATE__ "\n");
84 #endif
85 #ifdef ENIGMA2_CHECKOUT_ROOT
86                 fprintf(f, "enigma2 checked out from " ENIGMA2_CHECKOUT_ROOT "\n");
87 #endif
88                 fprintf(f, "please email this file to " CRASH_EMAILADDR "\n");
89                 std::string buffer = getLogBuffer();
90                 fwrite(buffer.c_str(), buffer.size(), 1, f);
91                 fclose(f);
92                 
93                 char cmd[256];
94                 sprintf(cmd, "find /usr/lib/enigma2/python/ -name \"*.py\" | xargs md5sum >> %s", logfile);
95                 system(cmd);
96         }
97         
98 #ifdef WITH_SDL
99         ePtr<gSDLDC> my_dc;
100         gSDLDC::getInstance(my_dc);
101 #else
102         ePtr<gFBDC> my_dc;
103         gFBDC::getInstance(my_dc);
104 #endif
105         
106         {
107                 gPainter p(my_dc);
108                 p.resetOffset();
109                 p.resetClip(eRect(ePoint(0, 0), my_dc->size()));
110 #ifdef ENIGMA2_CHECKOUT_TAG
111                 if (ENIGMA2_CHECKOUT_TAG[0] == 'T') /* tagged checkout (release) */
112                         p.setBackgroundColor(gRGB(0x0000C0));
113                 else if (ENIGMA2_CHECKOUT_TAG[0] == 'D') /* dated checkout (daily experimental build) */
114                 {
115                         srand(time(0));
116                         int r = rand();
117                         unsigned int col = 0;
118                         if (r & 1)
119                                 col |= 0x800000;
120                         if (r & 2)
121                                 col |= 0x008000;
122                         if (r & 4)
123                                 col |= 0x0000c0;
124                         p.setBackgroundColor(gRGB(col));
125                 }
126 #else
127                         p.setBackgroundColor(gRGB(0x008000));
128 #endif
129
130                 p.setForegroundColor(gRGB(0xFFFFFF));
131         
132                 ePtr<gFont> font = new gFont("Regular", 20);
133                 p.setFont(font);
134                 p.clear();
135         
136                 eRect usable_area = eRect(100, 70, my_dc->size().width() - 150, 100);
137         
138                 p.renderText(usable_area, 
139                         "We are really sorry. Something happened "
140                         "which should not have happened, and "
141                         "resulted in a crash. If you want to help "
142                         "us in improving this situation, please send "
143                         "the logfile created in /hdd/ to " CRASH_EMAILADDR "."
144                         "Your receiver restarts in 10 seconds !", gPainter::RT_WRAP|gPainter::RT_HALIGN_LEFT);
145         
146                 usable_area = eRect(100, 170, my_dc->size().width() - 180, my_dc->size().height() - 20);
147         
148                 int i;
149         
150                 size_t start = std::string::npos + 1;
151                 for (i=0; i<20; ++i)
152                 {
153                         start = lines.rfind('\n', start - 1);
154                         if (start == std::string::npos)
155                         {
156                                 start = 0;
157                                 break;
158                         }
159                 }
160         
161                 font = new gFont("Regular", 14);
162                 p.setFont(font);
163         
164                 p.renderText(usable_area, 
165                         lines.substr(start), gPainter::RT_HALIGN_LEFT);
166                 sleep(10);
167         }
168
169         raise(SIGKILL);
170 }
171
172 #if defined(__MIPSEL__)
173 void oops(const mcontext_t &context, int dumpcode)
174 {
175         eDebug("PC: %08lx, vaddr: %08lx", (unsigned long)context.pc, (unsigned long)context.badvaddr);
176         int i;
177         for (i=0; i<32; ++i)
178         {
179                 eDebugNoNewLine(" %08x", (int)context.gregs[i]);
180                 if ((i&3) == 3)
181                         eDebug("");
182         }
183                 /* this is temporary debug stuff. */
184         if (dumpcode && ((unsigned long)context.pc) > 0x10000) /* not a zero pointer */
185         {
186                 eDebug("As a final action, i will try to dump a bit of code.");
187                 eDebug("I just hope that this won't crash.");
188                 int i;
189                 eDebugNoNewLine("%08lx:", (unsigned long)context.pc);
190                 for (i=0; i<0x20; ++i)
191                         eDebugNoNewLine(" %02x", ((unsigned char*)context.pc)[i]);
192                 eDebug(" (end)");
193         }
194 }
195 #else
196 #warning "no oops support!"
197 #define NO_OOPS_SUPPORT
198 #endif
199
200 void handleFatalSignal(int signum, siginfo_t *si, void *ctx)
201 {
202         ucontext_t *uc = (ucontext_t*)ctx;
203         eDebug("KILLED BY signal %d", signum);
204 #ifndef NO_OOPS_SUPPORT
205         oops(uc->uc_mcontext, signum == SIGSEGV || signum == SIGABRT);
206 #endif
207         eDebug("-------");
208         bsodFatal();
209 }
210
211 void bsodCatchSignals()
212 {
213         struct sigaction act;
214         act.sa_handler = SIG_DFL;
215         act.sa_sigaction = handleFatalSignal;
216         act.sa_flags = SA_RESTART | SA_SIGINFO;
217         if (sigemptyset(&act.sa_mask) == -1)
218                 perror("sigemptyset");
219         
220                 /* start handling segfaults etc. */
221         sigaction(SIGSEGV, &act, 0);
222         sigaction(SIGILL, &act, 0);
223         sigaction(SIGBUS, &act, 0);
224         sigaction(SIGABRT, &act, 0);
225 }
226
227 void bsodLogInit()
228 {
229         logOutput.connect(addToLogbuffer);
230 }