| 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 |  | 
|---|