Improve NetBSD support: Allow VMA determination with fewer system calls.
[libsigsegv/ericb.git] / src / handler-unix.c
blobf62a56c79a0e53ee7a67923c7477d410c29a0b8d
1 /* Fault handler information. Unix version.
2 Copyright (C) 1993-1999, 2002-2003, 2006, 2008-2009 Bruno Haible <bruno@clisp.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Persuade glibc <sys/ucontext.h> to declare macros designating register
19 indices: REG_RSP on x86_64, REG_ESP on i386. */
20 #define _GNU_SOURCE 1
22 #include "sigsegv.h"
24 /* On the average Unix platform, we define
26 HAVE_SIGSEGV_RECOVERY
27 if there is a fault-*.h include file which defines
28 SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS.
30 HAVE_STACK_OVERFLOW_RECOVERY
31 if HAVE_SIGALTSTACK is set and
32 at least two of the following are true:
33 A) There is a fault-*.h include file which defines
34 SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS.
35 B) There is a fault-*.h include file which defines
36 SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_STACKPOINTER.
37 C) There is a stackvma-*.c, other than stackvma-none.c, which
38 defines sigsegv_get_vma.
40 Why? Obviously, to catch stack overflow, we need an alternate signal
41 stack; this requires kernel support. But we also need to distinguish
42 (with a reasonable confidence) a stack overflow from a regular SIGSEGV.
43 If we have A) and B), we use the
44 Heuristic AB: If the fault address is near the stack pointer, it's a
45 stack overflow.
46 If we have A) and C), we use the
47 Heuristic AC: If the fault address is near and beyond the bottom of
48 the stack's virtual memory area, it's a stack overflow.
49 If we have B) and C), we use the
50 Heuristic BC: If the stack pointer is near the bottom of the stack's
51 virtual memory area, it's a stack overflow.
52 This heuristic comes in two flavours: On OSes which let the stack's
53 VMA grow continuously, we determine the bottom by use of getrlimit().
54 On OSes which preallocate the stack's VMA with its maximum size
55 (like BeOS), we use the stack's VMA directly.
58 #include <stddef.h> /* needed for NULL on SunOS4 */
59 #include <stdlib.h>
60 #include <signal.h>
61 #if HAVE_SYS_SIGNAL_H
62 # include <sys/signal.h>
63 #endif
64 #include <errno.h>
66 /* For MacOSX. */
67 #ifndef SS_DISABLE
68 #define SS_DISABLE SA_DISABLE
69 #endif
71 #include "fault.h"
72 #include CFG_SIGNALS
74 #if HAVE_STACK_OVERFLOW_RECOVERY
76 #include <stdio.h> /* perror */
78 #if HAVE_GETRLIMIT
79 # include <sys/types.h>
80 # include <sys/time.h>
81 # include <sys/resource.h> /* declares struct rlimit */
82 #endif
84 /* Platform dependent:
85 Determine the virtual memory area of a given address. */
86 #include "stackvma.h"
88 /* Platform dependent:
89 Leaving a signal handler executing on the alternate stack. */
90 #include "leave.h"
92 #if HAVE_STACKVMA
94 /* Address of the last byte belonging to the stack vma. */
95 static unsigned long stack_top = 0;
97 /* Needs to be called once only. */
98 static void
99 remember_stack_top (void *some_variable_on_stack)
101 struct vma_struct vma;
103 if (sigsegv_get_vma ((unsigned long) some_variable_on_stack, &vma) >= 0)
104 stack_top = vma.end - 1;
107 #endif /* HAVE_STACKVMA */
109 static stackoverflow_handler_t stk_user_handler = (stackoverflow_handler_t)NULL;
110 static unsigned long stk_extra_stack;
111 static unsigned long stk_extra_stack_size;
113 #endif /* HAVE_STACK_OVERFLOW_RECOVERY */
115 #if HAVE_SIGSEGV_RECOVERY
117 /* User's SIGSEGV handler. */
118 static sigsegv_handler_t user_handler = (sigsegv_handler_t)NULL;
120 #endif /* HAVE_SIGSEGV_RECOVERY */
123 /* Our SIGSEGV handler, with OS dependent argument list. */
125 #if HAVE_SIGSEGV_RECOVERY
127 static void
128 sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST)
130 void *address = (void *) (SIGSEGV_FAULT_ADDRESS);
132 #if HAVE_STACK_OVERFLOW_RECOVERY
133 #if !(HAVE_STACKVMA || defined SIGSEGV_FAULT_STACKPOINTER)
134 #error "Insufficient heuristics for detecting a stack overflow. Either define CFG_STACKVMA and HAVE_STACKVMA correctly, or define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!"
135 #endif
137 /* Call user's handler. */
138 if (user_handler && (*user_handler) (address, 0))
140 /* Handler successful. */
142 else
144 /* Handler declined responsibility. */
146 /* Did the user install a stack overflow handler? */
147 if (stk_user_handler)
149 /* See whether it was a stack overflow. If so, longjump away. */
150 #ifdef SIGSEGV_FAULT_STACKPOINTER
151 unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER);
152 #ifdef __ia64
153 unsigned long old_bsp = (unsigned long) (SIGSEGV_FAULT_BSP_POINTER);
154 #endif
155 #endif
157 #if HAVE_STACKVMA
158 /* Were we able to determine the stack top? */
159 if (stack_top)
161 /* Determine stack bounds. */
162 int saved_errno;
163 struct vma_struct vma;
164 int ret;
166 saved_errno = errno;
167 ret = sigsegv_get_vma (stack_top, &vma);
168 errno = saved_errno;
169 if (ret >= 0)
171 /* Heuristic AC: If the fault_address is nearer to the stack
172 segment's [start,end] than to the previous segment, we
173 consider it a stack overflow.
174 In the case of IA-64, we know that the previous segment
175 is the up-growing bsp segment, and either of the two
176 stacks can overflow. */
177 unsigned long addr = (unsigned long) address;
179 #ifdef __ia64
180 if (addr >= vma.prev_end && addr <= vma.end - 1)
181 #else
182 #if STACK_DIRECTION < 0
183 if (addr >= vma.start
184 ? (addr <= vma.end - 1)
185 : vma.is_near_this (addr, &vma))
186 #else
187 if (addr <= vma.end - 1
188 ? (addr >= vma.start)
189 : vma.is_near_this (addr, &vma))
190 #endif
191 #endif
192 #else
193 /* Heuristic AB: If the fault address is near the stack pointer,
194 it's a stack overflow. */
195 unsigned long addr = (unsigned long) address;
197 if ((addr <= old_sp + 4096 && old_sp <= addr + 4096)
198 #ifdef __ia64
199 || (addr <= old_bsp + 4096 && old_bsp <= addr + 4096)
200 #endif
204 #endif
206 #ifdef SIGSEGV_FAULT_STACKPOINTER
207 int emergency =
208 (old_sp >= stk_extra_stack
209 && old_sp <= stk_extra_stack + stk_extra_stack_size);
210 stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT);
211 #else
212 int emergency = 0;
213 stackoverflow_context_t context = (void *) 0;
214 #endif
215 /* Call user's handler. */
216 (*stk_user_handler) (emergency, context);
221 #endif /* HAVE_STACK_OVERFLOW_RECOVERY */
223 if (user_handler && (*user_handler) (address, 1))
225 /* Handler successful. */
227 else
229 /* Handler declined responsibility for real. */
231 /* Remove ourselves and dump core. */
232 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
235 #if HAVE_STACK_OVERFLOW_RECOVERY
237 #endif /* HAVE_STACK_OVERFLOW_RECOVERY */
240 #elif HAVE_STACK_OVERFLOW_RECOVERY
242 static void
243 #ifdef SIGSEGV_FAULT_STACKPOINTER
244 sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST)
245 #else
246 sigsegv_handler (int sig)
247 #endif
249 #if !((HAVE_GETRLIMIT && defined RLIMIT_STACK) || defined SIGSEGV_FAULT_STACKPOINTER)
250 #error "Insufficient heuristics for detecting a stack overflow. Either define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!"
251 #endif
253 /* Did the user install a handler? */
254 if (stk_user_handler)
256 /* See whether it was a stack overflow. If so, longjump away. */
257 #ifdef SIGSEGV_FAULT_STACKPOINTER
258 unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER);
259 #endif
261 /* Were we able to determine the stack top? */
262 if (stack_top)
264 /* Determine stack bounds. */
265 int saved_errno;
266 struct vma_struct vma;
268 saved_errno = errno;
269 if (sigsegv_get_vma (stack_top, &vma) >= 0)
271 #if HAVE_GETRLIMIT && defined RLIMIT_STACK
272 /* Heuristic BC: If the stack size has reached its maximal size,
273 and old_sp is near the low end, we consider it a stack
274 overflow. */
275 struct rlimit rl;
277 if (getrlimit (RLIMIT_STACK, &rl) >= 0)
279 unsigned long current_stack_size = vma.end - vma.start;
280 unsigned long max_stack_size = rl.rlim_cur;
281 if (current_stack_size <= max_stack_size + 4096
282 && max_stack_size <= current_stack_size + 4096
283 #else
285 if (1
286 #endif
287 #ifdef SIGSEGV_FAULT_STACKPOINTER
288 /* Heuristic BC: If we know old_sp, and it is neither
289 near the low end, nor in the alternate stack, then
290 it's probably not a stack overflow. */
291 && ((old_sp >= stk_extra_stack
292 && old_sp <= stk_extra_stack + stk_extra_stack_size)
293 #if STACK_DIRECTION < 0
294 || (old_sp <= vma.start + 4096
295 && vma.start <= old_sp + 4096))
296 #else
297 || (old_sp <= vma.end + 4096
298 && vma.end <= old_sp + 4096))
299 #endif
300 #endif
303 #ifdef SIGSEGV_FAULT_STACKPOINTER
304 int emergency =
305 (old_sp >= stk_extra_stack
306 && old_sp <= stk_extra_stack + stk_extra_stack_size);
307 stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT);
308 #else
309 int emergency = 0;
310 stackoverflow_context_t context = (void *) 0;
311 #endif
312 /* Call user's handler. */
313 (*stk_user_handler)(emergency,context);
317 errno = saved_errno;
321 /* Remove ourselves and dump core. */
322 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
325 #endif
328 static void
329 install_for (int sig)
331 struct sigaction action;
333 #ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
334 action.sa_sigaction = &sigsegv_handler;
335 #else
336 action.sa_handler = (void (*) (int)) &sigsegv_handler;
337 #endif
338 /* Block most signals while SIGSEGV is being handled. */
339 /* Signals SIGKILL, SIGSTOP cannot be blocked. */
340 /* Signals SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU are not blocked because
341 dealing with these signals seems dangerous. */
342 /* Signals SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTRAP, SIGIOT, SIGEMT, SIGBUS,
343 SIGSYS, SIGSTKFLT are not blocked because these are synchronous signals,
344 which may require immediate intervention, otherwise the process may
345 starve. */
346 sigemptyset (&action.sa_mask);
347 #ifdef SIGHUP
348 sigaddset (&action.sa_mask,SIGHUP);
349 #endif
350 #ifdef SIGINT
351 sigaddset (&action.sa_mask,SIGINT);
352 #endif
353 #ifdef SIGQUIT
354 sigaddset (&action.sa_mask,SIGQUIT);
355 #endif
356 #ifdef SIGPIPE
357 sigaddset (&action.sa_mask,SIGPIPE);
358 #endif
359 #ifdef SIGALRM
360 sigaddset (&action.sa_mask,SIGALRM);
361 #endif
362 #ifdef SIGTERM
363 sigaddset (&action.sa_mask,SIGTERM);
364 #endif
365 #ifdef SIGUSR1
366 sigaddset (&action.sa_mask,SIGUSR1);
367 #endif
368 #ifdef SIGUSR2
369 sigaddset (&action.sa_mask,SIGUSR2);
370 #endif
371 #ifdef SIGCHLD
372 sigaddset (&action.sa_mask,SIGCHLD);
373 #endif
374 #ifdef SIGCLD
375 sigaddset (&action.sa_mask,SIGCLD);
376 #endif
377 #ifdef SIGURG
378 sigaddset (&action.sa_mask,SIGURG);
379 #endif
380 #ifdef SIGIO
381 sigaddset (&action.sa_mask,SIGIO);
382 #endif
383 #ifdef SIGPOLL
384 sigaddset (&action.sa_mask,SIGPOLL);
385 #endif
386 #ifdef SIGXCPU
387 sigaddset (&action.sa_mask,SIGXCPU);
388 #endif
389 #ifdef SIGXFSZ
390 sigaddset (&action.sa_mask,SIGXFSZ);
391 #endif
392 #ifdef SIGVTALRM
393 sigaddset (&action.sa_mask,SIGVTALRM);
394 #endif
395 #ifdef SIGPROF
396 sigaddset (&action.sa_mask,SIGPROF);
397 #endif
398 #ifdef SIGPWR
399 sigaddset (&action.sa_mask,SIGPWR);
400 #endif
401 #ifdef SIGLOST
402 sigaddset (&action.sa_mask,SIGLOST);
403 #endif
404 #ifdef SIGWINCH
405 sigaddset (&action.sa_mask,SIGWINCH);
406 #endif
407 /* Note that sigaction() implicitly adds sig itself to action.sa_mask. */
408 /* Ask the OS to provide a structure siginfo_t to the handler. */
409 #ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
410 action.sa_flags = SA_SIGINFO;
411 #else
412 action.sa_flags = 0;
413 #endif
414 #if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGALTSTACK /* not BeOS */
415 /* Work around Linux 2.2.5 bug: If SA_ONSTACK is specified but sigaltstack()
416 has not been called, the kernel will busy loop, eating CPU time. So
417 avoid setting SA_ONSTACK until the user has requested stack overflow
418 handling. */
419 if (stk_user_handler)
420 action.sa_flags |= SA_ONSTACK;
421 #endif
422 sigaction (sig, &action, (struct sigaction *) NULL);
426 sigsegv_install_handler (sigsegv_handler_t handler)
428 #if HAVE_SIGSEGV_RECOVERY
429 user_handler = handler;
431 SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
433 return 0;
434 #else
435 return -1;
436 #endif
439 void
440 sigsegv_deinstall_handler (void)
442 #if HAVE_SIGSEGV_RECOVERY
443 user_handler = (sigsegv_handler_t)NULL;
445 #if HAVE_STACK_OVERFLOW_RECOVERY
446 if (!stk_user_handler)
447 #endif
449 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
451 #endif
455 sigsegv_leave_handler (void (*continuation) (void*, void*, void*),
456 void* cont_arg1, void* cont_arg2, void* cont_arg3)
458 #if HAVE_STACK_OVERFLOW_RECOVERY
460 * Reset the system's knowledge that we are executing on the alternate
461 * stack. If we didn't do that, siglongjmp would be needed instead of
462 * longjmp to leave the signal handler.
464 sigsegv_reset_onstack_flag ();
465 #endif
466 (*continuation) (cont_arg1, cont_arg2, cont_arg3);
467 return 1;
470 #if !MIXING_UNIX_SIGSEGV_AND_WIN32_STACKOVERFLOW_HANDLING
473 stackoverflow_install_handler (stackoverflow_handler_t handler,
474 void *extra_stack, unsigned long extra_stack_size)
476 #if HAVE_STACK_OVERFLOW_RECOVERY
477 #if HAVE_STACKVMA
478 if (!stack_top)
480 int dummy;
481 remember_stack_top (&dummy);
482 if (!stack_top)
483 return -1;
485 #endif
487 stk_user_handler = handler;
488 stk_extra_stack = (unsigned long) extra_stack;
489 stk_extra_stack_size = extra_stack_size;
490 #ifdef __BEOS__
491 set_signal_stack (extra_stack, extra_stack_size);
492 #else /* HAVE_SIGALTSTACK */
494 stack_t ss;
495 #if SIGALTSTACK_SS_REVERSED
496 ss.ss_sp = (char *) extra_stack + extra_stack_size - sizeof (void *);
497 ss.ss_size = extra_stack_size - sizeof (void *);
498 #else
499 ss.ss_sp = extra_stack;
500 ss.ss_size = extra_stack_size;
501 #endif
502 ss.ss_flags = 0; /* no SS_DISABLE */
503 if (sigaltstack (&ss, (stack_t*)0) < 0)
504 return -1;
506 #endif
508 /* Install the signal handlers with SA_ONSTACK. */
509 SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
510 return 0;
511 #else
512 return -1;
513 #endif
516 void
517 stackoverflow_deinstall_handler (void)
519 #if HAVE_STACK_OVERFLOW_RECOVERY
520 stk_user_handler = (stackoverflow_handler_t) NULL;
522 #if HAVE_SIGSEGV_RECOVERY
523 if (user_handler)
525 /* Reinstall the signal handlers without SA_ONSTACK, to avoid Linux
526 bug. */
527 SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
529 else
530 #endif
532 SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
535 #ifdef __BEOS__
536 /* We cannot undo the effect of set_signal_stack. */
537 fprintf (stderr, "libsigsegv (stackoverflow_deinstall_handler): not supported on this platform\n");
538 #else /* HAVE_SIGALTSTACK */
540 stack_t ss;
541 ss.ss_flags = SS_DISABLE;
542 if (sigaltstack (&ss, (stack_t *) 0) < 0)
543 perror ("libsigsegv (stackoverflow_deinstall_handler)");
545 #endif
547 #endif
550 #endif /* !MIXING_UNIX_SIGSEGV_AND_WIN32_STACKOVERFLOW_HANDLING */