ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.4
Committed: 2001-06-26T22:35:41Z (23 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.3: +134 -9 lines
Log Message:
- added SIGSEGV support for Linux/Alpha (to be checked), Darwin/PPC
- added uniform virtual memory allocation
  (supports mmap(), vm_allocate(), or fallbacks to malloc()/free())
- cleaned up memory allocation in main_unix.cpp

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