]>
Commit | Line | Data |
---|---|---|
107f8131 | 1 | /* Catch segmentation faults and print backtrace. |
04277e02 | 2 | Copyright (C) 1998-2019 Free Software Foundation, Inc. |
107f8131 UD |
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 | |
41bdb6e2 AJ |
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. | |
107f8131 UD |
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 | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
107f8131 | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
107f8131 | 19 | |
c701ab9f | 20 | #include <alloca.h> |
ed1ac6a2 | 21 | #include <ctype.h> |
96b58136 | 22 | #include <errno.h> |
107f8131 UD |
23 | #include <execinfo.h> |
24 | #include <fcntl.h> | |
25 | #include <signal.h> | |
c701ab9f | 26 | #include <stdint.h> |
f2a37858 | 27 | #include <stdio.h> |
107f8131 | 28 | #include <stdlib.h> |
ed1ac6a2 | 29 | #include <string.h> |
107f8131 | 30 | #include <unistd.h> |
eb96ffb0 | 31 | #include <_itoa.h> |
ff151400 | 32 | #include <ldsodefs.h> |
107f8131 UD |
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 | ||
ed1ac6a2 UD |
38 | /* Get code to possibly dump the content of all registers. */ |
39 | #include <register-dump.h> | |
40 | ||
682e4437 | 41 | /* We'll use this a lot. */ |
f2a37858 UD |
42 | #define WRITE_STRING(s) write (fd, s, strlen (s)) |
43 | ||
f2a37858 UD |
44 | /* Name of the output file. */ |
45 | static const char *fname; | |
46 | ||
47 | ||
48 | /* We better should not use `strerror' since it can call far too many | |
49 | other functions which might fail. Do it here ourselves. */ | |
50 | static void | |
51 | write_strsignal (int fd, int signal) | |
52 | { | |
53 | if (signal < 0 || signal >= _NSIG || _sys_siglist[signal] == NULL) | |
54 | { | |
55 | char buf[30]; | |
56 | char *ptr = _itoa_word (signal, &buf[sizeof (buf)], 10, 0); | |
57 | WRITE_STRING ("signal "); | |
58 | write (fd, buf, &buf[sizeof (buf)] - ptr); | |
59 | } | |
60 | else | |
61 | WRITE_STRING (_sys_siglist[signal]); | |
62 | } | |
63 | ||
64 | ||
107f8131 | 65 | /* This function is called when a segmentation fault is caught. The system |
682e4437 | 66 | is in an unstable state now. This means especially that malloc() might |
107f8131 UD |
67 | not work anymore. */ |
68 | static void | |
69 | catch_segfault (int signal, SIGCONTEXT ctx) | |
70 | { | |
c701ab9f | 71 | int fd, cnt, i; |
107f8131 | 72 | void **arr; |
ed1ac6a2 | 73 | struct sigaction sa; |
c701ab9f | 74 | uintptr_t pc; |
107f8131 UD |
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; | |
f2a37858 | 79 | if (fname != NULL) |
107f8131 | 80 | { |
997a4165 | 81 | fd = open (fname, O_TRUNC | O_WRONLY | O_CREAT, 0666); |
107f8131 UD |
82 | if (fd == -1) |
83 | fd = 2; | |
84 | } | |
85 | ||
ed1ac6a2 | 86 | WRITE_STRING ("*** "); |
f2a37858 | 87 | write_strsignal (fd, signal); |
ed1ac6a2 UD |
88 | WRITE_STRING ("\n"); |
89 | ||
90 | #ifdef REGISTER_DUMP | |
91 | REGISTER_DUMP; | |
92 | #endif | |
93 | ||
94 | WRITE_STRING ("\nBacktrace:\n"); | |
107f8131 | 95 | |
c701ab9f UD |
96 | /* Get the backtrace. */ |
97 | arr = alloca (256 * sizeof (void *)); | |
98 | cnt = backtrace (arr, 256); | |
107f8131 | 99 | |
c701ab9f UD |
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 = (uintptr_t) 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; | |
107f8131 | 108 | |
c701ab9f UD |
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; | |
6075607b | 113 | |
107f8131 | 114 | /* Now generate nicely formatted output. */ |
c701ab9f | 115 | __backtrace_symbols_fd (arr + i, cnt - i, fd); |
107f8131 | 116 | |
45cca066 UD |
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 | ||
ed1ac6a2 UD |
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); | |
107f8131 UD |
140 | } |
141 | ||
142 | ||
143 | static void | |
144 | __attribute__ ((constructor)) | |
145 | install_handler (void) | |
146 | { | |
147 | struct sigaction sa; | |
ed1ac6a2 | 148 | const char *sigs = getenv ("SEGFAULT_SIGNALS"); |
f2a37858 | 149 | const char *name; |
107f8131 UD |
150 | |
151 | sa.sa_handler = (void *) catch_segfault; | |
152 | sigemptyset (&sa.sa_mask); | |
153 | sa.sa_flags = SA_RESTART; | |
154 | ||
b39c6f8b UD |
155 | /* Maybe we are expected to use an alternative stack. */ |
156 | if (getenv ("SEGFAULT_USE_ALTSTACK") != 0) | |
157 | { | |
158 | void *stack_mem = malloc (2 * SIGSTKSZ); | |
75531318 | 159 | stack_t ss; |
b39c6f8b UD |
160 | |
161 | if (stack_mem != NULL) | |
162 | { | |
163 | ss.ss_sp = stack_mem; | |
164 | ss.ss_flags = 0; | |
165 | ss.ss_size = 2 * SIGSTKSZ; | |
166 | ||
167 | if (sigaltstack (&ss, NULL) == 0) | |
168 | sa.sa_flags |= SA_ONSTACK; | |
169 | } | |
170 | } | |
48f6496e | 171 | |
ed1ac6a2 UD |
172 | if (sigs == NULL) |
173 | sigaction (SIGSEGV, &sa, NULL); | |
174 | else if (sigs[0] == '\0') | |
175 | /* Do not do anything. */ | |
176 | return; | |
177 | else | |
178 | { | |
179 | const char *where; | |
5f75d1e2 | 180 | int all = __strcasecmp (sigs, "all") == 0; |
ed1ac6a2 UD |
181 | |
182 | #define INSTALL_FOR_SIG(sig, name) \ | |
183 | where = __strcasestr (sigs, name); \ | |
184 | if (all || (where != NULL \ | |
185 | && (where == sigs || !isalnum (where[-1])) \ | |
186 | && !isalnum (where[sizeof (name) - 1]))) \ | |
187 | sigaction (sig, &sa, NULL); | |
188 | ||
189 | INSTALL_FOR_SIG (SIGSEGV, "segv"); | |
190 | INSTALL_FOR_SIG (SIGILL, "ill"); | |
997a4165 | 191 | #ifdef SIGBUS |
ed1ac6a2 | 192 | INSTALL_FOR_SIG (SIGBUS, "bus"); |
997a4165 UD |
193 | #endif |
194 | #ifdef SIGSTKFLT | |
ed1ac6a2 | 195 | INSTALL_FOR_SIG (SIGSTKFLT, "stkflt"); |
997a4165 | 196 | #endif |
ed1ac6a2 UD |
197 | INSTALL_FOR_SIG (SIGABRT, "abrt"); |
198 | INSTALL_FOR_SIG (SIGFPE, "fpe"); | |
199 | } | |
f2a37858 UD |
200 | |
201 | /* Preserve the output file name if there is any given. */ | |
202 | name = getenv ("SEGFAULT_OUTPUT_NAME"); | |
8c35c0da UD |
203 | if (name != NULL && name[0] != '\0') |
204 | { | |
205 | int ret = access (name, R_OK | W_OK); | |
206 | ||
207 | if (ret == 0 || (ret == -1 && errno == ENOENT)) | |
208 | fname = __strdup (name); | |
209 | } | |
107f8131 | 210 | } |