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.2 by gbeauche, 2001-05-21T03:21:54Z vs.
Revision 1.13 by gbeauche, 2002-05-19T21:58:42Z

# 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;
47 > static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
48 >
49 > // Function called to dump state if we can't handle the fault
50 > static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
51  
52   // Actual SIGSEGV handler installer
53   static bool sigsegv_do_install_handler(int sig);
# 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 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(((ucontext_t *)scp)->uc_mcontext.regs)
83 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
84 + #endif
85 + #endif
86   #endif
87  
88   #if HAVE_SIGCONTEXT_SUBTERFUGE
# Line 67 | Line 94 | static bool sigsegv_do_install_handler(i
94   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
95   #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
96   #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
97 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(&scs)
98 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
99   #endif
100   #if (defined(sparc) || defined(__sparc__))
101   #include <asm/sigcontext.h>
102 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext* scp, char* addr
102 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
103   #define SIGSEGV_FAULT_ADDRESS                   addr
104   #endif
105   #if (defined(powerpc) || defined(__powerpc__))
106   #include <asm/sigcontext.h>
107 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext* scp
107 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
108   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
109   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
110 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(scp->regs)
111 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
112 + #endif
113 + #if (defined(alpha) || defined(__alpha__))
114 + #include <asm/sigcontext.h>
115 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
116 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
117 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
118 +
119 + // From Boehm's GC 6.0alpha8
120 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
121 + {
122 +        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
123 +        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
124 +        fault_address += (signed long)(signed short)(instruction & 0xffff);
125 +        return (sigsegv_address_t)fault_address;
126 + }
127   #endif
128   #endif
129  
130   // Irix 5 or 6 on MIPS
131   #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
132 + #include <ucontext.h>
133   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
134   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
135   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
136   #endif
137  
138 + // HP-UX
139 + #if (defined(hpux) || defined(__hpux__))
140 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
141 + #define SIGSEGV_FAULT_ADDRESS                   scp->sc_sl.sl_ss.ss_narrow.ss_cr21
142 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
143 + #endif
144 +
145   // OSF/1 on Alpha
146   #if defined(__osf__)
147 + #include <ucontext.h>
148   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
149   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_traparg_a0
150   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
# Line 132 | Line 187 | static bool sigsegv_do_install_handler(i
187   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
188   #endif
189   #endif
190 +
191 + // MacOS X
192 + #if defined(__APPLE__) && defined(__MACH__)
193 + #if (defined(ppc) || defined(__ppc__))
194 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
195 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
196 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
197 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
198 +
199 + // From Boehm's GC 6.0alpha8
200 + #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
201 + #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
202 + #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
203 + #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
204 + #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
205 + #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
206 +
207 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
208 + {
209 +        unsigned int   instr = *((unsigned int *) scp->sc_ir);
210 +        unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
211 +        int            disp = 0, tmp;
212 +        unsigned int   baseA = 0, baseB = 0;
213 +        unsigned int   addr, alignmask = 0xFFFFFFFF;
214 +
215 +        switch(EXTRACT_OP1(instr)) {
216 +        case 38:   /* stb */
217 +        case 39:   /* stbu */
218 +        case 54:   /* stfd */
219 +        case 55:   /* stfdu */
220 +        case 52:   /* stfs */
221 +        case 53:   /* stfsu */
222 +        case 44:   /* sth */
223 +        case 45:   /* sthu */
224 +        case 47:   /* stmw */
225 +        case 36:   /* stw */
226 +        case 37:   /* stwu */
227 +                tmp = EXTRACT_REGA(instr);
228 +                if(tmp > 0)
229 +                        baseA = regs[tmp];
230 +                disp = EXTRACT_DISP(instr);
231 +                break;
232 +        case 31:
233 +                switch(EXTRACT_OP2(instr)) {
234 +                case 86:    /* dcbf */
235 +                case 54:    /* dcbst */
236 +                case 1014:  /* dcbz */
237 +                case 247:   /* stbux */
238 +                case 215:   /* stbx */
239 +                case 759:   /* stfdux */
240 +                case 727:   /* stfdx */
241 +                case 983:   /* stfiwx */
242 +                case 695:   /* stfsux */
243 +                case 663:   /* stfsx */
244 +                case 918:   /* sthbrx */
245 +                case 439:   /* sthux */
246 +                case 407:   /* sthx */
247 +                case 661:   /* stswx */
248 +                case 662:   /* stwbrx */
249 +                case 150:   /* stwcx. */
250 +                case 183:   /* stwux */
251 +                case 151:   /* stwx */
252 +                case 135:   /* stvebx */
253 +                case 167:   /* stvehx */
254 +                case 199:   /* stvewx */
255 +                case 231:   /* stvx */
256 +                case 487:   /* stvxl */
257 +                        tmp = EXTRACT_REGA(instr);
258 +                        if(tmp > 0)
259 +                                baseA = regs[tmp];
260 +                        baseB = regs[EXTRACT_REGC(instr)];
261 +                        /* determine Altivec alignment mask */
262 +                        switch(EXTRACT_OP2(instr)) {
263 +                        case 167:   /* stvehx */
264 +                                alignmask = 0xFFFFFFFE;
265 +                                break;
266 +                        case 199:   /* stvewx */
267 +                                alignmask = 0xFFFFFFFC;
268 +                                break;
269 +                        case 231:   /* stvx */
270 +                                alignmask = 0xFFFFFFF0;
271 +                                break;
272 +                        case 487:  /* stvxl */
273 +                                alignmask = 0xFFFFFFF0;
274 +                                break;
275 +                        }
276 +                        break;
277 +                case 725:   /* stswi */
278 +                        tmp = EXTRACT_REGA(instr);
279 +                        if(tmp > 0)
280 +                                baseA = regs[tmp];
281 +                        break;
282 +                default:   /* ignore instruction */
283 +                        return 0;
284 +                        break;
285 +                }
286 +                break;
287 +        default:   /* ignore instruction */
288 +                return 0;
289 +                break;
290 +        }
291 +        
292 +        addr = (baseA + baseB) + disp;
293 +        addr &= alignmask;
294 +        return (sigsegv_address_t)addr;
295 + }
296 + #endif
297 + #endif
298 + #endif
299 +
300 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
301 + // Decode and skip X86 instruction
302 + #if (defined(i386) || defined(__i386__))
303 + #if defined(__linux__)
304 + enum {
305 +        X86_REG_EIP = 14,
306 +        X86_REG_EAX = 11,
307 +        X86_REG_ECX = 10,
308 +        X86_REG_EDX = 9,
309 +        X86_REG_EBX = 8,
310 +        X86_REG_ESP = 7,
311 +        X86_REG_EBP = 6,
312 +        X86_REG_ESI = 5,
313 +        X86_REG_EDI = 4
314 + };
315 + #endif
316 + // FIXME: this is partly redundant with the instruction decoding phase
317 + // to discover transfer type and register number
318 + static inline int ix86_step_over_modrm(unsigned char * p)
319 + {
320 +        int mod = (p[0] >> 6) & 3;
321 +        int rm = p[0] & 7;
322 +        int offset = 0;
323 +
324 +        // ModR/M Byte
325 +        switch (mod) {
326 +        case 0: // [reg]
327 +                if (rm == 5) return 4; // disp32
328 +                break;
329 +        case 1: // disp8[reg]
330 +                offset = 1;
331 +                break;
332 +        case 2: // disp32[reg]
333 +                offset = 4;
334 +                break;
335 +        case 3: // register
336 +                return 0;
337 +        }
338 +        
339 +        // SIB Byte
340 +        if (rm == 4) {
341 +                if (mod == 0 && (p[1] & 7) == 5)
342 +                        offset = 5; // disp32[index]
343 +                else
344 +                        offset++;
345 +        }
346 +
347 +        return offset;
348 + }
349 +
350 + static bool ix86_skip_instruction(sigsegv_address_t fault_instruction, unsigned long * regs)
351 + {
352 +        unsigned char * eip = (unsigned char *)fault_instruction;
353 +
354 +        if (eip == 0)
355 +                return false;
356 +        
357 +        // Transfer type
358 +        enum {
359 +                TYPE_UNKNOWN,
360 +                TYPE_LOAD,
361 +                TYPE_STORE
362 +        } transfer_type = TYPE_UNKNOWN;
363 +        
364 +        // Transfer size
365 +        enum {
366 +                SIZE_BYTE,
367 +                SIZE_WORD,
368 +                SIZE_LONG
369 +        } transfer_size = SIZE_LONG;
370 +        
371 +        int reg = -1;
372 +        int len = 0;
373 +        
374 +        // Operand size prefix
375 +        if (*eip == 0x66) {
376 +                eip++;
377 +                len++;
378 +                transfer_size = SIZE_WORD;
379 +        }
380 +
381 +        // Decode instruction
382 +        switch (eip[0]) {
383 +        case 0x8a: // MOV r8, r/m8
384 +                transfer_size = SIZE_BYTE;
385 +        case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
386 +                switch (eip[1] & 0xc0) {
387 +                case 0x80:
388 +                        reg = (eip[1] >> 3) & 7;
389 +                        transfer_type = TYPE_LOAD;
390 +                        break;
391 +                case 0x40:
392 +                        reg = (eip[1] >> 3) & 7;
393 +                        transfer_type = TYPE_LOAD;
394 +                        break;
395 +                case 0x00:
396 +                        reg = (eip[1] >> 3) & 7;
397 +                        transfer_type = TYPE_LOAD;
398 +                        break;
399 +                }
400 +                len += 2 + ix86_step_over_modrm(eip + 1);
401 +                break;
402 +        case 0x88: // MOV r/m8, r8
403 +                transfer_size = SIZE_BYTE;
404 +        case 0x89: // MOV r/m32, r32 (or 16-bit operation)
405 +                switch (eip[1] & 0xc0) {
406 +                case 0x80:
407 +                        reg = (eip[1] >> 3) & 7;
408 +                        transfer_type = TYPE_STORE;
409 +                        break;
410 +                case 0x40:
411 +                        reg = (eip[1] >> 3) & 7;
412 +                        transfer_type = TYPE_STORE;
413 +                        break;
414 +                case 0x00:
415 +                        reg = (eip[1] >> 3) & 7;
416 +                        transfer_type = TYPE_STORE;
417 +                        break;
418 +                }
419 +                len += 2 + ix86_step_over_modrm(eip + 1);
420 +                break;
421 +        }
422 +
423 +        if (transfer_type == TYPE_UNKNOWN) {
424 +                // Unknown machine code, let it crash. Then patch the decoder
425 +                return false;
426 +        }
427 +
428 +        if (transfer_type == TYPE_LOAD && reg != -1) {
429 +                static const int x86_reg_map[8] = {
430 +                        X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
431 +                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
432 +                };
433 +                
434 +                if (reg < 0 || reg >= 8)
435 +                        return false;
436 +
437 +                int rloc = x86_reg_map[reg];
438 +                switch (transfer_size) {
439 +                case SIZE_BYTE:
440 +                        regs[rloc] = (regs[rloc] & ~0xff);
441 +                        break;
442 +                case SIZE_WORD:
443 +                        regs[rloc] = (regs[rloc] & ~0xffff);
444 +                        break;
445 +                case SIZE_LONG:
446 +                        regs[rloc] = 0;
447 +                        break;
448 +                }
449 +        }
450 +
451 + #if DEBUG
452 +        printf("%08x: %s %s access", fault_instruction,
453 +                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
454 +                   transfer_type == TYPE_LOAD ? "read" : "write");
455 +        
456 +        if (reg != -1) {
457 +                static const char * x86_reg_str_map[8] = {
458 +                        "eax", "ecx", "edx", "ebx",
459 +                        "esp", "ebp", "esi", "edi"
460 +                };
461 +                printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
462 +        }
463 +        printf(", %d bytes instruction\n", len);
464 + #endif
465 +        
466 +        regs[X86_REG_EIP] += len;
467 +        return true;
468 + }
469 + #endif
470 + // Decode and skip PPC instruction
471 + #if (defined(powerpc) || defined(__powerpc__))
472 + #if defined(__linux__)
473 + enum {
474 +        POWERPC_REG_GPR = 0,
475 +        POWERPC_REG_NIP = 32
476 + };
477 + #endif
478 + static bool powerpc_skip_instruction(sigsegv_address_t fault_instruction, unsigned long * regs)
479 + {
480 +        // Get opcode and divide into fields
481 +        unsigned int opcode = *((unsigned int *)fault_instruction);
482 +        unsigned int primop = opcode >> 26;
483 +        unsigned int exop = (opcode >> 1) & 0x3ff;
484 +        unsigned int ra = (opcode >> 16) & 0x1f;
485 +        unsigned int rb = (opcode >> 11) & 0x1f;
486 +        unsigned int rd = (opcode >> 21) & 0x1f;
487 +        signed int imm = (signed short)(opcode & 0xffff);
488 +        
489 +        // Analyze opcode
490 +        enum {
491 +                TYPE_UNKNOWN,
492 +                TYPE_LOAD,
493 +                TYPE_STORE
494 +        } transfer_type = TYPE_UNKNOWN;
495 +        enum {
496 +                SIZE_UNKNOWN,
497 +                SIZE_BYTE,
498 +                SIZE_HALFWORD,
499 +                SIZE_WORD
500 +        } transfer_size = SIZE_UNKNOWN;
501 +        enum {
502 +                MODE_UNKNOWN,
503 +                MODE_NORM,
504 +                MODE_U,
505 +                MODE_X,
506 +                MODE_UX
507 +        } addr_mode = MODE_UNKNOWN;
508 +        switch (primop) {
509 +        case 31:
510 +                switch (exop) {
511 +                case 23:        // lwzx
512 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
513 +                case 55:        // lwzux
514 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
515 +                case 87:        // lbzx
516 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
517 +                case 119:       // lbzux
518 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
519 +                case 151:       // stwx
520 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
521 +                case 183:       // stwux
522 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
523 +                case 215:       // stbx
524 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
525 +                case 247:       // stbux
526 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
527 +                case 279:       // lhzx
528 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
529 +                case 311:       // lhzux
530 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
531 +                case 343:       // lhax
532 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
533 +                case 375:       // lhaux
534 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
535 +                case 407:       // sthx
536 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
537 +                case 439:       // sthux
538 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
539 +                }
540 +                break;
541 +        
542 +        case 32:        // lwz
543 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
544 +        case 33:        // lwzu
545 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
546 +        case 34:        // lbz
547 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
548 +        case 35:        // lbzu
549 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
550 +        case 36:        // stw
551 +                transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
552 +        case 37:        // stwu
553 +                transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
554 +        case 38:        // stb
555 +                transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
556 +        case 39:        // stbu
557 +                transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
558 +        case 40:        // lhz
559 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
560 +        case 41:        // lhzu
561 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
562 +        case 42:        // lha
563 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
564 +        case 43:        // lhau
565 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
566 +        case 44:        // sth
567 +                transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
568 +        case 45:        // sthu
569 +                transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
570 +        }
571 +        
572 +        // Calculate effective address
573 +        unsigned int addr = 0;
574 +        switch (addr_mode) {
575 +        case MODE_X:
576 +        case MODE_UX:
577 +                if (ra == 0)
578 +                        addr = regs[POWERPC_REG_GPR + rb];
579 +                else
580 +                        addr = regs[POWERPC_REG_GPR + ra] + regs[POWERPC_REG_GPR + rb];
581 +                break;
582 +        case MODE_NORM:
583 +        case MODE_U:
584 +                if (ra == 0)
585 +                        addr = (signed int)(signed short)imm;
586 +                else
587 +                        addr = regs[POWERPC_REG_GPR + ra] + (signed int)(signed short)imm;
588 +                break;
589 +        default:
590 +                break;
591 +        }
592 +        
593 +        if (transfer_type == TYPE_UNKNOWN) {
594 +                // Unknown machine code, let it crash. Then patch the decoder
595 +                return false;
596 +        }
597 +
598 + #if DEBUG
599 +        printf("%08x: %s %s access", fault_instruction,
600 +                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "word" : "long",
601 +                   transfer_type == TYPE_LOAD ? "read" : "write");
602 +        
603 +        if (addr_mode == MODE_U || addr_mode == MODE_UX)
604 +                printf(" r%d (ra = %08x)\n", ra, addr);
605 +        if (transfer_type == TYPE_LOAD)
606 +                printf(" r%d (rd = 0)\n", rd);
607 + #endif
608 +        
609 +        if (addr_mode == MODE_U || addr_mode == MODE_UX)
610 +                regs[POWERPC_REG_GPR + ra] = addr;
611 +        if (transfer_type == TYPE_LOAD)
612 +                regs[POWERPC_REG_GPR + rd] = 0;
613 +        
614 +        regs[POWERPC_REG_NIP] += 4;
615 +        return true;
616 + }
617 + #endif
618   #endif
619  
620   // Fallbacks
# Line 152 | Line 635 | static bool sigsegv_do_install_handler(i
635   #ifdef HAVE_SIGSEGV_RECOVERY
636   static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
637   {
638 +        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
639 +        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
640 +        bool fault_recovered = false;
641 +        
642          // Call user's handler and reinstall the global handler, if required
643 <        if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
643 >        if (sigsegv_fault_handler(fault_address, fault_instruction)) {
644   #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
645                  sigsegv_do_install_handler(sig);
646   #endif
647 +                fault_recovered = true;
648          }
649 <        else {
649 > #if HAVE_SIGSEGV_SKIP_INSTRUCTION
650 >        else if (sigsegv_ignore_fault) {
651 >                // Call the instruction skipper with the register file available
652 >                if (SIGSEGV_SKIP_INSTRUCTION(fault_instruction, SIGSEGV_REGISTER_FILE))
653 >                        fault_recovered = true;
654 >        }
655 > #endif
656 >
657 >        if (!fault_recovered) {
658                  // FAIL: reinstall default handler for "safe" crash
659   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
660                  SIGSEGV_ALL_SIGNALS
661   #undef FAULT_HANDLER
662 +                
663 +                // We can't do anything with the fault_address, dump state?
664 +                if (sigsegv_state_dumper != 0)
665 +                        sigsegv_state_dumper(fault_address, fault_instruction);
666          }
667   }
668   #endif
# Line 209 | Line 709 | static bool sigsegv_do_install_handler(i
709   }
710   #endif
711  
712 < bool sigsegv_install_handler(sigsegv_handler_t handler)
712 > bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
713   {
714   #ifdef HAVE_SIGSEGV_RECOVERY
715 <        sigsegv_user_handler = handler;
715 >        sigsegv_fault_handler = handler;
716          bool success = true;
717   #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
718          SIGSEGV_ALL_SIGNALS
# Line 232 | Line 732 | bool sigsegv_install_handler(sigsegv_han
732   void sigsegv_deinstall_handler(void)
733   {
734   #ifdef HAVE_SIGSEGV_RECOVERY
735 <        sigsegv_user_handler = 0;
735 >        sigsegv_fault_handler = 0;
736   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
737          SIGSEGV_ALL_SIGNALS
738   #undef FAULT_HANDLER
739   #endif
740   }
741  
742 +
743 + /*
744 + *  SIGSEGV ignore state modifier
745 + */
746 +
747 + void sigsegv_set_ignore_state(bool ignore_fault)
748 + {
749 +        sigsegv_ignore_fault = ignore_fault;
750 + }
751 +
752 +
753 + /*
754 + *  Set callback function when we cannot handle the fault
755 + */
756 +
757 + void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
758 + {
759 +        sigsegv_state_dumper = handler;
760 + }
761 +
762 +
763   /*
764   *  Test program used for configure/test
765   */
766  
767 < #ifdef CONFIGURE_TEST
767 > #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
768   #include <stdio.h>
769   #include <stdlib.h>
249 #include <unistd.h>
770   #include <fcntl.h>
771   #include <sys/mman.h>
772 + #include "vm_alloc.h"
773  
253 static caddr_t page = 0;
774   static int page_size;
775 < static int handler_called = 0;
775 > static volatile char * page = 0;
776 > static volatile int handler_called = 0;
777  
778   static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
779   {
780          handler_called++;
781          if ((fault_address - 123) != page)
782                  exit(1);
783 <        if (mprotect((caddr_t)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0)
783 >        if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
784                  exit(1);
785          return true;
786   }
787  
788 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
789 + static bool sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
790 + {
791 +        return false;
792 + }
793 + #endif
794 +
795   int main(void)
796   {
797 <        int zero_fd = open("/dev/zero", O_RDWR);
270 <        if (zero_fd < 0)
797 >        if (vm_init() < 0)
798                  return 1;
799  
800          page_size = getpagesize();
801 <        page = (caddr_t)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0);
802 <        if (page == MAP_FAILED)
801 >        if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
802 >                return 1;
803 >        
804 >        if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
805                  return 1;
806          
807          if (!sigsegv_install_handler(sigsegv_test_handler))
# Line 284 | Line 813 | int main(void)
813          if (handler_called != 1)
814                  return 1;
815  
816 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
817 +        if (!sigsegv_install_handler(sigsegv_insn_handler))
818 +                return 1;
819 +        
820 +        if (vm_protect((char *)page, page_size, VM_PAGE_WRITE) < 0)
821 +                return 1;
822 +        
823 +        for (int i = 0; i < page_size; i++)
824 +                page[i] = (i + 1) % page_size;
825 +        
826 +        if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
827 +                return 1;
828 +        
829 +        sigsegv_set_ignore_state(true);
830 +
831 + #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
832 +                const unsigned int TAG = 0x12345678;                    \
833 +                TYPE data = *((TYPE *)(page + sizeof(TYPE)));   \
834 +                volatile unsigned int effect = data + TAG;              \
835 +                if (effect != TAG)                                                              \
836 +                        return 1;                                                                       \
837 +        } while (0)
838 +        
839 +        TEST_SKIP_INSTRUCTION(unsigned char);
840 +        TEST_SKIP_INSTRUCTION(unsigned short);
841 +        TEST_SKIP_INSTRUCTION(unsigned int);
842 + #endif
843 +
844 +        vm_exit();
845          return 0;
846   }
847   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines