dd274eca7485be54997158edc034aa8694b14937
[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 /************************************************/
11
12 #define CRASH_EMAILADDR "crashlog@dream-multimedia-tv.de"
13
14 #define RINGBUFFER_SIZE 16384
15 static char ringbuffer[RINGBUFFER_SIZE];
16 static int ringbuffer_head;
17
18 static void addToLogbuffer(const char *data, int len)
19 {
20         while (len)
21         {
22                 int remaining = RINGBUFFER_SIZE - ringbuffer_head;
23         
24                 if (remaining > len)
25                         remaining = len;
26         
27                 memcpy(ringbuffer + ringbuffer_head, data, remaining);
28                 len -= remaining;
29                 data += remaining;
30                 ringbuffer_head += remaining;
31                 if (ringbuffer_head >= RINGBUFFER_SIZE)
32                         ringbuffer_head = 0;
33         }
34 }
35
36 static std::string getLogBuffer()
37 {
38         int begin = ringbuffer_head;
39         while (ringbuffer[begin] == 0)
40         {
41                 ++begin;
42                 if (begin == RINGBUFFER_SIZE)
43                         begin = 0;
44                 if (begin == ringbuffer_head)
45                         return "";
46         }
47         if (begin < ringbuffer_head)
48                 return std::string(ringbuffer + begin, ringbuffer_head - begin);
49         else
50         {
51                 return std::string(ringbuffer + begin, RINGBUFFER_SIZE - begin) + std::string(ringbuffer, ringbuffer_head);
52         }
53 }
54
55 static void addToLogbuffer(int level, const std::string &log)
56 {
57         addToLogbuffer(log.c_str(), log.size());
58 }
59
60
61 extern std::string getLogBuffer();
62
63 void bsodFatal()
64 {
65         char logfile[128];
66         sprintf(logfile, "/media/hdd/enigma2_crash_%u.log", (unsigned int)time(0));
67         FILE *f = fopen(logfile, "wb");
68         
69         std::string lines = getLogBuffer();
70
71         if (f)
72         {
73                 time_t t = time(0);
74                 fprintf(f, "enigma2 crashed on %s", ctime(&t));
75                 fprintf(f, "please email this file to " CRASH_EMAILADDR "\n");
76                 std::string buffer = getLogBuffer();
77                 fwrite(buffer.c_str(), buffer.size(), 1, f);
78                 fclose(f);
79         }
80         
81         ePtr<gFBDC> my_dc;
82         gFBDC::getInstance(my_dc);
83         
84         {
85                 gPainter p(my_dc);
86                 p.resetClip(eRect(ePoint(0, 0), my_dc->size()));
87                 p.setBackgroundColor(gRGB(0x0000C0));
88                 p.setForegroundColor(gRGB(0xFFFFFF));
89         
90                 ePtr<gFont> font = new gFont("Regular", 20);
91                 p.setFont(font);
92                 p.clear();
93         
94                 eRect usable_area = eRect(100, 70, my_dc->size().width() - 200, 100);
95         
96                 p.renderText(usable_area, 
97                         "We are really sorry. Something happened "
98                         "which should not have happened, and "
99                         "resulted in a crash. If you want to help "
100                         "us in improving this situation, please send "
101                         "the logfile created in /hdd/ to " CRASH_EMAILADDR ".", gPainter::RT_WRAP|gPainter::RT_HALIGN_LEFT);
102         
103                 usable_area = eRect(100, 170, my_dc->size().width() - 200, my_dc->size().height() - 20);
104         
105                 int i;
106         
107                 size_t start = std::string::npos + 1;
108                 for (i=0; i<20; ++i)
109                 {
110                         start = lines.rfind('\n', start - 1);
111                         if (start == std::string::npos)
112                         {
113                                 start = 0;
114                                 break;
115                         }
116                 }
117         
118                 font = new gFont("Regular", 14);
119                 p.setFont(font);
120         
121                 p.renderText(usable_area, 
122                         lines.substr(start), gPainter::RT_HALIGN_LEFT);
123         }
124
125         raise(SIGKILL);
126 }
127
128 #if defined(__MIPSEL__)
129 void oops(const mcontext_t &context, int dumpcode)
130 {
131         eDebug("PC: %08lx, vaddr: %08lx", (unsigned long)context.pc, (unsigned long)context.badvaddr);
132 }
133 #else
134 #warning "no oops support!"
135 #error bla
136 #define NO_OOPS_SUPPORT
137 #endif
138
139 void handleFatalSignal(int signum, siginfo_t *si, void *ctx)
140 {
141         ucontext_t *uc = (ucontext_t*)ctx;
142         eDebug("KILLED BY signal %d", signum);
143 #ifndef NO_OOPS_SUPPORT
144         oops(uc->uc_mcontext, signum == SIGSEGV);
145 #endif
146         eDebug("-------");
147         bsodFatal();
148 }
149
150 void bsodCatchSignals()
151 {
152         struct sigaction act;
153         act.sa_handler = SIG_DFL;
154         act.sa_sigaction = handleFatalSignal;
155         act.sa_flags = 0;
156         if (sigemptyset(&act.sa_mask) == -1)
157                 perror("sigemptyset");
158         
159                 /* start handling segfaults etc. */
160         sigaction(SIGSEGV, &act, 0);
161         sigaction(SIGILL, &act, 0);
162         sigaction(SIGBUS, &act, 0);
163 }
164
165 void bsodLogInit()
166 {
167         logOutput.connect(addToLogbuffer);
168 }