Improve NetBSD support: Allow VMA determination with fewer system calls.
[libsigsegv/ericb.git] / m4 / fault.m4
blob2dd89f83f9ba330a15ff45e08b82e79a455f10ce
1 # fault.m4 serial 5 (libsigsegv-2.2)
2 dnl Copyright (C) 2002-2003 Bruno Haible <bruno@clisp.org>
3 dnl This file is free software, distributed under the terms of the GNU
4 dnl General Public License.  As a special exception to the GNU General
5 dnl Public License, this file may be distributed as part of a program
6 dnl that contains a configuration script generated by Autoconf, under
7 dnl the same distribution terms as the rest of that program.
9 dnl How to write a SIGSEGV handler with access to the fault address.
10 dnl SV_TRY_FAULT(KIND, CACHESYMBOL, KNOWN-SYSTEMS,
11 dnl              INCLUDES, FAULT_HANDLER_ARGLIST, FAULT_ADDRESS, [INSTALLCODE])
12 AC_DEFUN([SV_TRY_FAULT], [
13   AC_REQUIRE([AC_PROG_CC])
14   AC_REQUIRE([AC_CANONICAL_HOST])
16   AC_CACHE_CHECK([whether a fault handler according to $1 works], [$2], [
17     AC_RUN_IFELSE([
18       AC_LANG_SOURCE([[
19 #include <stdlib.h>
20 #include <signal.h>
21 #if HAVE_SYS_SIGNAL_H
22 # include <sys/signal.h>
23 #endif
25 #include <sys/types.h>
26 #include <sys/mman.h>
27 #if HAVE_MMAP_DEVZERO
28 # include <fcntl.h>
29 # ifndef MAP_FILE
30 #  define MAP_FILE 0
31 # endif
32 #endif
33 #ifndef PROT_NONE
34 # define PROT_NONE 0
35 #endif
36 #if HAVE_MMAP_ANON
37 # define zero_fd -1
38 # define map_flags MAP_ANON | MAP_PRIVATE
39 #elif HAVE_MMAP_ANONYMOUS
40 # define zero_fd -1
41 # define map_flags MAP_ANONYMOUS | MAP_PRIVATE
42 #elif HAVE_MMAP_DEVZERO
43 static int zero_fd;
44 # define map_flags MAP_FILE | MAP_PRIVATE
45 #endif
46 unsigned long page;
47 int handler_called = 0;
48 void sigsegv_handler ($5)
50   void *fault_address = (void *) ($6);
51   handler_called++;
52   if (handler_called == 10)
53     exit (4);
54   if (fault_address != (void*)(page + 0x678))
55     exit (3);
56   if (mprotect ((void *) page, 0x10000, PROT_READ | PROT_WRITE) < 0)
57     exit (2);
59 void crasher (unsigned long p)
61   *(int *) (p + 0x678) = 42;
63 int main ()
65   void *p;
66   struct sigaction action;
67   /* Preparations.  */
68 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
69   zero_fd = open ("/dev/zero", O_RDONLY, 0644);
70 #endif
71   /* Setup some mmaped memory.  */
72 #ifdef __hpux
73   /* HP-UX 10 mmap() often fails when given a hint.  So give the OS complete
74      freedom about the address range.  */
75   p = mmap ((void *) 0,          0x10000, PROT_READ | PROT_WRITE, map_flags, zero_fd, 0);
76 #else
77   p = mmap ((void *) 0x12340000, 0x10000, PROT_READ | PROT_WRITE, map_flags, zero_fd, 0);
78 #endif
79   if (p == (void *)(-1))
80     exit (2);
81   page = (unsigned long) p;
82   /* Make it read-only.  */
83   if (mprotect ((void *) page, 0x10000, PROT_READ) < 0)
84     exit (2);
85   /* Install the SIGSEGV handler.  */
86   sigemptyset(&action.sa_mask);
87 ]m4_if([$7], [], [
88   action.sa_handler = (void (*) (int)) &sigsegv_handler;
89   action.sa_flags = 0;
90 ], [$7])[
91   sigaction (SIGSEGV, &action, (struct sigaction *) NULL);
92   sigaction (SIGBUS, &action, (struct sigaction *) NULL);
93   /* The first write access should invoke the handler and then complete.  */
94   crasher (page);
95   /* The second write access should not invoke the handler.  */
96   crasher (page);
97   /* Check that the handler was called only once.  */
98   if (handler_called != 1)
99     exit (1);
100   /* Test passed!  */
101   return 0;
102 }]])],
103       [$2=yes],
104       [$2=no],
105       [case "$host" in
106          m4_if([$3], [], [], [[$3]) $2=yes ;;])
107          *)
108            AC_LINK_IFELSE([
109              AC_LANG_PROGRAM([[
110 #include <signal.h>
112 void sigsegv_handler ($5)
114   void *fault_address = (void *) ($6);
117                [[struct sigaction action;
118 $7]])],
119              [$2="guessing no"],
120              [$2=no])
121            ;;
122        esac
123       ])
124   ])