ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.7
Committed: 2002-01-15T14:58:37Z (22 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-15012002
Changes since 1.6: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

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