sigcatcher.c revision 3df6014a3d216d19be7d2286de24e8ee106f18ad
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
23struct 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
31static 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
134static struct str_table generic_code_table[] = {
135#ifdef SI_ASYNCNL
136	DEFINE_ENTRY(SI_ASYNCNL)
137#endif
138#ifdef SI_TKILL
139	DEFINE_ENTRY(SI_TKILL)
140#endif
141#ifdef SI_SIGIO
142	DEFINE_ENTRY(SI_SIGIO)
143#endif
144#ifdef SI_ASYNCIO
145	DEFINE_ENTRY(SI_ASYNCIO)
146#endif
147#ifdef SI_MESGQ
148	DEFINE_ENTRY(SI_MESGQ)
149#endif
150#ifdef SI_TIMER
151	DEFINE_ENTRY(SI_TIMER)
152#endif
153#ifdef SI_QUEUE
154	DEFINE_ENTRY(SI_QUEUE)
155#endif
156#ifdef SI_USER
157	DEFINE_ENTRY(SI_USER)
158#endif
159#ifdef SI_KERNEL
160	DEFINE_ENTRY(SI_KERNEL)
161#endif
162	END_TABLE
163};
164
165static struct str_table sigill_code_table[] = {
166#ifdef ILL_ILLOPC
167	DEFINE_ENTRY(ILL_ILLOPC)
168#endif
169#ifdef ILL_ILLOPN
170	DEFINE_ENTRY(ILL_ILLOPN)
171#endif
172#ifdef ILL_ILLADR
173	DEFINE_ENTRY(ILL_ILLADR)
174#endif
175#ifdef ILL_ILLTRP
176	DEFINE_ENTRY(ILL_ILLTRP)
177#endif
178#ifdef ILL_PRVOPC
179	DEFINE_ENTRY(ILL_PRVOPC)
180#endif
181#ifdef ILL_PRVREG
182	DEFINE_ENTRY(ILL_PRVREG)
183#endif
184#ifdef ILL_COPROC
185	DEFINE_ENTRY(ILL_COPROC)
186#endif
187#ifdef ILL_BADSTK
188	DEFINE_ENTRY(ILL_BADSTK)
189#endif
190#ifdef BUS_ADRALN
191	DEFINE_ENTRY(BUS_ADRALN)
192#endif
193#ifdef BUS_ADRERR
194	DEFINE_ENTRY(BUS_ADRERR)
195#endif
196#ifdef BUS_OBJERR
197	DEFINE_ENTRY(BUS_OBJERR)
198#endif
199	END_TABLE
200};
201
202static struct str_table sigfpe_code_table[] = {
203#ifdef FPE_INTDIV
204	DEFINE_ENTRY(FPE_INTDIV)
205#endif
206#ifdef FPE_INTOVF
207	DEFINE_ENTRY(FPE_INTOVF)
208#endif
209#ifdef FPE_FLTDIV
210	DEFINE_ENTRY(FPE_FLTDIV)
211#endif
212#ifdef FPE_FLTOVF
213	DEFINE_ENTRY(FPE_FLTOVF)
214#endif
215#ifdef FPE_FLTUND
216	DEFINE_ENTRY(FPE_FLTUND)
217#endif
218#ifdef FPE_FLTRES
219	DEFINE_ENTRY(FPE_FLTRES)
220#endif
221#ifdef FPE_FLTINV
222	DEFINE_ENTRY(FPE_FLTINV)
223#endif
224#ifdef FPE_FLTSUB
225	DEFINE_ENTRY(FPE_FLTSUB)
226#endif
227	END_TABLE
228};
229
230static struct str_table sigsegv_code_table[] = {
231#ifdef SEGV_MAPERR
232	DEFINE_ENTRY(SEGV_MAPERR)
233#endif
234#ifdef SEGV_ACCERR
235	DEFINE_ENTRY(SEGV_ACCERR)
236#endif
237	END_TABLE
238};
239
240
241static struct str_table sigbus_code_table[] = {
242#ifdef BUS_ADRALN
243	DEFINE_ENTRY(BUS_ADRALN)
244#endif
245#ifdef BUS_ADRERR
246	DEFINE_ENTRY(BUS_ADRERR)
247#endif
248#ifdef BUS_OBJERR
249	DEFINE_ENTRY(BUS_OBJERR)
250#endif
251	END_TABLE
252};
253
254#if 0 /* should this be hooked in somewhere? */
255static struct str_table sigstrap_code_table[] = {
256#ifdef TRAP_BRKPT
257	DEFINE_ENTRY(TRAP_BRKPT)
258#endif
259#ifdef TRAP_TRACE
260	DEFINE_ENTRY(TRAP_TRACE)
261#endif
262	END_TABLE
263};
264#endif
265
266static struct str_table sigcld_code_table[] = {
267#ifdef CLD_EXITED
268	DEFINE_ENTRY(CLD_EXITED)
269#endif
270#ifdef CLD_KILLED
271	DEFINE_ENTRY(CLD_KILLED)
272#endif
273#ifdef CLD_DUMPED
274	DEFINE_ENTRY(CLD_DUMPED)
275#endif
276#ifdef CLD_TRAPPED
277	DEFINE_ENTRY(CLD_TRAPPED)
278#endif
279#ifdef CLD_STOPPED
280	DEFINE_ENTRY(CLD_STOPPED)
281#endif
282#ifdef CLD_CONTINUED
283	DEFINE_ENTRY(CLD_CONTINUED)
284#endif
285	END_TABLE
286};
287
288#if 0 /* should this be hooked in somewhere? */
289static struct str_table sigpoll_code_table[] = {
290#ifdef POLL_IN
291	DEFINE_ENTRY(POLL_IN)
292#endif
293#ifdef POLL_OUT
294	DEFINE_ENTRY(POLL_OUT)
295#endif
296#ifdef POLL_MSG
297	DEFINE_ENTRY(POLL_MSG)
298#endif
299#ifdef POLL_ERR
300	DEFINE_ENTRY(POLL_ERR)
301#endif
302#ifdef POLL_PRI
303	DEFINE_ENTRY(POLL_PRI)
304#endif
305#ifdef POLL_HUP
306	DEFINE_ENTRY(POLL_HUP)
307#endif
308	END_TABLE
309};
310#endif
311
312static 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
322static 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
334static void die_signal_handler(int signum, siginfo_t *siginfo,
335			       void *context EXT2FS_ATTR((unused)))
336{
337       void *stack_syms[32];
338       int frames;
339       const char *cp;
340
341       fprintf(stderr, "Signal (%d) %s ", signum,
342	       lookup_table_fallback(signum, sig_table));
343       if (siginfo->si_code == SI_USER)
344	       fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid);
345       cp = lookup_table(siginfo->si_code, generic_code_table);
346       if (cp)
347	       fprintf(stderr, "si_code=%s ", cp);
348       else if (signum == SIGILL)
349	       fprintf(stderr, "si_code=%s ",
350		       lookup_table_fallback(siginfo->si_code,
351					     sigill_code_table));
352       else if (signum == SIGFPE)
353	       fprintf(stderr, "si_code=%s ",
354		       lookup_table_fallback(siginfo->si_code,
355					     sigfpe_code_table));
356       else if (signum == SIGSEGV)
357	       fprintf(stderr, "si_code=%s ",
358		       lookup_table_fallback(siginfo->si_code,
359					     sigsegv_code_table));
360       else if (signum == SIGBUS)
361	       fprintf(stderr, "si_code=%s ",
362		       lookup_table_fallback(siginfo->si_code,
363					     sigbus_code_table));
364       else if (signum == SIGCHLD)
365	       fprintf(stderr, "si_code=%s ",
366		       lookup_table_fallback(siginfo->si_code,
367					     sigcld_code_table));
368       else
369	       fprintf(stderr, "si code=%d ", siginfo->si_code);
370       if ((siginfo->si_code != SI_USER) &&
371	   (signum == SIGILL || signum == SIGFPE ||
372	    signum == SIGSEGV || signum == SIGBUS))
373	       fprintf(stderr, "fault addr=%p", siginfo->si_addr);
374       fprintf(stderr, "\n");
375
376#if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE)
377       frames = backtrace(stack_syms, 32);
378       backtrace_symbols_fd(stack_syms, frames, 2);
379#endif
380       exit(FSCK_ERROR);
381}
382
383void sigcatcher_setup(void)
384{
385	struct sigaction	sa;
386
387	memset(&sa, 0, sizeof(struct sigaction));
388	sa.sa_sigaction = die_signal_handler;
389	sa.sa_flags = SA_SIGINFO;
390
391	sigaction(SIGFPE, &sa, 0);
392	sigaction(SIGILL, &sa, 0);
393	sigaction(SIGBUS, &sa, 0);
394	sigaction(SIGSEGV, &sa, 0);
395}
396
397
398#ifdef DEBUG
399#include <getopt.h>
400
401void usage(void)
402{
403	fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
404	exit(1);
405}
406
407int main(int argc, char** argv)
408{
409	struct sigaction	sa;
410	char			*p = 0;
411	int 			i, c;
412	volatile		x=0;
413
414	memset(&sa, 0, sizeof(struct sigaction));
415	sa.sa_sigaction = die_signal_handler;
416	sa.sa_flags = SA_SIGINFO;
417	for (i=1; i < 31; i++)
418		sigaction(i, &sa, 0);
419
420	while ((c = getopt (argc, argv, "afkn")) != EOF)
421		switch (c) {
422		case 'a':
423			abort();
424			break;
425		case 'f':
426			printf("%d\n", 42/x);
427		case 'k':
428			kill(getpid(), SIGTERM);
429			break;
430		case 'n':
431			*p = 42;
432		default:
433			usage ();
434		}
435
436	printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",
437	       getpid());
438	fflush(stdout);
439	sleep(10);
440	exit(0);
441}
442#endif
443