ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.8
Committed: 2002-02-01T19:25:49Z (22 years, 9 months ago) by cebix
Branch: MAIN
Changes since 1.7: +4 -0 lines
Log Message:
direct addressing works under FreeBSD (says Michael Alyn Miller :-)

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-2002 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 #if defined(__NetBSD__) || defined(__FreeBSD__)
57 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
58 #else
59 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
60 #endif
61 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
62 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
63 #if defined(__linux__)
64 #if (defined(i386) || defined(__i386__))
65 #include <sys/ucontext.h>
66 #define SIGSEGV_FAULT_INSTRUCTION (((ucontext_t *)scp)->uc_mcontext.gregs[14]) /* should use REG_EIP instead */
67 #endif
68 #if (defined(ia64) || defined(__ia64__))
69 #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
70 #endif
71 #endif
72 #endif
73
74 #if HAVE_SIGCONTEXT_SUBTERFUGE
75 // Linux kernels prior to 2.4 ?
76 #if defined(__linux__)
77 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
78 #if (defined(i386) || defined(__i386__))
79 #include <asm/sigcontext.h>
80 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
81 #define SIGSEGV_FAULT_ADDRESS scs.cr2
82 #define SIGSEGV_FAULT_INSTRUCTION scs.eip
83 #endif
84 #if (defined(sparc) || defined(__sparc__))
85 #include <asm/sigcontext.h>
86 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
87 #define SIGSEGV_FAULT_ADDRESS addr
88 #endif
89 #if (defined(powerpc) || defined(__powerpc__))
90 #include <asm/sigcontext.h>
91 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
92 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
93 #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
94 #endif
95 #if (defined(alpha) || defined(__alpha__))
96 #include <asm/sigcontext.h>
97 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
98 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
99 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
100
101 // From Boehm's GC 6.0alpha8
102 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
103 {
104 unsigned int instruction = *((unsigned int *)(scp->sc_pc));
105 unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
106 fault_address += (signed long)(signed short)(instruction & 0xffff);
107 return (sigsegv_address_t)fault_address;
108 }
109 #endif
110 #endif
111
112 // Irix 5 or 6 on MIPS
113 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
114 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
115 #define SIGSEGV_FAULT_ADDRESS scp->sc_badvaddr
116 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
117 #endif
118
119 // OSF/1 on Alpha
120 #if defined(__osf__)
121 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
122 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
123 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
124 #endif
125
126 // AIX
127 #if defined(_AIX)
128 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
129 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
130 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
131 #endif
132
133 // NetBSD or FreeBSD
134 #if defined(__NetBSD__) || defined(__FreeBSD__)
135 #if (defined(m68k) || defined(__m68k__))
136 #include <m68k/frame.h>
137 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
138 #define SIGSEGV_FAULT_ADDRESS ({ \
139 struct sigstate { \
140 int ss_flags; \
141 struct frame ss_frame; \
142 }; \
143 struct sigstate *state = (struct sigstate *)scp->sc_ap; \
144 char *fault_addr; \
145 switch (state->ss_frame.f_format) { \
146 case 7: /* 68040 access error */ \
147 /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */ \
148 fault_addr = state->ss_frame.f_fmt7.f_fa; \
149 break; \
150 default: \
151 fault_addr = (char *)code; \
152 break; \
153 } \
154 fault_addr; \
155 })
156 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
157 #else
158 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, void *scp, char *addr
159 #define SIGSEGV_FAULT_ADDRESS addr
160 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
161 #endif
162 #endif
163
164 // MacOS X
165 #if defined(__APPLE__) && defined(__MACH__)
166 #if (defined(ppc) || defined(__ppc__))
167 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
168 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
169 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
170 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
171
172 // From Boehm's GC 6.0alpha8
173 #define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26)
174 #define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1)
175 #define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16)
176 #define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21)
177 #define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11)
178 #define EXTRACT_DISP(iw) ((short *) &(iw))[1]
179
180 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
181 {
182 unsigned int instr = *((unsigned int *) scp->sc_ir);
183 unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
184 int disp = 0, tmp;
185 unsigned int baseA = 0, baseB = 0;
186 unsigned int addr, alignmask = 0xFFFFFFFF;
187
188 switch(EXTRACT_OP1(instr)) {
189 case 38: /* stb */
190 case 39: /* stbu */
191 case 54: /* stfd */
192 case 55: /* stfdu */
193 case 52: /* stfs */
194 case 53: /* stfsu */
195 case 44: /* sth */
196 case 45: /* sthu */
197 case 47: /* stmw */
198 case 36: /* stw */
199 case 37: /* stwu */
200 tmp = EXTRACT_REGA(instr);
201 if(tmp > 0)
202 baseA = regs[tmp];
203 disp = EXTRACT_DISP(instr);
204 break;
205 case 31:
206 switch(EXTRACT_OP2(instr)) {
207 case 86: /* dcbf */
208 case 54: /* dcbst */
209 case 1014: /* dcbz */
210 case 247: /* stbux */
211 case 215: /* stbx */
212 case 759: /* stfdux */
213 case 727: /* stfdx */
214 case 983: /* stfiwx */
215 case 695: /* stfsux */
216 case 663: /* stfsx */
217 case 918: /* sthbrx */
218 case 439: /* sthux */
219 case 407: /* sthx */
220 case 661: /* stswx */
221 case 662: /* stwbrx */
222 case 150: /* stwcx. */
223 case 183: /* stwux */
224 case 151: /* stwx */
225 case 135: /* stvebx */
226 case 167: /* stvehx */
227 case 199: /* stvewx */
228 case 231: /* stvx */
229 case 487: /* stvxl */
230 tmp = EXTRACT_REGA(instr);
231 if(tmp > 0)
232 baseA = regs[tmp];
233 baseB = regs[EXTRACT_REGC(instr)];
234 /* determine Altivec alignment mask */
235 switch(EXTRACT_OP2(instr)) {
236 case 167: /* stvehx */
237 alignmask = 0xFFFFFFFE;
238 break;
239 case 199: /* stvewx */
240 alignmask = 0xFFFFFFFC;
241 break;
242 case 231: /* stvx */
243 alignmask = 0xFFFFFFF0;
244 break;
245 case 487: /* stvxl */
246 alignmask = 0xFFFFFFF0;
247 break;
248 }
249 break;
250 case 725: /* stswi */
251 tmp = EXTRACT_REGA(instr);
252 if(tmp > 0)
253 baseA = regs[tmp];
254 break;
255 default: /* ignore instruction */
256 return 0;
257 break;
258 }
259 break;
260 default: /* ignore instruction */
261 return 0;
262 break;
263 }
264
265 addr = (baseA + baseB) + disp;
266 addr &= alignmask;
267 return (sigsegv_address_t)addr;
268 }
269 #endif
270 #endif
271 #endif
272
273 // Fallbacks
274 #ifndef SIGSEGV_FAULT_INSTRUCTION
275 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
276 #endif
277
278 // SIGSEGV recovery supported ?
279 #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
280 #define HAVE_SIGSEGV_RECOVERY
281 #endif
282
283
284 /*
285 * SIGSEGV global handler
286 */
287
288 #ifdef HAVE_SIGSEGV_RECOVERY
289 static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
290 {
291 // Call user's handler and reinstall the global handler, if required
292 if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
293 #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
294 sigsegv_do_install_handler(sig);
295 #endif
296 }
297 else {
298 // FAIL: reinstall default handler for "safe" crash
299 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
300 SIGSEGV_ALL_SIGNALS
301 #undef FAULT_HANDLER
302 }
303 }
304 #endif
305
306
307 /*
308 * SIGSEGV handler initialization
309 */
310
311 #if defined(HAVE_SIGINFO_T)
312 static bool sigsegv_do_install_handler(int sig)
313 {
314 // Setup SIGSEGV handler to process writes to frame buffer
315 #ifdef HAVE_SIGACTION
316 struct sigaction vosf_sa;
317 sigemptyset(&vosf_sa.sa_mask);
318 vosf_sa.sa_sigaction = sigsegv_handler;
319 vosf_sa.sa_flags = SA_SIGINFO;
320 return (sigaction(sig, &vosf_sa, 0) == 0);
321 #else
322 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
323 #endif
324 }
325 #endif
326
327 #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
328 static bool sigsegv_do_install_handler(int sig)
329 {
330 // Setup SIGSEGV handler to process writes to frame buffer
331 #ifdef HAVE_SIGACTION
332 struct sigaction vosf_sa;
333 sigemptyset(&vosf_sa.sa_mask);
334 vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
335 #if !EMULATED_68K && defined(__NetBSD__)
336 sigaddset(&vosf_sa.sa_mask, SIGALRM);
337 vosf_sa.sa_flags = SA_ONSTACK;
338 #else
339 vosf_sa.sa_flags = 0;
340 #endif
341 return (sigaction(sig, &vosf_sa, 0) == 0);
342 #else
343 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
344 #endif
345 }
346 #endif
347
348 bool sigsegv_install_handler(sigsegv_handler_t handler)
349 {
350 #ifdef HAVE_SIGSEGV_RECOVERY
351 sigsegv_user_handler = handler;
352 bool success = true;
353 #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
354 SIGSEGV_ALL_SIGNALS
355 #undef FAULT_HANDLER
356 return success;
357 #else
358 // FAIL: no siginfo_t nor sigcontext subterfuge is available
359 return false;
360 #endif
361 }
362
363
364 /*
365 * SIGSEGV handler deinitialization
366 */
367
368 void sigsegv_deinstall_handler(void)
369 {
370 #ifdef HAVE_SIGSEGV_RECOVERY
371 sigsegv_user_handler = 0;
372 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
373 SIGSEGV_ALL_SIGNALS
374 #undef FAULT_HANDLER
375 #endif
376 }
377
378 /*
379 * Test program used for configure/test
380 */
381
382 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
383 #include <stdio.h>
384 #include <stdlib.h>
385 #include <fcntl.h>
386 #include <sys/mman.h>
387 #include "vm_alloc.h"
388
389 static int page_size;
390 static volatile char * page = 0;
391 static volatile int handler_called = 0;
392
393 static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
394 {
395 handler_called++;
396 if ((fault_address - 123) != page)
397 exit(1);
398 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
399 exit(1);
400 return true;
401 }
402
403 int main(void)
404 {
405 if (vm_init() < 0)
406 return 1;
407
408 page_size = getpagesize();
409 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
410 return 1;
411
412 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
413 return 1;
414
415 if (!sigsegv_install_handler(sigsegv_test_handler))
416 return 1;
417
418 page[123] = 45;
419 page[123] = 45;
420
421 if (handler_called != 1)
422 return 1;
423
424 vm_exit();
425 return 0;
426 }
427 #endif