1 /* Test the dispatcher.
2 Copyright (C) 2002-2006, 2008, 2011, 2016 Bruno Haible <bruno@clisp.org>
3
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.
8
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.
13
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. */
17
18 #ifndef _MSC_VER
19 # include <config.h>
20 #endif
21
22 #include "sigsegv.h"
23 #include <stdint.h>
24 #include <stdio.h>
25
26 #if HAVE_SIGSEGV_RECOVERY
27
28 #include "mmaputil.h"
29 #include <stdlib.h>
30
31 static sigsegv_dispatcher dispatcher;
32
33 static volatile unsigned int logcount = 0;
34 static volatile uintptr_t logdata[10];
35
36 /* Note about SIGSEGV_FAULT_ADDRESS_ALIGNMENT: It does not matter whether
37 fault_address is rounded off here because all intervals that we pass to
38 sigsegv_register are page-aligned. */
39
40 static int
area_handler(void * fault_address,void * user_arg)41 area_handler (void *fault_address, void *user_arg)
42 {
43 uintptr_t area = *(uintptr_t *)user_arg;
44 logdata[logcount++] = area;
45 if (logcount >= sizeof (logdata) / sizeof (logdata[0]))
46 abort ();
47 if (!((uintptr_t)fault_address >= area
48 && (uintptr_t)fault_address - area < 0x4000))
49 abort ();
50 if (mprotect ((void *) area, 0x4000, PROT_READ_WRITE) == 0)
51 return 1;
52 return 0;
53 }
54
55 static int
handler(void * fault_address,int serious)56 handler (void *fault_address, int serious)
57 {
58 return sigsegv_dispatch (&dispatcher, fault_address);
59 }
60
61 static void
barrier()62 barrier ()
63 {
64 }
65
66 int
main()67 main ()
68 {
69 int prot_unwritable;
70 void *p;
71 uintptr_t area1;
72 uintptr_t area2;
73 uintptr_t area3;
74
75 /* Preparations. */
76 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
77 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
78 #endif
79 sigsegv_init (&dispatcher);
80 sigsegv_install_handler (&handler);
81
82 #if defined __linux__ && defined __sparc__
83 /* On Linux 2.6.26/SPARC64, PROT_READ has the same effect as
84 PROT_READ | PROT_WRITE. */
85 prot_unwritable = PROT_NONE;
86 #else
87 prot_unwritable = PROT_READ;
88 #endif
89
90 /* Setup some mmaped memory. */
91
92 p = mmap_zeromap ((void *) 0x12340000, 0x4000);
93 if (p == (void *)(-1))
94 {
95 fprintf (stderr, "mmap_zeromap failed.\n");
96 exit (2);
97 }
98 area1 = (uintptr_t) p;
99 sigsegv_register (&dispatcher, (void *) area1, 0x4000, &area_handler, &area1);
100 if (mprotect ((void *) area1, 0x4000, PROT_NONE) < 0)
101 {
102 fprintf (stderr, "mprotect failed.\n");
103 exit (2);
104 }
105
106 p = mmap_zeromap ((void *) 0x0BEE0000, 0x4000);
107 if (p == (void *)(-1))
108 {
109 fprintf (stderr, "mmap_zeromap failed.\n");
110 exit (2);
111 }
112 area2 = (uintptr_t) p;
113 sigsegv_register (&dispatcher, (void *) area2, 0x4000, &area_handler, &area2);
114 if (mprotect ((void *) area2, 0x4000, prot_unwritable) < 0)
115 {
116 fprintf (stderr, "mprotect failed.\n");
117 exit (2);
118 }
119 if (mprotect ((void *) area2, 0x4000, PROT_READ_WRITE) < 0
120 || mprotect ((void *) area2, 0x4000, prot_unwritable) < 0)
121 {
122 fprintf (stderr, "mprotect failed.\n");
123 exit (2);
124 }
125
126 p = mmap_zeromap ((void *) 0x06990000, 0x4000);
127 if (p == (void *)(-1))
128 {
129 fprintf (stderr, "mmap_zeromap failed.\n");
130 exit (2);
131 }
132 area3 = (uintptr_t) p;
133 sigsegv_register (&dispatcher, (void *) area3, 0x4000, &area_handler, &area3);
134 mprotect ((void *) area3, 0x4000, prot_unwritable);
135
136 /* This access should call the handler. */
137 ((volatile int *)area2)[230] = 22;
138 /* This access should call the handler. */
139 ((volatile int *)area3)[412] = 33;
140 /* This access should not give a signal. */
141 ((volatile int *)area2)[135] = 22;
142 /* This access should call the handler. */
143 ((volatile int *)area1)[612] = 11;
144
145 barrier();
146
147 /* Check that the handler was called three times. */
148 if (logcount != 3)
149 exit (1);
150 if (!(logdata[0] == area2 && logdata[1] == area3 && logdata[2] == area1))
151 exit (1);
152 printf ("Test passed.\n");
153 return 0;
154 }
155
156 #else
157
158 int
main()159 main ()
160 {
161 return 77;
162 }
163
164 #endif
165