• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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 
165 static 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 
202 static 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 
230 static 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 
241 static 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? */
255 static 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 
266 static 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? */
289 static 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 
lookup_table(int num,struct str_table * table)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 
lookup_table_fallback(int num,struct str_table * table)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 
die_signal_handler(int signum,siginfo_t * siginfo,void * context EXT2FS_ATTR ((unused)))334 static void die_signal_handler(int signum, siginfo_t *siginfo,
335 			       void *context EXT2FS_ATTR((unused)))
336 {
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));
362        else if (signum == SIGCHLD)
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 
374 #if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE)
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        }
382 #endif
383        exit(FSCK_ERROR);
384 }
385 
sigcatcher_setup(void)386 void sigcatcher_setup(void)
387 {
388 	struct sigaction	sa;
389 
390 	memset(&sa, 0, sizeof(struct sigaction));
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);
398 	sigaction(SIGABRT, &sa, 0);
399 }
400 
401 
402 #ifdef DEBUG
403 #include <getopt.h>
404 
usage(void)405 void usage(void)
406 {
407 	fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
408 	exit(1);
409 }
410 
main(int argc,char ** argv)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
447