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