ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/sigsegv.cpp (file contents):
Revision 1.3 by gbeauche, 2001-06-05T12:16:34Z vs.
Revision 1.11 by gbeauche, 2002-05-12T13:51:22Z

# Line 4 | Line 4
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
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
# Line 40 | Line 40
40   // Type of the system signal handler
41   typedef RETSIGTYPE (*signal_handler)(int);
42  
43 + // Is the fault to be ignored?
44 + static bool sigsegv_ignore_fault = false;
45 +
46   // User's SIGSEGV handler
47   static sigsegv_handler_t sigsegv_user_handler = 0;
48  
49 + // Function called to dump state if we can't handle the fault
50 + static sigsegv_handler_t sigsegv_dump_state = 0;
51 +
52   // Actual SIGSEGV handler installer
53   static bool sigsegv_do_install_handler(int sig);
54  
# Line 53 | Line 59 | static bool sigsegv_do_install_handler(i
59  
60   #if HAVE_SIGINFO_T
61   // Generic extended signal handler
62 + #if defined(__NetBSD__) || defined(__FreeBSD__)
63 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
64 + #else
65   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
66 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *
66 > #endif
67 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *scp
68   #define SIGSEGV_FAULT_ADDRESS                   sip->si_addr
69 + #if defined(__linux__)
70 + #if (defined(i386) || defined(__i386__))
71 + #include <sys/ucontext.h>
72 + #define SIGSEGV_FAULT_INSTRUCTION               (((ucontext_t *)scp)->uc_mcontext.gregs[14]) /* should use REG_EIP instead */
73 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(((ucontext_t *)scp)->uc_mcontext.gregs)
74 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
75 + #endif
76 + #if (defined(ia64) || defined(__ia64__))
77 + #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
78 + #endif
79 + #if (defined(powerpc) || defined(__powerpc__))
80 + #include <sys/ucontext.h>
81 + #define SIGSEGV_FAULT_INSTRUCTION               (((ucontext_t *)scp)->uc_mcontext.regs->nip)
82 + #endif
83 + #endif
84   #endif
85  
86   #if HAVE_SIGCONTEXT_SUBTERFUGE
# Line 67 | Line 92 | static bool sigsegv_do_install_handler(i
92   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
93   #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
94   #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
95 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(&scs)
96 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
97   #endif
98   #if (defined(sparc) || defined(__sparc__))
99   #include <asm/sigcontext.h>
100 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext* scp, char* addr
100 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
101   #define SIGSEGV_FAULT_ADDRESS                   addr
102   #endif
103   #if (defined(powerpc) || defined(__powerpc__))
104   #include <asm/sigcontext.h>
105 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext* scp
105 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
106   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
107   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
108   #endif
109 + #if (defined(alpha) || defined(__alpha__))
110 + #include <asm/sigcontext.h>
111 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
112 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
113 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
114 +
115 + // From Boehm's GC 6.0alpha8
116 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
117 + {
118 +        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
119 +        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
120 +        fault_address += (signed long)(signed short)(instruction & 0xffff);
121 +        return (sigsegv_address_t)fault_address;
122 + }
123 + #endif
124   #endif
125  
126   // Irix 5 or 6 on MIPS
127   #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
128 + #include <ucontext.h>
129   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
130   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
131   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
132   #endif
133  
134 + // HP-UX
135 + #if (defined(hpux) || defined(__hpux__))
136 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
137 + #define SIGSEGV_FAULT_ADDRESS                   scp->sc_sl.sl_ss.ss_narrow.ss_cr21
138 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
139 + #endif
140 +
141   // OSF/1 on Alpha
142   #if defined(__osf__)
143 + #include <ucontext.h>
144   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
145   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_traparg_a0
146   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
# Line 132 | Line 183 | static bool sigsegv_do_install_handler(i
183   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
184   #endif
185   #endif
186 +
187 + // MacOS X
188 + #if defined(__APPLE__) && defined(__MACH__)
189 + #if (defined(ppc) || defined(__ppc__))
190 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
191 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
192 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
193 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
194 +
195 + // From Boehm's GC 6.0alpha8
196 + #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
197 + #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
198 + #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
199 + #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
200 + #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
201 + #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
202 +
203 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
204 + {
205 +        unsigned int   instr = *((unsigned int *) scp->sc_ir);
206 +        unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
207 +        int            disp = 0, tmp;
208 +        unsigned int   baseA = 0, baseB = 0;
209 +        unsigned int   addr, alignmask = 0xFFFFFFFF;
210 +
211 +        switch(EXTRACT_OP1(instr)) {
212 +        case 38:   /* stb */
213 +        case 39:   /* stbu */
214 +        case 54:   /* stfd */
215 +        case 55:   /* stfdu */
216 +        case 52:   /* stfs */
217 +        case 53:   /* stfsu */
218 +        case 44:   /* sth */
219 +        case 45:   /* sthu */
220 +        case 47:   /* stmw */
221 +        case 36:   /* stw */
222 +        case 37:   /* stwu */
223 +                tmp = EXTRACT_REGA(instr);
224 +                if(tmp > 0)
225 +                        baseA = regs[tmp];
226 +                disp = EXTRACT_DISP(instr);
227 +                break;
228 +        case 31:
229 +                switch(EXTRACT_OP2(instr)) {
230 +                case 86:    /* dcbf */
231 +                case 54:    /* dcbst */
232 +                case 1014:  /* dcbz */
233 +                case 247:   /* stbux */
234 +                case 215:   /* stbx */
235 +                case 759:   /* stfdux */
236 +                case 727:   /* stfdx */
237 +                case 983:   /* stfiwx */
238 +                case 695:   /* stfsux */
239 +                case 663:   /* stfsx */
240 +                case 918:   /* sthbrx */
241 +                case 439:   /* sthux */
242 +                case 407:   /* sthx */
243 +                case 661:   /* stswx */
244 +                case 662:   /* stwbrx */
245 +                case 150:   /* stwcx. */
246 +                case 183:   /* stwux */
247 +                case 151:   /* stwx */
248 +                case 135:   /* stvebx */
249 +                case 167:   /* stvehx */
250 +                case 199:   /* stvewx */
251 +                case 231:   /* stvx */
252 +                case 487:   /* stvxl */
253 +                        tmp = EXTRACT_REGA(instr);
254 +                        if(tmp > 0)
255 +                                baseA = regs[tmp];
256 +                        baseB = regs[EXTRACT_REGC(instr)];
257 +                        /* determine Altivec alignment mask */
258 +                        switch(EXTRACT_OP2(instr)) {
259 +                        case 167:   /* stvehx */
260 +                                alignmask = 0xFFFFFFFE;
261 +                                break;
262 +                        case 199:   /* stvewx */
263 +                                alignmask = 0xFFFFFFFC;
264 +                                break;
265 +                        case 231:   /* stvx */
266 +                                alignmask = 0xFFFFFFF0;
267 +                                break;
268 +                        case 487:  /* stvxl */
269 +                                alignmask = 0xFFFFFFF0;
270 +                                break;
271 +                        }
272 +                        break;
273 +                case 725:   /* stswi */
274 +                        tmp = EXTRACT_REGA(instr);
275 +                        if(tmp > 0)
276 +                                baseA = regs[tmp];
277 +                        break;
278 +                default:   /* ignore instruction */
279 +                        return 0;
280 +                        break;
281 +                }
282 +                break;
283 +        default:   /* ignore instruction */
284 +                return 0;
285 +                break;
286 +        }
287 +        
288 +        addr = (baseA + baseB) + disp;
289 +        addr &= alignmask;
290 +        return (sigsegv_address_t)addr;
291 + }
292 + #endif
293 + #endif
294 + #endif
295 +
296 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
297 + // Decode and skip X86 instruction
298 + #if (defined(i386) || defined(__i386__))
299 + #if defined(__linux__)
300 + enum {
301 +        X86_REG_EIP = 14,
302 +        X86_REG_EAX = 11,
303 +        X86_REG_ECX = 10,
304 +        X86_REG_EDX = 9,
305 +        X86_REG_EBX = 8,
306 +        X86_REG_ESP = 7,
307 +        X86_REG_EBP = 6,
308 +        X86_REG_ESI = 5,
309 +        X86_REG_EDI = 4
310 + };
311 + #endif
312 + // FIXME: this is partly redundant with the instruction decoding phase
313 + // to discover transfer type and register number
314 + static inline int ix86_step_over_modrm(unsigned char * p)
315 + {
316 +        int mod = (p[0] >> 6) & 3;
317 +        int rm = p[0] & 7;
318 +        int offset = 0;
319 +
320 +        // ModR/M Byte
321 +        switch (mod) {
322 +        case 0: // [reg]
323 +                if (rm == 5) return 4; // disp32
324 +                break;
325 +        case 1: // disp8[reg]
326 +                offset = 1;
327 +                break;
328 +        case 2: // disp32[reg]
329 +                offset = 4;
330 +                break;
331 +        case 3: // register
332 +                return 0;
333 +        }
334 +        
335 +        // SIB Byte
336 +        if (rm == 4) {
337 +                if (mod == 0 && (p[1] & 7) == 5)
338 +                        offset = 5; // disp32[index]
339 +                else
340 +                        offset++;
341 +        }
342 +
343 +        return offset;
344 + }
345 +
346 + static bool ix86_skip_instruction(sigsegv_address_t fault_instruction, unsigned long * regs)
347 + {
348 +        unsigned char * eip = (unsigned char *)fault_instruction;
349 +
350 +        if (eip == 0)
351 +                return false;
352 +        
353 +        // Transfer type
354 +        enum {
355 +                TYPE_UNKNOWN,
356 +                TYPE_LOAD,
357 +                TYPE_STORE
358 +        } transfer_type = TYPE_UNKNOWN;
359 +        
360 +        // Transfer size
361 +        enum {
362 +                SIZE_BYTE,
363 +                SIZE_WORD,
364 +                SIZE_LONG
365 +        } transfer_size = SIZE_LONG;
366 +        
367 +        int reg = -1;
368 +        int len = 0;
369 +        
370 +        // Operand size prefix
371 +        if (*eip == 0x66) {
372 +                eip++;
373 +                len++;
374 +                transfer_size = SIZE_WORD;
375 +        }
376 +
377 +        // Decode instruction
378 +        switch (eip[0]) {
379 +        case 0x8a: // MOV r8, r/m8
380 +                transfer_size = SIZE_BYTE;
381 +        case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
382 +                switch (eip[1] & 0xc0) {
383 +                case 0x80:
384 +                        reg = (eip[1] >> 3) & 7;
385 +                        transfer_type = TYPE_LOAD;
386 +                        break;
387 +                case 0x40:
388 +                        reg = (eip[1] >> 3) & 7;
389 +                        transfer_type = TYPE_LOAD;
390 +                        break;
391 +                case 0x00:
392 +                        reg = (eip[1] >> 3) & 7;
393 +                        transfer_type = TYPE_LOAD;
394 +                        break;
395 +                }
396 +                len += 2 + ix86_step_over_modrm(eip + 1);
397 +                break;
398 +        case 0x88: // MOV r/m8, r8
399 +                transfer_size = SIZE_BYTE;
400 +        case 0x89: // MOV r/m32, r32 (or 16-bit operation)
401 +                switch (eip[1] & 0xc0) {
402 +                case 0x80:
403 +                        reg = (eip[1] >> 3) & 7;
404 +                        transfer_type = TYPE_STORE;
405 +                        break;
406 +                case 0x40:
407 +                        reg = (eip[1] >> 3) & 7;
408 +                        transfer_type = TYPE_STORE;
409 +                        break;
410 +                case 0x00:
411 +                        reg = (eip[1] >> 3) & 7;
412 +                        transfer_type = TYPE_STORE;
413 +                        break;
414 +                }
415 +                len += 2 + ix86_step_over_modrm(eip + 1);
416 +                break;
417 +        }
418 +
419 +        if (transfer_type == TYPE_UNKNOWN) {
420 +                // Unknown machine code, let it crash. Then patch the decoder
421 +                return false;
422 +        }
423 +
424 +        if (transfer_type == TYPE_LOAD && reg != -1) {
425 +                static const int x86_reg_map[8] = {
426 +                        X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
427 +                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
428 +                };
429 +                
430 +                if (reg < 0 || reg >= 8)
431 +                        return false;
432 +
433 +                int rloc = x86_reg_map[reg];
434 +                switch (transfer_size) {
435 +                case SIZE_BYTE:
436 +                        regs[rloc] = (regs[rloc] & ~0xff);
437 +                        break;
438 +                case SIZE_WORD:
439 +                        regs[rloc] = (regs[rloc] & ~0xffff);
440 +                        break;
441 +                case SIZE_LONG:
442 +                        regs[rloc] = 0;
443 +                        break;
444 +                }
445 +        }
446 +
447 + #if DEBUG
448 +        printf("%08x: %s %s access", regs[X86_REG_EIP],
449 +                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
450 +                   transfer_type == TYPE_LOAD ? "read" : "write");
451 +        
452 +        if (reg != -1) {
453 +                static const char * x86_reg_str_map[8] = {
454 +                        "eax", "ecx", "edx", "ebx",
455 +                        "esp", "ebp", "esi", "edi"
456 +                };
457 +                printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
458 +        }
459 +        printf(", %d bytes instruction\n", len);
460 + #endif
461 +        
462 +        regs[X86_REG_EIP] += len;
463 +        return true;
464 + }
465 + #endif
466   #endif
467  
468   // Fallbacks
# Line 152 | Line 483 | static bool sigsegv_do_install_handler(i
483   #ifdef HAVE_SIGSEGV_RECOVERY
484   static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
485   {
486 +        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
487 +        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
488 +        bool fault_recovered = false;
489 +        
490          // Call user's handler and reinstall the global handler, if required
491 <        if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
491 >        if (sigsegv_user_handler(fault_address, fault_instruction)) {
492   #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
493                  sigsegv_do_install_handler(sig);
494   #endif
495 +                fault_recovered = true;
496 +        }
497 + #if HAVE_SIGSEGV_SKIP_INSTRUCTION
498 +        else if (sigsegv_ignore_fault) {
499 +                // Call the instruction skipper with the register file available
500 +                if (SIGSEGV_SKIP_INSTRUCTION(fault_instruction, SIGSEGV_REGISTER_FILE))
501 +                        fault_recovered = true;
502          }
503 <        else {
503 > #endif
504 >
505 >        if (!fault_recovered) {
506                  // FAIL: reinstall default handler for "safe" crash
507   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
508                  SIGSEGV_ALL_SIGNALS
509   #undef FAULT_HANDLER
510 +                
511 +                // We can't do anything with the fault_address, dump state?
512 +                if (sigsegv_dump_state != 0)
513 +                        sigsegv_dump_state(fault_address, fault_instruction);
514          }
515   }
516   #endif
# Line 239 | Line 587 | void sigsegv_deinstall_handler(void)
587   #endif
588   }
589  
590 +
591 + /*
592 + *  SIGSEGV ignore state modifier
593 + */
594 +
595 + void sigsegv_set_ignore_state(bool ignore_fault)
596 + {
597 +        sigsegv_ignore_fault = ignore_fault;
598 + }
599 +
600 +
601 + /*
602 + *  Set callback function when we cannot handle the fault
603 + */
604 +
605 + void sigsegv_set_dump_state(sigsegv_handler_t handler)
606 + {
607 +        sigsegv_dump_state = handler;
608 + }
609 +
610 +
611   /*
612   *  Test program used for configure/test
613   */
614  
615 < #ifdef CONFIGURE_TEST
615 > #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
616   #include <stdio.h>
617   #include <stdlib.h>
249 #include <unistd.h>
618   #include <fcntl.h>
619   #include <sys/mman.h>
620 + #include "vm_alloc.h"
621  
622   static int page_size;
623   static volatile char * page = 0;
# Line 259 | Line 628 | static bool sigsegv_test_handler(sigsegv
628          handler_called++;
629          if ((fault_address - 123) != page)
630                  exit(1);
631 <        if (mprotect((char *)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0)
631 >        if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
632                  exit(1);
633          return true;
634   }
635  
636 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
637 + static bool sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
638 + {
639 +        return false;
640 + }
641 + #endif
642 +
643   int main(void)
644   {
645 <        int zero_fd = open("/dev/zero", O_RDWR);
270 <        if (zero_fd < 0)
645 >        if (vm_init() < 0)
646                  return 1;
647  
648          page_size = getpagesize();
649 <        page = (char *)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0);
650 <        if (page == MAP_FAILED)
649 >        if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
650 >                return 1;
651 >        
652 >        if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
653                  return 1;
654          
655          if (!sigsegv_install_handler(sigsegv_test_handler))
# Line 284 | Line 661 | int main(void)
661          if (handler_called != 1)
662                  return 1;
663  
664 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
665 +        if (!sigsegv_install_handler(sigsegv_insn_handler))
666 +                return 1;
667 +        
668 +        if (vm_protect((char *)page, page_size, VM_PAGE_WRITE) < 0)
669 +                return 1;
670 +        
671 +        for (int i = 0; i < page_size; i++)
672 +                page[i] = (i + 1) % page_size;
673 +        
674 +        if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
675 +                return 1;
676 +        
677 +        sigsegv_set_ignore_state(true);
678 +
679 + #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
680 +                const unsigned int TAG = 0x12345678;                    \
681 +                TYPE data = *((TYPE *)(page + sizeof(TYPE)));   \
682 +                volatile unsigned int effect = data + TAG;              \
683 +                if (effect != TAG)                                                              \
684 +                        return 1;                                                                       \
685 +        } while (0)
686 +        
687 +        TEST_SKIP_INSTRUCTION(unsigned char);
688 +        TEST_SKIP_INSTRUCTION(unsigned short);
689 +        TEST_SKIP_INSTRUCTION(unsigned int);
690 + #endif
691 +
692 +        vm_exit();
693          return 0;
694   }
695   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines