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.8 by cebix, 2002-02-01T19:25:49Z vs.
Revision 1.19 by gbeauche, 2002-06-27T14:28:59Z

# 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);
54  
55  
56   /*
57 + *  Instruction decoding aids
58 + */
59 +
60 + // Transfer type
61 + enum transfer_type_t {
62 +        TYPE_UNKNOWN,
63 +        TYPE_LOAD,
64 +        TYPE_STORE
65 + };
66 +
67 + // Transfer size
68 + enum transfer_size_t {
69 +        SIZE_UNKNOWN,
70 +        SIZE_BYTE,
71 +        SIZE_WORD,
72 +        SIZE_LONG
73 + };
74 +
75 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
76 + // Addressing mode
77 + enum addressing_mode_t {
78 +        MODE_UNKNOWN,
79 +        MODE_NORM,
80 +        MODE_U,
81 +        MODE_X,
82 +        MODE_UX
83 + };
84 +
85 + // Decoded instruction
86 + struct instruction_t {
87 +        transfer_type_t         transfer_type;
88 +        transfer_size_t         transfer_size;
89 +        addressing_mode_t       addr_mode;
90 +        unsigned int            addr;
91 +        char                            ra, rd;
92 + };
93 +
94 + static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
95 + {
96 +        // Get opcode and divide into fields
97 +        unsigned int opcode = *((unsigned int *)nip);
98 +        unsigned int primop = opcode >> 26;
99 +        unsigned int exop = (opcode >> 1) & 0x3ff;
100 +        unsigned int ra = (opcode >> 16) & 0x1f;
101 +        unsigned int rb = (opcode >> 11) & 0x1f;
102 +        unsigned int rd = (opcode >> 21) & 0x1f;
103 +        signed int imm = (signed short)(opcode & 0xffff);
104 +        
105 +        // Analyze opcode
106 +        transfer_type_t transfer_type = TYPE_UNKNOWN;
107 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
108 +        addressing_mode_t addr_mode = MODE_UNKNOWN;
109 +        switch (primop) {
110 +        case 31:
111 +                switch (exop) {
112 +                case 23:        // lwzx
113 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
114 +                case 55:        // lwzux
115 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
116 +                case 87:        // lbzx
117 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
118 +                case 119:       // lbzux
119 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
120 +                case 151:       // stwx
121 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
122 +                case 183:       // stwux
123 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
124 +                case 215:       // stbx
125 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
126 +                case 247:       // stbux
127 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
128 +                case 279:       // lhzx
129 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
130 +                case 311:       // lhzux
131 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
132 +                case 343:       // lhax
133 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
134 +                case 375:       // lhaux
135 +                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
136 +                case 407:       // sthx
137 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
138 +                case 439:       // sthux
139 +                        transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
140 +                }
141 +                break;
142 +        
143 +        case 32:        // lwz
144 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
145 +        case 33:        // lwzu
146 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
147 +        case 34:        // lbz
148 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
149 +        case 35:        // lbzu
150 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
151 +        case 36:        // stw
152 +                transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
153 +        case 37:        // stwu
154 +                transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
155 +        case 38:        // stb
156 +                transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
157 +        case 39:        // stbu
158 +                transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
159 +        case 40:        // lhz
160 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
161 +        case 41:        // lhzu
162 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
163 +        case 42:        // lha
164 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
165 +        case 43:        // lhau
166 +                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
167 +        case 44:        // sth
168 +                transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
169 +        case 45:        // sthu
170 +                transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
171 +        }
172 +        
173 +        // Calculate effective address
174 +        unsigned int addr = 0;
175 +        switch (addr_mode) {
176 +        case MODE_X:
177 +        case MODE_UX:
178 +                if (ra == 0)
179 +                        addr = gpr[rb];
180 +                else
181 +                        addr = gpr[ra] + gpr[rb];
182 +                break;
183 +        case MODE_NORM:
184 +        case MODE_U:
185 +                if (ra == 0)
186 +                        addr = (signed int)(signed short)imm;
187 +                else
188 +                        addr = gpr[ra] + (signed int)(signed short)imm;
189 +                break;
190 +        default:
191 +                break;
192 +        }
193 +        
194 +        // Commit decoded instruction
195 +        instruction->addr = addr;
196 +        instruction->addr_mode = addr_mode;
197 +        instruction->transfer_type = transfer_type;
198 +        instruction->transfer_size = transfer_size;
199 +        instruction->ra = ra;
200 +        instruction->rd = rd;
201 + }
202 + #endif
203 +
204 +
205 + /*
206   *  OS-dependant SIGSEGV signals support section
207   */
208  
# Line 60 | Line 215 | static bool sigsegv_do_install_handler(i
215   #endif
216   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *scp
217   #define SIGSEGV_FAULT_ADDRESS                   sip->si_addr
218 + #if defined(__NetBSD__) || defined(__FreeBSD__)
219 + #if (defined(i386) || defined(__i386__))
220 + #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_eip)
221 + #define SIGSEGV_REGISTER_FILE                   ((unsigned int *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
222 + /* (gb) Disable because this would hang configure script for some reason
223 + * though standalone testing gets it right. Any idea why?
224 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
225 + */
226 + #endif
227 + #endif
228   #if defined(__linux__)
229   #if (defined(i386) || defined(__i386__))
230   #include <sys/ucontext.h>
231 < #define SIGSEGV_FAULT_INSTRUCTION               (((ucontext_t *)scp)->uc_mcontext.gregs[14]) /* should use REG_EIP instead */
231 > #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
232 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
233 > #define SIGSEGV_REGISTER_FILE                   (unsigned int *)SIGSEGV_CONTEXT_REGS
234 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
235   #endif
236   #if (defined(ia64) || defined(__ia64__))
237   #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
238   #endif
239 + #if (defined(powerpc) || defined(__powerpc__))
240 + #include <sys/ucontext.h>
241 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.regs)
242 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->nip)
243 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
244 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
245 + #endif
246   #endif
247   #endif
248  
# Line 80 | Line 255 | static bool sigsegv_do_install_handler(i
255   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
256   #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
257   #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
258 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)(&scs)
259 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
260   #endif
261   #if (defined(sparc) || defined(__sparc__))
262   #include <asm/sigcontext.h>
# Line 91 | Line 268 | static bool sigsegv_do_install_handler(i
268   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
269   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
270   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
271 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
272 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
273   #endif
274   #if (defined(alpha) || defined(__alpha__))
275   #include <asm/sigcontext.h>
# Line 111 | Line 290 | static sigsegv_address_t get_fault_addre
290  
291   // Irix 5 or 6 on MIPS
292   #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
293 + #include <ucontext.h>
294   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
295   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
296   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
297   #endif
298  
299 + // HP-UX
300 + #if (defined(hpux) || defined(__hpux__))
301 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
302 + #define SIGSEGV_FAULT_ADDRESS                   scp->sc_sl.sl_ss.ss_narrow.ss_cr21
303 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
304 + #endif
305 +
306   // OSF/1 on Alpha
307   #if defined(__osf__)
308 + #include <ucontext.h>
309   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
310   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_traparg_a0
311   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
# Line 135 | Line 323 | static sigsegv_address_t get_fault_addre
323   #if (defined(m68k) || defined(__m68k__))
324   #include <m68k/frame.h>
325   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
326 < #define SIGSEGV_FAULT_ADDRESS                   ({                                                                                                                              \
139 <        struct sigstate {                                                                                                                                                                       \
140 <                int ss_flags;                                                                                                                                                                   \
141 <                struct frame ss_frame;                                                                                                                                                  \
142 <        };                                                                                                                                                                                                      \
143 <        struct sigstate *state = (struct sigstate *)scp->sc_ap;                                                                                         \
144 <        char *fault_addr;                                                                                                                                                                       \
145 <        switch (state->ss_frame.f_format) {                                                                                                                                     \
146 <        case 7:         /* 68040 access error */                                                                                                                                \
147 <                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */    \
148 <                fault_addr = state->ss_frame.f_fmt7.f_fa;                                                                                                               \
149 <                break;                                                                                                                                                                                  \
150 <        default:                                                                                                                                                                                        \
151 <                fault_addr = (char *)code;                                                                                                                                              \
152 <                break;                                                                                                                                                                                  \
153 <        }                                                                                                                                                                                                       \
154 <        fault_addr;                                                                                                                                                                                     \
155 < })
326 > #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
327   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
328 +
329 + // Use decoding scheme from BasiliskII/m68k native
330 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
331 + {
332 +        struct sigstate {
333 +                int ss_flags;
334 +                struct frame ss_frame;
335 +        };
336 +        struct sigstate *state = (struct sigstate *)scp->sc_ap;
337 +        char *fault_addr;
338 +        switch (state->ss_frame.f_format) {
339 +        case 7:         /* 68040 access error */
340 +                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
341 +                fault_addr = state->ss_frame.f_fmt7.f_fa;
342 +                break;
343 +        default:
344 +                fault_addr = (char *)code;
345 +                break;
346 +        }
347 +        return (sigsegv_address_t)fault_addr;
348 + }
349   #else
350   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, void *scp, char *addr
351   #define SIGSEGV_FAULT_ADDRESS                   addr
# Line 168 | Line 360 | static sigsegv_address_t get_fault_addre
360   #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
361   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
362   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
363 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
364 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
365  
366 < // From Boehm's GC 6.0alpha8
173 < #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
174 < #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
175 < #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
176 < #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
177 < #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
178 < #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
179 <
366 > // Use decoding scheme from SheepShaver
367   static sigsegv_address_t get_fault_address(struct sigcontext *scp)
368   {
369 <        unsigned int   instr = *((unsigned int *) scp->sc_ir);
370 <        unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
371 <        int            disp = 0, tmp;
372 <        unsigned int   baseA = 0, baseB = 0;
373 <        unsigned int   addr, alignmask = 0xFFFFFFFF;
374 <
375 <        switch(EXTRACT_OP1(instr)) {
376 <        case 38:   /* stb */
377 <        case 39:   /* stbu */
378 <        case 54:   /* stfd */
379 <        case 55:   /* stfdu */
380 <        case 52:   /* stfs */
381 <        case 53:   /* stfsu */
382 <        case 44:   /* sth */
383 <        case 45:   /* sthu */
384 <        case 47:   /* stmw */
385 <        case 36:   /* stw */
386 <        case 37:   /* stwu */
387 <                tmp = EXTRACT_REGA(instr);
388 <                if(tmp > 0)
389 <                        baseA = regs[tmp];
390 <                disp = EXTRACT_DISP(instr);
369 >        unsigned int   nip = (unsigned int) scp->sc_ir;
370 >        unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
371 >        instruction_t  instr;
372 >
373 >        powerpc_decode_instruction(&instr, nip, gpr);
374 >        return (sigsegv_address_t)instr.addr;
375 > }
376 > #endif
377 > #endif
378 > #endif
379 >
380 >
381 > /*
382 > *  Instruction skipping
383 > */
384 >
385 > #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
386 > // Decode and skip X86 instruction
387 > #if (defined(i386) || defined(__i386__))
388 > #if defined(__linux__)
389 > enum {
390 >        X86_REG_EIP = 14,
391 >        X86_REG_EAX = 11,
392 >        X86_REG_ECX = 10,
393 >        X86_REG_EDX = 9,
394 >        X86_REG_EBX = 8,
395 >        X86_REG_ESP = 7,
396 >        X86_REG_EBP = 6,
397 >        X86_REG_ESI = 5,
398 >        X86_REG_EDI = 4
399 > };
400 > #endif
401 > #if defined(__NetBSD__) || defined(__FreeBSD__)
402 > enum {
403 >        X86_REG_EIP = 10,
404 >        X86_REG_EAX = 7,
405 >        X86_REG_ECX = 6,
406 >        X86_REG_EDX = 5,
407 >        X86_REG_EBX = 4,
408 >        X86_REG_ESP = 13,
409 >        X86_REG_EBP = 2,
410 >        X86_REG_ESI = 1,
411 >        X86_REG_EDI = 0
412 > };
413 > #endif
414 > // FIXME: this is partly redundant with the instruction decoding phase
415 > // to discover transfer type and register number
416 > static inline int ix86_step_over_modrm(unsigned char * p)
417 > {
418 >        int mod = (p[0] >> 6) & 3;
419 >        int rm = p[0] & 7;
420 >        int offset = 0;
421 >
422 >        // ModR/M Byte
423 >        switch (mod) {
424 >        case 0: // [reg]
425 >                if (rm == 5) return 4; // disp32
426                  break;
427 <        case 31:
428 <                switch(EXTRACT_OP2(instr)) {
429 <                case 86:    /* dcbf */
430 <                case 54:    /* dcbst */
431 <                case 1014:  /* dcbz */
432 <                case 247:   /* stbux */
433 <                case 215:   /* stbx */
434 <                case 759:   /* stfdux */
435 <                case 727:   /* stfdx */
436 <                case 983:   /* stfiwx */
437 <                case 695:   /* stfsux */
438 <                case 663:   /* stfsx */
439 <                case 918:   /* sthbrx */
440 <                case 439:   /* sthux */
441 <                case 407:   /* sthx */
442 <                case 661:   /* stswx */
443 <                case 662:   /* stwbrx */
444 <                case 150:   /* stwcx. */
445 <                case 183:   /* stwux */
446 <                case 151:   /* stwx */
447 <                case 135:   /* stvebx */
448 <                case 167:   /* stvehx */
449 <                case 199:   /* stvewx */
450 <                case 231:   /* stvx */
451 <                case 487:   /* stvxl */
452 <                        tmp = EXTRACT_REGA(instr);
453 <                        if(tmp > 0)
454 <                                baseA = regs[tmp];
455 <                        baseB = regs[EXTRACT_REGC(instr)];
456 <                        /* determine Altivec alignment mask */
457 <                        switch(EXTRACT_OP2(instr)) {
458 <                        case 167:   /* stvehx */
459 <                                alignmask = 0xFFFFFFFE;
460 <                                break;
461 <                        case 199:   /* stvewx */
462 <                                alignmask = 0xFFFFFFFC;
463 <                                break;
464 <                        case 231:   /* stvx */
465 <                                alignmask = 0xFFFFFFF0;
466 <                                break;
467 <                        case 487:  /* stvxl */
468 <                                alignmask = 0xFFFFFFF0;
469 <                                break;
470 <                        }
427 >        case 1: // disp8[reg]
428 >                offset = 1;
429 >                break;
430 >        case 2: // disp32[reg]
431 >                offset = 4;
432 >                break;
433 >        case 3: // register
434 >                return 0;
435 >        }
436 >        
437 >        // SIB Byte
438 >        if (rm == 4) {
439 >                if (mod == 0 && (p[1] & 7) == 5)
440 >                        offset = 5; // disp32[index]
441 >                else
442 >                        offset++;
443 >        }
444 >
445 >        return offset;
446 > }
447 >
448 > static bool ix86_skip_instruction(unsigned int * regs)
449 > {
450 >        unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
451 >
452 >        if (eip == 0)
453 >                return false;
454 >        
455 >        transfer_type_t transfer_type = TYPE_UNKNOWN;
456 >        transfer_size_t transfer_size = SIZE_LONG;
457 >        
458 >        int reg = -1;
459 >        int len = 0;
460 >        
461 >        // Operand size prefix
462 >        if (*eip == 0x66) {
463 >                eip++;
464 >                len++;
465 >                transfer_size = SIZE_WORD;
466 >        }
467 >
468 >        // Decode instruction
469 >        switch (eip[0]) {
470 >        case 0x0f:
471 >            switch (eip[1]) {
472 >            case 0xb6: // MOVZX r32, r/m8
473 >            case 0xb7: // MOVZX r32, r/m16
474 >                switch (eip[2] & 0xc0) {
475 >                case 0x80:
476 >                    reg = (eip[2] >> 3) & 7;
477 >                    transfer_type = TYPE_LOAD;
478 >                    break;
479 >                case 0x40:
480 >                    reg = (eip[2] >> 3) & 7;
481 >                    transfer_type = TYPE_LOAD;
482 >                    break;
483 >                case 0x00:
484 >                    reg = (eip[2] >> 3) & 7;
485 >                    transfer_type = TYPE_LOAD;
486 >                    break;
487 >                }
488 >                len += 3 + ix86_step_over_modrm(eip + 2);
489 >                break;
490 >            }
491 >          break;
492 >        case 0x8a: // MOV r8, r/m8
493 >                transfer_size = SIZE_BYTE;
494 >        case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
495 >                switch (eip[1] & 0xc0) {
496 >                case 0x80:
497 >                        reg = (eip[1] >> 3) & 7;
498 >                        transfer_type = TYPE_LOAD;
499                          break;
500 <                case 725:   /* stswi */
501 <                        tmp = EXTRACT_REGA(instr);
502 <                        if(tmp > 0)
253 <                                baseA = regs[tmp];
500 >                case 0x40:
501 >                        reg = (eip[1] >> 3) & 7;
502 >                        transfer_type = TYPE_LOAD;
503                          break;
504 <                default:   /* ignore instruction */
505 <                        return 0;
504 >                case 0x00:
505 >                        reg = (eip[1] >> 3) & 7;
506 >                        transfer_type = TYPE_LOAD;
507                          break;
508                  }
509 +                len += 2 + ix86_step_over_modrm(eip + 1);
510                  break;
511 <        default:   /* ignore instruction */
512 <                return 0;
511 >        case 0x88: // MOV r/m8, r8
512 >                transfer_size = SIZE_BYTE;
513 >        case 0x89: // MOV r/m32, r32 (or 16-bit operation)
514 >                switch (eip[1] & 0xc0) {
515 >                case 0x80:
516 >                        reg = (eip[1] >> 3) & 7;
517 >                        transfer_type = TYPE_STORE;
518 >                        break;
519 >                case 0x40:
520 >                        reg = (eip[1] >> 3) & 7;
521 >                        transfer_type = TYPE_STORE;
522 >                        break;
523 >                case 0x00:
524 >                        reg = (eip[1] >> 3) & 7;
525 >                        transfer_type = TYPE_STORE;
526 >                        break;
527 >                }
528 >                len += 2 + ix86_step_over_modrm(eip + 1);
529                  break;
530          }
531 +
532 +        if (transfer_type == TYPE_UNKNOWN) {
533 +                // Unknown machine code, let it crash. Then patch the decoder
534 +                return false;
535 +        }
536 +
537 +        if (transfer_type == TYPE_LOAD && reg != -1) {
538 +                static const int x86_reg_map[8] = {
539 +                        X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
540 +                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
541 +                };
542 +                
543 +                if (reg < 0 || reg >= 8)
544 +                        return false;
545 +
546 +                int rloc = x86_reg_map[reg];
547 +                switch (transfer_size) {
548 +                case SIZE_BYTE:
549 +                        regs[rloc] = (regs[rloc] & ~0xff);
550 +                        break;
551 +                case SIZE_WORD:
552 +                        regs[rloc] = (regs[rloc] & ~0xffff);
553 +                        break;
554 +                case SIZE_LONG:
555 +                        regs[rloc] = 0;
556 +                        break;
557 +                }
558 +        }
559 +
560 + #if DEBUG
561 +        printf("%08x: %s %s access", regs[X86_REG_EIP],
562 +                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
563 +                   transfer_type == TYPE_LOAD ? "read" : "write");
564 +        
565 +        if (reg != -1) {
566 +                static const char * x86_reg_str_map[8] = {
567 +                        "eax", "ecx", "edx", "ebx",
568 +                        "esp", "ebp", "esi", "edi"
569 +                };
570 +                printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
571 +        }
572 +        printf(", %d bytes instruction\n", len);
573 + #endif
574          
575 <        addr = (baseA + baseB) + disp;
576 <        addr &= alignmask;
267 <        return (sigsegv_address_t)addr;
575 >        regs[X86_REG_EIP] += len;
576 >        return true;
577   }
578   #endif
579 +
580 + // Decode and skip PPC instruction
581 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
582 + static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
583 + {
584 +        instruction_t instr;
585 +        powerpc_decode_instruction(&instr, *nip_p, regs);
586 +        
587 +        if (instr.transfer_type == TYPE_UNKNOWN) {
588 +                // Unknown machine code, let it crash. Then patch the decoder
589 +                return false;
590 +        }
591 +
592 + #if DEBUG
593 +        printf("%08x: %s %s access", *nip_p,
594 +                   instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
595 +                   instr.transfer_type == TYPE_LOAD ? "read" : "write");
596 +        
597 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
598 +                printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
599 +        if (instr.transfer_type == TYPE_LOAD)
600 +                printf(" r%d (rd = 0)\n", instr.rd);
601 + #endif
602 +        
603 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
604 +                regs[instr.ra] = instr.addr;
605 +        if (instr.transfer_type == TYPE_LOAD)
606 +                regs[instr.rd] = 0;
607 +        
608 +        *nip_p += 4;
609 +        return true;
610 + }
611   #endif
612   #endif
613  
# Line 288 | Line 629 | static sigsegv_address_t get_fault_addre
629   #ifdef HAVE_SIGSEGV_RECOVERY
630   static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
631   {
632 +        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
633 +        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
634 +        bool fault_recovered = false;
635 +        
636          // Call user's handler and reinstall the global handler, if required
637 <        if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
637 >        if (sigsegv_fault_handler(fault_address, fault_instruction)) {
638   #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
639                  sigsegv_do_install_handler(sig);
640   #endif
641 +                fault_recovered = true;
642 +        }
643 + #if HAVE_SIGSEGV_SKIP_INSTRUCTION
644 +        else if (sigsegv_ignore_fault) {
645 +                // Call the instruction skipper with the register file available
646 +                if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
647 +                        fault_recovered = true;
648          }
649 <        else {
649 > #endif
650 >
651 >        if (!fault_recovered) {
652                  // FAIL: reinstall default handler for "safe" crash
653   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
654                  SIGSEGV_ALL_SIGNALS
655   #undef FAULT_HANDLER
656 +                
657 +                // We can't do anything with the fault_address, dump state?
658 +                if (sigsegv_state_dumper != 0)
659 +                        sigsegv_state_dumper(fault_address, fault_instruction);
660          }
661   }
662   #endif
# Line 345 | Line 703 | static bool sigsegv_do_install_handler(i
703   }
704   #endif
705  
706 < bool sigsegv_install_handler(sigsegv_handler_t handler)
706 > bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
707   {
708   #ifdef HAVE_SIGSEGV_RECOVERY
709 <        sigsegv_user_handler = handler;
709 >        sigsegv_fault_handler = handler;
710          bool success = true;
711   #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
712          SIGSEGV_ALL_SIGNALS
# Line 368 | Line 726 | bool sigsegv_install_handler(sigsegv_han
726   void sigsegv_deinstall_handler(void)
727   {
728   #ifdef HAVE_SIGSEGV_RECOVERY
729 <        sigsegv_user_handler = 0;
729 >        sigsegv_fault_handler = 0;
730   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
731          SIGSEGV_ALL_SIGNALS
732   #undef FAULT_HANDLER
733   #endif
734   }
735  
736 +
737 + /*
738 + *  SIGSEGV ignore state modifier
739 + */
740 +
741 + void sigsegv_set_ignore_state(bool ignore_fault)
742 + {
743 +        sigsegv_ignore_fault = ignore_fault;
744 + }
745 +
746 +
747 + /*
748 + *  Set callback function when we cannot handle the fault
749 + */
750 +
751 + void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
752 + {
753 +        sigsegv_state_dumper = handler;
754 + }
755 +
756 +
757   /*
758   *  Test program used for configure/test
759   */
# Line 400 | Line 779 | static bool sigsegv_test_handler(sigsegv
779          return true;
780   }
781  
782 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
783 + static bool sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
784 + {
785 +        return false;
786 + }
787 + #endif
788 +
789   int main(void)
790   {
791          if (vm_init() < 0)
# Line 421 | Line 807 | int main(void)
807          if (handler_called != 1)
808                  return 1;
809  
810 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
811 +        if (!sigsegv_install_handler(sigsegv_insn_handler))
812 +                return 1;
813 +        
814 +        if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
815 +                return 1;
816 +        
817 +        for (int i = 0; i < page_size; i++)
818 +                page[i] = (i + 1) % page_size;
819 +        
820 +        if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
821 +                return 1;
822 +        
823 +        sigsegv_set_ignore_state(true);
824 +
825 + #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
826 +                const unsigned int TAG = 0x12345678;                    \
827 +                TYPE data = *((TYPE *)(page + sizeof(TYPE)));   \
828 +                volatile unsigned int effect = data + TAG;              \
829 +                if (effect != TAG)                                                              \
830 +                        return 1;                                                                       \
831 +        } while (0)
832 +        
833 +        TEST_SKIP_INSTRUCTION(unsigned char);
834 +        TEST_SKIP_INSTRUCTION(unsigned short);
835 +        TEST_SKIP_INSTRUCTION(unsigned int);
836 + #endif
837 +
838          vm_exit();
839          return 0;
840   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines