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.11 by gbeauche, 2002-05-12T13:51:22Z vs.
Revision 1.23 by gbeauche, 2003-08-17T10:52:52Z

# 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 40 | Line 45
45   // Type of the system signal handler
46   typedef RETSIGTYPE (*signal_handler)(int);
47  
48 < // Is the fault to be ignored?
49 < static bool sigsegv_ignore_fault = false;
48 > // Ignore range chain
49 > struct ignore_range_t {
50 >        sigsegv_address_t       start;
51 >        unsigned long           length;
52 >        int                                     transfer_type;
53 > };
54 >
55 > typedef list<ignore_range_t> ignore_range_list_t;
56 > ignore_range_list_t sigsegv_ignore_ranges;
57  
58   // User's SIGSEGV handler
59 < static sigsegv_handler_t sigsegv_user_handler = 0;
59 > static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
60  
61   // Function called to dump state if we can't handle the fault
62 < static sigsegv_handler_t sigsegv_dump_state = 0;
62 > static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
63  
64   // Actual SIGSEGV handler installer
65   static bool sigsegv_do_install_handler(int sig);
66  
67 + // Find ignore range matching address
68 + static inline ignore_range_list_t::iterator sigsegv_find_ignore_range(sigsegv_address_t address)
69 + {
70 +        ignore_range_list_t::iterator it;
71 +        for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
72 +                if (address >= it->start && address < it->start + it->length)
73 +                        break;
74 +        return it;
75 + }
76 +
77 +
78 + /*
79 + *  Instruction decoding aids
80 + */
81 +
82 + // Transfer size
83 + enum transfer_size_t {
84 +        SIZE_UNKNOWN,
85 +        SIZE_BYTE,
86 +        SIZE_WORD,
87 +        SIZE_LONG
88 + };
89 +
90 + // Transfer type
91 + typedef sigsegv_transfer_type_t transfer_type_t;
92 +
93 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
94 + // Addressing mode
95 + enum addressing_mode_t {
96 +        MODE_UNKNOWN,
97 +        MODE_NORM,
98 +        MODE_U,
99 +        MODE_X,
100 +        MODE_UX
101 + };
102 +
103 + // Decoded instruction
104 + struct instruction_t {
105 +        transfer_type_t         transfer_type;
106 +        transfer_size_t         transfer_size;
107 +        addressing_mode_t       addr_mode;
108 +        unsigned int            addr;
109 +        char                            ra, rd;
110 + };
111 +
112 + static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
113 + {
114 +        // Get opcode and divide into fields
115 +        unsigned int opcode = *((unsigned int *)nip);
116 +        unsigned int primop = opcode >> 26;
117 +        unsigned int exop = (opcode >> 1) & 0x3ff;
118 +        unsigned int ra = (opcode >> 16) & 0x1f;
119 +        unsigned int rb = (opcode >> 11) & 0x1f;
120 +        unsigned int rd = (opcode >> 21) & 0x1f;
121 +        signed int imm = (signed short)(opcode & 0xffff);
122 +        
123 +        // Analyze opcode
124 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
125 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
126 +        addressing_mode_t addr_mode = MODE_UNKNOWN;
127 +        switch (primop) {
128 +        case 31:
129 +                switch (exop) {
130 +                case 23:        // lwzx
131 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
132 +                case 55:        // lwzux
133 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
134 +                case 87:        // lbzx
135 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
136 +                case 119:       // lbzux
137 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
138 +                case 151:       // stwx
139 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
140 +                case 183:       // stwux
141 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
142 +                case 215:       // stbx
143 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
144 +                case 247:       // stbux
145 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
146 +                case 279:       // lhzx
147 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
148 +                case 311:       // lhzux
149 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
150 +                case 343:       // lhax
151 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
152 +                case 375:       // lhaux
153 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
154 +                case 407:       // sthx
155 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
156 +                case 439:       // sthux
157 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
158 +                }
159 +                break;
160 +        
161 +        case 32:        // lwz
162 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
163 +        case 33:        // lwzu
164 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
165 +        case 34:        // lbz
166 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
167 +        case 35:        // lbzu
168 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
169 +        case 36:        // stw
170 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
171 +        case 37:        // stwu
172 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
173 +        case 38:        // stb
174 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
175 +        case 39:        // stbu
176 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
177 +        case 40:        // lhz
178 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
179 +        case 41:        // lhzu
180 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
181 +        case 42:        // lha
182 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
183 +        case 43:        // lhau
184 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
185 +        case 44:        // sth
186 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
187 +        case 45:        // sthu
188 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
189 +        }
190 +        
191 +        // Calculate effective address
192 +        unsigned int addr = 0;
193 +        switch (addr_mode) {
194 +        case MODE_X:
195 +        case MODE_UX:
196 +                if (ra == 0)
197 +                        addr = gpr[rb];
198 +                else
199 +                        addr = gpr[ra] + gpr[rb];
200 +                break;
201 +        case MODE_NORM:
202 +        case MODE_U:
203 +                if (ra == 0)
204 +                        addr = (signed int)(signed short)imm;
205 +                else
206 +                        addr = gpr[ra] + (signed int)(signed short)imm;
207 +                break;
208 +        default:
209 +                break;
210 +        }
211 +        
212 +        // Commit decoded instruction
213 +        instruction->addr = addr;
214 +        instruction->addr_mode = addr_mode;
215 +        instruction->transfer_type = transfer_type;
216 +        instruction->transfer_size = transfer_size;
217 +        instruction->ra = ra;
218 +        instruction->rd = rd;
219 + }
220 + #endif
221 +
222  
223   /*
224   *  OS-dependant SIGSEGV signals support section
# Line 66 | Line 233 | static bool sigsegv_do_install_handler(i
233   #endif
234   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *scp
235   #define SIGSEGV_FAULT_ADDRESS                   sip->si_addr
236 + #if defined(__NetBSD__) || defined(__FreeBSD__)
237 + #if (defined(i386) || defined(__i386__))
238 + #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_eip)
239 + #define SIGSEGV_REGISTER_FILE                   ((unsigned int *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
240 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
241 + #endif
242 + #endif
243   #if defined(__linux__)
244   #if (defined(i386) || defined(__i386__))
245   #include <sys/ucontext.h>
246 < #define SIGSEGV_FAULT_INSTRUCTION               (((ucontext_t *)scp)->uc_mcontext.gregs[14]) /* should use REG_EIP instead */
247 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(((ucontext_t *)scp)->uc_mcontext.gregs)
246 > #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
247 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
248 > #define SIGSEGV_REGISTER_FILE                   (unsigned int *)SIGSEGV_CONTEXT_REGS
249   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
250   #endif
251 + #if (defined(x86_64) || defined(__x86_64__))
252 + #include <sys/ucontext.h>
253 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
254 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
255 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
256 + #endif
257   #if (defined(ia64) || defined(__ia64__))
258   #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
259   #endif
260   #if (defined(powerpc) || defined(__powerpc__))
261   #include <sys/ucontext.h>
262 < #define SIGSEGV_FAULT_INSTRUCTION               (((ucontext_t *)scp)->uc_mcontext.regs->nip)
262 > #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.regs)
263 > #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->nip)
264 > #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
265 > #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
266   #endif
267   #endif
268   #endif
# Line 92 | Line 276 | static bool sigsegv_do_install_handler(i
276   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
277   #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
278   #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
279 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)(&scs)
279 > #define SIGSEGV_REGISTER_FILE                   (unsigned int *)(&scs)
280   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
281   #endif
282   #if (defined(sparc) || defined(__sparc__))
# Line 105 | Line 289 | static bool sigsegv_do_install_handler(i
289   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
290   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
291   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
292 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
293 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
294   #endif
295   #if (defined(alpha) || defined(__alpha__))
296   #include <asm/sigcontext.h>
# Line 158 | Line 344 | static sigsegv_address_t get_fault_addre
344   #if (defined(m68k) || defined(__m68k__))
345   #include <m68k/frame.h>
346   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
347 < #define SIGSEGV_FAULT_ADDRESS                   ({                                                                                                                              \
162 <        struct sigstate {                                                                                                                                                                       \
163 <                int ss_flags;                                                                                                                                                                   \
164 <                struct frame ss_frame;                                                                                                                                                  \
165 <        };                                                                                                                                                                                                      \
166 <        struct sigstate *state = (struct sigstate *)scp->sc_ap;                                                                                         \
167 <        char *fault_addr;                                                                                                                                                                       \
168 <        switch (state->ss_frame.f_format) {                                                                                                                                     \
169 <        case 7:         /* 68040 access error */                                                                                                                                \
170 <                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */    \
171 <                fault_addr = state->ss_frame.f_fmt7.f_fa;                                                                                                               \
172 <                break;                                                                                                                                                                                  \
173 <        default:                                                                                                                                                                                        \
174 <                fault_addr = (char *)code;                                                                                                                                              \
175 <                break;                                                                                                                                                                                  \
176 <        }                                                                                                                                                                                                       \
177 <        fault_addr;                                                                                                                                                                                     \
178 < })
347 > #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
348   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
349 +
350 + // Use decoding scheme from BasiliskII/m68k native
351 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
352 + {
353 +        struct sigstate {
354 +                int ss_flags;
355 +                struct frame ss_frame;
356 +        };
357 +        struct sigstate *state = (struct sigstate *)scp->sc_ap;
358 +        char *fault_addr;
359 +        switch (state->ss_frame.f_format) {
360 +        case 7:         /* 68040 access error */
361 +                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
362 +                fault_addr = state->ss_frame.f_fmt7.f_fa;
363 +                break;
364 +        default:
365 +                fault_addr = (char *)code;
366 +                break;
367 +        }
368 +        return (sigsegv_address_t)fault_addr;
369 + }
370   #else
371   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, void *scp, char *addr
372   #define SIGSEGV_FAULT_ADDRESS                   addr
# Line 191 | Line 381 | static sigsegv_address_t get_fault_addre
381   #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
382   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
383   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
384 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
385 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
386  
387 < // From Boehm's GC 6.0alpha8
196 < #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
197 < #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
198 < #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
199 < #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
200 < #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
201 < #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
202 <
387 > // Use decoding scheme from SheepShaver
388   static sigsegv_address_t get_fault_address(struct sigcontext *scp)
389   {
390 <        unsigned int   instr = *((unsigned int *) scp->sc_ir);
391 <        unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
392 <        int            disp = 0, tmp;
393 <        unsigned int   baseA = 0, baseB = 0;
394 <        unsigned int   addr, alignmask = 0xFFFFFFFF;
395 <
211 <        switch(EXTRACT_OP1(instr)) {
212 <        case 38:   /* stb */
213 <        case 39:   /* stbu */
214 <        case 54:   /* stfd */
215 <        case 55:   /* stfdu */
216 <        case 52:   /* stfs */
217 <        case 53:   /* stfsu */
218 <        case 44:   /* sth */
219 <        case 45:   /* sthu */
220 <        case 47:   /* stmw */
221 <        case 36:   /* stw */
222 <        case 37:   /* stwu */
223 <                tmp = EXTRACT_REGA(instr);
224 <                if(tmp > 0)
225 <                        baseA = regs[tmp];
226 <                disp = EXTRACT_DISP(instr);
227 <                break;
228 <        case 31:
229 <                switch(EXTRACT_OP2(instr)) {
230 <                case 86:    /* dcbf */
231 <                case 54:    /* dcbst */
232 <                case 1014:  /* dcbz */
233 <                case 247:   /* stbux */
234 <                case 215:   /* stbx */
235 <                case 759:   /* stfdux */
236 <                case 727:   /* stfdx */
237 <                case 983:   /* stfiwx */
238 <                case 695:   /* stfsux */
239 <                case 663:   /* stfsx */
240 <                case 918:   /* sthbrx */
241 <                case 439:   /* sthux */
242 <                case 407:   /* sthx */
243 <                case 661:   /* stswx */
244 <                case 662:   /* stwbrx */
245 <                case 150:   /* stwcx. */
246 <                case 183:   /* stwux */
247 <                case 151:   /* stwx */
248 <                case 135:   /* stvebx */
249 <                case 167:   /* stvehx */
250 <                case 199:   /* stvewx */
251 <                case 231:   /* stvx */
252 <                case 487:   /* stvxl */
253 <                        tmp = EXTRACT_REGA(instr);
254 <                        if(tmp > 0)
255 <                                baseA = regs[tmp];
256 <                        baseB = regs[EXTRACT_REGC(instr)];
257 <                        /* determine Altivec alignment mask */
258 <                        switch(EXTRACT_OP2(instr)) {
259 <                        case 167:   /* stvehx */
260 <                                alignmask = 0xFFFFFFFE;
261 <                                break;
262 <                        case 199:   /* stvewx */
263 <                                alignmask = 0xFFFFFFFC;
264 <                                break;
265 <                        case 231:   /* stvx */
266 <                                alignmask = 0xFFFFFFF0;
267 <                                break;
268 <                        case 487:  /* stvxl */
269 <                                alignmask = 0xFFFFFFF0;
270 <                                break;
271 <                        }
272 <                        break;
273 <                case 725:   /* stswi */
274 <                        tmp = EXTRACT_REGA(instr);
275 <                        if(tmp > 0)
276 <                                baseA = regs[tmp];
277 <                        break;
278 <                default:   /* ignore instruction */
279 <                        return 0;
280 <                        break;
281 <                }
282 <                break;
283 <        default:   /* ignore instruction */
284 <                return 0;
285 <                break;
286 <        }
287 <        
288 <        addr = (baseA + baseB) + disp;
289 <        addr &= alignmask;
290 <        return (sigsegv_address_t)addr;
390 >        unsigned int   nip = (unsigned int) scp->sc_ir;
391 >        unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
392 >        instruction_t  instr;
393 >
394 >        powerpc_decode_instruction(&instr, nip, gpr);
395 >        return (sigsegv_address_t)instr.addr;
396   }
397   #endif
398   #endif
399   #endif
400  
401 +
402 + /*
403 + *  Instruction skipping
404 + */
405 +
406   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
407   // Decode and skip X86 instruction
408   #if (defined(i386) || defined(__i386__))
# Line 309 | Line 419 | enum {
419          X86_REG_EDI = 4
420   };
421   #endif
422 + #if defined(__NetBSD__) || defined(__FreeBSD__)
423 + enum {
424 +        X86_REG_EIP = 10,
425 +        X86_REG_EAX = 7,
426 +        X86_REG_ECX = 6,
427 +        X86_REG_EDX = 5,
428 +        X86_REG_EBX = 4,
429 +        X86_REG_ESP = 13,
430 +        X86_REG_EBP = 2,
431 +        X86_REG_ESI = 1,
432 +        X86_REG_EDI = 0
433 + };
434 + #endif
435   // FIXME: this is partly redundant with the instruction decoding phase
436   // to discover transfer type and register number
437   static inline int ix86_step_over_modrm(unsigned char * p)
# Line 343 | Line 466 | static inline int ix86_step_over_modrm(u
466          return offset;
467   }
468  
469 < static bool ix86_skip_instruction(sigsegv_address_t fault_instruction, unsigned long * regs)
469 > static bool ix86_skip_instruction(unsigned int * regs)
470   {
471 <        unsigned char * eip = (unsigned char *)fault_instruction;
471 >        unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
472  
473          if (eip == 0)
474                  return false;
475          
476 <        // Transfer type
477 <        enum {
355 <                TYPE_UNKNOWN,
356 <                TYPE_LOAD,
357 <                TYPE_STORE
358 <        } transfer_type = TYPE_UNKNOWN;
359 <        
360 <        // Transfer size
361 <        enum {
362 <                SIZE_BYTE,
363 <                SIZE_WORD,
364 <                SIZE_LONG
365 <        } transfer_size = SIZE_LONG;
476 >        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
477 >        transfer_size_t transfer_size = SIZE_LONG;
478          
479          int reg = -1;
480          int len = 0;
# Line 376 | Line 488 | static bool ix86_skip_instruction(sigseg
488  
489          // Decode instruction
490          switch (eip[0]) {
491 +        case 0x0f:
492 +            switch (eip[1]) {
493 +            case 0xb6: // MOVZX r32, r/m8
494 +            case 0xb7: // MOVZX r32, r/m16
495 +                switch (eip[2] & 0xc0) {
496 +                case 0x80:
497 +                    reg = (eip[2] >> 3) & 7;
498 +                    transfer_type = SIGSEGV_TRANSFER_LOAD;
499 +                    break;
500 +                case 0x40:
501 +                    reg = (eip[2] >> 3) & 7;
502 +                    transfer_type = SIGSEGV_TRANSFER_LOAD;
503 +                    break;
504 +                case 0x00:
505 +                    reg = (eip[2] >> 3) & 7;
506 +                    transfer_type = SIGSEGV_TRANSFER_LOAD;
507 +                    break;
508 +                }
509 +                len += 3 + ix86_step_over_modrm(eip + 2);
510 +                break;
511 +            }
512 +          break;
513          case 0x8a: // MOV r8, r/m8
514                  transfer_size = SIZE_BYTE;
515          case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
516                  switch (eip[1] & 0xc0) {
517                  case 0x80:
518                          reg = (eip[1] >> 3) & 7;
519 <                        transfer_type = TYPE_LOAD;
519 >                        transfer_type = SIGSEGV_TRANSFER_LOAD;
520                          break;
521                  case 0x40:
522                          reg = (eip[1] >> 3) & 7;
523 <                        transfer_type = TYPE_LOAD;
523 >                        transfer_type = SIGSEGV_TRANSFER_LOAD;
524                          break;
525                  case 0x00:
526                          reg = (eip[1] >> 3) & 7;
527 <                        transfer_type = TYPE_LOAD;
527 >                        transfer_type = SIGSEGV_TRANSFER_LOAD;
528                          break;
529                  }
530                  len += 2 + ix86_step_over_modrm(eip + 1);
# Line 401 | Line 535 | static bool ix86_skip_instruction(sigseg
535                  switch (eip[1] & 0xc0) {
536                  case 0x80:
537                          reg = (eip[1] >> 3) & 7;
538 <                        transfer_type = TYPE_STORE;
538 >                        transfer_type = SIGSEGV_TRANSFER_STORE;
539                          break;
540                  case 0x40:
541                          reg = (eip[1] >> 3) & 7;
542 <                        transfer_type = TYPE_STORE;
542 >                        transfer_type = SIGSEGV_TRANSFER_STORE;
543                          break;
544                  case 0x00:
545                          reg = (eip[1] >> 3) & 7;
546 <                        transfer_type = TYPE_STORE;
546 >                        transfer_type = SIGSEGV_TRANSFER_STORE;
547                          break;
548                  }
549                  len += 2 + ix86_step_over_modrm(eip + 1);
550                  break;
551          }
552  
553 <        if (transfer_type == TYPE_UNKNOWN) {
553 >        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
554                  // Unknown machine code, let it crash. Then patch the decoder
555                  return false;
556          }
557  
558 <        if (transfer_type == TYPE_LOAD && reg != -1) {
558 >        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
559                  static const int x86_reg_map[8] = {
560                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
561                          X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
# Line 447 | Line 581 | static bool ix86_skip_instruction(sigseg
581   #if DEBUG
582          printf("%08x: %s %s access", regs[X86_REG_EIP],
583                     transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
584 <                   transfer_type == TYPE_LOAD ? "read" : "write");
584 >                   transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
585          
586          if (reg != -1) {
587                  static const char * x86_reg_str_map[8] = {
588                          "eax", "ecx", "edx", "ebx",
589                          "esp", "ebp", "esi", "edi"
590                  };
591 <                printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
591 >                printf(" %s register %%%s", transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from", x86_reg_str_map[reg]);
592          }
593          printf(", %d bytes instruction\n", len);
594   #endif
# Line 463 | Line 597 | static bool ix86_skip_instruction(sigseg
597          return true;
598   }
599   #endif
600 +
601 + // Decode and skip PPC instruction
602 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
603 + static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
604 + {
605 +        instruction_t instr;
606 +        powerpc_decode_instruction(&instr, *nip_p, regs);
607 +        
608 +        if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
609 +                // Unknown machine code, let it crash. Then patch the decoder
610 +                return false;
611 +        }
612 +
613 +        ignore_range_list_t::iterator it = sigsegv_find_ignore_range((sigsegv_address_t)instr.addr);
614 +        if (it == sigsegv_ignore_ranges.end() || ((it->transfer_type & instr.transfer_type) != instr.transfer_type)) {
615 +                // Address doesn't fall into ignore ranges list, let it crash.
616 +                return false;
617 +        }
618 +
619 + #if DEBUG
620 +        printf("%08x: %s %s access", *nip_p,
621 +                   instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
622 +                   instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
623 +        
624 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
625 +                printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
626 +        if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
627 +                printf(" r%d (rd = 0)\n", instr.rd);
628 + #endif
629 +        
630 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
631 +                regs[instr.ra] = instr.addr;
632 +        if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
633 +                regs[instr.rd] = 0;
634 +        
635 +        *nip_p += 4;
636 +        return true;
637 + }
638 + #endif
639   #endif
640  
641   // Fallbacks
# Line 488 | Line 661 | static void sigsegv_handler(SIGSEGV_FAUL
661          bool fault_recovered = false;
662          
663          // Call user's handler and reinstall the global handler, if required
664 <        if (sigsegv_user_handler(fault_address, fault_instruction)) {
664 >        if (sigsegv_fault_handler(fault_address, fault_instruction)) {
665   #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
666                  sigsegv_do_install_handler(sig);
667   #endif
668                  fault_recovered = true;
669          }
670   #if HAVE_SIGSEGV_SKIP_INSTRUCTION
671 <        else if (sigsegv_ignore_fault) {
671 >        else if (sigsegv_ignore_ranges.size() > 0) {
672                  // Call the instruction skipper with the register file available
673 <                if (SIGSEGV_SKIP_INSTRUCTION(fault_instruction, SIGSEGV_REGISTER_FILE))
673 >                if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
674                          fault_recovered = true;
675          }
676   #endif
# Line 509 | Line 682 | static void sigsegv_handler(SIGSEGV_FAUL
682   #undef FAULT_HANDLER
683                  
684                  // We can't do anything with the fault_address, dump state?
685 <                if (sigsegv_dump_state != 0)
686 <                        sigsegv_dump_state(fault_address, fault_instruction);
685 >                if (sigsegv_state_dumper != 0)
686 >                        sigsegv_state_dumper(fault_address, fault_instruction);
687          }
688   }
689   #endif
# Line 525 | Line 698 | static bool sigsegv_do_install_handler(i
698   {
699          // Setup SIGSEGV handler to process writes to frame buffer
700   #ifdef HAVE_SIGACTION
701 <        struct sigaction vosf_sa;
702 <        sigemptyset(&vosf_sa.sa_mask);
703 <        vosf_sa.sa_sigaction = sigsegv_handler;
704 <        vosf_sa.sa_flags = SA_SIGINFO;
705 <        return (sigaction(sig, &vosf_sa, 0) == 0);
701 >        struct sigaction sigsegv_sa;
702 >        sigemptyset(&sigsegv_sa.sa_mask);
703 >        sigsegv_sa.sa_sigaction = sigsegv_handler;
704 >        sigsegv_sa.sa_flags = SA_SIGINFO;
705 >        return (sigaction(sig, &sigsegv_sa, 0) == 0);
706   #else
707          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
708   #endif
# Line 541 | Line 714 | static bool sigsegv_do_install_handler(i
714   {
715          // Setup SIGSEGV handler to process writes to frame buffer
716   #ifdef HAVE_SIGACTION
717 <        struct sigaction vosf_sa;
718 <        sigemptyset(&vosf_sa.sa_mask);
719 <        vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
717 >        struct sigaction sigsegv_sa;
718 >        sigemptyset(&sigsegv_sa.sa_mask);
719 >        sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
720 >        sigsegv_sa.sa_flags = 0;
721   #if !EMULATED_68K && defined(__NetBSD__)
722 <        sigaddset(&vosf_sa.sa_mask, SIGALRM);
723 <        vosf_sa.sa_flags = SA_ONSTACK;
550 < #else
551 <        vosf_sa.sa_flags = 0;
722 >        sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
723 >        sigsegv_sa.sa_flags |= SA_ONSTACK;
724   #endif
725 <        return (sigaction(sig, &vosf_sa, 0) == 0);
725 >        return (sigaction(sig, &sigsegv_sa, 0) == 0);
726   #else
727          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
728   #endif
729   }
730   #endif
731  
732 < bool sigsegv_install_handler(sigsegv_handler_t handler)
732 > bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
733   {
734   #ifdef HAVE_SIGSEGV_RECOVERY
735 <        sigsegv_user_handler = handler;
735 >        sigsegv_fault_handler = handler;
736          bool success = true;
737   #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
738          SIGSEGV_ALL_SIGNALS
# Line 580 | Line 752 | bool sigsegv_install_handler(sigsegv_han
752   void sigsegv_deinstall_handler(void)
753   {
754   #ifdef HAVE_SIGSEGV_RECOVERY
755 <        sigsegv_user_handler = 0;
755 >        sigsegv_fault_handler = 0;
756   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
757          SIGSEGV_ALL_SIGNALS
758   #undef FAULT_HANDLER
# Line 589 | Line 761 | void sigsegv_deinstall_handler(void)
761  
762  
763   /*
764 < *  SIGSEGV ignore state modifier
764 > *  Add SIGSEGV ignore range
765   */
766  
767 < void sigsegv_set_ignore_state(bool ignore_fault)
767 > void sigsegv_add_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
768   {
769 <        sigsegv_ignore_fault = ignore_fault;
769 >        ignore_range_t ignore_range;
770 >        ignore_range.start = address;
771 >        ignore_range.length = length;
772 >        ignore_range.transfer_type = transfer_type;
773 >        sigsegv_ignore_ranges.push_front(ignore_range);
774 > }
775 >
776 >
777 > /*
778 > *  Remove SIGSEGV ignore range. Range must match installed one, otherwise FALSE is returned.
779 > */
780 >
781 > bool sigsegv_remove_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
782 > {
783 >        ignore_range_list_t::iterator it;
784 >        for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
785 >                if (it->start == address && it->length == length && ((it->transfer_type & transfer_type) == transfer_type))
786 >                        break;
787 >
788 >        if (it != sigsegv_ignore_ranges.end()) {
789 >                if (it->transfer_type != transfer_type)
790 >                        it->transfer_type &= ~transfer_type;
791 >                else
792 >                        sigsegv_ignore_ranges.erase(it);
793 >                return true;
794 >        }
795 >
796 >        return false;
797   }
798  
799  
# Line 602 | Line 801 | void sigsegv_set_ignore_state(bool ignor
801   *  Set callback function when we cannot handle the fault
802   */
803  
804 < void sigsegv_set_dump_state(sigsegv_handler_t handler)
804 > void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
805   {
806 <        sigsegv_dump_state = handler;
806 >        sigsegv_state_dumper = handler;
807   }
808  
809  
# Line 665 | Line 864 | int main(void)
864          if (!sigsegv_install_handler(sigsegv_insn_handler))
865                  return 1;
866          
867 <        if (vm_protect((char *)page, page_size, VM_PAGE_WRITE) < 0)
867 >        if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
868                  return 1;
869          
870          for (int i = 0; i < page_size; i++)
# Line 674 | Line 873 | int main(void)
873          if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
874                  return 1;
875          
876 <        sigsegv_set_ignore_state(true);
876 >        sigsegv_add_ignore_range((char *)page, page_size, SIGSEGV_TRANSFER_LOAD | SIGSEGV_TRANSFER_STORE);
877  
878   #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
879                  const unsigned int TAG = 0x12345678;                    \

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines