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