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.1 by gbeauche, 2001-05-20T20:31:50Z vs.
Revision 1.20 by gbeauche, 2002-07-17T06:51:05Z

# 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);
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  
209   #if HAVE_SIGINFO_T
210   // Generic extended signal handler
211 + #if defined(__NetBSD__) || defined(__FreeBSD__)
212 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
213 + #else
214   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
215 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *
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_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(x86_64) || defined(__x86_64__))
237 + #include <sys/ucontext.h>
238 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
239 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
240 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
241 + #endif
242 + #if (defined(ia64) || defined(__ia64__))
243 + #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
244 + #endif
245 + #if (defined(powerpc) || defined(__powerpc__))
246 + #include <sys/ucontext.h>
247 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.regs)
248 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->nip)
249 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
250 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
251 + #endif
252 + #endif
253   #endif
254  
255   #if HAVE_SIGCONTEXT_SUBTERFUGE
# Line 67 | Line 261 | static bool sigsegv_do_install_handler(i
261   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
262   #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
263   #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
264 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)(&scs)
265 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
266   #endif
267   #if (defined(sparc) || defined(__sparc__))
268   #include <asm/sigcontext.h>
269 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext* scp, char* addr
269 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
270   #define SIGSEGV_FAULT_ADDRESS                   addr
271   #endif
272   #if (defined(powerpc) || defined(__powerpc__))
273   #include <asm/sigcontext.h>
274 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext* scp
274 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
275   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
276   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
277 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
278 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
279 + #endif
280 + #if (defined(alpha) || defined(__alpha__))
281 + #include <asm/sigcontext.h>
282 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
283 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
284 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
285 +
286 + // From Boehm's GC 6.0alpha8
287 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
288 + {
289 +        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
290 +        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
291 +        fault_address += (signed long)(signed short)(instruction & 0xffff);
292 +        return (sigsegv_address_t)fault_address;
293 + }
294   #endif
295   #endif
296  
297   // Irix 5 or 6 on MIPS
298   #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
299 + #include <ucontext.h>
300   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
301   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
302   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
303   #endif
304  
305 + // HP-UX
306 + #if (defined(hpux) || defined(__hpux__))
307 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
308 + #define SIGSEGV_FAULT_ADDRESS                   scp->sc_sl.sl_ss.ss_narrow.ss_cr21
309 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
310 + #endif
311 +
312   // OSF/1 on Alpha
313   #if defined(__osf__)
314 + #include <ucontext.h>
315   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
316   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_traparg_a0
317   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
# Line 107 | Line 329 | static bool sigsegv_do_install_handler(i
329   #if (defined(m68k) || defined(__m68k__))
330   #include <m68k/frame.h>
331   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
332 < #define SIGSEGV_FAULT_ADDRESS                   ({                                                                                                                              \
111 <        struct sigstate {                                                                                                                                                                       \
112 <                int ss_flags;                                                                                                                                                                   \
113 <                struct frame ss_frame;                                                                                                                                                  \
114 <        };                                                                                                                                                                                                      \
115 <        struct sigstate *state = (struct sigstate *)scp->sc_ap;                                                                                         \
116 <        char *fault_addr;                                                                                                                                                                       \
117 <        switch (state->ss_frame.f_format) {                                                                                                                                     \
118 <        case 7:         /* 68040 access error */                                                                                                                                \
119 <                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */    \
120 <                fault_addr = state->ss_frame.f_fmt7.f_fa;                                                                                                               \
121 <                break;                                                                                                                                                                                  \
122 <        default:                                                                                                                                                                                        \
123 <                fault_addr = (char *)code;                                                                                                                                              \
124 <                break;                                                                                                                                                                                  \
125 <        }                                                                                                                                                                                                       \
126 <        fault_addr;                                                                                                                                                                                     \
127 < })
332 > #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
333   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
334 +
335 + // Use decoding scheme from BasiliskII/m68k native
336 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
337 + {
338 +        struct sigstate {
339 +                int ss_flags;
340 +                struct frame ss_frame;
341 +        };
342 +        struct sigstate *state = (struct sigstate *)scp->sc_ap;
343 +        char *fault_addr;
344 +        switch (state->ss_frame.f_format) {
345 +        case 7:         /* 68040 access error */
346 +                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
347 +                fault_addr = state->ss_frame.f_fmt7.f_fa;
348 +                break;
349 +        default:
350 +                fault_addr = (char *)code;
351 +                break;
352 +        }
353 +        return (sigsegv_address_t)fault_addr;
354 + }
355   #else
356   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, void *scp, char *addr
357   #define SIGSEGV_FAULT_ADDRESS                   addr
358   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
359   #endif
360   #endif
361 +
362 + // MacOS X
363 + #if defined(__APPLE__) && defined(__MACH__)
364 + #if (defined(ppc) || defined(__ppc__))
365 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
366 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
367 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
368 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
369 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
370 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
371 +
372 + // Use decoding scheme from SheepShaver
373 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
374 + {
375 +        unsigned int   nip = (unsigned int) scp->sc_ir;
376 +        unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
377 +        instruction_t  instr;
378 +
379 +        powerpc_decode_instruction(&instr, nip, gpr);
380 +        return (sigsegv_address_t)instr.addr;
381 + }
382 + #endif
383 + #endif
384 + #endif
385 +
386 +
387 + /*
388 + *  Instruction skipping
389 + */
390 +
391 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
392 + // Decode and skip X86 instruction
393 + #if (defined(i386) || defined(__i386__))
394 + #if defined(__linux__)
395 + enum {
396 +        X86_REG_EIP = 14,
397 +        X86_REG_EAX = 11,
398 +        X86_REG_ECX = 10,
399 +        X86_REG_EDX = 9,
400 +        X86_REG_EBX = 8,
401 +        X86_REG_ESP = 7,
402 +        X86_REG_EBP = 6,
403 +        X86_REG_ESI = 5,
404 +        X86_REG_EDI = 4
405 + };
406 + #endif
407 + #if defined(__NetBSD__) || defined(__FreeBSD__)
408 + enum {
409 +        X86_REG_EIP = 10,
410 +        X86_REG_EAX = 7,
411 +        X86_REG_ECX = 6,
412 +        X86_REG_EDX = 5,
413 +        X86_REG_EBX = 4,
414 +        X86_REG_ESP = 13,
415 +        X86_REG_EBP = 2,
416 +        X86_REG_ESI = 1,
417 +        X86_REG_EDI = 0
418 + };
419 + #endif
420 + // FIXME: this is partly redundant with the instruction decoding phase
421 + // to discover transfer type and register number
422 + static inline int ix86_step_over_modrm(unsigned char * p)
423 + {
424 +        int mod = (p[0] >> 6) & 3;
425 +        int rm = p[0] & 7;
426 +        int offset = 0;
427 +
428 +        // ModR/M Byte
429 +        switch (mod) {
430 +        case 0: // [reg]
431 +                if (rm == 5) return 4; // disp32
432 +                break;
433 +        case 1: // disp8[reg]
434 +                offset = 1;
435 +                break;
436 +        case 2: // disp32[reg]
437 +                offset = 4;
438 +                break;
439 +        case 3: // register
440 +                return 0;
441 +        }
442 +        
443 +        // SIB Byte
444 +        if (rm == 4) {
445 +                if (mod == 0 && (p[1] & 7) == 5)
446 +                        offset = 5; // disp32[index]
447 +                else
448 +                        offset++;
449 +        }
450 +
451 +        return offset;
452 + }
453 +
454 + static bool ix86_skip_instruction(unsigned int * regs)
455 + {
456 +        unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
457 +
458 +        if (eip == 0)
459 +                return false;
460 +        
461 +        transfer_type_t transfer_type = TYPE_UNKNOWN;
462 +        transfer_size_t transfer_size = SIZE_LONG;
463 +        
464 +        int reg = -1;
465 +        int len = 0;
466 +        
467 +        // Operand size prefix
468 +        if (*eip == 0x66) {
469 +                eip++;
470 +                len++;
471 +                transfer_size = SIZE_WORD;
472 +        }
473 +
474 +        // Decode instruction
475 +        switch (eip[0]) {
476 +        case 0x0f:
477 +            switch (eip[1]) {
478 +            case 0xb6: // MOVZX r32, r/m8
479 +            case 0xb7: // MOVZX r32, r/m16
480 +                switch (eip[2] & 0xc0) {
481 +                case 0x80:
482 +                    reg = (eip[2] >> 3) & 7;
483 +                    transfer_type = TYPE_LOAD;
484 +                    break;
485 +                case 0x40:
486 +                    reg = (eip[2] >> 3) & 7;
487 +                    transfer_type = TYPE_LOAD;
488 +                    break;
489 +                case 0x00:
490 +                    reg = (eip[2] >> 3) & 7;
491 +                    transfer_type = TYPE_LOAD;
492 +                    break;
493 +                }
494 +                len += 3 + ix86_step_over_modrm(eip + 2);
495 +                break;
496 +            }
497 +          break;
498 +        case 0x8a: // MOV r8, r/m8
499 +                transfer_size = SIZE_BYTE;
500 +        case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
501 +                switch (eip[1] & 0xc0) {
502 +                case 0x80:
503 +                        reg = (eip[1] >> 3) & 7;
504 +                        transfer_type = TYPE_LOAD;
505 +                        break;
506 +                case 0x40:
507 +                        reg = (eip[1] >> 3) & 7;
508 +                        transfer_type = TYPE_LOAD;
509 +                        break;
510 +                case 0x00:
511 +                        reg = (eip[1] >> 3) & 7;
512 +                        transfer_type = TYPE_LOAD;
513 +                        break;
514 +                }
515 +                len += 2 + ix86_step_over_modrm(eip + 1);
516 +                break;
517 +        case 0x88: // MOV r/m8, r8
518 +                transfer_size = SIZE_BYTE;
519 +        case 0x89: // MOV r/m32, r32 (or 16-bit operation)
520 +                switch (eip[1] & 0xc0) {
521 +                case 0x80:
522 +                        reg = (eip[1] >> 3) & 7;
523 +                        transfer_type = TYPE_STORE;
524 +                        break;
525 +                case 0x40:
526 +                        reg = (eip[1] >> 3) & 7;
527 +                        transfer_type = TYPE_STORE;
528 +                        break;
529 +                case 0x00:
530 +                        reg = (eip[1] >> 3) & 7;
531 +                        transfer_type = TYPE_STORE;
532 +                        break;
533 +                }
534 +                len += 2 + ix86_step_over_modrm(eip + 1);
535 +                break;
536 +        }
537 +
538 +        if (transfer_type == TYPE_UNKNOWN) {
539 +                // Unknown machine code, let it crash. Then patch the decoder
540 +                return false;
541 +        }
542 +
543 +        if (transfer_type == TYPE_LOAD && reg != -1) {
544 +                static const int x86_reg_map[8] = {
545 +                        X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
546 +                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
547 +                };
548 +                
549 +                if (reg < 0 || reg >= 8)
550 +                        return false;
551 +
552 +                int rloc = x86_reg_map[reg];
553 +                switch (transfer_size) {
554 +                case SIZE_BYTE:
555 +                        regs[rloc] = (regs[rloc] & ~0xff);
556 +                        break;
557 +                case SIZE_WORD:
558 +                        regs[rloc] = (regs[rloc] & ~0xffff);
559 +                        break;
560 +                case SIZE_LONG:
561 +                        regs[rloc] = 0;
562 +                        break;
563 +                }
564 +        }
565 +
566 + #if DEBUG
567 +        printf("%08x: %s %s access", regs[X86_REG_EIP],
568 +                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
569 +                   transfer_type == TYPE_LOAD ? "read" : "write");
570 +        
571 +        if (reg != -1) {
572 +                static const char * x86_reg_str_map[8] = {
573 +                        "eax", "ecx", "edx", "ebx",
574 +                        "esp", "ebp", "esi", "edi"
575 +                };
576 +                printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
577 +        }
578 +        printf(", %d bytes instruction\n", len);
579 + #endif
580 +        
581 +        regs[X86_REG_EIP] += len;
582 +        return true;
583 + }
584 + #endif
585 +
586 + // Decode and skip PPC instruction
587 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
588 + static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
589 + {
590 +        instruction_t instr;
591 +        powerpc_decode_instruction(&instr, *nip_p, regs);
592 +        
593 +        if (instr.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", *nip_p,
600 +                   instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
601 +                   instr.transfer_type == TYPE_LOAD ? "read" : "write");
602 +        
603 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
604 +                printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
605 +        if (instr.transfer_type == TYPE_LOAD)
606 +                printf(" r%d (rd = 0)\n", instr.rd);
607 + #endif
608 +        
609 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
610 +                regs[instr.ra] = instr.addr;
611 +        if (instr.transfer_type == TYPE_LOAD)
612 +                regs[instr.rd] = 0;
613 +        
614 +        *nip_p += 4;
615 +        return true;
616 + }
617 + #endif
618   #endif
619  
620   // Fallbacks
# Line 139 | Line 622 | static bool sigsegv_do_install_handler(i
622   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
623   #endif
624  
625 + // SIGSEGV recovery supported ?
626 + #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
627 + #define HAVE_SIGSEGV_RECOVERY
628 + #endif
629 +
630  
631   /*
632   *  SIGSEGV global handler
633   */
634  
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 + #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(SIGSEGV_REGISTER_FILE))
653 +                        fault_recovered = true;
654          }
655 <        else {
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
669  
670  
671   /*
# Line 179 | Line 686 | static bool sigsegv_do_install_handler(i
686          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
687   #endif
688   }
689 < #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
689 > #endif
690 >
691 > #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
692   static bool sigsegv_do_install_handler(int sig)
693   {
694          // Setup SIGSEGV handler to process writes to frame buffer
# Line 200 | 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 < #if defined(HAVE_SIGINFO_T) || defined(HAVE_SIGCONTEXT_SUBTERFUGE)
715 <        sigsegv_user_handler = handler;
714 > #ifdef HAVE_SIGSEGV_RECOVERY
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 222 | Line 731 | bool sigsegv_install_handler(sigsegv_han
731  
732   void sigsegv_deinstall_handler(void)
733   {
734 <        sigsegv_user_handler = 0;
734 > #ifdef HAVE_SIGSEGV_RECOVERY
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>
238 #include <unistd.h>
770   #include <fcntl.h>
771   #include <sys/mman.h>
772 + #include "vm_alloc.h"
773  
242 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);
259 <        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 273 | 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_READ | 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