ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.5
Committed: 2001-07-07T09:12:15Z (23 years, 4 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +7 -2 lines
Log Message:
- small fixes for Linux/ia64

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