blob: b0bc132dca3729ea874a438f087f807cd71198d5 [file] [log] [blame]
Theodore Ts'o9b3018a2011-08-11 14:56:49 -04001/*
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
Theodore Ts'od1154eb2011-09-18 17:34:37 -040012#include "config.h"
Theodore Ts'o9b3018a2011-08-11 14:56:49 -040013#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 DEFINE_ENTRY(SIGHUP)
33 DEFINE_ENTRY(SIGINT)
34 DEFINE_ENTRY(SIGQUIT)
35 DEFINE_ENTRY(SIGILL)
36 DEFINE_ENTRY(SIGTRAP)
37 DEFINE_ENTRY(SIGABRT)
38 DEFINE_ENTRY(SIGIOT)
39 DEFINE_ENTRY(SIGBUS)
40 DEFINE_ENTRY(SIGFPE)
41 DEFINE_ENTRY(SIGKILL)
42 DEFINE_ENTRY(SIGUSR1)
43 DEFINE_ENTRY(SIGSEGV)
44 DEFINE_ENTRY(SIGUSR2)
45 DEFINE_ENTRY(SIGPIPE)
46 DEFINE_ENTRY(SIGALRM)
47 DEFINE_ENTRY(SIGTERM)
48 DEFINE_ENTRY(SIGSTKFLT)
49 DEFINE_ENTRY(SIGCHLD)
50 DEFINE_ENTRY(SIGCONT)
51 DEFINE_ENTRY(SIGSTOP)
52 DEFINE_ENTRY(SIGTSTP)
53 DEFINE_ENTRY(SIGTTIN)
54 DEFINE_ENTRY(SIGTTOU)
55 DEFINE_ENTRY(SIGURG)
56 DEFINE_ENTRY(SIGXCPU)
57 DEFINE_ENTRY(SIGXFSZ)
58 DEFINE_ENTRY(SIGVTALRM)
59 DEFINE_ENTRY(SIGPROF)
60 DEFINE_ENTRY(SIGWINCH)
61 DEFINE_ENTRY(SIGIO)
62 DEFINE_ENTRY(SIGPOLL)
63 DEFINE_ENTRY(SIGPWR)
64 DEFINE_ENTRY(SIGSYS)
65 END_TABLE
66};
67
68static struct str_table generic_code_table[] = {
69 DEFINE_ENTRY(SI_ASYNCNL)
70 DEFINE_ENTRY(SI_TKILL)
71 DEFINE_ENTRY(SI_SIGIO)
72 DEFINE_ENTRY(SI_ASYNCIO)
73 DEFINE_ENTRY(SI_MESGQ)
74 DEFINE_ENTRY(SI_TIMER)
75 DEFINE_ENTRY(SI_QUEUE)
76 DEFINE_ENTRY(SI_USER)
77 DEFINE_ENTRY(SI_KERNEL)
78 END_TABLE
79};
80
81static struct str_table sigill_code_table[] = {
82 DEFINE_ENTRY(ILL_ILLOPC)
83 DEFINE_ENTRY(ILL_ILLOPN)
84 DEFINE_ENTRY(ILL_ILLADR)
85 DEFINE_ENTRY(ILL_ILLTRP)
86 DEFINE_ENTRY(ILL_PRVOPC)
87 DEFINE_ENTRY(ILL_PRVREG)
88 DEFINE_ENTRY(ILL_COPROC)
89 DEFINE_ENTRY(ILL_BADSTK)
90 DEFINE_ENTRY(BUS_ADRALN)
91 DEFINE_ENTRY(BUS_ADRERR)
92 DEFINE_ENTRY(BUS_OBJERR)
93 END_TABLE
94};
95
96static struct str_table sigfpe_code_table[] = {
97 DEFINE_ENTRY(FPE_INTDIV)
98 DEFINE_ENTRY(FPE_INTOVF)
99 DEFINE_ENTRY(FPE_FLTDIV)
100 DEFINE_ENTRY(FPE_FLTOVF)
101 DEFINE_ENTRY(FPE_FLTUND)
102 DEFINE_ENTRY(FPE_FLTRES)
103 DEFINE_ENTRY(FPE_FLTINV)
104 DEFINE_ENTRY(FPE_FLTSUB)
105 END_TABLE
106};
107
108static struct str_table sigsegv_code_table[] = {
109 DEFINE_ENTRY(SEGV_MAPERR)
110 DEFINE_ENTRY(SEGV_ACCERR)
111 END_TABLE
112};
113
114
115static struct str_table sigbus_code_table[] = {
116 DEFINE_ENTRY(BUS_ADRALN)
117 DEFINE_ENTRY(BUS_ADRERR)
118 DEFINE_ENTRY(BUS_OBJERR)
119 END_TABLE
120};
121
122static struct str_table sigstrap_code_table[] = {
123 DEFINE_ENTRY(TRAP_BRKPT)
124 DEFINE_ENTRY(TRAP_TRACE)
125 END_TABLE
126};
127
128static struct str_table sigcld_code_table[] = {
129 DEFINE_ENTRY(CLD_EXITED)
130 DEFINE_ENTRY(CLD_KILLED)
131 DEFINE_ENTRY(CLD_DUMPED)
132 DEFINE_ENTRY(CLD_TRAPPED)
133 DEFINE_ENTRY(CLD_STOPPED)
134 DEFINE_ENTRY(CLD_CONTINUED)
135 END_TABLE
136};
137
138static struct str_table sigpoll_code_table[] = {
139 DEFINE_ENTRY(POLL_IN)
140 DEFINE_ENTRY(POLL_OUT)
141 DEFINE_ENTRY(POLL_MSG)
142 DEFINE_ENTRY(POLL_ERR)
143 DEFINE_ENTRY(POLL_PRI)
144 DEFINE_ENTRY(POLL_HUP)
145 END_TABLE
146};
147
148static const char *lookup_table(int num, struct str_table *table)
149{
150 struct str_table *p;
151
152 for (p=table; p->name; p++)
153 if (num == p->num)
154 return(p->name);
155 return NULL;
156}
157
158static const char *lookup_table_fallback(int num, struct str_table *table)
159{
160 static char buf[32];
161 const char *ret = lookup_table(num, table);
162
163 if (ret)
164 return ret;
165 snprintf(buf, sizeof(buf), "%d", num);
166 buf[sizeof(buf)-1] = 0;
167 return buf;
168}
169
170static void die_signal_handler(int signum, siginfo_t *siginfo, void *context)
171{
172 void *stack_syms[32];
173 int frames;
174 const char *cp;
175
176 fprintf(stderr, "Signal (%d) %s ", signum,
177 lookup_table_fallback(signum, sig_table));
178 if (siginfo->si_code == SI_USER)
179 fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid);
180 cp = lookup_table(siginfo->si_code, generic_code_table);
181 if (cp)
182 fprintf(stderr, "si_code=%s ", cp);
183 else if (signum == SIGILL)
184 fprintf(stderr, "si_code=%s ",
185 lookup_table_fallback(siginfo->si_code,
186 sigill_code_table));
187 else if (signum == SIGFPE)
188 fprintf(stderr, "si_code=%s ",
189 lookup_table_fallback(siginfo->si_code,
190 sigfpe_code_table));
191 else if (signum == SIGSEGV)
192 fprintf(stderr, "si_code=%s ",
193 lookup_table_fallback(siginfo->si_code,
194 sigsegv_code_table));
195 else if (signum == SIGBUS)
196 fprintf(stderr, "si_code=%s ",
197 lookup_table_fallback(siginfo->si_code,
198 sigbus_code_table));
199 else if (signum == SIGCLD)
200 fprintf(stderr, "si_code=%s ",
201 lookup_table_fallback(siginfo->si_code,
202 sigcld_code_table));
203 else
204 fprintf(stderr, "si code=%d ", siginfo->si_code);
205 if ((siginfo->si_code != SI_USER) &&
206 (signum == SIGILL || signum == SIGFPE ||
207 signum == SIGSEGV || signum == SIGBUS))
208 fprintf(stderr, "fault addr=%p", siginfo->si_addr);
209 fprintf(stderr, "\n");
210
211#ifdef HAVE_BACKTRACE
212 frames = backtrace(stack_syms, 32);
213 backtrace_symbols_fd(stack_syms, frames, 2);
214#endif
215 exit(FSCK_ERROR);
216}
217
218void sigcatcher_setup(void)
219{
220 struct sigaction sa;
221
Theodore Ts'odd62d852011-09-03 09:43:50 -0400222 memset(&sa, 0, sizeof(struct sigaction));
Theodore Ts'o9b3018a2011-08-11 14:56:49 -0400223 sa.sa_sigaction = die_signal_handler;
224 sa.sa_flags = SA_SIGINFO;
225
226 sigaction(SIGFPE, &sa, 0);
227 sigaction(SIGILL, &sa, 0);
228 sigaction(SIGBUS, &sa, 0);
229 sigaction(SIGSEGV, &sa, 0);
230}
231
232
233#ifdef DEBUG
234#include <getopt.h>
235
236void usage(void)
237{
238 fprintf(stderr, "tst_sigcatcher: [-akfn]\n");
239 exit(1);
240}
241
242int main(int argc, char** argv)
243{
244 struct sigaction sa;
245 char *p = 0;
246 int i, c;
247 volatile x=0;
248
249 memset(&sa, 0, sizeof(struct sigaction));
250 sa.sa_sigaction = die_signal_handler;
251 sa.sa_flags = SA_SIGINFO;
252 for (i=1; i < 31; i++)
253 sigaction(i, &sa, 0);
254
255 while ((c = getopt (argc, argv, "afkn")) != EOF)
256 switch (c) {
257 case 'a':
258 abort();
259 break;
260 case 'f':
261 printf("%d\n", 42/x);
262 case 'k':
263 kill(getpid(), SIGTERM);
264 break;
265 case 'n':
266 *p = 42;
267 default:
268 usage ();
269 }
270
271 printf("Sleeping for 10 seconds, send kill signal to pid %u...\n",
272 getpid());
273 fflush(stdout);
274 sleep(10);
275 exit(0);
276}
277#endif