Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-01 08:54:23

0001 /* Page fault handling library.
0002    Copyright (C) 1998-1999, 2002, 2004-2011, 2016-2018, 2021-2022  Bruno Haible <bruno@clisp.org>
0003 
0004    This program is free software: you can redistribute it and/or modify
0005    it under the terms of the GNU General Public License as published by
0006    the Free Software Foundation; either version 2 of the License, or
0007    (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012    GNU General Public License for more details.
0013 
0014    You should have received a copy of the GNU General Public License
0015    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
0016 
0017 #ifndef _SIGSEGV_H
0018 #define _SIGSEGV_H
0019 
0020 /* Get size_t.  */
0021 #include <stddef.h>
0022 
0023 #include <ucontext.h>
0024 
0025 /* Correct the value of SIGSTKSZ on some systems.
0026    glibc >= 2.34: When _GNU_SOURCE is defined, SIGSTKSZ is no longer a
0027    compile-time constant.  But most programs need a simple constant.
0028    AIX 64-bit: original value 4096 is too small.
0029    HP-UX: original value 8192 is too small.
0030    Solaris 11/x86_64: original value 8192 is too small.  */
0031 #include <signal.h>
0032 #if __GLIBC__ >= 2
0033 # undef SIGSTKSZ
0034 # if defined __ia64__
0035 #  define SIGSTKSZ 262144
0036 # else
0037 #  define SIGSTKSZ 65536
0038 # endif
0039 #endif
0040 #if defined _AIX && defined _ARCH_PPC64
0041 # undef SIGSTKSZ
0042 # define SIGSTKSZ 8192
0043 #endif
0044 #if defined __hpux || (defined __sun && (defined __x86_64__ || defined __amd64__))
0045 # undef SIGSTKSZ
0046 # define SIGSTKSZ 16384
0047 #endif
0048 
0049 /* HAVE_SIGSEGV_RECOVERY
0050    is defined if the system supports catching SIGSEGV.  */
0051 #if 1
0052 # define HAVE_SIGSEGV_RECOVERY 1
0053 #endif
0054 
0055 /* HAVE_STACK_OVERFLOW_RECOVERY
0056    is defined if stack overflow can be caught.  */
0057 #if 1
0058 # define HAVE_STACK_OVERFLOW_RECOVERY 1
0059 #endif
0060 
0061 
0062 #ifdef __cplusplus
0063 extern "C" {
0064 #endif
0065 
0066 #define LIBSIGSEGV_VERSION 0x020E    /* version number: (major<<8) + minor */
0067 extern int libsigsegv_version;       /* Likewise */
0068 
0069 /* -------------------------------------------------------------------------- */
0070 
0071 /*
0072  * The mask of bits that are set to zero in a fault address that gets passed
0073  * to a global SIGSEGV handler.
0074  * On some platforms, the precise fault address is not known, only the memory
0075  * page into which the fault address falls. This is apparently allowed by POSIX:
0076  * <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html>
0077  * says: "For some implementations, the value of si_addr may be inaccurate."
0078  * In this case, the returned fault address is rounded down to a multiple of
0079  * getpagesize() = sysconf(_SC_PAGESIZE).
0080  * On such platforms, we define SIGSEGV_FAULT_ADDRESS_ALIGNMENT to be an upper
0081  * bound for getpagesize() (and, like getpagesize(), also a power of 2).
0082  * On the platforms where the returned fault address is the precise one, we
0083  * define SIGSEGV_FAULT_ADDRESS_ALIGNMENT to 1.
0084  */
0085 #if defined __NetBSD__ && (defined __sparc__ || defined __sparc64__)
0086   /* getpagesize () is 0x1000 or 0x2000, depending on hardware.  */
0087 # define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 0x2000UL
0088 #elif defined __linux__ && (defined __s390__ || defined __s390x__)
0089   /* getpagesize () is 0x1000.  */
0090 # define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 0x1000UL
0091 #else
0092 # define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 1UL
0093 #endif
0094 
0095 /*
0096  * The type of a global SIGSEGV handler.
0097  * The fault address, with the bits (SIGSEGV_FAULT_ADDRESS_ALIGNMENT - 1)
0098  * cleared, is passed as argument.
0099  * The access type (read access or write access) is not passed; your handler
0100  * has to know itself how to distinguish these two cases.
0101  * The second argument is 0, meaning it could also be a stack overflow, or 1,
0102  * meaning the handler should seriously try to fix the fault.
0103  * The return value should be nonzero if the handler has done its job
0104  * and no other handler should be called, or 0 if the handler declines
0105  * responsibility for the given address.
0106  *
0107  * The handler is run at a moment when nothing about the global state of the
0108  * program is known. Therefore it cannot use facilities that manipulate global
0109  * variables or locks. In particular, it cannot use malloc(); use mmap()
0110  * instead. It cannot use fopen(); use open() instead. Etc. All global
0111  * variables that are accessed by the handler should be marked 'volatile'.
0112  */
0113 typedef int (*sigsegv_handler_t) (void* fault_address, int serious);
0114 
0115 /*
0116  * Installs a global SIGSEGV handler.
0117  * This should be called once only, and it ignores any previously installed
0118  * SIGSEGV handler.
0119  * Returns 0 on success, or -1 if the system doesn't support catching SIGSEGV.
0120  */
0121 extern int sigsegv_install_handler (sigsegv_handler_t handler);
0122 
0123 /*
0124  * Deinstalls the global SIGSEGV handler.
0125  * This goes back to the state where no SIGSEGV handler is installed.
0126  */
0127 extern void sigsegv_deinstall_handler (void);
0128 
0129 #if LIBSIGSEGV_VERSION >= 0x0206
0130 /*
0131  * Prepares leaving a SIGSEGV handler (through longjmp or similar means).
0132  * Control is transferred by calling CONTINUATION with CONT_ARG1, CONT_ARG2,
0133  * CONT_ARG3 as arguments.
0134  * CONTINUATION must not return.
0135  * The sigsegv_leave_handler function may return if called from a SIGSEGV
0136  * handler; its return value should be used as the handler's return value.
0137  * The sigsegv_leave_handler function does not return if called from a
0138  * stack overflow handler.
0139  */
0140 extern int sigsegv_leave_handler (void (*continuation) (void*, void*, void*), void* cont_arg1, void* cont_arg2, void* cont_arg3);
0141 #else /* older versions of libsigsegv */
0142 /*
0143  * Prepares leaving a SIGSEGV handler (through longjmp or similar means).
0144  * Limitation: This function could only be called once on MacOS X.
0145  */
0146 extern void sigsegv_leave_handler (void);
0147 #endif
0148 
0149 /*
0150  * The type of a context passed to a stack overflow handler.
0151  * This type is system dependent; on some platforms it is an 'ucontext_t *',
0152  * on some platforms it is a 'struct sigcontext *', on others merely an
0153  * opaque 'void *'.
0154  */
0155 typedef ucontext_t *stackoverflow_context_t;
0156 
0157 /*
0158  * The type of a stack overflow handler.
0159  * Such a handler should perform a longjmp call in order to reduce the amount
0160  * of stack needed. It must not return.
0161  * The emergency argument is 0 when the stack could be repared, or 1 if the
0162  * application should better save its state and exit now.
0163  *
0164  * The handler is run at a moment when nothing about the global state of the
0165  * program is known. Therefore it cannot use facilities that manipulate global
0166  * variables or locks. In particular, it cannot use malloc(); use mmap()
0167  * instead. It cannot use fopen(); use open() instead. Etc. All global
0168  * variables that are accessed by the handler should be marked 'volatile'.
0169  */
0170 typedef void (*stackoverflow_handler_t) (int emergency, stackoverflow_context_t scp);
0171 
0172 /*
0173  * Installs a stack overflow handler.
0174  * The extra_stack argument is a pointer to a pre-allocated area used as a
0175  * stack for executing the handler. It typically comes from a static variable
0176  * or from heap-allocated memoty; placing it on the main stack may fail on
0177  * some operating systems.
0178  * Its size, passed in extra_stack_size, should be sufficiently large.  The
0179  * following code determines an appropriate size:
0180  *   #include <signal.h>
0181  *   #ifndef SIGSTKSZ         / * glibc defines SIGSTKSZ for this purpose * /
0182  *   # define SIGSTKSZ 16384  / * on most platforms, 16 KB are sufficient * /
0183  *   #endif
0184  * Returns 0 on success, or -1 if the system doesn't support catching stack
0185  * overflow.
0186  */
0187 extern int stackoverflow_install_handler (stackoverflow_handler_t handler,
0188                                           void* extra_stack, size_t extra_stack_size);
0189 
0190 /*
0191  * Deinstalls the stack overflow handler.
0192  */
0193 extern void stackoverflow_deinstall_handler (void);
0194 
0195 /* -------------------------------------------------------------------------- */
0196 
0197 /*
0198  * The following structure and functions permit to define different SIGSEGV
0199  * policies on different address ranges.
0200  */
0201 
0202 /*
0203  * The type of a local SIGSEGV handler.
0204  * The fault address is passed as argument.
0205  * The second argument is fixed arbitrary user data.
0206  * The return value should be nonzero if the handler has done its job
0207  * and no other handler should be called, or 0 if the handler declines
0208  * responsibility for the given address.
0209  */
0210 typedef int (*sigsegv_area_handler_t) (void* fault_address, void* user_arg);
0211 
0212 /*
0213  * This structure represents a table of memory areas (address range intervals),
0214  * with an local SIGSEGV handler for each.
0215  */
0216 typedef
0217 struct sigsegv_dispatcher {
0218   void* tree;
0219 }
0220 sigsegv_dispatcher;
0221 
0222 /*
0223  * Initializes a sigsegv_dispatcher structure.
0224  */
0225 extern void sigsegv_init (sigsegv_dispatcher* dispatcher);
0226 
0227 /*
0228  * Adds a local SIGSEGV handler to a sigsegv_dispatcher structure.
0229  * It will cover the interval [address..address+len-1].
0230  * The address and len arguments must be multiples of
0231  * SIGSEGV_FAULT_ADDRESS_ALIGNMENT.
0232  * Returns a "ticket" that can be used to remove the handler later.
0233  */
0234 extern void* sigsegv_register (sigsegv_dispatcher* dispatcher,
0235                                void* address, size_t len,
0236                                sigsegv_area_handler_t handler, void* handler_arg);
0237 
0238 /*
0239  * Removes a local SIGSEGV handler.
0240  */
0241 extern void sigsegv_unregister (sigsegv_dispatcher* dispatcher, void* ticket);
0242 
0243 /*
0244  * Call the local SIGSEGV handler responsible for the given fault address.
0245  * Return the handler's return value. 0 means that no handler has been found,
0246  * or that a handler was found but declined responsibility.
0247  */
0248 extern int sigsegv_dispatch (sigsegv_dispatcher* dispatcher, void* fault_address);
0249 
0250 /* -------------------------------------------------------------------------- */
0251 
0252 #ifdef __cplusplus
0253 }
0254 #endif
0255 
0256 #endif /* _SIGSEGV_H */