1 | /* Catch segmentation faults and print backtrace. |
2 | Copyright (C) 1998-2020 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. |
5 | |
6 | The GNU C Library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2.1 of the License, or (at your option) any later version. |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Lesser General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, see |
18 | <https://www.gnu.org/licenses/>. */ |
19 | |
20 | #include <alloca.h> |
21 | #include <ctype.h> |
22 | #include <errno.h> |
23 | #include <execinfo.h> |
24 | #include <fcntl.h> |
25 | #include <signal.h> |
26 | #include <stdint.h> |
27 | #include <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | #include <unistd.h> |
31 | #include <_itoa.h> |
32 | #include <ldsodefs.h> |
33 | |
34 | /* This file defines macros to access the content of the sigcontext element |
35 | passed up by the signal handler. */ |
36 | #include <sigcontextinfo.h> |
37 | |
38 | #ifdef SA_SIGINFO |
39 | # define SIGCONTEXT siginfo_t *info, void * |
40 | #endif |
41 | |
42 | /* Get code to possibly dump the content of all registers. */ |
43 | #include <register-dump.h> |
44 | |
45 | /* We'll use this a lot. */ |
46 | #define WRITE_STRING(s) write (fd, s, strlen (s)) |
47 | |
48 | /* Name of the output file. */ |
49 | static const char *fname; |
50 | |
51 | |
52 | /* Print the signal number SIGNAL. Either strerror or strsignal might |
53 | call local internal functions and these in turn call far too many |
54 | other functions and might even allocate memory which might fail. */ |
55 | static void |
56 | write_strsignal (int fd, int signal) |
57 | { |
58 | char buf[30]; |
59 | char *ptr = _itoa_word (signal, &buf[sizeof (buf)], 10, 0); |
60 | WRITE_STRING ("signal " ); |
61 | write (fd, buf, &buf[sizeof (buf)] - ptr); |
62 | } |
63 | |
64 | |
65 | /* This function is called when a segmentation fault is caught. The system |
66 | is in an unstable state now. This means especially that malloc() might |
67 | not work anymore. */ |
68 | static void |
69 | catch_segfault (int signal, SIGCONTEXT ctx) |
70 | { |
71 | int fd, cnt, i; |
72 | void **arr; |
73 | struct sigaction sa; |
74 | uintptr_t pc; |
75 | |
76 | /* This is the name of the file we are writing to. If none is given |
77 | or we cannot write to this file write to stderr. */ |
78 | fd = 2; |
79 | if (fname != NULL) |
80 | { |
81 | fd = open (fname, O_TRUNC | O_WRONLY | O_CREAT, 0666); |
82 | if (fd == -1) |
83 | fd = 2; |
84 | } |
85 | |
86 | WRITE_STRING ("*** " ); |
87 | write_strsignal (fd, signal); |
88 | WRITE_STRING ("\n" ); |
89 | |
90 | #ifdef REGISTER_DUMP |
91 | REGISTER_DUMP; |
92 | #endif |
93 | |
94 | WRITE_STRING ("\nBacktrace:\n" ); |
95 | |
96 | /* Get the backtrace. */ |
97 | arr = alloca (256 * sizeof (void *)); |
98 | cnt = backtrace (arr, 256); |
99 | |
100 | /* Now try to locate the PC from signal context in the backtrace. |
101 | Normally it will be found at arr[2], but it might appear later |
102 | if there were some signal handler wrappers. Allow a few bytes |
103 | difference to cope with as many arches as possible. */ |
104 | pc = sigcontext_get_pc (ctx); |
105 | for (i = 0; i < cnt; ++i) |
106 | if ((uintptr_t) arr[i] >= pc - 16 && (uintptr_t) arr[i] <= pc + 16) |
107 | break; |
108 | |
109 | /* If we haven't found it, better dump full backtrace even including |
110 | the signal handler frames instead of not dumping anything. */ |
111 | if (i == cnt) |
112 | i = 0; |
113 | |
114 | /* Now generate nicely formatted output. */ |
115 | __backtrace_symbols_fd (arr + i, cnt - i, fd); |
116 | |
117 | #ifdef HAVE_PROC_SELF |
118 | /* Now the link map. */ |
119 | int mapfd = open ("/proc/self/maps" , O_RDONLY); |
120 | if (mapfd != -1) |
121 | { |
122 | write (fd, "\nMemory map:\n\n" , 14); |
123 | |
124 | char buf[256]; |
125 | ssize_t n; |
126 | |
127 | while ((n = TEMP_FAILURE_RETRY (read (mapfd, buf, sizeof (buf)))) > 0) |
128 | TEMP_FAILURE_RETRY (write (fd, buf, n)); |
129 | |
130 | close (mapfd); |
131 | } |
132 | #endif |
133 | |
134 | /* Pass on the signal (so that a core file is produced). */ |
135 | sa.sa_handler = SIG_DFL; |
136 | sigemptyset (&sa.sa_mask); |
137 | sa.sa_flags = 0; |
138 | sigaction (signal, &sa, NULL); |
139 | raise (signal); |
140 | } |
141 | |
142 | |
143 | static void |
144 | __attribute__ ((constructor)) |
145 | install_handler (void) |
146 | { |
147 | struct sigaction sa; |
148 | const char *sigs = getenv ("SEGFAULT_SIGNALS" ); |
149 | const char *name; |
150 | |
151 | #ifdef SA_SIGINFO |
152 | sa.sa_sigaction = catch_segfault; |
153 | sa.sa_flags = SA_SIGINFO; |
154 | #else |
155 | sa.sa_handler = (void*) catch_segfault; |
156 | sa.sa_flags = 0; |
157 | #endif |
158 | sigemptyset (&sa.sa_mask); |
159 | sa.sa_flags |= SA_RESTART; |
160 | |
161 | /* Maybe we are expected to use an alternative stack. */ |
162 | if (getenv ("SEGFAULT_USE_ALTSTACK" ) != 0) |
163 | { |
164 | void *stack_mem = malloc (2 * SIGSTKSZ); |
165 | stack_t ss; |
166 | |
167 | if (stack_mem != NULL) |
168 | { |
169 | ss.ss_sp = stack_mem; |
170 | ss.ss_flags = 0; |
171 | ss.ss_size = 2 * SIGSTKSZ; |
172 | |
173 | if (sigaltstack (&ss, NULL) == 0) |
174 | sa.sa_flags |= SA_ONSTACK; |
175 | } |
176 | } |
177 | |
178 | if (sigs == NULL) |
179 | sigaction (SIGSEGV, &sa, NULL); |
180 | else if (sigs[0] == '\0') |
181 | /* Do not do anything. */ |
182 | return; |
183 | else |
184 | { |
185 | const char *where; |
186 | int all = __strcasecmp (sigs, "all" ) == 0; |
187 | |
188 | #define INSTALL_FOR_SIG(sig, name) \ |
189 | where = __strcasestr (sigs, name); \ |
190 | if (all || (where != NULL \ |
191 | && (where == sigs || !isalnum (where[-1])) \ |
192 | && !isalnum (where[sizeof (name) - 1]))) \ |
193 | sigaction (sig, &sa, NULL); |
194 | |
195 | INSTALL_FOR_SIG (SIGSEGV, "segv" ); |
196 | INSTALL_FOR_SIG (SIGILL, "ill" ); |
197 | #ifdef SIGBUS |
198 | INSTALL_FOR_SIG (SIGBUS, "bus" ); |
199 | #endif |
200 | #ifdef SIGSTKFLT |
201 | INSTALL_FOR_SIG (SIGSTKFLT, "stkflt" ); |
202 | #endif |
203 | INSTALL_FOR_SIG (SIGABRT, "abrt" ); |
204 | INSTALL_FOR_SIG (SIGFPE, "fpe" ); |
205 | } |
206 | |
207 | /* Preserve the output file name if there is any given. */ |
208 | name = getenv ("SEGFAULT_OUTPUT_NAME" ); |
209 | if (name != NULL && name[0] != '\0') |
210 | { |
211 | int ret = access (name, R_OK | W_OK); |
212 | |
213 | if (ret == 0 || (ret == -1 && errno == ENOENT)) |
214 | fname = __strdup (name); |
215 | } |
216 | } |
217 | |