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.9 by gbeauche, 2002-03-16T21:36:12Z vs.
Revision 1.26 by gbeauche, 2003-09-29T08:04:22Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines