1 /* Test the dispatcher.
2    Copyright (C) 2002-2006  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 #include "sigsegv.h"
19 #include <stdio.h>
20 
21 #if HAVE_SIGSEGV_RECOVERY
22 
23 #include "mmaputil.h"
24 #include <stdlib.h>
25 
26 static sigsegv_dispatcher dispatcher;
27 
28 static volatile unsigned int logcount = 0;
29 static volatile unsigned long logdata[10];
30 
31 static int
area_handler(void * fault_address,void * user_arg)32 area_handler (void *fault_address, void *user_arg)
33 {
34   unsigned long area = *(unsigned long *)user_arg;
35   logdata[logcount++] = area;
36   if (logcount >= sizeof (logdata) / sizeof (logdata[0]))
37     abort ();
38   if (!((unsigned long)fault_address >= area
39         && (unsigned long)fault_address - area < 0x4000))
40     abort ();
41   if (mprotect ((void *) area, 0x4000, PROT_READ_WRITE) == 0)
42     return 1;
43   return 0;
44 }
45 
46 static int
handler(void * fault_address,int serious)47 handler (void *fault_address, int serious)
48 {
49   return sigsegv_dispatch (&dispatcher, fault_address);
50 }
51 
52 static void
barrier()53 barrier ()
54 {
55 }
56 
57 int
main()58 main ()
59 {
60   void *p;
61   unsigned long area1;
62   unsigned long area2;
63   unsigned long area3;
64 
65   /* Preparations.  */
66 #if !HAVE_MMAP_ANON && !HAVE_MMAP_ANONYMOUS && HAVE_MMAP_DEVZERO
67   zero_fd = open ("/dev/zero", O_RDONLY, 0644);
68 #endif
69   sigsegv_init (&dispatcher);
70   sigsegv_install_handler (&handler);
71 
72   /* Setup some mmaped memory.  */
73 
74   p = mmap_zeromap ((void *) 0x12340000, 0x4000);
75   if (p == (void *)(-1))
76     {
77       fprintf (stderr, "mmap_zeromap failed.\n");
78       exit (2);
79     }
80   area1 = (unsigned long) p;
81   sigsegv_register (&dispatcher, (void *) area1, 0x4000, &area_handler, &area1);
82   if (mprotect ((void *) area1, 0x4000, PROT_NONE) < 0)
83     {
84       fprintf (stderr, "mprotect failed.\n");
85       exit (2);
86     }
87 
88   p = mmap_zeromap ((void *) 0x0BEE0000, 0x4000);
89   if (p == (void *)(-1))
90     {
91       fprintf (stderr, "mmap_zeromap failed.\n");
92       exit (2);
93     }
94   area2 = (unsigned long) p;
95   sigsegv_register (&dispatcher, (void *) area2, 0x4000, &area_handler, &area2);
96   if (mprotect ((void *) area2, 0x4000, PROT_READ) < 0)
97     {
98       fprintf (stderr, "mprotect failed.\n");
99       exit (2);
100     }
101   if (mprotect ((void *) area2, 0x4000, PROT_READ_WRITE) < 0
102       || mprotect ((void *) area2, 0x4000, PROT_READ) < 0)
103     {
104       fprintf (stderr, "mprotect failed.\n");
105       exit (2);
106     }
107 
108   p = mmap_zeromap ((void *) 0x06990000, 0x4000);
109   if (p == (void *)(-1))
110     {
111       fprintf (stderr, "mmap_zeromap failed.\n");
112       exit (2);
113     }
114   area3 = (unsigned long) p;
115   sigsegv_register (&dispatcher, (void *) area3, 0x4000, &area_handler, &area3);
116   mprotect ((void *) area3, 0x4000, PROT_READ);
117 
118   /* This access should call the handler.  */
119   ((volatile int *)area2)[230] = 22;
120   /* This access should call the handler.  */
121   ((volatile int *)area3)[412] = 33;
122   /* This access should not give a signal.  */
123   ((volatile int *)area2)[135] = 22;
124   /* This access should call the handler.  */
125   ((volatile int *)area1)[612] = 11;
126 
127   barrier();
128 
129   /* Check that the handler was called three times.  */
130   if (logcount != 3)
131     exit (1);
132   if (!(logdata[0] == area2 && logdata[1] == area3 && logdata[2] == area1))
133     exit (1);
134   printf ("Test passed.\n");
135   return 0;
136 }
137 
138 #else
139 
140 int
main()141 main ()
142 {
143   return 77;
144 }
145 
146 #endif
147