aboutsummaryrefslogtreecommitdiffstats
path: root/libsigsegv/src/handler-unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsigsegv/src/handler-unix.c')
-rw-r--r--libsigsegv/src/handler-unix.c542
1 files changed, 0 insertions, 542 deletions
diff --git a/libsigsegv/src/handler-unix.c b/libsigsegv/src/handler-unix.c
deleted file mode 100644
index 3718eb98..00000000
--- a/libsigsegv/src/handler-unix.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/* Fault handler information. Unix version.
- Copyright (C) 1993-1999, 2002-2003, 2006, 2008 Bruno Haible <bruno@clisp.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-
-#include "sigsegv.h"
-
-/* On the average Unix platform, we define
-
- HAVE_SIGSEGV_RECOVERY
- if there is a fault-*.h include file which defines
- SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS.
-
- HAVE_STACK_OVERFLOW_RECOVERY
- if HAVE_SIGALTSTACK is set and
- at least two of the following are true:
- A) There is a fault-*.h include file which defines
- SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS.
- B) There is a fault-*.h include file which defines
- SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_STACKPOINTER.
- C) There is a stackvma-*.c, other than stackvma-none.c, which
- defines sigsegv_get_vma.
-
- Why? Obviously, to catch stack overflow, we need an alternate signal
- stack; this requires kernel support. But we also need to distinguish
- (with a reasonable confidence) a stack overflow from a regular SIGSEGV.
- If we have A) and B), we use the
- Heuristic AB: If the fault address is near the stack pointer, it's a
- stack overflow.
- If we have A) and C), we use the
- Heuristic AC: If the fault address is near and beyond the bottom of
- the stack's virtual memory area, it's a stack overflow.
- If we have B) and C), we use the
- Heuristic BC: If the stack pointer is near the bottom of the stack's
- virtual memory area, it's a stack overflow.
- This heuristic comes in two flavours: On OSes which let the stack's
- VMA grow continuously, we determine the bottom by use of getrlimit().
- On OSes which preallocate the stack's VMA with its maximum size
- (like BeOS), we use the stack's VMA directly.
- */
-
-#include <stddef.h> /* needed for NULL on SunOS4 */
-#include <stdlib.h>
-#include <signal.h>
-#if HAVE_SYS_SIGNAL_H
-# include <sys/signal.h>
-#endif
-#include <errno.h>
-
-/* For MacOSX. */
-#ifndef SS_DISABLE
-#define SS_DISABLE SA_DISABLE
-#endif
-
-#include "fault.h"
-#include CFG_SIGNALS
-
-#if HAVE_STACK_OVERFLOW_RECOVERY
-
-#include <stdio.h> /* perror */
-
-#if HAVE_GETRLIMIT
-# include <sys/types.h>
-# include <sys/time.h>
-# include <sys/resource.h> /* declares struct rlimit */
-#endif
-
-/* Platform dependent:
- Determine the virtual memory area of a given address. */
-#include "stackvma.h"
-
-/* Platform dependent:
- Leaving a signal handler executing on the alternate stack. */
-#include "leave.h"
-
-#if HAVE_STACKVMA
-
-/* Address of the last byte belonging to the stack vma. */
-static unsigned long stack_top = 0;
-
-/* Needs to be called once only. */
-static void
-remember_stack_top (void *some_variable_on_stack)
-{
- struct vma_struct vma;
-
- if (sigsegv_get_vma ((unsigned long) some_variable_on_stack, &vma) >= 0)
- stack_top = vma.end - 1;
-}
-
-#endif /* HAVE_STACKVMA */
-
-static stackoverflow_handler_t stk_user_handler = (stackoverflow_handler_t)NULL;
-static unsigned long stk_extra_stack;
-static unsigned long stk_extra_stack_size;
-
-#endif /* HAVE_STACK_OVERFLOW_RECOVERY */
-
-#if HAVE_SIGSEGV_RECOVERY
-
-/* User's SIGSEGV handler. */
-static sigsegv_handler_t user_handler = (sigsegv_handler_t)NULL;
-
-#endif /* HAVE_SIGSEGV_RECOVERY */
-
-
-/* Our SIGSEGV handler, with OS dependent argument list. */
-
-#if HAVE_SIGSEGV_RECOVERY
-
-static void
-sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST)
-{
- void *address = (void *) (SIGSEGV_FAULT_ADDRESS);
-
-#if HAVE_STACK_OVERFLOW_RECOVERY
-#if !(HAVE_STACKVMA || defined SIGSEGV_FAULT_STACKPOINTER)
-#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!"
-#endif
-
- /* Call user's handler. */
- if (user_handler && (*user_handler) (address, 0))
- {
- /* Handler successful. */
- }
- else
- {
- /* Handler declined responsibility. */
-
- /* Did the user install a stack overflow handler? */
- if (stk_user_handler)
- {
- /* See whether it was a stack overflow. If so, longjump away. */
-#ifdef SIGSEGV_FAULT_STACKPOINTER
- unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER);
-#ifdef __ia64
- unsigned long old_bsp = (unsigned long) (SIGSEGV_FAULT_BSP_POINTER);
-#endif
-#endif
-
-#if HAVE_STACKVMA
- /* Were we able to determine the stack top? */
- if (stack_top)
- {
- /* Determine stack bounds. */
- int saved_errno;
- struct vma_struct vma;
- int ret;
-
- saved_errno = errno;
- ret = sigsegv_get_vma (stack_top, &vma);
- errno = saved_errno;
- if (ret >= 0)
- {
- /* Heuristic AC: If the fault_address is nearer to the stack
- segment's [start,end] than to the previous segment, we
- consider it a stack overflow.
- In the case of IA-64, we know that the previous segment
- is the up-growing bsp segment, and either of the two
- stacks can overflow. */
- unsigned long addr = (unsigned long) address;
-
-#ifdef __ia64
- if (addr >= vma.prev_end && addr <= vma.end - 1)
-#else
-#if STACK_DIRECTION < 0
- if (addr >= vma.start
- ? (addr <= vma.end - 1)
- : vma.is_near_this (addr, &vma))
-#else
- if (addr <= vma.end - 1
- ? (addr >= vma.start)
- : vma.is_near_this (addr, &vma))
-#endif
-#endif
-#else
- /* Heuristic AB: If the fault address is near the stack pointer,
- it's a stack overflow. */
- unsigned long addr = (unsigned long) address;
-
- if ((addr <= old_sp + 4096 && old_sp <= addr + 4096)
-#ifdef __ia64
- || (addr <= old_bsp + 4096 && old_bsp <= addr + 4096)
-#endif
- )
- {
- {
-#endif
- {
-#ifdef SIGSEGV_FAULT_STACKPOINTER
- int emergency =
- (old_sp >= stk_extra_stack
- && old_sp <= stk_extra_stack + stk_extra_stack_size);
- stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT);
-#else
- int emergency = 0;
- stackoverflow_context_t context = (void *) 0;
-#endif
- /* Call user's handler. */
- (*stk_user_handler) (emergency, context);
- }
- }
- }
- }
-#endif /* HAVE_STACK_OVERFLOW_RECOVERY */
-
- if (user_handler && (*user_handler) (address, 1))
- {
- /* Handler successful. */
- }
- else
- {
- /* Handler declined responsibility for real. */
-
- /* Remove ourselves and dump core. */
- SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
- }
-
-#if HAVE_STACK_OVERFLOW_RECOVERY
- }
-#endif /* HAVE_STACK_OVERFLOW_RECOVERY */
-}
-
-#elif HAVE_STACK_OVERFLOW_RECOVERY
-
-static void
-#ifdef SIGSEGV_FAULT_STACKPOINTER
-sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST)
-#else
-sigsegv_handler (int sig)
-#endif
-{
-#if !((HAVE_GETRLIMIT && defined RLIMIT_STACK) || defined SIGSEGV_FAULT_STACKPOINTER)
-#error "Insufficient heuristics for detecting a stack overflow. Either define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!"
-#endif
-
- /* Did the user install a handler? */
- if (stk_user_handler)
- {
- /* See whether it was a stack overflow. If so, longjump away. */
-#ifdef SIGSEGV_FAULT_STACKPOINTER
- unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER);
-#endif
-
- /* Were we able to determine the stack top? */
- if (stack_top)
- {
- /* Determine stack bounds. */
- int saved_errno;
- struct vma_struct vma;
-
- saved_errno = errno;
- if (sigsegv_get_vma (stack_top, &vma) >= 0)
- {
-#if HAVE_GETRLIMIT && defined RLIMIT_STACK
- /* Heuristic BC: If the stack size has reached its maximal size,
- and old_sp is near the low end, we consider it a stack
- overflow. */
- struct rlimit rl;
-
- if (getrlimit (RLIMIT_STACK, &rl) >= 0)
- {
- unsigned long current_stack_size = vma.end - vma.start;
- unsigned long max_stack_size = rl.rlim_cur;
- if (current_stack_size <= max_stack_size + 4096
- && max_stack_size <= current_stack_size + 4096
-#else
- {
- if (1
-#endif
-#ifdef SIGSEGV_FAULT_STACKPOINTER
- /* Heuristic BC: If we know old_sp, and it is neither
- near the low end, nor in the alternate stack, then
- it's probably not a stack overflow. */
- && ((old_sp >= stk_extra_stack
- && old_sp <= stk_extra_stack + stk_extra_stack_size)
-#if STACK_DIRECTION < 0
- || (old_sp <= vma.start + 4096
- && vma.start <= old_sp + 4096))
-#else
- || (old_sp <= vma.end + 4096
- && vma.end <= old_sp + 4096))
-#endif
-#endif
- )
- {
-#ifdef SIGSEGV_FAULT_STACKPOINTER
- int emergency =
- (old_sp >= stk_extra_stack
- && old_sp <= stk_extra_stack + stk_extra_stack_size);
- stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT);
-#else
- int emergency = 0;
- stackoverflow_context_t context = (void *) 0;
-#endif
- /* Call user's handler. */
- (*stk_user_handler)(emergency,context);
- }
- }
- }
- errno = saved_errno;
- }
- }
-
- /* Remove ourselves and dump core. */
- SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
-}
-
-#endif
-
-
-static void
-install_for (int sig)
-{
- struct sigaction action;
-
-#ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
- action.sa_sigaction = &sigsegv_handler;
-#else
- action.sa_handler = (void (*) (int)) &sigsegv_handler;
-#endif
- /* Block most signals while SIGSEGV is being handled. */
- /* Signals SIGKILL, SIGSTOP cannot be blocked. */
- /* Signals SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU are not blocked because
- dealing with these signals seems dangerous. */
- /* Signals SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTRAP, SIGIOT, SIGEMT, SIGBUS,
- SIGSYS, SIGSTKFLT are not blocked because these are synchronous signals,
- which may require immediate intervention, otherwise the process may
- starve. */
- sigemptyset (&action.sa_mask);
-#ifdef SIGHUP
- sigaddset (&action.sa_mask,SIGHUP);
-#endif
-#ifdef SIGINT
- sigaddset (&action.sa_mask,SIGINT);
-#endif
-#ifdef SIGQUIT
- sigaddset (&action.sa_mask,SIGQUIT);
-#endif
-#ifdef SIGPIPE
- sigaddset (&action.sa_mask,SIGPIPE);
-#endif
-#ifdef SIGALRM
- sigaddset (&action.sa_mask,SIGALRM);
-#endif
-#ifdef SIGTERM
- sigaddset (&action.sa_mask,SIGTERM);
-#endif
-#ifdef SIGUSR1
- sigaddset (&action.sa_mask,SIGUSR1);
-#endif
-#ifdef SIGUSR2
- sigaddset (&action.sa_mask,SIGUSR2);
-#endif
-#ifdef SIGCHLD
- sigaddset (&action.sa_mask,SIGCHLD);
-#endif
-#ifdef SIGCLD
- sigaddset (&action.sa_mask,SIGCLD);
-#endif
-#ifdef SIGURG
- sigaddset (&action.sa_mask,SIGURG);
-#endif
-#ifdef SIGIO
- sigaddset (&action.sa_mask,SIGIO);
-#endif
-#ifdef SIGPOLL
- sigaddset (&action.sa_mask,SIGPOLL);
-#endif
-#ifdef SIGXCPU
- sigaddset (&action.sa_mask,SIGXCPU);
-#endif
-#ifdef SIGXFSZ
- sigaddset (&action.sa_mask,SIGXFSZ);
-#endif
-#ifdef SIGVTALRM
- sigaddset (&action.sa_mask,SIGVTALRM);
-#endif
-#ifdef SIGPROF
- sigaddset (&action.sa_mask,SIGPROF);
-#endif
-#ifdef SIGPWR
- sigaddset (&action.sa_mask,SIGPWR);
-#endif
-#ifdef SIGLOST
- sigaddset (&action.sa_mask,SIGLOST);
-#endif
-#ifdef SIGWINCH
- sigaddset (&action.sa_mask,SIGWINCH);
-#endif
- /* Note that sigaction() implicitly adds sig itself to action.sa_mask. */
- /* Ask the OS to provide a structure siginfo_t to the handler. */
-#ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
- action.sa_flags = SA_SIGINFO;
-#else
- action.sa_flags = 0;
-#endif
-#if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGALTSTACK /* not BeOS */
- /* Work around Linux 2.2.5 bug: If SA_ONSTACK is specified but sigaltstack()
- has not been called, the kernel will busy loop, eating CPU time. So
- avoid setting SA_ONSTACK until the user has requested stack overflow
- handling. */
- if (stk_user_handler)
- action.sa_flags |= SA_ONSTACK;
-#endif
- sigaction (sig, &action, (struct sigaction *) NULL);
-}
-
-int
-sigsegv_install_handler (sigsegv_handler_t handler)
-{
-#if HAVE_SIGSEGV_RECOVERY
- user_handler = handler;
-
- SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
-
- return 0;
-#else
- return -1;
-#endif
-}
-
-void
-sigsegv_deinstall_handler (void)
-{
-#if HAVE_SIGSEGV_RECOVERY
- user_handler = (sigsegv_handler_t)NULL;
-
-#if HAVE_STACK_OVERFLOW_RECOVERY
- if (!stk_user_handler)
-#endif
- {
- SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
- }
-#endif
-}
-
-int
-sigsegv_leave_handler (void (*continuation) (void*, void*, void*),
- void* cont_arg1, void* cont_arg2, void* cont_arg3)
-{
-#if HAVE_STACK_OVERFLOW_RECOVERY
- /*
- * Reset the system's knowledge that we are executing on the alternate
- * stack. If we didn't do that, siglongjmp would be needed instead of
- * longjmp to leave the signal handler.
- */
- sigsegv_reset_onstack_flag ();
-#endif
- (*continuation) (cont_arg1, cont_arg2, cont_arg3);
- return 1;
-}
-
-int
-stackoverflow_install_handler (stackoverflow_handler_t handler,
- void *extra_stack, unsigned long extra_stack_size)
-{
-#if HAVE_STACK_OVERFLOW_RECOVERY
-#if HAVE_STACKVMA
- if (!stack_top)
- {
- int dummy;
- remember_stack_top (&dummy);
- if (!stack_top)
- return -1;
- }
-#endif
-
- stk_user_handler = handler;
- stk_extra_stack = (unsigned long) extra_stack;
- stk_extra_stack_size = extra_stack_size;
-#ifdef __BEOS__
- set_signal_stack (extra_stack, extra_stack_size);
-#else /* HAVE_SIGALTSTACK */
- {
- stack_t ss;
-#if SIGALTSTACK_SS_REVERSED
- ss.ss_sp = (char *) extra_stack + extra_stack_size - sizeof (void *);
- ss.ss_size = extra_stack_size - sizeof (void *);
-#else
- ss.ss_sp = extra_stack;
- ss.ss_size = extra_stack_size;
-#endif
- ss.ss_flags = 0; /* no SS_DISABLE */
- if (sigaltstack (&ss, (stack_t*)0) < 0)
- return -1;
- }
-#endif
-
- /* Install the signal handlers with SA_ONSTACK. */
- SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
- return 0;
-#else
- return -1;
-#endif
-}
-
-void
-stackoverflow_deinstall_handler (void)
-{
-#if HAVE_STACK_OVERFLOW_RECOVERY
- stk_user_handler = (stackoverflow_handler_t) NULL;
-
-#if HAVE_SIGSEGV_RECOVERY
- if (user_handler)
- {
- /* Reinstall the signal handlers without SA_ONSTACK, to avoid Linux
- bug. */
- SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);)
- }
- else
-#endif
- {
- SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);)
- }
-
-#ifdef __BEOS__
- /* We cannot undo the effect of set_signal_stack. */
- fprintf (stderr, "libsigsegv (stackoverflow_deinstall_handler): not supported on this platform\n");
-#else /* HAVE_SIGALTSTACK */
- {
- stack_t ss;
- ss.ss_flags = SS_DISABLE;
- if (sigaltstack (&ss, (stack_t *) 0) < 0)
- perror ("libsigsegv (stackoverflow_deinstall_handler)");
- }
-#endif
-
-#endif
-}