ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.71
Committed: 2008-01-01T09:40:33Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.70: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * sigsegv.cpp - SIGSEGV signals support
3     *
4     * Derived from Bruno Haible's work on his SIGSEGV library for clisp
5     * <http://clisp.sourceforge.net/>
6     *
7 gbeauche 1.27 * MacOS X support derived from the post by Timothy J. Wood to the
8     * omnigroup macosx-dev list:
9     * Mach Exception Handlers 101 (Was Re: ptrace, gdb)
10     * tjw@omnigroup.com Sun, 4 Jun 2000
11     * www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
12     *
13 gbeauche 1.71 * Basilisk II (C) 1997-2008 Christian Bauer
14 gbeauche 1.1 *
15     * This program is free software; you can redistribute it and/or modify
16     * it under the terms of the GNU General Public License as published by
17     * the Free Software Foundation; either version 2 of the License, or
18     * (at your option) any later version.
19     *
20     * This program is distributed in the hope that it will be useful,
21     * but WITHOUT ANY WARRANTY; without even the implied warranty of
22     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23     * GNU General Public License for more details.
24     *
25     * You should have received a copy of the GNU General Public License
26     * along with this program; if not, write to the Free Software
27     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28     */
29    
30     #ifdef HAVE_UNISTD_H
31     #include <unistd.h>
32     #endif
33    
34     #ifdef HAVE_CONFIG_H
35     #include "config.h"
36     #endif
37    
38 gbeauche 1.22 #include <list>
39 gbeauche 1.39 #include <stdio.h>
40 gbeauche 1.1 #include <signal.h>
41     #include "sigsegv.h"
42    
43 gbeauche 1.22 #ifndef NO_STD_NAMESPACE
44     using std::list;
45     #endif
46    
47 gbeauche 1.1 // Return value type of a signal handler (standard type if not defined)
48     #ifndef RETSIGTYPE
49     #define RETSIGTYPE void
50     #endif
51    
52     // Type of the system signal handler
53     typedef RETSIGTYPE (*signal_handler)(int);
54    
55     // User's SIGSEGV handler
56 gbeauche 1.12 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
57 gbeauche 1.1
58 gbeauche 1.10 // Function called to dump state if we can't handle the fault
59 gbeauche 1.12 static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
60 gbeauche 1.10
61 gbeauche 1.1 // Actual SIGSEGV handler installer
62     static bool sigsegv_do_install_handler(int sig);
63    
64    
65     /*
66 gbeauche 1.14 * Instruction decoding aids
67     */
68    
69 gbeauche 1.64 // Transfer type
70     enum transfer_type_t {
71     SIGSEGV_TRANSFER_UNKNOWN = 0,
72     SIGSEGV_TRANSFER_LOAD = 1,
73     SIGSEGV_TRANSFER_STORE = 2,
74     };
75    
76 gbeauche 1.14 // Transfer size
77     enum transfer_size_t {
78     SIZE_UNKNOWN,
79     SIZE_BYTE,
80 gbeauche 1.34 SIZE_WORD, // 2 bytes
81     SIZE_LONG, // 4 bytes
82     SIZE_QUAD, // 8 bytes
83 gbeauche 1.14 };
84    
85 gbeauche 1.69 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
86 gbeauche 1.14 // Addressing mode
87     enum addressing_mode_t {
88     MODE_UNKNOWN,
89     MODE_NORM,
90     MODE_U,
91     MODE_X,
92     MODE_UX
93     };
94    
95     // Decoded instruction
96     struct instruction_t {
97     transfer_type_t transfer_type;
98     transfer_size_t transfer_size;
99     addressing_mode_t addr_mode;
100     unsigned int addr;
101     char ra, rd;
102     };
103    
104 gbeauche 1.49 static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
105 gbeauche 1.14 {
106     // Get opcode and divide into fields
107 gbeauche 1.49 unsigned int opcode = *((unsigned int *)(unsigned long)nip);
108 gbeauche 1.14 unsigned int primop = opcode >> 26;
109     unsigned int exop = (opcode >> 1) & 0x3ff;
110     unsigned int ra = (opcode >> 16) & 0x1f;
111     unsigned int rb = (opcode >> 11) & 0x1f;
112     unsigned int rd = (opcode >> 21) & 0x1f;
113     signed int imm = (signed short)(opcode & 0xffff);
114    
115     // Analyze opcode
116 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
117 gbeauche 1.14 transfer_size_t transfer_size = SIZE_UNKNOWN;
118     addressing_mode_t addr_mode = MODE_UNKNOWN;
119     switch (primop) {
120     case 31:
121     switch (exop) {
122     case 23: // lwzx
123 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
124 gbeauche 1.14 case 55: // lwzux
125 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
126 gbeauche 1.14 case 87: // lbzx
127 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
128 gbeauche 1.14 case 119: // lbzux
129 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
130 gbeauche 1.14 case 151: // stwx
131 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
132 gbeauche 1.14 case 183: // stwux
133 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
134 gbeauche 1.14 case 215: // stbx
135 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
136 gbeauche 1.14 case 247: // stbux
137 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
138 gbeauche 1.14 case 279: // lhzx
139 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
140 gbeauche 1.14 case 311: // lhzux
141 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
142 gbeauche 1.14 case 343: // lhax
143 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
144 gbeauche 1.14 case 375: // lhaux
145 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
146 gbeauche 1.14 case 407: // sthx
147 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
148 gbeauche 1.14 case 439: // sthux
149 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
150 gbeauche 1.14 }
151     break;
152    
153     case 32: // lwz
154 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
155 gbeauche 1.14 case 33: // lwzu
156 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
157 gbeauche 1.14 case 34: // lbz
158 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
159 gbeauche 1.14 case 35: // lbzu
160 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
161 gbeauche 1.14 case 36: // stw
162 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
163 gbeauche 1.14 case 37: // stwu
164 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
165 gbeauche 1.14 case 38: // stb
166 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
167 gbeauche 1.14 case 39: // stbu
168 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
169 gbeauche 1.14 case 40: // lhz
170 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
171 gbeauche 1.14 case 41: // lhzu
172 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
173 gbeauche 1.14 case 42: // lha
174 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
175 gbeauche 1.14 case 43: // lhau
176 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
177 gbeauche 1.14 case 44: // sth
178 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
179 gbeauche 1.14 case 45: // sthu
180 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
181 gbeauche 1.49 case 58: // ld, ldu, lwa
182     transfer_type = SIGSEGV_TRANSFER_LOAD;
183     transfer_size = SIZE_QUAD;
184     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
185     imm &= ~3;
186     break;
187     case 62: // std, stdu, stq
188     transfer_type = SIGSEGV_TRANSFER_STORE;
189     transfer_size = SIZE_QUAD;
190     addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
191     imm &= ~3;
192     break;
193 gbeauche 1.14 }
194    
195     // Calculate effective address
196     unsigned int addr = 0;
197     switch (addr_mode) {
198     case MODE_X:
199     case MODE_UX:
200     if (ra == 0)
201     addr = gpr[rb];
202     else
203     addr = gpr[ra] + gpr[rb];
204     break;
205     case MODE_NORM:
206     case MODE_U:
207     if (ra == 0)
208     addr = (signed int)(signed short)imm;
209     else
210     addr = gpr[ra] + (signed int)(signed short)imm;
211     break;
212     default:
213     break;
214     }
215    
216     // Commit decoded instruction
217     instruction->addr = addr;
218     instruction->addr_mode = addr_mode;
219     instruction->transfer_type = transfer_type;
220     instruction->transfer_size = transfer_size;
221     instruction->ra = ra;
222     instruction->rd = rd;
223     }
224     #endif
225    
226    
227     /*
228 gbeauche 1.1 * OS-dependant SIGSEGV signals support section
229     */
230    
231     #if HAVE_SIGINFO_T
232     // Generic extended signal handler
233 gbeauche 1.51 #if defined(__FreeBSD__)
234 cebix 1.8 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
235     #else
236 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
237 cebix 1.8 #endif
238 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
239 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
240     #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
241 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
242 gbeauche 1.37 #if (defined(sgi) || defined(__sgi))
243     #include <ucontext.h>
244     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
245     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
246 gbeauche 1.38 #if (defined(mips) || defined(__mips))
247 gbeauche 1.65 #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0]
248 gbeauche 1.38 #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
249     #endif
250 gbeauche 1.37 #endif
251 gbeauche 1.32 #if defined(__sun__)
252     #if (defined(sparc) || defined(__sparc__))
253 gbeauche 1.40 #include <sys/stack.h>
254     #include <sys/regset.h>
255 gbeauche 1.32 #include <sys/ucontext.h>
256     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
257     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
258 gbeauche 1.40 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
259     #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
260     #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
261     #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
262 gbeauche 1.32 #endif
263 gbeauche 1.54 #if defined(__i386__)
264     #include <sys/regset.h>
265     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
266     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[EIP]
267     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
268     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
269     #endif
270 gbeauche 1.32 #endif
271 gbeauche 1.55 #if defined(__FreeBSD__) || defined(__OpenBSD__)
272 gbeauche 1.17 #if (defined(i386) || defined(__i386__))
273     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
274 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
275 gbeauche 1.17 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
276 gbeauche 1.19 #endif
277 gbeauche 1.17 #endif
278 gbeauche 1.51 #if defined(__NetBSD__)
279     #if (defined(i386) || defined(__i386__))
280     #include <sys/ucontext.h>
281     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
282     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_EIP]
283     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
284     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
285     #endif
286 gbeauche 1.53 #if (defined(powerpc) || defined(__powerpc__))
287     #include <sys/ucontext.h>
288     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs)
289     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_PC]
290     #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
291     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
292     #endif
293 gbeauche 1.51 #endif
294 gbeauche 1.5 #if defined(__linux__)
295 gbeauche 1.6 #if (defined(i386) || defined(__i386__))
296     #include <sys/ucontext.h>
297 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
298     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
299 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
300 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
301 gbeauche 1.6 #endif
302 gbeauche 1.20 #if (defined(x86_64) || defined(__x86_64__))
303     #include <sys/ucontext.h>
304     #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
305     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
306     #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
307 gbeauche 1.34 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
308 gbeauche 1.20 #endif
309 gbeauche 1.5 #if (defined(ia64) || defined(__ia64__))
310     #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
311     #endif
312 gbeauche 1.9 #if (defined(powerpc) || defined(__powerpc__))
313     #include <sys/ucontext.h>
314 gbeauche 1.14 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
315     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
316 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
317 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
318 gbeauche 1.9 #endif
319 gbeauche 1.39 #if (defined(hppa) || defined(__hppa__))
320     #undef SIGSEGV_FAULT_ADDRESS
321     #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
322     #endif
323 gbeauche 1.42 #if (defined(arm) || defined(__arm__))
324     #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
325     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
326     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc)
327 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE (&SIGSEGV_CONTEXT_REGS.arm_r0)
328     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
329 gbeauche 1.42 #endif
330 gbeauche 1.65 #if (defined(mips) || defined(__mips__))
331     #include <sys/ucontext.h>
332     #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext)
333     #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.pc)
334     #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
335     #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
336     #endif
337 gbeauche 1.5 #endif
338 gbeauche 1.1 #endif
339    
340     #if HAVE_SIGCONTEXT_SUBTERFUGE
341     // Linux kernels prior to 2.4 ?
342     #if defined(__linux__)
343     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
344     #if (defined(i386) || defined(__i386__))
345     #include <asm/sigcontext.h>
346     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
347 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
348     #define SIGSEGV_FAULT_HANDLER_ARGS &scs
349     #define SIGSEGV_FAULT_ADDRESS scp->cr2
350     #define SIGSEGV_FAULT_INSTRUCTION scp->eip
351 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
352 gbeauche 1.10 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
353 gbeauche 1.1 #endif
354     #if (defined(sparc) || defined(__sparc__))
355     #include <asm/sigcontext.h>
356 gbeauche 1.5 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
357 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
358 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
359     #endif
360     #if (defined(powerpc) || defined(__powerpc__))
361     #include <asm/sigcontext.h>
362 gbeauche 1.4 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
363 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
364 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
365     #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
366 gbeauche 1.49 #define SIGSEGV_REGISTER_FILE (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
367 gbeauche 1.13 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
368 gbeauche 1.1 #endif
369 gbeauche 1.4 #if (defined(alpha) || defined(__alpha__))
370     #include <asm/sigcontext.h>
371     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
372 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
373 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
374     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
375 gbeauche 1.42 #endif
376     #if (defined(arm) || defined(__arm__))
377     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc
378     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
379     #define SIGSEGV_FAULT_HANDLER_ARGS &sc
380     #define SIGSEGV_FAULT_ADDRESS scp->fault_address
381     #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc
382 gbeauche 1.44 #define SIGSEGV_REGISTER_FILE &scp->arm_r0
383     #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction
384 gbeauche 1.4 #endif
385 gbeauche 1.1 #endif
386    
387     // Irix 5 or 6 on MIPS
388 gbeauche 1.37 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
389 gbeauche 1.11 #include <ucontext.h>
390 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
391 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
392 gbeauche 1.37 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
393     #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
394 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
395     #endif
396    
397 gbeauche 1.11 // HP-UX
398     #if (defined(hpux) || defined(__hpux__))
399     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
400 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
401 gbeauche 1.11 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
402     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
403     #endif
404    
405 gbeauche 1.1 // OSF/1 on Alpha
406     #if defined(__osf__)
407 gbeauche 1.11 #include <ucontext.h>
408 gbeauche 1.1 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
409 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
410 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
411     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
412     #endif
413    
414     // AIX
415     #if defined(_AIX)
416     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
417 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
418 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
419     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
420     #endif
421    
422 gbeauche 1.33 // NetBSD
423     #if defined(__NetBSD__)
424 gbeauche 1.1 #if (defined(m68k) || defined(__m68k__))
425     #include <m68k/frame.h>
426     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
427 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
428 gbeauche 1.14 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
429 gbeauche 1.1 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
430 gbeauche 1.14
431     // Use decoding scheme from BasiliskII/m68k native
432     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
433     {
434     struct sigstate {
435     int ss_flags;
436     struct frame ss_frame;
437     };
438     struct sigstate *state = (struct sigstate *)scp->sc_ap;
439     char *fault_addr;
440     switch (state->ss_frame.f_format) {
441     case 7: /* 68040 access error */
442     /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
443     fault_addr = state->ss_frame.f_fmt7.f_fa;
444     break;
445     default:
446     fault_addr = (char *)code;
447     break;
448     }
449     return (sigsegv_address_t)fault_addr;
450     }
451 gbeauche 1.33 #endif
452     #if (defined(alpha) || defined(__alpha__))
453     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
454     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
455     #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
456     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
457     #endif
458     #if (defined(i386) || defined(__i386__))
459     #error "FIXME: need to decode instruction and compute EA"
460     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
461     #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
462     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
463     #endif
464     #endif
465     #if defined(__FreeBSD__)
466 gbeauche 1.39 #if (defined(i386) || defined(__i386__))
467 gbeauche 1.33 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
468     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
469 gbeauche 1.30 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
470 gbeauche 1.1 #define SIGSEGV_FAULT_ADDRESS addr
471 gbeauche 1.33 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
472 gbeauche 1.34 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
473 gbeauche 1.33 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
474 gbeauche 1.1 #endif
475 gbeauche 1.39 #if (defined(alpha) || defined(__alpha__))
476     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
477     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
478     #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
479     #define SIGSEGV_FAULT_ADDRESS addr
480     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
481     #endif
482 gbeauche 1.1 #endif
483 gbeauche 1.33
484     // Extract fault address out of a sigcontext
485     #if (defined(alpha) || defined(__alpha__))
486     // From Boehm's GC 6.0alpha8
487     static sigsegv_address_t get_fault_address(struct sigcontext *scp)
488     {
489     unsigned int instruction = *((unsigned int *)(scp->sc_pc));
490     unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
491     fault_address += (signed long)(signed short)(instruction & 0xffff);
492     return (sigsegv_address_t)fault_address;
493     }
494     #endif
495    
496 gbeauche 1.4
497 gbeauche 1.27 // MacOS X, not sure which version this works in. Under 10.1
498     // vm_protect does not appear to work from a signal handler. Under
499     // 10.2 signal handlers get siginfo type arguments but the si_addr
500     // field is the address of the faulting instruction and not the
501     // address that caused the SIGBUS. Maybe this works in 10.0? In any
502     // case with Mach exception handlers there is a way to do what this
503     // was meant to do.
504     #ifndef HAVE_MACH_EXCEPTIONS
505 gbeauche 1.4 #if defined(__APPLE__) && defined(__MACH__)
506     #if (defined(ppc) || defined(__ppc__))
507     #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
508 gbeauche 1.27 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
509 gbeauche 1.4 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
510     #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
511     #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
512 gbeauche 1.14 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
513     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
514 gbeauche 1.4
515 gbeauche 1.14 // Use decoding scheme from SheepShaver
516 gbeauche 1.4 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
517     {
518 gbeauche 1.14 unsigned int nip = (unsigned int) scp->sc_ir;
519     unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
520     instruction_t instr;
521    
522     powerpc_decode_instruction(&instr, nip, gpr);
523     return (sigsegv_address_t)instr.addr;
524 gbeauche 1.4 }
525     #endif
526     #endif
527 gbeauche 1.1 #endif
528 gbeauche 1.27 #endif
529    
530 gbeauche 1.48 #if HAVE_WIN32_EXCEPTIONS
531     #define WIN32_LEAN_AND_MEAN /* avoid including junk */
532     #include <windows.h>
533     #include <winerror.h>
534    
535     #define SIGSEGV_FAULT_HANDLER_ARGLIST EXCEPTION_POINTERS *ExceptionInfo
536     #define SIGSEGV_FAULT_HANDLER_ARGS ExceptionInfo
537     #define SIGSEGV_FAULT_ADDRESS ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
538     #define SIGSEGV_CONTEXT_REGS ExceptionInfo->ContextRecord
539     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Eip
540     #define SIGSEGV_REGISTER_FILE ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
541     #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
542     #endif
543    
544 gbeauche 1.27 #if HAVE_MACH_EXCEPTIONS
545    
546     // This can easily be extended to other Mach systems, but really who
547     // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
548     // Mach 2.5/3.0?
549     #if defined(__APPLE__) && defined(__MACH__)
550    
551     #include <sys/types.h>
552     #include <stdlib.h>
553     #include <stdio.h>
554     #include <pthread.h>
555    
556     /*
557     * If you are familiar with MIG then you will understand the frustration
558     * that was necessary to get these embedded into C++ code by hand.
559     */
560     extern "C" {
561     #include <mach/mach.h>
562     #include <mach/mach_error.h>
563    
564     extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
565     extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
566     mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
567     extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
568     exception_type_t, exception_data_t, mach_msg_type_number_t);
569     extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
570     exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
571     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
572     extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
573     exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
574     thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
575     }
576    
577     // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
578     #define HANDLER_COUNT 64
579    
580     // structure to tuck away existing exception handlers
581     typedef struct _ExceptionPorts {
582     mach_msg_type_number_t maskCount;
583     exception_mask_t masks[HANDLER_COUNT];
584     exception_handler_t handlers[HANDLER_COUNT];
585     exception_behavior_t behaviors[HANDLER_COUNT];
586     thread_state_flavor_t flavors[HANDLER_COUNT];
587     } ExceptionPorts;
588    
589     // exception handler thread
590     static pthread_t exc_thread;
591    
592     // place where old exception handler info is stored
593     static ExceptionPorts ports;
594    
595     // our exception port
596     static mach_port_t _exceptionPort = MACH_PORT_NULL;
597    
598     #define MACH_CHECK_ERROR(name,ret) \
599     if (ret != KERN_SUCCESS) { \
600     mach_error(#name, ret); \
601     exit (1); \
602     }
603    
604 gbeauche 1.56 #ifdef __ppc__
605 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t
606     #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE
607     #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
608 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS sip->exc_state.dar
609 gbeauche 1.56 #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
610     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
611     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
612 gbeauche 1.68 #define SIGSEGV_FAULT_INSTRUCTION sip->thr_state.srr0
613 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
614 gbeauche 1.68 #define SIGSEGV_REGISTER_FILE (unsigned long *)&sip->thr_state.srr0, (unsigned long *)&sip->thr_state.r0
615 gbeauche 1.56 #endif
616 gbeauche 1.69 #ifdef __ppc64__
617     #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state64_t
618     #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE64
619     #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
620     #define SIGSEGV_FAULT_ADDRESS sip->exc_state.dar
621     #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t
622     #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64
623     #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
624     #define SIGSEGV_FAULT_INSTRUCTION sip->thr_state.srr0
625     #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
626     #define SIGSEGV_REGISTER_FILE (unsigned long *)&sip->thr_state.srr0, (unsigned long *)&sip->thr_state.r0
627     #endif
628 gbeauche 1.56 #ifdef __i386__
629 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE struct i386_exception_state
630     #define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE
631     #define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT
632 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS sip->exc_state.faultvaddr
633 gbeauche 1.57 #define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state
634     #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
635     #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
636 gbeauche 1.68 #define SIGSEGV_FAULT_INSTRUCTION sip->thr_state.eip
637 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
638 gbeauche 1.68 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&sip->thr_state.eax) /* EAX is the first GPR we consider */
639 gbeauche 1.56 #endif
640 gbeauche 1.66 #ifdef __x86_64__
641     #define SIGSEGV_EXCEPTION_STATE_TYPE struct x86_exception_state64
642     #define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64
643     #define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
644 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS sip->exc_state.faultvaddr
645 gbeauche 1.66 #define SIGSEGV_THREAD_STATE_TYPE struct x86_thread_state64
646     #define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64
647     #define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
648 gbeauche 1.68 #define SIGSEGV_FAULT_INSTRUCTION sip->thr_state.rip
649 gbeauche 1.66 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
650 gbeauche 1.68 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&sip->thr_state.rax) /* RAX is the first GPR we consider */
651 gbeauche 1.66 #endif
652 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS_FAST code[1]
653     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS
654 gbeauche 1.66 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code
655     #define SIGSEGV_FAULT_HANDLER_ARGS thread, code
656 gbeauche 1.27
657     // Since there can only be one exception thread running at any time
658     // this is not a problem.
659     #define MSG_SIZE 512
660     static char msgbuf[MSG_SIZE];
661     static char replybuf[MSG_SIZE];
662    
663     /*
664     * This is the entry point for the exception handler thread. The job
665     * of this thread is to wait for exception messages on the exception
666     * port that was setup beforehand and to pass them on to exc_server.
667     * exc_server is a MIG generated function that is a part of Mach.
668     * Its job is to decide what to do with the exception message. In our
669     * case exc_server calls catch_exception_raise on our behalf. After
670     * exc_server returns, it is our responsibility to send the reply.
671     */
672     static void *
673     handleExceptions(void *priv)
674     {
675     mach_msg_header_t *msg, *reply;
676     kern_return_t krc;
677    
678     msg = (mach_msg_header_t *)msgbuf;
679     reply = (mach_msg_header_t *)replybuf;
680    
681     for (;;) {
682     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
683     _exceptionPort, 0, MACH_PORT_NULL);
684     MACH_CHECK_ERROR(mach_msg, krc);
685    
686     if (!exc_server(msg, reply)) {
687     fprintf(stderr, "exc_server hated the message\n");
688     exit(1);
689     }
690    
691     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
692     msg->msgh_local_port, 0, MACH_PORT_NULL);
693     if (krc != KERN_SUCCESS) {
694     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
695     krc, mach_error_string(krc));
696     exit(1);
697     }
698     }
699     }
700     #endif
701     #endif
702 gbeauche 1.1
703 gbeauche 1.14
704     /*
705     * Instruction skipping
706     */
707    
708 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
709     // Decode and skip X86 instruction
710 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
711 gbeauche 1.10 #if defined(__linux__)
712     enum {
713 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
714 gbeauche 1.10 X86_REG_EIP = 14,
715     X86_REG_EAX = 11,
716     X86_REG_ECX = 10,
717     X86_REG_EDX = 9,
718     X86_REG_EBX = 8,
719     X86_REG_ESP = 7,
720     X86_REG_EBP = 6,
721     X86_REG_ESI = 5,
722     X86_REG_EDI = 4
723 gbeauche 1.34 #endif
724     #if defined(__x86_64__)
725     X86_REG_R8 = 0,
726     X86_REG_R9 = 1,
727     X86_REG_R10 = 2,
728     X86_REG_R11 = 3,
729     X86_REG_R12 = 4,
730     X86_REG_R13 = 5,
731     X86_REG_R14 = 6,
732     X86_REG_R15 = 7,
733     X86_REG_EDI = 8,
734     X86_REG_ESI = 9,
735     X86_REG_EBP = 10,
736     X86_REG_EBX = 11,
737     X86_REG_EDX = 12,
738     X86_REG_EAX = 13,
739     X86_REG_ECX = 14,
740     X86_REG_ESP = 15,
741     X86_REG_EIP = 16
742     #endif
743 gbeauche 1.10 };
744     #endif
745 gbeauche 1.51 #if defined(__NetBSD__)
746     enum {
747     #if (defined(i386) || defined(__i386__))
748     X86_REG_EIP = _REG_EIP,
749     X86_REG_EAX = _REG_EAX,
750     X86_REG_ECX = _REG_ECX,
751     X86_REG_EDX = _REG_EDX,
752     X86_REG_EBX = _REG_EBX,
753     X86_REG_ESP = _REG_ESP,
754     X86_REG_EBP = _REG_EBP,
755     X86_REG_ESI = _REG_ESI,
756     X86_REG_EDI = _REG_EDI
757     #endif
758     };
759     #endif
760     #if defined(__FreeBSD__)
761 gbeauche 1.17 enum {
762 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
763 gbeauche 1.17 X86_REG_EIP = 10,
764     X86_REG_EAX = 7,
765     X86_REG_ECX = 6,
766     X86_REG_EDX = 5,
767     X86_REG_EBX = 4,
768     X86_REG_ESP = 13,
769     X86_REG_EBP = 2,
770     X86_REG_ESI = 1,
771     X86_REG_EDI = 0
772 gbeauche 1.34 #endif
773 gbeauche 1.17 };
774     #endif
775 gbeauche 1.55 #if defined(__OpenBSD__)
776     enum {
777     #if defined(__i386__)
778     // EDI is the first register we consider
779     #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
780     #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
781     X86_REG_EIP = DREG(eip), // 7
782     X86_REG_EAX = DREG(eax), // 6
783     X86_REG_ECX = DREG(ecx), // 5
784     X86_REG_EDX = DREG(edx), // 4
785     X86_REG_EBX = DREG(ebx), // 3
786     X86_REG_ESP = DREG(esp), // 10
787     X86_REG_EBP = DREG(ebp), // 2
788     X86_REG_ESI = DREG(esi), // 1
789     X86_REG_EDI = DREG(edi) // 0
790     #undef DREG
791     #undef OREG
792     #endif
793     };
794     #endif
795 gbeauche 1.54 #if defined(__sun__)
796     // Same as for Linux, need to check for x86-64
797     enum {
798     #if defined(__i386__)
799     X86_REG_EIP = EIP,
800     X86_REG_EAX = EAX,
801     X86_REG_ECX = ECX,
802     X86_REG_EDX = EDX,
803     X86_REG_EBX = EBX,
804     X86_REG_ESP = ESP,
805     X86_REG_EBP = EBP,
806     X86_REG_ESI = ESI,
807     X86_REG_EDI = EDI
808     #endif
809     };
810     #endif
811 gbeauche 1.56 #if defined(__APPLE__) && defined(__MACH__)
812     enum {
813 gbeauche 1.66 #if (defined(i386) || defined(__i386__))
814 gbeauche 1.57 #ifdef i386_SAVED_STATE
815     // same as FreeBSD (in Open Darwin 8.0.1)
816 gbeauche 1.56 X86_REG_EIP = 10,
817     X86_REG_EAX = 7,
818     X86_REG_ECX = 6,
819     X86_REG_EDX = 5,
820     X86_REG_EBX = 4,
821     X86_REG_ESP = 13,
822     X86_REG_EBP = 2,
823     X86_REG_ESI = 1,
824     X86_REG_EDI = 0
825 gbeauche 1.57 #else
826     // new layout (MacOS X 10.4.4 for x86)
827     X86_REG_EIP = 10,
828     X86_REG_EAX = 0,
829     X86_REG_ECX = 2,
830 gbeauche 1.66 X86_REG_EDX = 3,
831 gbeauche 1.57 X86_REG_EBX = 1,
832     X86_REG_ESP = 7,
833     X86_REG_EBP = 6,
834     X86_REG_ESI = 5,
835     X86_REG_EDI = 4
836     #endif
837 gbeauche 1.66 #endif
838     #if defined(__x86_64__)
839     X86_REG_R8 = 8,
840     X86_REG_R9 = 9,
841     X86_REG_R10 = 10,
842     X86_REG_R11 = 11,
843     X86_REG_R12 = 12,
844     X86_REG_R13 = 13,
845     X86_REG_R14 = 14,
846     X86_REG_R15 = 15,
847     X86_REG_EDI = 4,
848     X86_REG_ESI = 5,
849     X86_REG_EBP = 6,
850     X86_REG_EBX = 1,
851     X86_REG_EDX = 3,
852     X86_REG_EAX = 0,
853     X86_REG_ECX = 2,
854     X86_REG_ESP = 7,
855     X86_REG_EIP = 16
856     #endif
857 gbeauche 1.56 };
858     #endif
859 gbeauche 1.48 #if defined(_WIN32)
860     enum {
861     #if (defined(i386) || defined(__i386__))
862     X86_REG_EIP = 7,
863     X86_REG_EAX = 5,
864     X86_REG_ECX = 4,
865     X86_REG_EDX = 3,
866     X86_REG_EBX = 2,
867     X86_REG_ESP = 10,
868     X86_REG_EBP = 6,
869     X86_REG_ESI = 1,
870     X86_REG_EDI = 0
871     #endif
872     };
873     #endif
874 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
875     // to discover transfer type and register number
876     static inline int ix86_step_over_modrm(unsigned char * p)
877     {
878     int mod = (p[0] >> 6) & 3;
879     int rm = p[0] & 7;
880     int offset = 0;
881    
882     // ModR/M Byte
883     switch (mod) {
884     case 0: // [reg]
885     if (rm == 5) return 4; // disp32
886     break;
887     case 1: // disp8[reg]
888     offset = 1;
889     break;
890     case 2: // disp32[reg]
891     offset = 4;
892     break;
893     case 3: // register
894     return 0;
895     }
896    
897     // SIB Byte
898     if (rm == 4) {
899     if (mod == 0 && (p[1] & 7) == 5)
900     offset = 5; // disp32[index]
901     else
902     offset++;
903     }
904    
905     return offset;
906     }
907    
908 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
909 gbeauche 1.10 {
910 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
911 gbeauche 1.10
912     if (eip == 0)
913     return false;
914 gbeauche 1.50 #ifdef _WIN32
915     if (IsBadCodePtr((FARPROC)eip))
916     return false;
917     #endif
918 gbeauche 1.10
919 gbeauche 1.64 enum instruction_type_t {
920     i_MOV,
921     i_ADD
922     };
923    
924 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
925 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
926 gbeauche 1.64 instruction_type_t instruction_type = i_MOV;
927 gbeauche 1.10
928     int reg = -1;
929     int len = 0;
930 gbeauche 1.34
931     #if DEBUG
932     printf("IP: %p [%02x %02x %02x %02x...]\n",
933     eip, eip[0], eip[1], eip[2], eip[3]);
934     #endif
935    
936 gbeauche 1.10 // Operand size prefix
937     if (*eip == 0x66) {
938     eip++;
939     len++;
940     transfer_size = SIZE_WORD;
941     }
942    
943 gbeauche 1.34 // REX prefix
944     #if defined(__x86_64__)
945     struct rex_t {
946     unsigned char W;
947     unsigned char R;
948     unsigned char X;
949     unsigned char B;
950     };
951     rex_t rex = { 0, 0, 0, 0 };
952     bool has_rex = false;
953     if ((*eip & 0xf0) == 0x40) {
954     has_rex = true;
955     const unsigned char b = *eip;
956     rex.W = b & (1 << 3);
957     rex.R = b & (1 << 2);
958     rex.X = b & (1 << 1);
959     rex.B = b & (1 << 0);
960     #if DEBUG
961     printf("REX: %c,%c,%c,%c\n",
962     rex.W ? 'W' : '_',
963     rex.R ? 'R' : '_',
964     rex.X ? 'X' : '_',
965     rex.B ? 'B' : '_');
966     #endif
967     eip++;
968     len++;
969     if (rex.W)
970     transfer_size = SIZE_QUAD;
971     }
972     #else
973     const bool has_rex = false;
974     #endif
975    
976 gbeauche 1.10 // Decode instruction
977 gbeauche 1.64 int op_len = 1;
978 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
979 gbeauche 1.10 switch (eip[0]) {
980 gbeauche 1.17 case 0x0f:
981 gbeauche 1.45 target_size = transfer_size;
982 gbeauche 1.18 switch (eip[1]) {
983 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
984 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
985 gbeauche 1.45 transfer_size = SIZE_BYTE;
986     goto do_mov_extend;
987 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
988 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
989 gbeauche 1.45 transfer_size = SIZE_WORD;
990     goto do_mov_extend;
991     do_mov_extend:
992 gbeauche 1.64 op_len = 2;
993     goto do_transfer_load;
994     }
995     break;
996 gbeauche 1.62 #if defined(__x86_64__)
997     case 0x63: // MOVSXD r64, r/m32
998     if (has_rex && rex.W) {
999     transfer_size = SIZE_LONG;
1000     target_size = SIZE_QUAD;
1001     }
1002     else if (transfer_size != SIZE_WORD) {
1003     transfer_size = SIZE_LONG;
1004     target_size = SIZE_QUAD;
1005     }
1006 gbeauche 1.64 goto do_transfer_load;
1007 gbeauche 1.62 #endif
1008 gbeauche 1.64 case 0x02: // ADD r8, r/m8
1009     transfer_size = SIZE_BYTE;
1010     case 0x03: // ADD r32, r/m32
1011     instruction_type = i_ADD;
1012     goto do_transfer_load;
1013 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
1014     transfer_size = SIZE_BYTE;
1015     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1016 gbeauche 1.64 do_transfer_load:
1017     switch (eip[op_len] & 0xc0) {
1018 gbeauche 1.10 case 0x80:
1019 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1020 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1021 gbeauche 1.10 break;
1022     case 0x40:
1023 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1024 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1025 gbeauche 1.10 break;
1026     case 0x00:
1027 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1028 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1029 gbeauche 1.10 break;
1030     }
1031 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1032 gbeauche 1.10 break;
1033 gbeauche 1.64 case 0x00: // ADD r/m8, r8
1034     transfer_size = SIZE_BYTE;
1035     case 0x01: // ADD r/m32, r32
1036     instruction_type = i_ADD;
1037     goto do_transfer_store;
1038 gbeauche 1.10 case 0x88: // MOV r/m8, r8
1039     transfer_size = SIZE_BYTE;
1040     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1041 gbeauche 1.64 do_transfer_store:
1042     switch (eip[op_len] & 0xc0) {
1043 gbeauche 1.10 case 0x80:
1044 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1045 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1046 gbeauche 1.10 break;
1047     case 0x40:
1048 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1049 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1050 gbeauche 1.10 break;
1051     case 0x00:
1052 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1053 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1054 gbeauche 1.10 break;
1055     }
1056 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1057 gbeauche 1.10 break;
1058     }
1059 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
1060     target_size = transfer_size;
1061 gbeauche 1.10
1062 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1063 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
1064     return false;
1065     }
1066    
1067 gbeauche 1.34 #if defined(__x86_64__)
1068     if (rex.R)
1069     reg += 8;
1070     #endif
1071    
1072 gbeauche 1.64 if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1073 gbeauche 1.34 static const int x86_reg_map[] = {
1074 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1075 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1076     #if defined(__x86_64__)
1077     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1078     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1079     #endif
1080 gbeauche 1.10 };
1081    
1082 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1083 gbeauche 1.10 return false;
1084    
1085 gbeauche 1.34 // Set 0 to the relevant register part
1086     // NOTE: this is only valid for MOV alike instructions
1087 gbeauche 1.10 int rloc = x86_reg_map[reg];
1088 gbeauche 1.45 switch (target_size) {
1089 gbeauche 1.10 case SIZE_BYTE:
1090 gbeauche 1.36 if (has_rex || reg < 4)
1091     regs[rloc] = (regs[rloc] & ~0x00ffL);
1092     else {
1093     rloc = x86_reg_map[reg - 4];
1094     regs[rloc] = (regs[rloc] & ~0xff00L);
1095     }
1096 gbeauche 1.10 break;
1097     case SIZE_WORD:
1098 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1099 gbeauche 1.10 break;
1100     case SIZE_LONG:
1101 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1102 gbeauche 1.10 regs[rloc] = 0;
1103     break;
1104     }
1105     }
1106    
1107     #if DEBUG
1108 gbeauche 1.64 printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1109 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1110     transfer_size == SIZE_WORD ? "word" :
1111     transfer_size == SIZE_LONG ? "long" :
1112     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1113 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1114 gbeauche 1.10
1115     if (reg != -1) {
1116 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1117     "al", "cl", "dl", "bl",
1118     "spl", "bpl", "sil", "dil",
1119     "r8b", "r9b", "r10b", "r11b",
1120     "r12b", "r13b", "r14b", "r15b",
1121     "ah", "ch", "dh", "bh",
1122     };
1123     static const char * x86_word_reg_str_map[] = {
1124     "ax", "cx", "dx", "bx",
1125     "sp", "bp", "si", "di",
1126     "r8w", "r9w", "r10w", "r11w",
1127     "r12w", "r13w", "r14w", "r15w",
1128     };
1129     static const char *x86_long_reg_str_map[] = {
1130     "eax", "ecx", "edx", "ebx",
1131     "esp", "ebp", "esi", "edi",
1132     "r8d", "r9d", "r10d", "r11d",
1133     "r12d", "r13d", "r14d", "r15d",
1134     };
1135     static const char *x86_quad_reg_str_map[] = {
1136     "rax", "rcx", "rdx", "rbx",
1137     "rsp", "rbp", "rsi", "rdi",
1138     "r8", "r9", "r10", "r11",
1139     "r12", "r13", "r14", "r15",
1140 gbeauche 1.10 };
1141 gbeauche 1.34 const char * reg_str = NULL;
1142 gbeauche 1.46 switch (target_size) {
1143 gbeauche 1.34 case SIZE_BYTE:
1144     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1145     break;
1146     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1147     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1148     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1149     }
1150     if (reg_str)
1151     printf(" %s register %%%s",
1152     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1153     reg_str);
1154 gbeauche 1.10 }
1155     printf(", %d bytes instruction\n", len);
1156     #endif
1157    
1158     regs[X86_REG_EIP] += len;
1159 gbeauche 1.13 return true;
1160     }
1161     #endif
1162 gbeauche 1.14
1163 gbeauche 1.13 // Decode and skip PPC instruction
1164 gbeauche 1.69 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1165 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1166 gbeauche 1.13 {
1167 gbeauche 1.14 instruction_t instr;
1168     powerpc_decode_instruction(&instr, *nip_p, regs);
1169 gbeauche 1.13
1170 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1171 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1172     return false;
1173     }
1174    
1175     #if DEBUG
1176 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1177 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1178     instr.transfer_size == SIZE_WORD ? "word" :
1179     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1180 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1181 gbeauche 1.14
1182     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1183     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1184 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1185 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1186     #endif
1187    
1188     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1189     regs[instr.ra] = instr.addr;
1190 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1191 gbeauche 1.14 regs[instr.rd] = 0;
1192 gbeauche 1.13
1193 gbeauche 1.14 *nip_p += 4;
1194 gbeauche 1.10 return true;
1195 gbeauche 1.38 }
1196     #endif
1197    
1198     // Decode and skip MIPS instruction
1199     #if (defined(mips) || defined(__mips))
1200 gbeauche 1.65 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1201 gbeauche 1.38 {
1202 gbeauche 1.65 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1203 gbeauche 1.38
1204     if (epc == 0)
1205     return false;
1206    
1207     #if DEBUG
1208     printf("IP: %p [%08x]\n", epc, epc[0]);
1209     #endif
1210    
1211     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1212     transfer_size_t transfer_size = SIZE_LONG;
1213     int direction = 0;
1214    
1215     const unsigned int opcode = epc[0];
1216     switch (opcode >> 26) {
1217     case 32: // Load Byte
1218     case 36: // Load Byte Unsigned
1219     transfer_type = SIGSEGV_TRANSFER_LOAD;
1220     transfer_size = SIZE_BYTE;
1221     break;
1222     case 33: // Load Halfword
1223     case 37: // Load Halfword Unsigned
1224     transfer_type = SIGSEGV_TRANSFER_LOAD;
1225     transfer_size = SIZE_WORD;
1226     break;
1227     case 35: // Load Word
1228     case 39: // Load Word Unsigned
1229     transfer_type = SIGSEGV_TRANSFER_LOAD;
1230     transfer_size = SIZE_LONG;
1231     break;
1232     case 34: // Load Word Left
1233     transfer_type = SIGSEGV_TRANSFER_LOAD;
1234     transfer_size = SIZE_LONG;
1235     direction = -1;
1236     break;
1237     case 38: // Load Word Right
1238     transfer_type = SIGSEGV_TRANSFER_LOAD;
1239     transfer_size = SIZE_LONG;
1240     direction = 1;
1241     break;
1242     case 55: // Load Doubleword
1243     transfer_type = SIGSEGV_TRANSFER_LOAD;
1244     transfer_size = SIZE_QUAD;
1245     break;
1246     case 26: // Load Doubleword Left
1247     transfer_type = SIGSEGV_TRANSFER_LOAD;
1248     transfer_size = SIZE_QUAD;
1249     direction = -1;
1250     break;
1251     case 27: // Load Doubleword Right
1252     transfer_type = SIGSEGV_TRANSFER_LOAD;
1253     transfer_size = SIZE_QUAD;
1254     direction = 1;
1255     break;
1256     case 40: // Store Byte
1257     transfer_type = SIGSEGV_TRANSFER_STORE;
1258     transfer_size = SIZE_BYTE;
1259     break;
1260     case 41: // Store Halfword
1261     transfer_type = SIGSEGV_TRANSFER_STORE;
1262     transfer_size = SIZE_WORD;
1263     break;
1264     case 43: // Store Word
1265     case 42: // Store Word Left
1266     case 46: // Store Word Right
1267     transfer_type = SIGSEGV_TRANSFER_STORE;
1268     transfer_size = SIZE_LONG;
1269     break;
1270     case 63: // Store Doubleword
1271     case 44: // Store Doubleword Left
1272     case 45: // Store Doubleword Right
1273     transfer_type = SIGSEGV_TRANSFER_STORE;
1274     transfer_size = SIZE_QUAD;
1275     break;
1276     /* Misc instructions unlikely to be used within CPU emulators */
1277     case 48: // Load Linked Word
1278     transfer_type = SIGSEGV_TRANSFER_LOAD;
1279     transfer_size = SIZE_LONG;
1280     break;
1281     case 52: // Load Linked Doubleword
1282     transfer_type = SIGSEGV_TRANSFER_LOAD;
1283     transfer_size = SIZE_QUAD;
1284     break;
1285     case 56: // Store Conditional Word
1286     transfer_type = SIGSEGV_TRANSFER_STORE;
1287     transfer_size = SIZE_LONG;
1288     break;
1289     case 60: // Store Conditional Doubleword
1290     transfer_type = SIGSEGV_TRANSFER_STORE;
1291     transfer_size = SIZE_QUAD;
1292     break;
1293     }
1294    
1295     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1296     // Unknown machine code, let it crash. Then patch the decoder
1297     return false;
1298     }
1299    
1300     // Zero target register in case of a load operation
1301     const int reg = (opcode >> 16) & 0x1f;
1302     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1303     if (direction == 0)
1304     regs[reg] = 0;
1305     else {
1306     // FIXME: untested code
1307     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1308     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1309     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1310     unsigned long value;
1311     if (direction > 0) {
1312     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1313     value = regs[reg] & rmask;
1314     }
1315     else {
1316     const unsigned long lmask = (1L << (offset * 8)) - 1;
1317     value = regs[reg] & lmask;
1318     }
1319     // restore most significant bits
1320     if (transfer_size == SIZE_LONG)
1321     value = (signed long)(signed int)value;
1322     regs[reg] = value;
1323     }
1324     }
1325    
1326     #if DEBUG
1327     #if (defined(_ABIN32) || defined(_ABI64))
1328     static const char * mips_gpr_names[32] = {
1329     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1330     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1331     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1332     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1333     };
1334     #else
1335     static const char * mips_gpr_names[32] = {
1336     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1337     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1338     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1339     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1340     };
1341     #endif
1342     printf("%s %s register %s\n",
1343     transfer_size == SIZE_BYTE ? "byte" :
1344     transfer_size == SIZE_WORD ? "word" :
1345     transfer_size == SIZE_LONG ? "long" :
1346     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1347     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1348     mips_gpr_names[reg]);
1349     #endif
1350    
1351 gbeauche 1.65 *pc_p += 4;
1352 gbeauche 1.40 return true;
1353     }
1354     #endif
1355    
1356     // Decode and skip SPARC instruction
1357     #if (defined(sparc) || defined(__sparc__))
1358     enum {
1359     #if (defined(__sun__))
1360     SPARC_REG_G1 = REG_G1,
1361     SPARC_REG_O0 = REG_O0,
1362     SPARC_REG_PC = REG_PC,
1363 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
1364 gbeauche 1.40 #endif
1365     };
1366     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1367     {
1368     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1369    
1370     if (pc == 0)
1371     return false;
1372    
1373     #if DEBUG
1374     printf("IP: %p [%08x]\n", pc, pc[0]);
1375     #endif
1376    
1377     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1378     transfer_size_t transfer_size = SIZE_LONG;
1379     bool register_pair = false;
1380    
1381     const unsigned int opcode = pc[0];
1382     if ((opcode >> 30) != 3)
1383     return false;
1384     switch ((opcode >> 19) & 0x3f) {
1385     case 9: // Load Signed Byte
1386     case 1: // Load Unsigned Byte
1387     transfer_type = SIGSEGV_TRANSFER_LOAD;
1388     transfer_size = SIZE_BYTE;
1389     break;
1390     case 10:// Load Signed Halfword
1391     case 2: // Load Unsigned Word
1392     transfer_type = SIGSEGV_TRANSFER_LOAD;
1393     transfer_size = SIZE_WORD;
1394     break;
1395     case 8: // Load Word
1396     case 0: // Load Unsigned Word
1397     transfer_type = SIGSEGV_TRANSFER_LOAD;
1398     transfer_size = SIZE_LONG;
1399     break;
1400     case 11:// Load Extended Word
1401     transfer_type = SIGSEGV_TRANSFER_LOAD;
1402     transfer_size = SIZE_QUAD;
1403     break;
1404     case 3: // Load Doubleword
1405     transfer_type = SIGSEGV_TRANSFER_LOAD;
1406     transfer_size = SIZE_LONG;
1407     register_pair = true;
1408     break;
1409     case 5: // Store Byte
1410     transfer_type = SIGSEGV_TRANSFER_STORE;
1411     transfer_size = SIZE_BYTE;
1412     break;
1413     case 6: // Store Halfword
1414     transfer_type = SIGSEGV_TRANSFER_STORE;
1415     transfer_size = SIZE_WORD;
1416     break;
1417     case 4: // Store Word
1418     transfer_type = SIGSEGV_TRANSFER_STORE;
1419     transfer_size = SIZE_LONG;
1420     break;
1421     case 14:// Store Extended Word
1422     transfer_type = SIGSEGV_TRANSFER_STORE;
1423     transfer_size = SIZE_QUAD;
1424     break;
1425     case 7: // Store Doubleword
1426     transfer_type = SIGSEGV_TRANSFER_STORE;
1427 gbeauche 1.58 transfer_size = SIZE_LONG;
1428 gbeauche 1.40 register_pair = true;
1429     break;
1430     }
1431    
1432     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1433     // Unknown machine code, let it crash. Then patch the decoder
1434     return false;
1435     }
1436    
1437 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
1438    
1439     #if DEBUG
1440     static const char * reg_names[] = {
1441     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1442     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1443     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1444     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1445     };
1446     printf("%s %s register %s\n",
1447     transfer_size == SIZE_BYTE ? "byte" :
1448     transfer_size == SIZE_WORD ? "word" :
1449     transfer_size == SIZE_LONG ? "long" :
1450     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1451     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1452     reg_names[reg]);
1453     #endif
1454    
1455 gbeauche 1.40 // Zero target register in case of a load operation
1456     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1457     // FIXME: code to handle local & input registers is not tested
1458 gbeauche 1.58 if (reg >= 1 && reg < 8) {
1459 gbeauche 1.40 // global registers
1460     regs[reg - 1 + SPARC_REG_G1] = 0;
1461     }
1462 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
1463 gbeauche 1.40 // output registers
1464     regs[reg - 8 + SPARC_REG_O0] = 0;
1465     }
1466 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
1467 gbeauche 1.40 // local registers (in register windows)
1468     if (gwins)
1469     gwins->wbuf->rw_local[reg - 16] = 0;
1470     else
1471     rwin->rw_local[reg - 16] = 0;
1472     }
1473     else {
1474     // input registers (in register windows)
1475     if (gwins)
1476     gwins->wbuf->rw_in[reg - 24] = 0;
1477     else
1478     rwin->rw_in[reg - 24] = 0;
1479     }
1480     }
1481    
1482     regs[SPARC_REG_PC] += 4;
1483 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
1484 gbeauche 1.38 return true;
1485 gbeauche 1.10 }
1486     #endif
1487     #endif
1488    
1489 gbeauche 1.44 // Decode and skip ARM instruction
1490     #if (defined(arm) || defined(__arm__))
1491     enum {
1492     #if (defined(__linux__))
1493     ARM_REG_PC = 15,
1494     ARM_REG_CPSR = 16
1495     #endif
1496     };
1497     static bool arm_skip_instruction(unsigned long * regs)
1498     {
1499     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1500    
1501     if (pc == 0)
1502     return false;
1503    
1504     #if DEBUG
1505     printf("IP: %p [%08x]\n", pc, pc[0]);
1506     #endif
1507    
1508     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1509     transfer_size_t transfer_size = SIZE_UNKNOWN;
1510     enum { op_sdt = 1, op_sdth = 2 };
1511     int op = 0;
1512    
1513     // Handle load/store instructions only
1514     const unsigned int opcode = pc[0];
1515     switch ((opcode >> 25) & 7) {
1516     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1517     op = op_sdth;
1518     // Determine transfer size (S/H bits)
1519     switch ((opcode >> 5) & 3) {
1520     case 0: // SWP instruction
1521     break;
1522     case 1: // Unsigned halfwords
1523     case 3: // Signed halfwords
1524     transfer_size = SIZE_WORD;
1525     break;
1526     case 2: // Signed byte
1527     transfer_size = SIZE_BYTE;
1528     break;
1529     }
1530     break;
1531     case 2:
1532     case 3: // Single Data Transfer (LDR, STR)
1533     op = op_sdt;
1534     // Determine transfer size (B bit)
1535     if (((opcode >> 22) & 1) == 1)
1536     transfer_size = SIZE_BYTE;
1537     else
1538     transfer_size = SIZE_LONG;
1539     break;
1540     default:
1541     // FIXME: support load/store mutliple?
1542     return false;
1543     }
1544    
1545     // Check for invalid transfer size (SWP instruction?)
1546     if (transfer_size == SIZE_UNKNOWN)
1547     return false;
1548    
1549     // Determine transfer type (L bit)
1550     if (((opcode >> 20) & 1) == 1)
1551     transfer_type = SIGSEGV_TRANSFER_LOAD;
1552     else
1553     transfer_type = SIGSEGV_TRANSFER_STORE;
1554    
1555     // Compute offset
1556     int offset;
1557     if (((opcode >> 25) & 1) == 0) {
1558     if (op == op_sdt)
1559     offset = opcode & 0xfff;
1560     else if (op == op_sdth) {
1561     int rm = opcode & 0xf;
1562     if (((opcode >> 22) & 1) == 0) {
1563     // register offset
1564     offset = regs[rm];
1565     }
1566     else {
1567     // immediate offset
1568     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1569     }
1570     }
1571     }
1572     else {
1573     const int rm = opcode & 0xf;
1574     const int sh = (opcode >> 7) & 0x1f;
1575     if (((opcode >> 4) & 1) == 1) {
1576     // we expect only legal load/store instructions
1577     printf("FATAL: invalid shift operand\n");
1578     return false;
1579     }
1580     const unsigned int v = regs[rm];
1581     switch ((opcode >> 5) & 3) {
1582     case 0: // logical shift left
1583     offset = sh ? v << sh : v;
1584     break;
1585     case 1: // logical shift right
1586     offset = sh ? v >> sh : 0;
1587     break;
1588     case 2: // arithmetic shift right
1589     if (sh)
1590     offset = ((signed int)v) >> sh;
1591     else
1592     offset = (v & 0x80000000) ? 0xffffffff : 0;
1593     break;
1594     case 3: // rotate right
1595     if (sh)
1596     offset = (v >> sh) | (v << (32 - sh));
1597     else
1598     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1599     break;
1600     }
1601     }
1602     if (((opcode >> 23) & 1) == 0)
1603     offset = -offset;
1604    
1605     int rd = (opcode >> 12) & 0xf;
1606     int rn = (opcode >> 16) & 0xf;
1607     #if DEBUG
1608     static const char * reg_names[] = {
1609     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1610     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1611     };
1612     printf("%s %s register %s\n",
1613     transfer_size == SIZE_BYTE ? "byte" :
1614     transfer_size == SIZE_WORD ? "word" :
1615     transfer_size == SIZE_LONG ? "long" : "unknown",
1616     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1617     reg_names[rd]);
1618     #endif
1619    
1620     unsigned int base = regs[rn];
1621     if (((opcode >> 24) & 1) == 1)
1622     base += offset;
1623    
1624     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1625     regs[rd] = 0;
1626    
1627     if (((opcode >> 24) & 1) == 0) // post-index addressing
1628     regs[rn] += offset;
1629     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1630     regs[rn] = base;
1631    
1632     regs[ARM_REG_PC] += 4;
1633     return true;
1634     }
1635     #endif
1636    
1637    
1638 gbeauche 1.1 // Fallbacks
1639 gbeauche 1.68 #ifndef SIGSEGV_FAULT_ADDRESS_FAST
1640     #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS
1641     #endif
1642     #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
1643     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION
1644     #endif
1645 gbeauche 1.1 #ifndef SIGSEGV_FAULT_INSTRUCTION
1646 gbeauche 1.67 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
1647 gbeauche 1.1 #endif
1648 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1649     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1650     #endif
1651 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1652 gbeauche 1.67 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
1653 gbeauche 1.31 #endif
1654 gbeauche 1.1
1655 gbeauche 1.2 // SIGSEGV recovery supported ?
1656     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1657     #define HAVE_SIGSEGV_RECOVERY
1658     #endif
1659    
1660 gbeauche 1.1
1661     /*
1662     * SIGSEGV global handler
1663     */
1664    
1665 gbeauche 1.67 struct sigsegv_info_t {
1666     sigsegv_address_t addr;
1667     sigsegv_address_t pc;
1668 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
1669     mach_port_t thread;
1670     bool has_exc_state;
1671     SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
1672     mach_msg_type_number_t exc_state_count;
1673     bool has_thr_state;
1674     SIGSEGV_THREAD_STATE_TYPE thr_state;
1675     mach_msg_type_number_t thr_state_count;
1676     #endif
1677 gbeauche 1.67 };
1678    
1679 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
1680     static void mach_get_exception_state(sigsegv_info_t *sip)
1681     {
1682     sip->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
1683     kern_return_t krc = thread_get_state(sip->thread,
1684     SIGSEGV_EXCEPTION_STATE_FLAVOR,
1685     (natural_t *)&sip->exc_state,
1686     &sip->exc_state_count);
1687     MACH_CHECK_ERROR(thread_get_state, krc);
1688     sip->has_exc_state = true;
1689     }
1690    
1691     static void mach_get_thread_state(sigsegv_info_t *sip)
1692     {
1693     sip->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
1694     kern_return_t krc = thread_get_state(sip->thread,
1695     SIGSEGV_THREAD_STATE_FLAVOR,
1696     (natural_t *)&sip->thr_state,
1697     &sip->thr_state_count);
1698     MACH_CHECK_ERROR(thread_get_state, krc);
1699     sip->has_thr_state = true;
1700     }
1701    
1702     static void mach_set_thread_state(sigsegv_info_t *sip)
1703     {
1704     kern_return_t krc = thread_set_state(sip->thread,
1705     SIGSEGV_THREAD_STATE_FLAVOR,
1706     (natural_t *)&sip->thr_state,
1707     sip->thr_state_count);
1708     MACH_CHECK_ERROR(thread_set_state, krc);
1709     }
1710     #endif
1711    
1712 gbeauche 1.67 // Return the address of the invalid memory reference
1713     sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip)
1714     {
1715 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
1716     static int use_fast_path = -1;
1717     if (use_fast_path != 1 && !sip->has_exc_state) {
1718 gbeauche 1.70 mach_get_exception_state(sip);
1719 gbeauche 1.68
1720     sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1721     if (use_fast_path < 0)
1722     use_fast_path = addr == sip->addr;
1723     sip->addr = addr;
1724     }
1725     #endif
1726 gbeauche 1.67 return sip->addr;
1727     }
1728    
1729     // Return the address of the instruction that caused the fault, or
1730     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
1731     sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip)
1732     {
1733 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
1734     if (!sip->has_thr_state) {
1735 gbeauche 1.70 mach_get_thread_state(sip);
1736 gbeauche 1.68
1737     sip->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1738     }
1739     #endif
1740 gbeauche 1.67 return sip->pc;
1741     }
1742    
1743 gbeauche 1.27 // This function handles the badaccess to memory.
1744     // It is called from the signal handler or the exception handler.
1745 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1746 gbeauche 1.1 {
1747 gbeauche 1.68 sigsegv_info_t si;
1748     si.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
1749     si.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
1750 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1751 gbeauche 1.68 si.thread = thread;
1752     si.has_exc_state = false;
1753     si.has_thr_state = false;
1754 gbeauche 1.56 #endif
1755 gbeauche 1.68 sigsegv_info_t * const sip = &si;
1756 gbeauche 1.56
1757 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1758 gbeauche 1.68 switch (SIGSEGV_FAULT_HANDLER_INVOKE(sip)) {
1759 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1760 gbeauche 1.27 return true;
1761    
1762 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1763 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1764 gbeauche 1.27 // Call the instruction skipper with the register file
1765     // available
1766 gbeauche 1.70 #ifdef HAVE_MACH_EXCEPTIONS
1767     if (!sip->has_thr_state)
1768     mach_get_thread_state(sip);
1769     #endif
1770 gbeauche 1.27 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1771     #ifdef HAVE_MACH_EXCEPTIONS
1772     // Unlike UNIX signals where the thread state
1773     // is modified off of the stack, in Mach we
1774     // need to actually call thread_set_state to
1775     // have the register values updated.
1776 gbeauche 1.70 mach_set_thread_state(sip);
1777 gbeauche 1.27 #endif
1778     return true;
1779     }
1780 gbeauche 1.24 break;
1781     #endif
1782 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1783 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1784     if (sigsegv_state_dumper != 0)
1785 gbeauche 1.68 sigsegv_state_dumper(sip);
1786 gbeauche 1.50 break;
1787 gbeauche 1.10 }
1788 gbeauche 1.27
1789     return false;
1790     }
1791    
1792    
1793     /*
1794     * There are two mechanisms for handling a bad memory access,
1795     * Mach exceptions and UNIX signals. The implementation specific
1796     * code appears below. Its reponsibility is to call handle_badaccess
1797     * which is the routine that handles the fault in an implementation
1798     * agnostic manner. The implementation specific code below is then
1799     * reponsible for checking whether handle_badaccess was able
1800     * to handle the memory access error and perform any implementation
1801     * specific tasks necessary afterwards.
1802     */
1803    
1804     #ifdef HAVE_MACH_EXCEPTIONS
1805     /*
1806     * We need to forward all exceptions that we do not handle.
1807     * This is important, there are many exceptions that may be
1808     * handled by other exception handlers. For example debuggers
1809     * use exceptions and the exception hander is in another
1810     * process in such a case. (Timothy J. Wood states in his
1811     * message to the list that he based this code on that from
1812     * gdb for Darwin.)
1813     */
1814     static inline kern_return_t
1815     forward_exception(mach_port_t thread_port,
1816     mach_port_t task_port,
1817     exception_type_t exception_type,
1818     exception_data_t exception_data,
1819     mach_msg_type_number_t data_count,
1820     ExceptionPorts *oldExceptionPorts)
1821     {
1822     kern_return_t kret;
1823     unsigned int portIndex;
1824     mach_port_t port;
1825     exception_behavior_t behavior;
1826     thread_state_flavor_t flavor;
1827 gbeauche 1.57 thread_state_data_t thread_state;
1828 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1829    
1830     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1831     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1832     // This handler wants the exception
1833     break;
1834     }
1835     }
1836    
1837     if (portIndex >= oldExceptionPorts->maskCount) {
1838     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1839     return KERN_FAILURE;
1840     }
1841    
1842     port = oldExceptionPorts->handlers[portIndex];
1843     behavior = oldExceptionPorts->behaviors[portIndex];
1844     flavor = oldExceptionPorts->flavors[portIndex];
1845    
1846 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1847     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1848     return KERN_FAILURE;
1849     }
1850    
1851 gbeauche 1.27 /*
1852     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1853     */
1854    
1855     if (behavior != EXCEPTION_DEFAULT) {
1856     thread_state_count = THREAD_STATE_MAX;
1857 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1858 gbeauche 1.27 &thread_state_count);
1859     MACH_CHECK_ERROR (thread_get_state, kret);
1860     }
1861    
1862     switch (behavior) {
1863     case EXCEPTION_DEFAULT:
1864     // fprintf(stderr, "forwarding to exception_raise\n");
1865     kret = exception_raise(port, thread_port, task_port, exception_type,
1866     exception_data, data_count);
1867     MACH_CHECK_ERROR (exception_raise, kret);
1868     break;
1869     case EXCEPTION_STATE:
1870     // fprintf(stderr, "forwarding to exception_raise_state\n");
1871     kret = exception_raise_state(port, exception_type, exception_data,
1872     data_count, &flavor,
1873 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1874     (natural_t *)&thread_state, &thread_state_count);
1875 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
1876     break;
1877     case EXCEPTION_STATE_IDENTITY:
1878     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1879     kret = exception_raise_state_identity(port, thread_port, task_port,
1880     exception_type, exception_data,
1881     data_count, &flavor,
1882 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1883     (natural_t *)&thread_state, &thread_state_count);
1884 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1885     break;
1886     default:
1887     fprintf(stderr, "forward_exception got unknown behavior\n");
1888 gbeauche 1.63 kret = KERN_FAILURE;
1889 gbeauche 1.27 break;
1890     }
1891    
1892     if (behavior != EXCEPTION_DEFAULT) {
1893 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1894 gbeauche 1.27 thread_state_count);
1895     MACH_CHECK_ERROR (thread_set_state, kret);
1896     }
1897    
1898 gbeauche 1.63 return kret;
1899 gbeauche 1.27 }
1900    
1901     /*
1902     * This is the code that actually handles the exception.
1903     * It is called by exc_server. For Darwin 5 Apple changed
1904     * this a bit from how this family of functions worked in
1905     * Mach. If you are familiar with that it is a little
1906     * different. The main variation that concerns us here is
1907     * that code is an array of exception specific codes and
1908     * codeCount is a count of the number of codes in the code
1909     * array. In typical Mach all exceptions have a code
1910     * and sub-code. It happens to be the case that for a
1911     * EXC_BAD_ACCESS exception the first entry is the type of
1912     * bad access that occurred and the second entry is the
1913     * faulting address so these entries correspond exactly to
1914     * how the code and sub-code are used on Mach.
1915     *
1916     * This is a MIG interface. No code in Basilisk II should
1917     * call this directley. This has to have external C
1918     * linkage because that is what exc_server expects.
1919     */
1920     kern_return_t
1921     catch_exception_raise(mach_port_t exception_port,
1922     mach_port_t thread,
1923     mach_port_t task,
1924     exception_type_t exception,
1925     exception_data_t code,
1926 gbeauche 1.66 mach_msg_type_number_t code_count)
1927 gbeauche 1.27 {
1928     kern_return_t krc;
1929    
1930 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
1931     switch (code[0]) {
1932     case KERN_PROTECTION_FAILURE:
1933     case KERN_INVALID_ADDRESS:
1934     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1935     return KERN_SUCCESS;
1936     break;
1937     }
1938 gbeauche 1.27 }
1939    
1940     // In Mach we do not need to remove the exception handler.
1941     // If we forward the exception, eventually some exception handler
1942     // will take care of this exception.
1943 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
1944 gbeauche 1.27
1945     return krc;
1946     }
1947     #endif
1948    
1949     #ifdef HAVE_SIGSEGV_RECOVERY
1950     // Handle bad memory accesses with signal handler
1951     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1952     {
1953     // Call handler and reinstall the global handler, if required
1954     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1955     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1956     sigsegv_do_install_handler(sig);
1957     #endif
1958     return;
1959     }
1960 gbeauche 1.10
1961 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1962 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1963 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1964 gbeauche 1.1 #undef FAULT_HANDLER
1965     }
1966 gbeauche 1.2 #endif
1967 gbeauche 1.1
1968    
1969     /*
1970     * SIGSEGV handler initialization
1971     */
1972    
1973     #if defined(HAVE_SIGINFO_T)
1974     static bool sigsegv_do_install_handler(int sig)
1975     {
1976     // Setup SIGSEGV handler to process writes to frame buffer
1977     #ifdef HAVE_SIGACTION
1978 gbeauche 1.22 struct sigaction sigsegv_sa;
1979     sigemptyset(&sigsegv_sa.sa_mask);
1980     sigsegv_sa.sa_sigaction = sigsegv_handler;
1981     sigsegv_sa.sa_flags = SA_SIGINFO;
1982     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1983 gbeauche 1.1 #else
1984     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1985     #endif
1986     }
1987 gbeauche 1.2 #endif
1988    
1989     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1990 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1991     {
1992     // Setup SIGSEGV handler to process writes to frame buffer
1993     #ifdef HAVE_SIGACTION
1994 gbeauche 1.22 struct sigaction sigsegv_sa;
1995     sigemptyset(&sigsegv_sa.sa_mask);
1996     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1997     sigsegv_sa.sa_flags = 0;
1998 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1999 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2000     sigsegv_sa.sa_flags |= SA_ONSTACK;
2001 gbeauche 1.1 #endif
2002 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
2003 gbeauche 1.1 #else
2004     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2005     #endif
2006     }
2007     #endif
2008    
2009 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
2010     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2011     {
2012     /*
2013     * Except for the exception port functions, this should be
2014     * pretty much stock Mach. If later you choose to support
2015     * other Mach's besides Darwin, just check for __MACH__
2016     * here and __APPLE__ where the actual differences are.
2017     */
2018     #if defined(__APPLE__) && defined(__MACH__)
2019     if (sigsegv_fault_handler != NULL) {
2020     sigsegv_fault_handler = handler;
2021     return true;
2022     }
2023    
2024     kern_return_t krc;
2025    
2026     // create the the exception port
2027     krc = mach_port_allocate(mach_task_self(),
2028     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2029     if (krc != KERN_SUCCESS) {
2030     mach_error("mach_port_allocate", krc);
2031     return false;
2032     }
2033    
2034     // add a port send right
2035     krc = mach_port_insert_right(mach_task_self(),
2036     _exceptionPort, _exceptionPort,
2037     MACH_MSG_TYPE_MAKE_SEND);
2038     if (krc != KERN_SUCCESS) {
2039     mach_error("mach_port_insert_right", krc);
2040     return false;
2041     }
2042    
2043     // get the old exception ports
2044     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2045     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2046     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2047     if (krc != KERN_SUCCESS) {
2048     mach_error("thread_get_exception_ports", krc);
2049     return false;
2050     }
2051    
2052     // set the new exception port
2053     //
2054     // We could have used EXCEPTION_STATE_IDENTITY instead of
2055     // EXCEPTION_DEFAULT to get the thread state in the initial
2056     // message, but it turns out that in the common case this is not
2057     // neccessary. If we need it we can later ask for it from the
2058     // suspended thread.
2059     //
2060     // Even with THREAD_STATE_NONE, Darwin provides the program
2061     // counter in the thread state. The comments in the header file
2062     // seem to imply that you can count on the GPR's on an exception
2063     // as well but just to be safe I use MACHINE_THREAD_STATE because
2064     // you have to ask for all of the GPR's anyway just to get the
2065     // program counter. In any case because of update effective
2066     // address from immediate and update address from effective
2067     // addresses of ra and rb modes (as good an name as any for these
2068     // addressing modes) used in PPC instructions, you will need the
2069     // GPR state anyway.
2070     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2071 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2072 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2073     mach_error("thread_set_exception_ports", krc);
2074     return false;
2075     }
2076    
2077     // create the exception handler thread
2078     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2079     (void)fprintf(stderr, "creation of exception thread failed\n");
2080     return false;
2081     }
2082    
2083     // do not care about the exception thread any longer, let is run standalone
2084     (void)pthread_detach(exc_thread);
2085    
2086     sigsegv_fault_handler = handler;
2087     return true;
2088     #else
2089     return false;
2090     #endif
2091     }
2092     #endif
2093    
2094 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2095     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2096     {
2097     if (sigsegv_fault_handler != NULL
2098     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2099     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2100     && handle_badaccess(ExceptionInfo))
2101     return EXCEPTION_CONTINUE_EXECUTION;
2102    
2103     return EXCEPTION_CONTINUE_SEARCH;
2104     }
2105    
2106     #if defined __CYGWIN__ && defined __i386__
2107     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2108     installs a global exception handler. We have to dig deep in order to install
2109     our main_exception_filter. */
2110    
2111     /* Data structures for the current thread's exception handler chain.
2112     On the x86 Windows uses register fs, offset 0 to point to the current
2113     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2114    
2115     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2116    
2117     struct exception_list {
2118     struct exception_list *prev;
2119     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2120     };
2121     typedef struct exception_list exception_list;
2122    
2123     /* Magic taken from winsup/cygwin/exceptions.cc. */
2124    
2125     __asm__ (".equ __except_list,0");
2126    
2127     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2128    
2129     /* For debugging. _except_list is not otherwise accessible from gdb. */
2130     static exception_list *
2131     debug_get_except_list ()
2132     {
2133     return _except_list;
2134     }
2135    
2136     /* Cygwin's original exception handler. */
2137     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2138    
2139     /* Our exception handler. */
2140     static int
2141     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2142     {
2143     EXCEPTION_POINTERS ExceptionInfo;
2144     ExceptionInfo.ExceptionRecord = exception;
2145     ExceptionInfo.ContextRecord = context;
2146     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2147     return cygwin_exception_handler (exception, frame, context, dispatch);
2148     else
2149     return 0;
2150     }
2151    
2152     static void
2153     do_install_main_exception_filter ()
2154     {
2155     /* We cannot insert any handler into the chain, because such handlers
2156     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2157     global exception handler. */
2158     cygwin_exception_handler = _except_list->handler;
2159     _except_list->handler = libsigsegv_exception_handler;
2160     }
2161    
2162     #else
2163    
2164     static void
2165     do_install_main_exception_filter ()
2166     {
2167     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2168     }
2169     #endif
2170    
2171     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2172     {
2173     static bool main_exception_filter_installed = false;
2174     if (!main_exception_filter_installed) {
2175     do_install_main_exception_filter();
2176     main_exception_filter_installed = true;
2177     }
2178     sigsegv_fault_handler = handler;
2179     return true;
2180     }
2181     #endif
2182    
2183 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2184 gbeauche 1.1 {
2185 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2186 gbeauche 1.1 bool success = true;
2187     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2188     SIGSEGV_ALL_SIGNALS
2189     #undef FAULT_HANDLER
2190 gbeauche 1.27 if (success)
2191     sigsegv_fault_handler = handler;
2192 gbeauche 1.1 return success;
2193 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2194 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2195 gbeauche 1.1 #else
2196     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2197     return false;
2198     #endif
2199     }
2200    
2201    
2202     /*
2203     * SIGSEGV handler deinitialization
2204     */
2205    
2206     void sigsegv_deinstall_handler(void)
2207     {
2208 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2209     // suspended if not already so, and we might mess with other
2210     // exception handlers that came after we registered ours. There is
2211     // no need to remove the exception handler, in fact this function is
2212     // not called anywhere in Basilisk II.
2213 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2214 gbeauche 1.12 sigsegv_fault_handler = 0;
2215 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2216     SIGSEGV_ALL_SIGNALS
2217     #undef FAULT_HANDLER
2218 gbeauche 1.2 #endif
2219 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2220     sigsegv_fault_handler = NULL;
2221     #endif
2222 gbeauche 1.1 }
2223    
2224 gbeauche 1.10
2225     /*
2226     * Set callback function when we cannot handle the fault
2227     */
2228    
2229 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2230 gbeauche 1.10 {
2231 gbeauche 1.12 sigsegv_state_dumper = handler;
2232 gbeauche 1.10 }
2233    
2234    
2235 gbeauche 1.1 /*
2236     * Test program used for configure/test
2237     */
2238    
2239 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2240 gbeauche 1.1 #include <stdio.h>
2241     #include <stdlib.h>
2242     #include <fcntl.h>
2243 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2244 gbeauche 1.1 #include <sys/mman.h>
2245 gbeauche 1.48 #endif
2246 gbeauche 1.4 #include "vm_alloc.h"
2247 gbeauche 1.1
2248 gbeauche 1.32 const int REF_INDEX = 123;
2249     const int REF_VALUE = 45;
2250    
2251 gbeauche 1.1 static int page_size;
2252 gbeauche 1.3 static volatile char * page = 0;
2253     static volatile int handler_called = 0;
2254 gbeauche 1.1
2255 gbeauche 1.61 /* Barriers */
2256     #ifdef __GNUC__
2257     #define BARRIER() asm volatile ("" : : : "memory")
2258     #else
2259     #define BARRIER() /* nothing */
2260     #endif
2261    
2262 gbeauche 1.32 #ifdef __GNUC__
2263     // Code range where we expect the fault to come from
2264     static void *b_region, *e_region;
2265     #endif
2266    
2267 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2268 gbeauche 1.1 {
2269 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2270     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2271 gbeauche 1.39 #if DEBUG
2272     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2273     printf("expected fault at %p\n", page + REF_INDEX);
2274     #ifdef __GNUC__
2275     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2276     #endif
2277     #endif
2278 gbeauche 1.1 handler_called++;
2279 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2280 gbeauche 1.29 exit(10);
2281 gbeauche 1.32 #ifdef __GNUC__
2282     // Make sure reported fault instruction address falls into
2283     // expected code range
2284 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
2285 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
2286     (instruction_address >= (sigsegv_address_t)e_region)))
2287     exit(11);
2288     #endif
2289 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2290 gbeauche 1.32 exit(12);
2291 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2292 gbeauche 1.1 }
2293    
2294 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2295 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
2296 gbeauche 1.10 {
2297 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2298     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2299 gbeauche 1.44 #if DEBUG
2300     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2301     #endif
2302 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2303     #ifdef __GNUC__
2304     // Make sure reported fault instruction address falls into
2305     // expected code range
2306 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
2307 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
2308     (instruction_address >= (sigsegv_address_t)e_region)))
2309     return SIGSEGV_RETURN_FAILURE;
2310     #endif
2311 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2312 gbeauche 1.28 }
2313    
2314 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2315 gbeauche 1.10 }
2316 gbeauche 1.34
2317     // More sophisticated tests for instruction skipper
2318     static bool arch_insn_skipper_tests()
2319     {
2320     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2321     static const unsigned char code[] = {
2322     0x8a, 0x00, // mov (%eax),%al
2323     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2324     0x88, 0x20, // mov %ah,(%eax)
2325     0x88, 0x08, // mov %cl,(%eax)
2326     0x66, 0x8b, 0x00, // mov (%eax),%ax
2327     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2328     0x66, 0x89, 0x00, // mov %ax,(%eax)
2329     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2330     0x8b, 0x00, // mov (%eax),%eax
2331     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2332     0x89, 0x00, // mov %eax,(%eax)
2333     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2334     #if defined(__x86_64__)
2335     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2336     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2337     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2338     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2339     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2340     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2341     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2342     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2343     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2344     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2345     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2346     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2347     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2348     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2349     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2350     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2351     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2352     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2353     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2354     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2355     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2356     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2357 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
2358     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
2359 gbeauche 1.34 #endif
2360     0 // end
2361     };
2362     const int N_REGS = 20;
2363     unsigned long regs[N_REGS];
2364     for (int i = 0; i < N_REGS; i++)
2365     regs[i] = i;
2366     const unsigned long start_code = (unsigned long)&code;
2367     regs[X86_REG_EIP] = start_code;
2368     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2369     && ix86_skip_instruction(regs))
2370     ; /* simply iterate */
2371     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2372     #endif
2373     return true;
2374     }
2375 gbeauche 1.10 #endif
2376    
2377 gbeauche 1.1 int main(void)
2378     {
2379 gbeauche 1.4 if (vm_init() < 0)
2380 gbeauche 1.1 return 1;
2381    
2382 gbeauche 1.54 page_size = vm_get_page_size();
2383 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2384 gbeauche 1.29 return 2;
2385 gbeauche 1.4
2386 gbeauche 1.32 memset((void *)page, 0, page_size);
2387 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2388 gbeauche 1.29 return 3;
2389 gbeauche 1.1
2390     if (!sigsegv_install_handler(sigsegv_test_handler))
2391 gbeauche 1.29 return 4;
2392 gbeauche 1.1
2393 gbeauche 1.32 #ifdef __GNUC__
2394     b_region = &&L_b_region1;
2395     e_region = &&L_e_region1;
2396     #endif
2397     L_b_region1:
2398     page[REF_INDEX] = REF_VALUE;
2399     if (page[REF_INDEX] != REF_VALUE)
2400     exit(20);
2401     page[REF_INDEX] = REF_VALUE;
2402 gbeauche 1.61 BARRIER();
2403 gbeauche 1.32 L_e_region1:
2404    
2405 gbeauche 1.1 if (handler_called != 1)
2406 gbeauche 1.29 return 5;
2407 gbeauche 1.10
2408     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2409     if (!sigsegv_install_handler(sigsegv_insn_handler))
2410 gbeauche 1.29 return 6;
2411 gbeauche 1.10
2412 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2413 gbeauche 1.29 return 7;
2414 gbeauche 1.10
2415     for (int i = 0; i < page_size; i++)
2416     page[i] = (i + 1) % page_size;
2417    
2418     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2419 gbeauche 1.29 return 8;
2420 gbeauche 1.10
2421     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2422 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2423     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2424 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2425 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2426 gbeauche 1.10 if (effect != TAG) \
2427 gbeauche 1.29 return 9; \
2428 gbeauche 1.10 } while (0)
2429    
2430 gbeauche 1.28 #ifdef __GNUC__
2431 gbeauche 1.32 b_region = &&L_b_region2;
2432     e_region = &&L_e_region2;
2433 gbeauche 1.28 #endif
2434 gbeauche 1.32 L_b_region2:
2435 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2436     TEST_SKIP_INSTRUCTION(unsigned short);
2437     TEST_SKIP_INSTRUCTION(unsigned int);
2438 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2439 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2440     TEST_SKIP_INSTRUCTION(signed short);
2441     TEST_SKIP_INSTRUCTION(signed int);
2442     TEST_SKIP_INSTRUCTION(signed long);
2443 gbeauche 1.61 BARRIER();
2444 gbeauche 1.32 L_e_region2:
2445 gbeauche 1.1
2446 gbeauche 1.34 if (!arch_insn_skipper_tests())
2447     return 20;
2448 gbeauche 1.35 #endif
2449 gbeauche 1.34
2450 gbeauche 1.4 vm_exit();
2451 gbeauche 1.1 return 0;
2452     }
2453     #endif