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
22 struct 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
30 static 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
133 static 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
164 static 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
201 static 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
229 static 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
240 static 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? */
254 static 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
265 static 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? */
288 static 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
lookup_table(int num,struct str_table * table)311 static 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
lookup_table_fallback(int num,struct str_table * table)321 static 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
die_signal_handler(int signum,siginfo_t * siginfo,void * context EXT2FS_ATTR ((unused)))333 static 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
sigcatcher_setup(void)382 void 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
usage(void)400 void usage(void)
401 {
402 fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
403 exit(1);
404 }
405
main(int argc,char ** argv)406 int 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