]>
git.ipfire.org Git - thirdparty/glibc.git/blob - debug/segfault.c
1 /* Catch segmentation faults and print backtrace.
2 Copyright (C) 1998-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
33 /* This file defines macros to access the content of the sigcontext element
34 passed up by the signal handler. */
35 #include <sigcontextinfo.h>
38 # define SIGCONTEXT siginfo_t *info, void *
41 /* Get code to possibly dump the content of all registers. */
42 #include <register-dump.h>
44 /* We'll use this a lot. */
45 #define WRITE_STRING(s) write (fd, s, strlen (s))
47 /* Name of the output file. */
48 static const char *fname
;
51 /* Print the signal number SIGNAL. Either strerror or strsignal might
52 call local internal functions and these in turn call far too many
53 other functions and might even allocate memory which might fail. */
55 write_strsignal (int fd
, int signal
)
58 char *ptr
= _itoa_word (signal
, &buf
[sizeof (buf
)], 10, 0);
59 WRITE_STRING ("signal ");
60 write (fd
, ptr
, &buf
[sizeof (buf
)] - ptr
);
64 /* This function is called when a segmentation fault is caught. The system
65 is in an unstable state now. This means especially that malloc() might
68 catch_segfault (int signal
, SIGCONTEXT ctx
)
75 /* This is the name of the file we are writing to. If none is given
76 or we cannot write to this file write to stderr. */
80 fd
= open (fname
, O_TRUNC
| O_WRONLY
| O_CREAT
, 0666);
85 WRITE_STRING ("*** ");
86 write_strsignal (fd
, signal
);
93 WRITE_STRING ("\nBacktrace:\n");
95 /* Get the backtrace. */
96 arr
= alloca (256 * sizeof (void *));
97 cnt
= backtrace (arr
, 256);
99 /* Now try to locate the PC from signal context in the backtrace.
100 Normally it will be found at arr[2], but it might appear later
101 if there were some signal handler wrappers. Allow a few bytes
102 difference to cope with as many arches as possible. */
103 pc
= sigcontext_get_pc (ctx
);
104 for (i
= 0; i
< cnt
; ++i
)
105 if ((uintptr_t) arr
[i
] >= pc
- 16 && (uintptr_t) arr
[i
] <= pc
+ 16)
108 /* If we haven't found it, better dump full backtrace even including
109 the signal handler frames instead of not dumping anything. */
113 /* Now generate nicely formatted output. */
114 __backtrace_symbols_fd (arr
+ i
, cnt
- i
, fd
);
116 #ifdef HAVE_PROC_SELF
117 /* Now the link map. */
118 int mapfd
= open ("/proc/self/maps", O_RDONLY
);
121 write (fd
, "\nMemory map:\n\n", 14);
126 while ((n
= TEMP_FAILURE_RETRY (read (mapfd
, buf
, sizeof (buf
)))) > 0)
127 TEMP_FAILURE_RETRY (write (fd
, buf
, n
));
133 /* Pass on the signal (so that a core file is produced). */
134 sa
.sa_handler
= SIG_DFL
;
135 sigemptyset (&sa
.sa_mask
);
137 sigaction (signal
, &sa
, NULL
);
143 __attribute__ ((constructor
))
144 install_handler (void)
147 const char *sigs
= getenv ("SEGFAULT_SIGNALS");
151 sa
.sa_sigaction
= catch_segfault
;
152 sa
.sa_flags
= SA_SIGINFO
;
154 sa
.sa_handler
= (void*) catch_segfault
;
157 sigemptyset (&sa
.sa_mask
);
158 sa
.sa_flags
|= SA_RESTART
;
160 /* Maybe we are expected to use an alternative stack. */
161 if (getenv ("SEGFAULT_USE_ALTSTACK") != 0)
163 void *stack_mem
= malloc (2 * SIGSTKSZ
);
166 if (stack_mem
!= NULL
)
168 ss
.ss_sp
= stack_mem
;
170 ss
.ss_size
= 2 * SIGSTKSZ
;
172 if (sigaltstack (&ss
, NULL
) == 0)
173 sa
.sa_flags
|= SA_ONSTACK
;
178 sigaction (SIGSEGV
, &sa
, NULL
);
179 else if (sigs
[0] == '\0')
180 /* Do not do anything. */
185 int all
= __strcasecmp (sigs
, "all") == 0;
187 #define INSTALL_FOR_SIG(sig, name) \
188 where = __strcasestr (sigs, name); \
189 if (all || (where != NULL \
190 && (where == sigs || !isalnum (where[-1])) \
191 && !isalnum (where[sizeof (name) - 1]))) \
192 sigaction (sig, &sa, NULL);
194 INSTALL_FOR_SIG (SIGSEGV
, "segv");
195 INSTALL_FOR_SIG (SIGILL
, "ill");
197 INSTALL_FOR_SIG (SIGBUS
, "bus");
200 INSTALL_FOR_SIG (SIGSTKFLT
, "stkflt");
202 INSTALL_FOR_SIG (SIGABRT
, "abrt");
203 INSTALL_FOR_SIG (SIGFPE
, "fpe");
206 /* Preserve the output file name if there is any given. */
207 name
= getenv ("SEGFAULT_OUTPUT_NAME");
208 if (name
!= NULL
&& name
[0] != '\0')
210 int ret
= access (name
, R_OK
| W_OK
);
212 if (ret
== 0 || (ret
== -1 && errno
== ENOENT
))
213 fname
= __strdup (name
);