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