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