ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.3
Committed: 2001-06-05T12:16:34Z (23 years, 1 month ago) by gbeauche
Branch: MAIN
Changes since 1.2: +4 -4 lines
Log Message:
- use "volatile" to prevent from optimization for writes to page

File Contents

# Content
1 /*
2 * sigsegv.cpp - SIGSEGV signals support
3 *
4 * Derived from Bruno Haible's work on his SIGSEGV library for clisp
5 * <http://clisp.sourceforge.net/>
6 *
7 * Basilisk II (C) 1997-2001 Christian Bauer
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <signal.h>
33 #include "sigsegv.h"
34
35 // Return value type of a signal handler (standard type if not defined)
36 #ifndef RETSIGTYPE
37 #define RETSIGTYPE void
38 #endif
39
40 // Type of the system signal handler
41 typedef RETSIGTYPE (*signal_handler)(int);
42
43 // User's SIGSEGV handler
44 static sigsegv_handler_t sigsegv_user_handler = 0;
45
46 // Actual SIGSEGV handler installer
47 static bool sigsegv_do_install_handler(int sig);
48
49
50 /*
51 * OS-dependant SIGSEGV signals support section
52 */
53
54 #if HAVE_SIGINFO_T
55 // Generic extended signal handler
56 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
57 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *
58 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
59 #endif
60
61 #if HAVE_SIGCONTEXT_SUBTERFUGE
62 // Linux kernels prior to 2.4 ?
63 #if defined(__linux__)
64 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
65 #if (defined(i386) || defined(__i386__))
66 #include <asm/sigcontext.h>
67 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
68 #define SIGSEGV_FAULT_ADDRESS scs.cr2
69 #define SIGSEGV_FAULT_INSTRUCTION scs.eip
70 #endif
71 #if (defined(sparc) || defined(__sparc__))
72 #include <asm/sigcontext.h>
73 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext* scp, char* addr
74 #define SIGSEGV_FAULT_ADDRESS addr
75 #endif
76 #if (defined(powerpc) || defined(__powerpc__))
77 #include <asm/sigcontext.h>
78 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext* scp
79 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
80 #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
81 #endif
82 #endif
83
84 // Irix 5 or 6 on MIPS
85 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
86 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
87 #define SIGSEGV_FAULT_ADDRESS scp->sc_badvaddr
88 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
89 #endif
90
91 // OSF/1 on Alpha
92 #if defined(__osf__)
93 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
94 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
95 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
96 #endif
97
98 // AIX
99 #if defined(_AIX)
100 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
101 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
102 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
103 #endif
104
105 // NetBSD or FreeBSD
106 #if defined(__NetBSD__) || defined(__FreeBSD__)
107 #if (defined(m68k) || defined(__m68k__))
108 #include <m68k/frame.h>
109 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
110 #define SIGSEGV_FAULT_ADDRESS ({ \
111 struct sigstate { \
112 int ss_flags; \
113 struct frame ss_frame; \
114 }; \
115 struct sigstate *state = (struct sigstate *)scp->sc_ap; \
116 char *fault_addr; \
117 switch (state->ss_frame.f_format) { \
118 case 7: /* 68040 access error */ \
119 /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */ \
120 fault_addr = state->ss_frame.f_fmt7.f_fa; \
121 break; \
122 default: \
123 fault_addr = (char *)code; \
124 break; \
125 } \
126 fault_addr; \
127 })
128 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
129 #else
130 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, void *scp, char *addr
131 #define SIGSEGV_FAULT_ADDRESS addr
132 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
133 #endif
134 #endif
135 #endif
136
137 // Fallbacks
138 #ifndef SIGSEGV_FAULT_INSTRUCTION
139 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
140 #endif
141
142 // SIGSEGV recovery supported ?
143 #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
144 #define HAVE_SIGSEGV_RECOVERY
145 #endif
146
147
148 /*
149 * SIGSEGV global handler
150 */
151
152 #ifdef HAVE_SIGSEGV_RECOVERY
153 static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
154 {
155 // Call user's handler and reinstall the global handler, if required
156 if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
157 #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
158 sigsegv_do_install_handler(sig);
159 #endif
160 }
161 else {
162 // FAIL: reinstall default handler for "safe" crash
163 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
164 SIGSEGV_ALL_SIGNALS
165 #undef FAULT_HANDLER
166 }
167 }
168 #endif
169
170
171 /*
172 * SIGSEGV handler initialization
173 */
174
175 #if defined(HAVE_SIGINFO_T)
176 static bool sigsegv_do_install_handler(int sig)
177 {
178 // Setup SIGSEGV handler to process writes to frame buffer
179 #ifdef HAVE_SIGACTION
180 struct sigaction vosf_sa;
181 sigemptyset(&vosf_sa.sa_mask);
182 vosf_sa.sa_sigaction = sigsegv_handler;
183 vosf_sa.sa_flags = SA_SIGINFO;
184 return (sigaction(sig, &vosf_sa, 0) == 0);
185 #else
186 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
187 #endif
188 }
189 #endif
190
191 #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
192 static bool sigsegv_do_install_handler(int sig)
193 {
194 // Setup SIGSEGV handler to process writes to frame buffer
195 #ifdef HAVE_SIGACTION
196 struct sigaction vosf_sa;
197 sigemptyset(&vosf_sa.sa_mask);
198 vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
199 #if !EMULATED_68K && defined(__NetBSD__)
200 sigaddset(&vosf_sa.sa_mask, SIGALRM);
201 vosf_sa.sa_flags = SA_ONSTACK;
202 #else
203 vosf_sa.sa_flags = 0;
204 #endif
205 return (sigaction(sig, &vosf_sa, 0) == 0);
206 #else
207 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
208 #endif
209 }
210 #endif
211
212 bool sigsegv_install_handler(sigsegv_handler_t handler)
213 {
214 #ifdef HAVE_SIGSEGV_RECOVERY
215 sigsegv_user_handler = handler;
216 bool success = true;
217 #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
218 SIGSEGV_ALL_SIGNALS
219 #undef FAULT_HANDLER
220 return success;
221 #else
222 // FAIL: no siginfo_t nor sigcontext subterfuge is available
223 return false;
224 #endif
225 }
226
227
228 /*
229 * SIGSEGV handler deinitialization
230 */
231
232 void sigsegv_deinstall_handler(void)
233 {
234 #ifdef HAVE_SIGSEGV_RECOVERY
235 sigsegv_user_handler = 0;
236 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
237 SIGSEGV_ALL_SIGNALS
238 #undef FAULT_HANDLER
239 #endif
240 }
241
242 /*
243 * Test program used for configure/test
244 */
245
246 #ifdef CONFIGURE_TEST
247 #include <stdio.h>
248 #include <stdlib.h>
249 #include <unistd.h>
250 #include <fcntl.h>
251 #include <sys/mman.h>
252
253 static int page_size;
254 static volatile char * page = 0;
255 static volatile int handler_called = 0;
256
257 static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
258 {
259 handler_called++;
260 if ((fault_address - 123) != page)
261 exit(1);
262 if (mprotect((char *)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0)
263 exit(1);
264 return true;
265 }
266
267 int main(void)
268 {
269 int zero_fd = open("/dev/zero", O_RDWR);
270 if (zero_fd < 0)
271 return 1;
272
273 page_size = getpagesize();
274 page = (char *)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0);
275 if (page == MAP_FAILED)
276 return 1;
277
278 if (!sigsegv_install_handler(sigsegv_test_handler))
279 return 1;
280
281 page[123] = 45;
282 page[123] = 45;
283
284 if (handler_called != 1)
285 return 1;
286
287 return 0;
288 }
289 #endif