Whamcloud - gitweb
3b8d5820fc5aa4a6f5344f4146f0d2366d6aa179
[tools/e2fsprogs.git] / e2fsck / sigcatcher.c
1 /*
2  * sigcatcher.c --- print a backtrace on a SIGSEGV, et. al
3  *
4  * Copyright (C) 2011 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11
12 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <signal.h>
16 #include <string.h>
17 #ifdef HAVE_EXECINFO_H
18 #include <execinfo.h>
19 #endif
20
21 #include "e2fsck.h"
22
23 struct str_table {
24         int     num;
25         const char      *name;
26 };
27
28 #define DEFINE_ENTRY(SYM)       { SYM, #SYM },
29 #define END_TABLE               { 0, 0 }
30
31 static struct str_table sig_table[] = {
32 #ifdef SIGHUP
33         DEFINE_ENTRY(SIGHUP)
34 #endif
35 #ifdef SIGINT
36         DEFINE_ENTRY(SIGINT)
37 #endif
38 #ifdef SIGQUIT
39         DEFINE_ENTRY(SIGQUIT)
40 #endif
41 #ifdef SIGILL
42         DEFINE_ENTRY(SIGILL)
43 #endif
44 #ifdef SIGTRAP
45         DEFINE_ENTRY(SIGTRAP)
46 #endif
47 #ifdef SIGABRT
48         DEFINE_ENTRY(SIGABRT)
49 #endif
50 #ifdef SIGIOT
51         DEFINE_ENTRY(SIGIOT)
52 #endif
53 #ifdef SIGBUS
54         DEFINE_ENTRY(SIGBUS)
55 #endif
56 #ifdef SIGFPE
57         DEFINE_ENTRY(SIGFPE)
58 #endif
59 #ifdef SIGKILL
60         DEFINE_ENTRY(SIGKILL)
61 #endif
62 #ifdef SIGUSR1
63         DEFINE_ENTRY(SIGUSR1)
64 #endif
65 #ifdef SIGSEGV
66         DEFINE_ENTRY(SIGSEGV)
67 #endif
68 #ifdef SIGUSR2
69         DEFINE_ENTRY(SIGUSR2)
70 #endif
71 #ifdef SIGPIPE
72         DEFINE_ENTRY(SIGPIPE)
73 #endif
74 #ifdef SIGALRM
75         DEFINE_ENTRY(SIGALRM)
76 #endif
77 #ifdef SIGTERM
78         DEFINE_ENTRY(SIGTERM)
79 #endif
80 #ifdef SIGSTKFLT
81         DEFINE_ENTRY(SIGSTKFLT)
82 #endif
83 #ifdef SIGCHLD
84         DEFINE_ENTRY(SIGCHLD)
85 #endif
86 #ifdef SIGCONT
87         DEFINE_ENTRY(SIGCONT)
88 #endif
89 #ifdef SIGSTOP
90         DEFINE_ENTRY(SIGSTOP)
91 #endif
92 #ifdef SIGTSTP
93         DEFINE_ENTRY(SIGTSTP)
94 #endif
95 #ifdef SIGTTIN
96         DEFINE_ENTRY(SIGTTIN)
97 #endif
98 #ifdef SIGTTOU
99         DEFINE_ENTRY(SIGTTOU)
100 #endif
101 #ifdef SIGURG
102         DEFINE_ENTRY(SIGURG)
103 #endif
104 #ifdef SIGXCPU
105         DEFINE_ENTRY(SIGXCPU)
106 #endif
107 #ifdef SIGXFSZ
108         DEFINE_ENTRY(SIGXFSZ)
109 #endif
110 #ifdef SIGVTALRM
111         DEFINE_ENTRY(SIGVTALRM)
112 #endif
113 #ifdef SIGPROF
114         DEFINE_ENTRY(SIGPROF)
115 #endif
116 #ifdef SIGWINCH
117         DEFINE_ENTRY(SIGWINCH)
118 #endif
119 #ifdef SIGIO
120         DEFINE_ENTRY(SIGIO)
121 #endif
122 #ifdef SIGPOLL
123         DEFINE_ENTRY(SIGPOLL)
124 #endif
125 #ifdef SIGPWR
126         DEFINE_ENTRY(SIGPWR)
127 #endif
128 #ifdef SIGSYS
129         DEFINE_ENTRY(SIGSYS)
130 #endif
131         END_TABLE
132 };
133
134 static struct str_table generic_code_table[] = {
135         DEFINE_ENTRY(SI_ASYNCNL)
136         DEFINE_ENTRY(SI_TKILL)
137         DEFINE_ENTRY(SI_SIGIO)
138         DEFINE_ENTRY(SI_ASYNCIO)
139         DEFINE_ENTRY(SI_MESGQ)
140         DEFINE_ENTRY(SI_TIMER)
141         DEFINE_ENTRY(SI_QUEUE)
142         DEFINE_ENTRY(SI_USER)
143         DEFINE_ENTRY(SI_KERNEL)
144         END_TABLE
145 };
146
147 static struct str_table sigill_code_table[] = {
148 #ifdef ILL_ILLOPC
149         DEFINE_ENTRY(ILL_ILLOPC)
150 #endif
151 #ifdef ILL_ILLOPN
152         DEFINE_ENTRY(ILL_ILLOPN)
153 #endif
154 #ifdef ILL_ILLADR
155         DEFINE_ENTRY(ILL_ILLADR)
156 #endif
157 #ifdef ILL_ILLTRP
158         DEFINE_ENTRY(ILL_ILLTRP)
159 #endif
160 #ifdef ILL_PRVOPC
161         DEFINE_ENTRY(ILL_PRVOPC)
162 #endif
163 #ifdef ILL_PRVREG
164         DEFINE_ENTRY(ILL_PRVREG)
165 #endif
166 #ifdef ILL_COPROC
167         DEFINE_ENTRY(ILL_COPROC)
168 #endif
169 #ifdef ILL_BADSTK
170         DEFINE_ENTRY(ILL_BADSTK)
171 #endif
172 #ifdef BUS_ADRALN
173         DEFINE_ENTRY(BUS_ADRALN)
174 #endif
175 #ifdef BUS_ADRERR
176         DEFINE_ENTRY(BUS_ADRERR)
177 #endif
178 #ifdef BUS_OBJERR
179         DEFINE_ENTRY(BUS_OBJERR)
180 #endif
181         END_TABLE
182 };
183
184 static struct str_table sigfpe_code_table[] = {
185 #ifdef FPE_INTDIV
186         DEFINE_ENTRY(FPE_INTDIV)
187 #endif
188 #ifdef FPE_INTOVF
189         DEFINE_ENTRY(FPE_INTOVF)
190 #endif
191 #ifdef FPE_FLTDIV
192         DEFINE_ENTRY(FPE_FLTDIV)
193 #endif
194 #ifdef FPE_FLTOVF
195         DEFINE_ENTRY(FPE_FLTOVF)
196 #endif
197 #ifdef FPE_FLTUND
198         DEFINE_ENTRY(FPE_FLTUND)
199 #endif
200 #ifdef FPE_FLTRES
201         DEFINE_ENTRY(FPE_FLTRES)
202 #endif
203 #ifdef FPE_FLTINV
204         DEFINE_ENTRY(FPE_FLTINV)
205 #endif
206 #ifdef FPE_FLTSUB
207         DEFINE_ENTRY(FPE_FLTSUB)
208 #endif
209         END_TABLE
210 };
211
212 static struct str_table sigsegv_code_table[] = {
213 #ifdef SEGV_MAPERR
214         DEFINE_ENTRY(SEGV_MAPERR)
215 #endif
216 #ifdef SEGV_ACCERR
217         DEFINE_ENTRY(SEGV_ACCERR)
218 #endif
219         END_TABLE
220 };
221
222
223 static struct str_table sigbus_code_table[] = {
224 #ifdef BUS_ADRALN
225         DEFINE_ENTRY(BUS_ADRALN)
226 #endif
227 #ifdef BUS_ADRERR
228         DEFINE_ENTRY(BUS_ADRERR)
229 #endif
230 #ifdef BUS_OBJERR
231         DEFINE_ENTRY(BUS_OBJERR)
232 #endif
233         END_TABLE
234 };
235
236 static struct str_table sigstrap_code_table[] = {
237 #ifdef TRAP_BRKPT
238         DEFINE_ENTRY(TRAP_BRKPT)
239 #endif
240 #ifdef TRAP_TRACE
241         DEFINE_ENTRY(TRAP_TRACE)
242 #endif
243         END_TABLE
244 };
245
246 static struct str_table sigcld_code_table[] = {
247 #ifdef CLD_EXITED
248         DEFINE_ENTRY(CLD_EXITED)
249 #endif
250 #ifdef CLD_KILLED
251         DEFINE_ENTRY(CLD_KILLED)
252 #endif
253 #ifdef CLD_DUMPED
254         DEFINE_ENTRY(CLD_DUMPED)
255 #endif
256 #ifdef CLD_TRAPPED
257         DEFINE_ENTRY(CLD_TRAPPED)
258 #endif
259 #ifdef CLD_STOPPED
260         DEFINE_ENTRY(CLD_STOPPED)
261 #endif
262 #ifdef CLD_CONTINUED
263         DEFINE_ENTRY(CLD_CONTINUED)
264 #endif
265         END_TABLE
266 };
267
268 static struct str_table sigpoll_code_table[] = {
269 #ifdef POLL_IN
270         DEFINE_ENTRY(POLL_IN)
271 #endif
272 #ifdef POLL_OUT
273         DEFINE_ENTRY(POLL_OUT)
274 #endif
275 #ifdef POLL_MSG
276         DEFINE_ENTRY(POLL_MSG)
277 #endif
278 #ifdef POLL_ERR
279         DEFINE_ENTRY(POLL_ERR)
280 #endif
281 #ifdef POLL_PRI
282         DEFINE_ENTRY(POLL_PRI)
283 #endif
284 #ifdef POLL_HUP
285         DEFINE_ENTRY(POLL_HUP)
286 #endif
287         END_TABLE
288 };
289
290 static const char *lookup_table(int num, struct str_table *table)
291 {
292         struct str_table *p;
293
294         for (p=table; p->name; p++)
295                 if (num == p->num)
296                         return(p->name);
297         return NULL;
298 }
299
300 static const char *lookup_table_fallback(int num, struct str_table *table)
301 {
302         static char buf[32];
303         const char *ret = lookup_table(num, table);
304
305         if (ret)
306                 return ret;
307         snprintf(buf, sizeof(buf), "%d", num);
308         buf[sizeof(buf)-1] = 0;
309         return buf;
310 }
311
312 static void die_signal_handler(int signum, siginfo_t *siginfo, void *context)
313 {
314        void *stack_syms[32];
315        int frames;
316        const char *cp;
317
318        fprintf(stderr, "Signal (%d) %s ", signum,
319                lookup_table_fallback(signum, sig_table));
320        if (siginfo->si_code == SI_USER)
321                fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid);
322        cp = lookup_table(siginfo->si_code, generic_code_table);
323        if (cp)
324                fprintf(stderr, "si_code=%s ", cp);
325        else if (signum == SIGILL)
326                fprintf(stderr, "si_code=%s ",
327                        lookup_table_fallback(siginfo->si_code,
328                                              sigill_code_table));
329        else if (signum == SIGFPE)
330                fprintf(stderr, "si_code=%s ",
331                        lookup_table_fallback(siginfo->si_code,
332                                              sigfpe_code_table));
333        else if (signum == SIGSEGV)
334                fprintf(stderr, "si_code=%s ",
335                        lookup_table_fallback(siginfo->si_code,
336                                              sigsegv_code_table));
337        else if (signum == SIGBUS)
338                fprintf(stderr, "si_code=%s ",
339                        lookup_table_fallback(siginfo->si_code,
340                                              sigbus_code_table));
341        else if (signum == SIGCLD)
342                fprintf(stderr, "si_code=%s ",
343                        lookup_table_fallback(siginfo->si_code,
344                                              sigcld_code_table));
345        else
346                fprintf(stderr, "si code=%d ", siginfo->si_code);
347        if ((siginfo->si_code != SI_USER) &&
348            (signum == SIGILL || signum == SIGFPE ||
349             signum == SIGSEGV || signum == SIGBUS))
350                fprintf(stderr, "fault addr=%p", siginfo->si_addr);
351        fprintf(stderr, "\n");
352
353 #ifdef HAVE_BACKTRACE
354        frames = backtrace(stack_syms, 32);
355        backtrace_symbols_fd(stack_syms, frames, 2);
356 #endif
357        exit(FSCK_ERROR);
358 }
359
360 void sigcatcher_setup(void)
361 {
362         struct sigaction        sa;
363         
364         memset(&sa, 0, sizeof(struct sigaction));
365         sa.sa_sigaction = die_signal_handler;
366         sa.sa_flags = SA_SIGINFO;
367
368         sigaction(SIGFPE, &sa, 0);
369         sigaction(SIGILL, &sa, 0);
370         sigaction(SIGBUS, &sa, 0);
371         sigaction(SIGSEGV, &sa, 0);
372 }       
373
374
375 #ifdef DEBUG
376 #include <getopt.h>
377
378 void usage(void)
379 {
380         fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
381         exit(1);
382 }
383
384 int main(int argc, char** argv)
385 {
386         struct sigaction        sa;
387         char                    *p = 0;
388         int                     i, c;
389         volatile                x=0;
390
391         memset(&sa, 0, sizeof(struct sigaction));
392         sa.sa_sigaction = die_signal_handler;
393         sa.sa_flags = SA_SIGINFO;
394         for (i=1; i < 31; i++)
395                 sigaction(i, &sa, 0);
396
397         while ((c = getopt (argc, argv, "afkn")) != EOF)
398                 switch (c) {
399                 case 'a':
400                         abort();
401                         break;
402                 case 'f':
403                         printf("%d\n", 42/x);
404                 case 'k':
405                         kill(getpid(), SIGTERM);
406                         break;
407                 case 'n':
408                         *p = 42;
409                 default:
410                         usage ();
411                 }
412
413         printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",
414                getpid());
415         fflush(stdout);
416         sleep(10);
417         exit(0);
418 }
419 #endif