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 <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
442