ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.68
Committed: 2007-12-30T12:11:17Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.67: +70 -50 lines
Log Message:
According to kernel sources, that is XNU 344.49 (10.2.8), XNU 517.12.7 (10.3.9),
XNU 792.21.3 (10.4.10) and XNU 1228 (10.5.0), exception handler code[1] always
contains the fault address nowadays. So make it the default fast path but keep
provisions to check that at run-time first.

This yields a nearly 4x improvement in SIGSEGV recovery but MacOS X is still
suboptimal wrt. Linux, so VOSF is still not possible with frameskip == 0.

XXX: the ppc kernel had bugs that caused DAR (put into code[1]) to be incorrectly
decoded. This would need a broader test audience or more careful audit of the
sources changes.

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.52 * Basilisk II (C) 1997-2005 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     #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
86     // 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     #ifdef __i386__
617 gbeauche 1.66 #define SIGSEGV_EXCEPTION_STATE_TYPE struct i386_exception_state
618     #define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE
619     #define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT
620 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS sip->exc_state.faultvaddr
621 gbeauche 1.57 #define SIGSEGV_THREAD_STATE_TYPE struct i386_thread_state
622     #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE
623     #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
624 gbeauche 1.68 #define SIGSEGV_FAULT_INSTRUCTION sip->thr_state.eip
625 gbeauche 1.56 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
626 gbeauche 1.68 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&sip->thr_state.eax) /* EAX is the first GPR we consider */
627 gbeauche 1.56 #endif
628 gbeauche 1.66 #ifdef __x86_64__
629     #define SIGSEGV_EXCEPTION_STATE_TYPE struct x86_exception_state64
630     #define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64
631     #define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
632 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS sip->exc_state.faultvaddr
633 gbeauche 1.66 #define SIGSEGV_THREAD_STATE_TYPE struct x86_thread_state64
634     #define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64
635     #define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
636 gbeauche 1.68 #define SIGSEGV_FAULT_INSTRUCTION sip->thr_state.rip
637 gbeauche 1.66 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
638 gbeauche 1.68 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&sip->thr_state.rax) /* RAX is the first GPR we consider */
639 gbeauche 1.66 #endif
640 gbeauche 1.68 #define SIGSEGV_FAULT_ADDRESS_FAST code[1]
641     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS
642 gbeauche 1.66 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code
643     #define SIGSEGV_FAULT_HANDLER_ARGS thread, code
644 gbeauche 1.27
645     // Since there can only be one exception thread running at any time
646     // this is not a problem.
647     #define MSG_SIZE 512
648     static char msgbuf[MSG_SIZE];
649     static char replybuf[MSG_SIZE];
650    
651     /*
652     * This is the entry point for the exception handler thread. The job
653     * of this thread is to wait for exception messages on the exception
654     * port that was setup beforehand and to pass them on to exc_server.
655     * exc_server is a MIG generated function that is a part of Mach.
656     * Its job is to decide what to do with the exception message. In our
657     * case exc_server calls catch_exception_raise on our behalf. After
658     * exc_server returns, it is our responsibility to send the reply.
659     */
660     static void *
661     handleExceptions(void *priv)
662     {
663     mach_msg_header_t *msg, *reply;
664     kern_return_t krc;
665    
666     msg = (mach_msg_header_t *)msgbuf;
667     reply = (mach_msg_header_t *)replybuf;
668    
669     for (;;) {
670     krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
671     _exceptionPort, 0, MACH_PORT_NULL);
672     MACH_CHECK_ERROR(mach_msg, krc);
673    
674     if (!exc_server(msg, reply)) {
675     fprintf(stderr, "exc_server hated the message\n");
676     exit(1);
677     }
678    
679     krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
680     msg->msgh_local_port, 0, MACH_PORT_NULL);
681     if (krc != KERN_SUCCESS) {
682     fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
683     krc, mach_error_string(krc));
684     exit(1);
685     }
686     }
687     }
688     #endif
689     #endif
690 gbeauche 1.1
691 gbeauche 1.14
692     /*
693     * Instruction skipping
694     */
695    
696 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
697     // Decode and skip X86 instruction
698 gbeauche 1.34 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
699 gbeauche 1.10 #if defined(__linux__)
700     enum {
701 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
702 gbeauche 1.10 X86_REG_EIP = 14,
703     X86_REG_EAX = 11,
704     X86_REG_ECX = 10,
705     X86_REG_EDX = 9,
706     X86_REG_EBX = 8,
707     X86_REG_ESP = 7,
708     X86_REG_EBP = 6,
709     X86_REG_ESI = 5,
710     X86_REG_EDI = 4
711 gbeauche 1.34 #endif
712     #if defined(__x86_64__)
713     X86_REG_R8 = 0,
714     X86_REG_R9 = 1,
715     X86_REG_R10 = 2,
716     X86_REG_R11 = 3,
717     X86_REG_R12 = 4,
718     X86_REG_R13 = 5,
719     X86_REG_R14 = 6,
720     X86_REG_R15 = 7,
721     X86_REG_EDI = 8,
722     X86_REG_ESI = 9,
723     X86_REG_EBP = 10,
724     X86_REG_EBX = 11,
725     X86_REG_EDX = 12,
726     X86_REG_EAX = 13,
727     X86_REG_ECX = 14,
728     X86_REG_ESP = 15,
729     X86_REG_EIP = 16
730     #endif
731 gbeauche 1.10 };
732     #endif
733 gbeauche 1.51 #if defined(__NetBSD__)
734     enum {
735     #if (defined(i386) || defined(__i386__))
736     X86_REG_EIP = _REG_EIP,
737     X86_REG_EAX = _REG_EAX,
738     X86_REG_ECX = _REG_ECX,
739     X86_REG_EDX = _REG_EDX,
740     X86_REG_EBX = _REG_EBX,
741     X86_REG_ESP = _REG_ESP,
742     X86_REG_EBP = _REG_EBP,
743     X86_REG_ESI = _REG_ESI,
744     X86_REG_EDI = _REG_EDI
745     #endif
746     };
747     #endif
748     #if defined(__FreeBSD__)
749 gbeauche 1.17 enum {
750 gbeauche 1.34 #if (defined(i386) || defined(__i386__))
751 gbeauche 1.17 X86_REG_EIP = 10,
752     X86_REG_EAX = 7,
753     X86_REG_ECX = 6,
754     X86_REG_EDX = 5,
755     X86_REG_EBX = 4,
756     X86_REG_ESP = 13,
757     X86_REG_EBP = 2,
758     X86_REG_ESI = 1,
759     X86_REG_EDI = 0
760 gbeauche 1.34 #endif
761 gbeauche 1.17 };
762     #endif
763 gbeauche 1.55 #if defined(__OpenBSD__)
764     enum {
765     #if defined(__i386__)
766     // EDI is the first register we consider
767     #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
768     #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
769     X86_REG_EIP = DREG(eip), // 7
770     X86_REG_EAX = DREG(eax), // 6
771     X86_REG_ECX = DREG(ecx), // 5
772     X86_REG_EDX = DREG(edx), // 4
773     X86_REG_EBX = DREG(ebx), // 3
774     X86_REG_ESP = DREG(esp), // 10
775     X86_REG_EBP = DREG(ebp), // 2
776     X86_REG_ESI = DREG(esi), // 1
777     X86_REG_EDI = DREG(edi) // 0
778     #undef DREG
779     #undef OREG
780     #endif
781     };
782     #endif
783 gbeauche 1.54 #if defined(__sun__)
784     // Same as for Linux, need to check for x86-64
785     enum {
786     #if defined(__i386__)
787     X86_REG_EIP = EIP,
788     X86_REG_EAX = EAX,
789     X86_REG_ECX = ECX,
790     X86_REG_EDX = EDX,
791     X86_REG_EBX = EBX,
792     X86_REG_ESP = ESP,
793     X86_REG_EBP = EBP,
794     X86_REG_ESI = ESI,
795     X86_REG_EDI = EDI
796     #endif
797     };
798     #endif
799 gbeauche 1.56 #if defined(__APPLE__) && defined(__MACH__)
800     enum {
801 gbeauche 1.66 #if (defined(i386) || defined(__i386__))
802 gbeauche 1.57 #ifdef i386_SAVED_STATE
803     // same as FreeBSD (in Open Darwin 8.0.1)
804 gbeauche 1.56 X86_REG_EIP = 10,
805     X86_REG_EAX = 7,
806     X86_REG_ECX = 6,
807     X86_REG_EDX = 5,
808     X86_REG_EBX = 4,
809     X86_REG_ESP = 13,
810     X86_REG_EBP = 2,
811     X86_REG_ESI = 1,
812     X86_REG_EDI = 0
813 gbeauche 1.57 #else
814     // new layout (MacOS X 10.4.4 for x86)
815     X86_REG_EIP = 10,
816     X86_REG_EAX = 0,
817     X86_REG_ECX = 2,
818 gbeauche 1.66 X86_REG_EDX = 3,
819 gbeauche 1.57 X86_REG_EBX = 1,
820     X86_REG_ESP = 7,
821     X86_REG_EBP = 6,
822     X86_REG_ESI = 5,
823     X86_REG_EDI = 4
824     #endif
825 gbeauche 1.66 #endif
826     #if defined(__x86_64__)
827     X86_REG_R8 = 8,
828     X86_REG_R9 = 9,
829     X86_REG_R10 = 10,
830     X86_REG_R11 = 11,
831     X86_REG_R12 = 12,
832     X86_REG_R13 = 13,
833     X86_REG_R14 = 14,
834     X86_REG_R15 = 15,
835     X86_REG_EDI = 4,
836     X86_REG_ESI = 5,
837     X86_REG_EBP = 6,
838     X86_REG_EBX = 1,
839     X86_REG_EDX = 3,
840     X86_REG_EAX = 0,
841     X86_REG_ECX = 2,
842     X86_REG_ESP = 7,
843     X86_REG_EIP = 16
844     #endif
845 gbeauche 1.56 };
846     #endif
847 gbeauche 1.48 #if defined(_WIN32)
848     enum {
849     #if (defined(i386) || defined(__i386__))
850     X86_REG_EIP = 7,
851     X86_REG_EAX = 5,
852     X86_REG_ECX = 4,
853     X86_REG_EDX = 3,
854     X86_REG_EBX = 2,
855     X86_REG_ESP = 10,
856     X86_REG_EBP = 6,
857     X86_REG_ESI = 1,
858     X86_REG_EDI = 0
859     #endif
860     };
861     #endif
862 gbeauche 1.10 // FIXME: this is partly redundant with the instruction decoding phase
863     // to discover transfer type and register number
864     static inline int ix86_step_over_modrm(unsigned char * p)
865     {
866     int mod = (p[0] >> 6) & 3;
867     int rm = p[0] & 7;
868     int offset = 0;
869    
870     // ModR/M Byte
871     switch (mod) {
872     case 0: // [reg]
873     if (rm == 5) return 4; // disp32
874     break;
875     case 1: // disp8[reg]
876     offset = 1;
877     break;
878     case 2: // disp32[reg]
879     offset = 4;
880     break;
881     case 3: // register
882     return 0;
883     }
884    
885     // SIB Byte
886     if (rm == 4) {
887     if (mod == 0 && (p[1] & 7) == 5)
888     offset = 5; // disp32[index]
889     else
890     offset++;
891     }
892    
893     return offset;
894     }
895    
896 gbeauche 1.34 static bool ix86_skip_instruction(unsigned long * regs)
897 gbeauche 1.10 {
898 gbeauche 1.14 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
899 gbeauche 1.10
900     if (eip == 0)
901     return false;
902 gbeauche 1.50 #ifdef _WIN32
903     if (IsBadCodePtr((FARPROC)eip))
904     return false;
905     #endif
906 gbeauche 1.10
907 gbeauche 1.64 enum instruction_type_t {
908     i_MOV,
909     i_ADD
910     };
911    
912 gbeauche 1.22 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
913 gbeauche 1.14 transfer_size_t transfer_size = SIZE_LONG;
914 gbeauche 1.64 instruction_type_t instruction_type = i_MOV;
915 gbeauche 1.10
916     int reg = -1;
917     int len = 0;
918 gbeauche 1.34
919     #if DEBUG
920     printf("IP: %p [%02x %02x %02x %02x...]\n",
921     eip, eip[0], eip[1], eip[2], eip[3]);
922     #endif
923    
924 gbeauche 1.10 // Operand size prefix
925     if (*eip == 0x66) {
926     eip++;
927     len++;
928     transfer_size = SIZE_WORD;
929     }
930    
931 gbeauche 1.34 // REX prefix
932     #if defined(__x86_64__)
933     struct rex_t {
934     unsigned char W;
935     unsigned char R;
936     unsigned char X;
937     unsigned char B;
938     };
939     rex_t rex = { 0, 0, 0, 0 };
940     bool has_rex = false;
941     if ((*eip & 0xf0) == 0x40) {
942     has_rex = true;
943     const unsigned char b = *eip;
944     rex.W = b & (1 << 3);
945     rex.R = b & (1 << 2);
946     rex.X = b & (1 << 1);
947     rex.B = b & (1 << 0);
948     #if DEBUG
949     printf("REX: %c,%c,%c,%c\n",
950     rex.W ? 'W' : '_',
951     rex.R ? 'R' : '_',
952     rex.X ? 'X' : '_',
953     rex.B ? 'B' : '_');
954     #endif
955     eip++;
956     len++;
957     if (rex.W)
958     transfer_size = SIZE_QUAD;
959     }
960     #else
961     const bool has_rex = false;
962     #endif
963    
964 gbeauche 1.10 // Decode instruction
965 gbeauche 1.64 int op_len = 1;
966 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
967 gbeauche 1.10 switch (eip[0]) {
968 gbeauche 1.17 case 0x0f:
969 gbeauche 1.45 target_size = transfer_size;
970 gbeauche 1.18 switch (eip[1]) {
971 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
972 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
973 gbeauche 1.45 transfer_size = SIZE_BYTE;
974     goto do_mov_extend;
975 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
976 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
977 gbeauche 1.45 transfer_size = SIZE_WORD;
978     goto do_mov_extend;
979     do_mov_extend:
980 gbeauche 1.64 op_len = 2;
981     goto do_transfer_load;
982     }
983     break;
984 gbeauche 1.62 #if defined(__x86_64__)
985     case 0x63: // MOVSXD r64, r/m32
986     if (has_rex && rex.W) {
987     transfer_size = SIZE_LONG;
988     target_size = SIZE_QUAD;
989     }
990     else if (transfer_size != SIZE_WORD) {
991     transfer_size = SIZE_LONG;
992     target_size = SIZE_QUAD;
993     }
994 gbeauche 1.64 goto do_transfer_load;
995 gbeauche 1.62 #endif
996 gbeauche 1.64 case 0x02: // ADD r8, r/m8
997     transfer_size = SIZE_BYTE;
998     case 0x03: // ADD r32, r/m32
999     instruction_type = i_ADD;
1000     goto do_transfer_load;
1001 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
1002     transfer_size = SIZE_BYTE;
1003     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1004 gbeauche 1.64 do_transfer_load:
1005     switch (eip[op_len] & 0xc0) {
1006 gbeauche 1.10 case 0x80:
1007 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1008 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1009 gbeauche 1.10 break;
1010     case 0x40:
1011 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1012 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1013 gbeauche 1.10 break;
1014     case 0x00:
1015 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1016 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
1017 gbeauche 1.10 break;
1018     }
1019 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1020 gbeauche 1.10 break;
1021 gbeauche 1.64 case 0x00: // ADD r/m8, r8
1022     transfer_size = SIZE_BYTE;
1023     case 0x01: // ADD r/m32, r32
1024     instruction_type = i_ADD;
1025     goto do_transfer_store;
1026 gbeauche 1.10 case 0x88: // MOV r/m8, r8
1027     transfer_size = SIZE_BYTE;
1028     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1029 gbeauche 1.64 do_transfer_store:
1030     switch (eip[op_len] & 0xc0) {
1031 gbeauche 1.10 case 0x80:
1032 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1033 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1034 gbeauche 1.10 break;
1035     case 0x40:
1036 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1037 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1038 gbeauche 1.10 break;
1039     case 0x00:
1040 gbeauche 1.64 reg = (eip[op_len] >> 3) & 7;
1041 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
1042 gbeauche 1.10 break;
1043     }
1044 gbeauche 1.64 len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1045 gbeauche 1.10 break;
1046     }
1047 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
1048     target_size = transfer_size;
1049 gbeauche 1.10
1050 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1051 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
1052     return false;
1053     }
1054    
1055 gbeauche 1.34 #if defined(__x86_64__)
1056     if (rex.R)
1057     reg += 8;
1058     #endif
1059    
1060 gbeauche 1.64 if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1061 gbeauche 1.34 static const int x86_reg_map[] = {
1062 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1063 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1064     #if defined(__x86_64__)
1065     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
1066     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1067     #endif
1068 gbeauche 1.10 };
1069    
1070 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1071 gbeauche 1.10 return false;
1072    
1073 gbeauche 1.34 // Set 0 to the relevant register part
1074     // NOTE: this is only valid for MOV alike instructions
1075 gbeauche 1.10 int rloc = x86_reg_map[reg];
1076 gbeauche 1.45 switch (target_size) {
1077 gbeauche 1.10 case SIZE_BYTE:
1078 gbeauche 1.36 if (has_rex || reg < 4)
1079     regs[rloc] = (regs[rloc] & ~0x00ffL);
1080     else {
1081     rloc = x86_reg_map[reg - 4];
1082     regs[rloc] = (regs[rloc] & ~0xff00L);
1083     }
1084 gbeauche 1.10 break;
1085     case SIZE_WORD:
1086 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
1087 gbeauche 1.10 break;
1088     case SIZE_LONG:
1089 gbeauche 1.34 case SIZE_QUAD: // zero-extension
1090 gbeauche 1.10 regs[rloc] = 0;
1091     break;
1092     }
1093     }
1094    
1095     #if DEBUG
1096 gbeauche 1.64 printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1097 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
1098     transfer_size == SIZE_WORD ? "word" :
1099     transfer_size == SIZE_LONG ? "long" :
1100     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1101 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1102 gbeauche 1.10
1103     if (reg != -1) {
1104 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
1105     "al", "cl", "dl", "bl",
1106     "spl", "bpl", "sil", "dil",
1107     "r8b", "r9b", "r10b", "r11b",
1108     "r12b", "r13b", "r14b", "r15b",
1109     "ah", "ch", "dh", "bh",
1110     };
1111     static const char * x86_word_reg_str_map[] = {
1112     "ax", "cx", "dx", "bx",
1113     "sp", "bp", "si", "di",
1114     "r8w", "r9w", "r10w", "r11w",
1115     "r12w", "r13w", "r14w", "r15w",
1116     };
1117     static const char *x86_long_reg_str_map[] = {
1118     "eax", "ecx", "edx", "ebx",
1119     "esp", "ebp", "esi", "edi",
1120     "r8d", "r9d", "r10d", "r11d",
1121     "r12d", "r13d", "r14d", "r15d",
1122     };
1123     static const char *x86_quad_reg_str_map[] = {
1124     "rax", "rcx", "rdx", "rbx",
1125     "rsp", "rbp", "rsi", "rdi",
1126     "r8", "r9", "r10", "r11",
1127     "r12", "r13", "r14", "r15",
1128 gbeauche 1.10 };
1129 gbeauche 1.34 const char * reg_str = NULL;
1130 gbeauche 1.46 switch (target_size) {
1131 gbeauche 1.34 case SIZE_BYTE:
1132     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1133     break;
1134     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1135     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1136     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1137     }
1138     if (reg_str)
1139     printf(" %s register %%%s",
1140     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1141     reg_str);
1142 gbeauche 1.10 }
1143     printf(", %d bytes instruction\n", len);
1144     #endif
1145    
1146     regs[X86_REG_EIP] += len;
1147 gbeauche 1.13 return true;
1148     }
1149     #endif
1150 gbeauche 1.14
1151 gbeauche 1.13 // Decode and skip PPC instruction
1152 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1153 gbeauche 1.49 static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1154 gbeauche 1.13 {
1155 gbeauche 1.14 instruction_t instr;
1156     powerpc_decode_instruction(&instr, *nip_p, regs);
1157 gbeauche 1.13
1158 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1159 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
1160     return false;
1161     }
1162    
1163     #if DEBUG
1164 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
1165 gbeauche 1.49 instr.transfer_size == SIZE_BYTE ? "byte" :
1166     instr.transfer_size == SIZE_WORD ? "word" :
1167     instr.transfer_size == SIZE_LONG ? "long" : "quad",
1168 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1169 gbeauche 1.14
1170     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1171     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
1172 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1173 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
1174     #endif
1175    
1176     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
1177     regs[instr.ra] = instr.addr;
1178 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
1179 gbeauche 1.14 regs[instr.rd] = 0;
1180 gbeauche 1.13
1181 gbeauche 1.14 *nip_p += 4;
1182 gbeauche 1.10 return true;
1183 gbeauche 1.38 }
1184     #endif
1185    
1186     // Decode and skip MIPS instruction
1187     #if (defined(mips) || defined(__mips))
1188 gbeauche 1.65 static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1189 gbeauche 1.38 {
1190 gbeauche 1.65 unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1191 gbeauche 1.38
1192     if (epc == 0)
1193     return false;
1194    
1195     #if DEBUG
1196     printf("IP: %p [%08x]\n", epc, epc[0]);
1197     #endif
1198    
1199     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1200     transfer_size_t transfer_size = SIZE_LONG;
1201     int direction = 0;
1202    
1203     const unsigned int opcode = epc[0];
1204     switch (opcode >> 26) {
1205     case 32: // Load Byte
1206     case 36: // Load Byte Unsigned
1207     transfer_type = SIGSEGV_TRANSFER_LOAD;
1208     transfer_size = SIZE_BYTE;
1209     break;
1210     case 33: // Load Halfword
1211     case 37: // Load Halfword Unsigned
1212     transfer_type = SIGSEGV_TRANSFER_LOAD;
1213     transfer_size = SIZE_WORD;
1214     break;
1215     case 35: // Load Word
1216     case 39: // Load Word Unsigned
1217     transfer_type = SIGSEGV_TRANSFER_LOAD;
1218     transfer_size = SIZE_LONG;
1219     break;
1220     case 34: // Load Word Left
1221     transfer_type = SIGSEGV_TRANSFER_LOAD;
1222     transfer_size = SIZE_LONG;
1223     direction = -1;
1224     break;
1225     case 38: // Load Word Right
1226     transfer_type = SIGSEGV_TRANSFER_LOAD;
1227     transfer_size = SIZE_LONG;
1228     direction = 1;
1229     break;
1230     case 55: // Load Doubleword
1231     transfer_type = SIGSEGV_TRANSFER_LOAD;
1232     transfer_size = SIZE_QUAD;
1233     break;
1234     case 26: // Load Doubleword Left
1235     transfer_type = SIGSEGV_TRANSFER_LOAD;
1236     transfer_size = SIZE_QUAD;
1237     direction = -1;
1238     break;
1239     case 27: // Load Doubleword Right
1240     transfer_type = SIGSEGV_TRANSFER_LOAD;
1241     transfer_size = SIZE_QUAD;
1242     direction = 1;
1243     break;
1244     case 40: // Store Byte
1245     transfer_type = SIGSEGV_TRANSFER_STORE;
1246     transfer_size = SIZE_BYTE;
1247     break;
1248     case 41: // Store Halfword
1249     transfer_type = SIGSEGV_TRANSFER_STORE;
1250     transfer_size = SIZE_WORD;
1251     break;
1252     case 43: // Store Word
1253     case 42: // Store Word Left
1254     case 46: // Store Word Right
1255     transfer_type = SIGSEGV_TRANSFER_STORE;
1256     transfer_size = SIZE_LONG;
1257     break;
1258     case 63: // Store Doubleword
1259     case 44: // Store Doubleword Left
1260     case 45: // Store Doubleword Right
1261     transfer_type = SIGSEGV_TRANSFER_STORE;
1262     transfer_size = SIZE_QUAD;
1263     break;
1264     /* Misc instructions unlikely to be used within CPU emulators */
1265     case 48: // Load Linked Word
1266     transfer_type = SIGSEGV_TRANSFER_LOAD;
1267     transfer_size = SIZE_LONG;
1268     break;
1269     case 52: // Load Linked Doubleword
1270     transfer_type = SIGSEGV_TRANSFER_LOAD;
1271     transfer_size = SIZE_QUAD;
1272     break;
1273     case 56: // Store Conditional Word
1274     transfer_type = SIGSEGV_TRANSFER_STORE;
1275     transfer_size = SIZE_LONG;
1276     break;
1277     case 60: // Store Conditional Doubleword
1278     transfer_type = SIGSEGV_TRANSFER_STORE;
1279     transfer_size = SIZE_QUAD;
1280     break;
1281     }
1282    
1283     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1284     // Unknown machine code, let it crash. Then patch the decoder
1285     return false;
1286     }
1287    
1288     // Zero target register in case of a load operation
1289     const int reg = (opcode >> 16) & 0x1f;
1290     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1291     if (direction == 0)
1292     regs[reg] = 0;
1293     else {
1294     // FIXME: untested code
1295     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1296     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1297     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1298     unsigned long value;
1299     if (direction > 0) {
1300     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1301     value = regs[reg] & rmask;
1302     }
1303     else {
1304     const unsigned long lmask = (1L << (offset * 8)) - 1;
1305     value = regs[reg] & lmask;
1306     }
1307     // restore most significant bits
1308     if (transfer_size == SIZE_LONG)
1309     value = (signed long)(signed int)value;
1310     regs[reg] = value;
1311     }
1312     }
1313    
1314     #if DEBUG
1315     #if (defined(_ABIN32) || defined(_ABI64))
1316     static const char * mips_gpr_names[32] = {
1317     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1318     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1319     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1320     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1321     };
1322     #else
1323     static const char * mips_gpr_names[32] = {
1324     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1325     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1326     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1327     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1328     };
1329     #endif
1330     printf("%s %s register %s\n",
1331     transfer_size == SIZE_BYTE ? "byte" :
1332     transfer_size == SIZE_WORD ? "word" :
1333     transfer_size == SIZE_LONG ? "long" :
1334     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1335     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1336     mips_gpr_names[reg]);
1337     #endif
1338    
1339 gbeauche 1.65 *pc_p += 4;
1340 gbeauche 1.40 return true;
1341     }
1342     #endif
1343    
1344     // Decode and skip SPARC instruction
1345     #if (defined(sparc) || defined(__sparc__))
1346     enum {
1347     #if (defined(__sun__))
1348     SPARC_REG_G1 = REG_G1,
1349     SPARC_REG_O0 = REG_O0,
1350     SPARC_REG_PC = REG_PC,
1351 gbeauche 1.59 SPARC_REG_nPC = REG_nPC
1352 gbeauche 1.40 #endif
1353     };
1354     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1355     {
1356     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1357    
1358     if (pc == 0)
1359     return false;
1360    
1361     #if DEBUG
1362     printf("IP: %p [%08x]\n", pc, pc[0]);
1363     #endif
1364    
1365     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1366     transfer_size_t transfer_size = SIZE_LONG;
1367     bool register_pair = false;
1368    
1369     const unsigned int opcode = pc[0];
1370     if ((opcode >> 30) != 3)
1371     return false;
1372     switch ((opcode >> 19) & 0x3f) {
1373     case 9: // Load Signed Byte
1374     case 1: // Load Unsigned Byte
1375     transfer_type = SIGSEGV_TRANSFER_LOAD;
1376     transfer_size = SIZE_BYTE;
1377     break;
1378     case 10:// Load Signed Halfword
1379     case 2: // Load Unsigned Word
1380     transfer_type = SIGSEGV_TRANSFER_LOAD;
1381     transfer_size = SIZE_WORD;
1382     break;
1383     case 8: // Load Word
1384     case 0: // Load Unsigned Word
1385     transfer_type = SIGSEGV_TRANSFER_LOAD;
1386     transfer_size = SIZE_LONG;
1387     break;
1388     case 11:// Load Extended Word
1389     transfer_type = SIGSEGV_TRANSFER_LOAD;
1390     transfer_size = SIZE_QUAD;
1391     break;
1392     case 3: // Load Doubleword
1393     transfer_type = SIGSEGV_TRANSFER_LOAD;
1394     transfer_size = SIZE_LONG;
1395     register_pair = true;
1396     break;
1397     case 5: // Store Byte
1398     transfer_type = SIGSEGV_TRANSFER_STORE;
1399     transfer_size = SIZE_BYTE;
1400     break;
1401     case 6: // Store Halfword
1402     transfer_type = SIGSEGV_TRANSFER_STORE;
1403     transfer_size = SIZE_WORD;
1404     break;
1405     case 4: // Store Word
1406     transfer_type = SIGSEGV_TRANSFER_STORE;
1407     transfer_size = SIZE_LONG;
1408     break;
1409     case 14:// Store Extended Word
1410     transfer_type = SIGSEGV_TRANSFER_STORE;
1411     transfer_size = SIZE_QUAD;
1412     break;
1413     case 7: // Store Doubleword
1414     transfer_type = SIGSEGV_TRANSFER_STORE;
1415 gbeauche 1.58 transfer_size = SIZE_LONG;
1416 gbeauche 1.40 register_pair = true;
1417     break;
1418     }
1419    
1420     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1421     // Unknown machine code, let it crash. Then patch the decoder
1422     return false;
1423     }
1424    
1425 gbeauche 1.58 const int reg = (opcode >> 25) & 0x1f;
1426    
1427     #if DEBUG
1428     static const char * reg_names[] = {
1429     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1430     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1431     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1432     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1433     };
1434     printf("%s %s register %s\n",
1435     transfer_size == SIZE_BYTE ? "byte" :
1436     transfer_size == SIZE_WORD ? "word" :
1437     transfer_size == SIZE_LONG ? "long" :
1438     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1439     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1440     reg_names[reg]);
1441     #endif
1442    
1443 gbeauche 1.40 // Zero target register in case of a load operation
1444     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1445     // FIXME: code to handle local & input registers is not tested
1446 gbeauche 1.58 if (reg >= 1 && reg < 8) {
1447 gbeauche 1.40 // global registers
1448     regs[reg - 1 + SPARC_REG_G1] = 0;
1449     }
1450 gbeauche 1.58 else if (reg >= 8 && reg < 16) {
1451 gbeauche 1.40 // output registers
1452     regs[reg - 8 + SPARC_REG_O0] = 0;
1453     }
1454 gbeauche 1.58 else if (reg >= 16 && reg < 24) {
1455 gbeauche 1.40 // local registers (in register windows)
1456     if (gwins)
1457     gwins->wbuf->rw_local[reg - 16] = 0;
1458     else
1459     rwin->rw_local[reg - 16] = 0;
1460     }
1461     else {
1462     // input registers (in register windows)
1463     if (gwins)
1464     gwins->wbuf->rw_in[reg - 24] = 0;
1465     else
1466     rwin->rw_in[reg - 24] = 0;
1467     }
1468     }
1469    
1470     regs[SPARC_REG_PC] += 4;
1471 gbeauche 1.59 regs[SPARC_REG_nPC] += 4;
1472 gbeauche 1.38 return true;
1473 gbeauche 1.10 }
1474     #endif
1475     #endif
1476    
1477 gbeauche 1.44 // Decode and skip ARM instruction
1478     #if (defined(arm) || defined(__arm__))
1479     enum {
1480     #if (defined(__linux__))
1481     ARM_REG_PC = 15,
1482     ARM_REG_CPSR = 16
1483     #endif
1484     };
1485     static bool arm_skip_instruction(unsigned long * regs)
1486     {
1487     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1488    
1489     if (pc == 0)
1490     return false;
1491    
1492     #if DEBUG
1493     printf("IP: %p [%08x]\n", pc, pc[0]);
1494     #endif
1495    
1496     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1497     transfer_size_t transfer_size = SIZE_UNKNOWN;
1498     enum { op_sdt = 1, op_sdth = 2 };
1499     int op = 0;
1500    
1501     // Handle load/store instructions only
1502     const unsigned int opcode = pc[0];
1503     switch ((opcode >> 25) & 7) {
1504     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1505     op = op_sdth;
1506     // Determine transfer size (S/H bits)
1507     switch ((opcode >> 5) & 3) {
1508     case 0: // SWP instruction
1509     break;
1510     case 1: // Unsigned halfwords
1511     case 3: // Signed halfwords
1512     transfer_size = SIZE_WORD;
1513     break;
1514     case 2: // Signed byte
1515     transfer_size = SIZE_BYTE;
1516     break;
1517     }
1518     break;
1519     case 2:
1520     case 3: // Single Data Transfer (LDR, STR)
1521     op = op_sdt;
1522     // Determine transfer size (B bit)
1523     if (((opcode >> 22) & 1) == 1)
1524     transfer_size = SIZE_BYTE;
1525     else
1526     transfer_size = SIZE_LONG;
1527     break;
1528     default:
1529     // FIXME: support load/store mutliple?
1530     return false;
1531     }
1532    
1533     // Check for invalid transfer size (SWP instruction?)
1534     if (transfer_size == SIZE_UNKNOWN)
1535     return false;
1536    
1537     // Determine transfer type (L bit)
1538     if (((opcode >> 20) & 1) == 1)
1539     transfer_type = SIGSEGV_TRANSFER_LOAD;
1540     else
1541     transfer_type = SIGSEGV_TRANSFER_STORE;
1542    
1543     // Compute offset
1544     int offset;
1545     if (((opcode >> 25) & 1) == 0) {
1546     if (op == op_sdt)
1547     offset = opcode & 0xfff;
1548     else if (op == op_sdth) {
1549     int rm = opcode & 0xf;
1550     if (((opcode >> 22) & 1) == 0) {
1551     // register offset
1552     offset = regs[rm];
1553     }
1554     else {
1555     // immediate offset
1556     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1557     }
1558     }
1559     }
1560     else {
1561     const int rm = opcode & 0xf;
1562     const int sh = (opcode >> 7) & 0x1f;
1563     if (((opcode >> 4) & 1) == 1) {
1564     // we expect only legal load/store instructions
1565     printf("FATAL: invalid shift operand\n");
1566     return false;
1567     }
1568     const unsigned int v = regs[rm];
1569     switch ((opcode >> 5) & 3) {
1570     case 0: // logical shift left
1571     offset = sh ? v << sh : v;
1572     break;
1573     case 1: // logical shift right
1574     offset = sh ? v >> sh : 0;
1575     break;
1576     case 2: // arithmetic shift right
1577     if (sh)
1578     offset = ((signed int)v) >> sh;
1579     else
1580     offset = (v & 0x80000000) ? 0xffffffff : 0;
1581     break;
1582     case 3: // rotate right
1583     if (sh)
1584     offset = (v >> sh) | (v << (32 - sh));
1585     else
1586     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1587     break;
1588     }
1589     }
1590     if (((opcode >> 23) & 1) == 0)
1591     offset = -offset;
1592    
1593     int rd = (opcode >> 12) & 0xf;
1594     int rn = (opcode >> 16) & 0xf;
1595     #if DEBUG
1596     static const char * reg_names[] = {
1597     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1598     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1599     };
1600     printf("%s %s register %s\n",
1601     transfer_size == SIZE_BYTE ? "byte" :
1602     transfer_size == SIZE_WORD ? "word" :
1603     transfer_size == SIZE_LONG ? "long" : "unknown",
1604     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1605     reg_names[rd]);
1606     #endif
1607    
1608     unsigned int base = regs[rn];
1609     if (((opcode >> 24) & 1) == 1)
1610     base += offset;
1611    
1612     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1613     regs[rd] = 0;
1614    
1615     if (((opcode >> 24) & 1) == 0) // post-index addressing
1616     regs[rn] += offset;
1617     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1618     regs[rn] = base;
1619    
1620     regs[ARM_REG_PC] += 4;
1621     return true;
1622     }
1623     #endif
1624    
1625    
1626 gbeauche 1.1 // Fallbacks
1627 gbeauche 1.68 #ifndef SIGSEGV_FAULT_ADDRESS_FAST
1628     #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS
1629     #endif
1630     #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
1631     #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION
1632     #endif
1633 gbeauche 1.1 #ifndef SIGSEGV_FAULT_INSTRUCTION
1634 gbeauche 1.67 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS
1635 gbeauche 1.1 #endif
1636 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1637     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1638     #endif
1639 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1640 gbeauche 1.67 #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
1641 gbeauche 1.31 #endif
1642 gbeauche 1.1
1643 gbeauche 1.2 // SIGSEGV recovery supported ?
1644     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1645     #define HAVE_SIGSEGV_RECOVERY
1646     #endif
1647    
1648 gbeauche 1.1
1649     /*
1650     * SIGSEGV global handler
1651     */
1652    
1653 gbeauche 1.67 struct sigsegv_info_t {
1654     sigsegv_address_t addr;
1655     sigsegv_address_t pc;
1656 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
1657     mach_port_t thread;
1658     bool has_exc_state;
1659     SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
1660     mach_msg_type_number_t exc_state_count;
1661     bool has_thr_state;
1662     SIGSEGV_THREAD_STATE_TYPE thr_state;
1663     mach_msg_type_number_t thr_state_count;
1664     #endif
1665 gbeauche 1.67 };
1666    
1667     // Return the address of the invalid memory reference
1668     sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip)
1669     {
1670 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
1671     static int use_fast_path = -1;
1672     if (use_fast_path != 1 && !sip->has_exc_state) {
1673     sip->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
1674     kern_return_t krc = thread_get_state(sip->thread,
1675     SIGSEGV_EXCEPTION_STATE_FLAVOR,
1676     (natural_t *)&sip->exc_state,
1677     &sip->exc_state_count);
1678     MACH_CHECK_ERROR(thread_get_state, krc);
1679     sip->has_exc_state = true;
1680    
1681     sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1682     if (use_fast_path < 0)
1683     use_fast_path = addr == sip->addr;
1684     sip->addr = addr;
1685     }
1686     #endif
1687 gbeauche 1.67 return sip->addr;
1688     }
1689    
1690     // Return the address of the instruction that caused the fault, or
1691     // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
1692     sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip)
1693     {
1694 gbeauche 1.68 #ifdef HAVE_MACH_EXCEPTIONS
1695     if (!sip->has_thr_state) {
1696     sip->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
1697     kern_return_t krc = thread_get_state(sip->thread,
1698     SIGSEGV_THREAD_STATE_FLAVOR,
1699     (natural_t *)&sip->thr_state,
1700     &sip->thr_state_count);
1701     MACH_CHECK_ERROR(thread_get_state, krc);
1702     sip->has_thr_state = true;
1703    
1704     sip->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1705     }
1706     #endif
1707 gbeauche 1.67 return sip->pc;
1708     }
1709    
1710 gbeauche 1.27 // This function handles the badaccess to memory.
1711     // It is called from the signal handler or the exception handler.
1712 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1713 gbeauche 1.1 {
1714 gbeauche 1.68 sigsegv_info_t si;
1715     si.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
1716     si.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
1717 gbeauche 1.56 #ifdef HAVE_MACH_EXCEPTIONS
1718 gbeauche 1.68 si.thread = thread;
1719     si.has_exc_state = false;
1720     si.has_thr_state = false;
1721 gbeauche 1.56 #endif
1722 gbeauche 1.68 sigsegv_info_t * const sip = &si;
1723 gbeauche 1.56
1724 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1725 gbeauche 1.68 switch (SIGSEGV_FAULT_HANDLER_INVOKE(sip)) {
1726 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1727 gbeauche 1.27 return true;
1728    
1729 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1730 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1731 gbeauche 1.27 // Call the instruction skipper with the register file
1732     // available
1733     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1734     #ifdef HAVE_MACH_EXCEPTIONS
1735     // Unlike UNIX signals where the thread state
1736     // is modified off of the stack, in Mach we
1737     // need to actually call thread_set_state to
1738     // have the register values updated.
1739 gbeauche 1.68 kern_return_t krc = thread_set_state(sip->thread,
1740     SIGSEGV_THREAD_STATE_FLAVOR,
1741     (natural_t *)&sip->thr_state,
1742     sip->thr_state_count);
1743     MACH_CHECK_ERROR(thread_set_state, krc);
1744 gbeauche 1.27 #endif
1745     return true;
1746     }
1747 gbeauche 1.24 break;
1748     #endif
1749 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1750 gbeauche 1.50 // We can't do anything with the fault_address, dump state?
1751     if (sigsegv_state_dumper != 0)
1752 gbeauche 1.68 sigsegv_state_dumper(sip);
1753 gbeauche 1.50 break;
1754 gbeauche 1.10 }
1755 gbeauche 1.27
1756     return false;
1757     }
1758    
1759    
1760     /*
1761     * There are two mechanisms for handling a bad memory access,
1762     * Mach exceptions and UNIX signals. The implementation specific
1763     * code appears below. Its reponsibility is to call handle_badaccess
1764     * which is the routine that handles the fault in an implementation
1765     * agnostic manner. The implementation specific code below is then
1766     * reponsible for checking whether handle_badaccess was able
1767     * to handle the memory access error and perform any implementation
1768     * specific tasks necessary afterwards.
1769     */
1770    
1771     #ifdef HAVE_MACH_EXCEPTIONS
1772     /*
1773     * We need to forward all exceptions that we do not handle.
1774     * This is important, there are many exceptions that may be
1775     * handled by other exception handlers. For example debuggers
1776     * use exceptions and the exception hander is in another
1777     * process in such a case. (Timothy J. Wood states in his
1778     * message to the list that he based this code on that from
1779     * gdb for Darwin.)
1780     */
1781     static inline kern_return_t
1782     forward_exception(mach_port_t thread_port,
1783     mach_port_t task_port,
1784     exception_type_t exception_type,
1785     exception_data_t exception_data,
1786     mach_msg_type_number_t data_count,
1787     ExceptionPorts *oldExceptionPorts)
1788     {
1789     kern_return_t kret;
1790     unsigned int portIndex;
1791     mach_port_t port;
1792     exception_behavior_t behavior;
1793     thread_state_flavor_t flavor;
1794 gbeauche 1.57 thread_state_data_t thread_state;
1795 gbeauche 1.27 mach_msg_type_number_t thread_state_count;
1796    
1797     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1798     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1799     // This handler wants the exception
1800     break;
1801     }
1802     }
1803    
1804     if (portIndex >= oldExceptionPorts->maskCount) {
1805     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1806     return KERN_FAILURE;
1807     }
1808    
1809     port = oldExceptionPorts->handlers[portIndex];
1810     behavior = oldExceptionPorts->behaviors[portIndex];
1811     flavor = oldExceptionPorts->flavors[portIndex];
1812    
1813 gbeauche 1.63 if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1814     fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1815     return KERN_FAILURE;
1816     }
1817    
1818 gbeauche 1.27 /*
1819     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1820     */
1821    
1822     if (behavior != EXCEPTION_DEFAULT) {
1823     thread_state_count = THREAD_STATE_MAX;
1824 gbeauche 1.60 kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1825 gbeauche 1.27 &thread_state_count);
1826     MACH_CHECK_ERROR (thread_get_state, kret);
1827     }
1828    
1829     switch (behavior) {
1830     case EXCEPTION_DEFAULT:
1831     // fprintf(stderr, "forwarding to exception_raise\n");
1832     kret = exception_raise(port, thread_port, task_port, exception_type,
1833     exception_data, data_count);
1834     MACH_CHECK_ERROR (exception_raise, kret);
1835     break;
1836     case EXCEPTION_STATE:
1837     // fprintf(stderr, "forwarding to exception_raise_state\n");
1838     kret = exception_raise_state(port, exception_type, exception_data,
1839     data_count, &flavor,
1840 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1841     (natural_t *)&thread_state, &thread_state_count);
1842 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state, kret);
1843     break;
1844     case EXCEPTION_STATE_IDENTITY:
1845     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1846     kret = exception_raise_state_identity(port, thread_port, task_port,
1847     exception_type, exception_data,
1848     data_count, &flavor,
1849 gbeauche 1.60 (natural_t *)&thread_state, thread_state_count,
1850     (natural_t *)&thread_state, &thread_state_count);
1851 gbeauche 1.27 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1852     break;
1853     default:
1854     fprintf(stderr, "forward_exception got unknown behavior\n");
1855 gbeauche 1.63 kret = KERN_FAILURE;
1856 gbeauche 1.27 break;
1857     }
1858    
1859     if (behavior != EXCEPTION_DEFAULT) {
1860 gbeauche 1.60 kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1861 gbeauche 1.27 thread_state_count);
1862     MACH_CHECK_ERROR (thread_set_state, kret);
1863     }
1864    
1865 gbeauche 1.63 return kret;
1866 gbeauche 1.27 }
1867    
1868     /*
1869     * This is the code that actually handles the exception.
1870     * It is called by exc_server. For Darwin 5 Apple changed
1871     * this a bit from how this family of functions worked in
1872     * Mach. If you are familiar with that it is a little
1873     * different. The main variation that concerns us here is
1874     * that code is an array of exception specific codes and
1875     * codeCount is a count of the number of codes in the code
1876     * array. In typical Mach all exceptions have a code
1877     * and sub-code. It happens to be the case that for a
1878     * EXC_BAD_ACCESS exception the first entry is the type of
1879     * bad access that occurred and the second entry is the
1880     * faulting address so these entries correspond exactly to
1881     * how the code and sub-code are used on Mach.
1882     *
1883     * This is a MIG interface. No code in Basilisk II should
1884     * call this directley. This has to have external C
1885     * linkage because that is what exc_server expects.
1886     */
1887     kern_return_t
1888     catch_exception_raise(mach_port_t exception_port,
1889     mach_port_t thread,
1890     mach_port_t task,
1891     exception_type_t exception,
1892     exception_data_t code,
1893 gbeauche 1.66 mach_msg_type_number_t code_count)
1894 gbeauche 1.27 {
1895     kern_return_t krc;
1896    
1897 gbeauche 1.66 if (exception == EXC_BAD_ACCESS) {
1898     switch (code[0]) {
1899     case KERN_PROTECTION_FAILURE:
1900     case KERN_INVALID_ADDRESS:
1901     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1902     return KERN_SUCCESS;
1903     break;
1904     }
1905 gbeauche 1.27 }
1906    
1907     // In Mach we do not need to remove the exception handler.
1908     // If we forward the exception, eventually some exception handler
1909     // will take care of this exception.
1910 gbeauche 1.66 krc = forward_exception(thread, task, exception, code, code_count, &ports);
1911 gbeauche 1.27
1912     return krc;
1913     }
1914     #endif
1915    
1916     #ifdef HAVE_SIGSEGV_RECOVERY
1917     // Handle bad memory accesses with signal handler
1918     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1919     {
1920     // Call handler and reinstall the global handler, if required
1921     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1922     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1923     sigsegv_do_install_handler(sig);
1924     #endif
1925     return;
1926     }
1927 gbeauche 1.10
1928 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1929 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1930 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1931 gbeauche 1.1 #undef FAULT_HANDLER
1932     }
1933 gbeauche 1.2 #endif
1934 gbeauche 1.1
1935    
1936     /*
1937     * SIGSEGV handler initialization
1938     */
1939    
1940     #if defined(HAVE_SIGINFO_T)
1941     static bool sigsegv_do_install_handler(int sig)
1942     {
1943     // Setup SIGSEGV handler to process writes to frame buffer
1944     #ifdef HAVE_SIGACTION
1945 gbeauche 1.22 struct sigaction sigsegv_sa;
1946     sigemptyset(&sigsegv_sa.sa_mask);
1947     sigsegv_sa.sa_sigaction = sigsegv_handler;
1948     sigsegv_sa.sa_flags = SA_SIGINFO;
1949     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1950 gbeauche 1.1 #else
1951     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1952     #endif
1953     }
1954 gbeauche 1.2 #endif
1955    
1956     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1957 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1958     {
1959     // Setup SIGSEGV handler to process writes to frame buffer
1960     #ifdef HAVE_SIGACTION
1961 gbeauche 1.22 struct sigaction sigsegv_sa;
1962     sigemptyset(&sigsegv_sa.sa_mask);
1963     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1964     sigsegv_sa.sa_flags = 0;
1965 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1966 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1967     sigsegv_sa.sa_flags |= SA_ONSTACK;
1968 gbeauche 1.1 #endif
1969 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1970 gbeauche 1.1 #else
1971     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1972     #endif
1973     }
1974     #endif
1975    
1976 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1977     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1978     {
1979     /*
1980     * Except for the exception port functions, this should be
1981     * pretty much stock Mach. If later you choose to support
1982     * other Mach's besides Darwin, just check for __MACH__
1983     * here and __APPLE__ where the actual differences are.
1984     */
1985     #if defined(__APPLE__) && defined(__MACH__)
1986     if (sigsegv_fault_handler != NULL) {
1987     sigsegv_fault_handler = handler;
1988     return true;
1989     }
1990    
1991     kern_return_t krc;
1992    
1993     // create the the exception port
1994     krc = mach_port_allocate(mach_task_self(),
1995     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1996     if (krc != KERN_SUCCESS) {
1997     mach_error("mach_port_allocate", krc);
1998     return false;
1999     }
2000    
2001     // add a port send right
2002     krc = mach_port_insert_right(mach_task_self(),
2003     _exceptionPort, _exceptionPort,
2004     MACH_MSG_TYPE_MAKE_SEND);
2005     if (krc != KERN_SUCCESS) {
2006     mach_error("mach_port_insert_right", krc);
2007     return false;
2008     }
2009    
2010     // get the old exception ports
2011     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2012     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2013     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2014     if (krc != KERN_SUCCESS) {
2015     mach_error("thread_get_exception_ports", krc);
2016     return false;
2017     }
2018    
2019     // set the new exception port
2020     //
2021     // We could have used EXCEPTION_STATE_IDENTITY instead of
2022     // EXCEPTION_DEFAULT to get the thread state in the initial
2023     // message, but it turns out that in the common case this is not
2024     // neccessary. If we need it we can later ask for it from the
2025     // suspended thread.
2026     //
2027     // Even with THREAD_STATE_NONE, Darwin provides the program
2028     // counter in the thread state. The comments in the header file
2029     // seem to imply that you can count on the GPR's on an exception
2030     // as well but just to be safe I use MACHINE_THREAD_STATE because
2031     // you have to ask for all of the GPR's anyway just to get the
2032     // program counter. In any case because of update effective
2033     // address from immediate and update address from effective
2034     // addresses of ra and rb modes (as good an name as any for these
2035     // addressing modes) used in PPC instructions, you will need the
2036     // GPR state anyway.
2037     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2038 gbeauche 1.56 EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2039 gbeauche 1.27 if (krc != KERN_SUCCESS) {
2040     mach_error("thread_set_exception_ports", krc);
2041     return false;
2042     }
2043    
2044     // create the exception handler thread
2045     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2046     (void)fprintf(stderr, "creation of exception thread failed\n");
2047     return false;
2048     }
2049    
2050     // do not care about the exception thread any longer, let is run standalone
2051     (void)pthread_detach(exc_thread);
2052    
2053     sigsegv_fault_handler = handler;
2054     return true;
2055     #else
2056     return false;
2057     #endif
2058     }
2059     #endif
2060    
2061 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2062     static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2063     {
2064     if (sigsegv_fault_handler != NULL
2065     && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2066     && ExceptionInfo->ExceptionRecord->NumberParameters == 2
2067     && handle_badaccess(ExceptionInfo))
2068     return EXCEPTION_CONTINUE_EXECUTION;
2069    
2070     return EXCEPTION_CONTINUE_SEARCH;
2071     }
2072    
2073     #if defined __CYGWIN__ && defined __i386__
2074     /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2075     installs a global exception handler. We have to dig deep in order to install
2076     our main_exception_filter. */
2077    
2078     /* Data structures for the current thread's exception handler chain.
2079     On the x86 Windows uses register fs, offset 0 to point to the current
2080     exception handler; Cygwin mucks with it, so we must do the same... :-/ */
2081    
2082     /* Magic taken from winsup/cygwin/include/exceptions.h. */
2083    
2084     struct exception_list {
2085     struct exception_list *prev;
2086     int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2087     };
2088     typedef struct exception_list exception_list;
2089    
2090     /* Magic taken from winsup/cygwin/exceptions.cc. */
2091    
2092     __asm__ (".equ __except_list,0");
2093    
2094     extern exception_list *_except_list __asm__ ("%fs:__except_list");
2095    
2096     /* For debugging. _except_list is not otherwise accessible from gdb. */
2097     static exception_list *
2098     debug_get_except_list ()
2099     {
2100     return _except_list;
2101     }
2102    
2103     /* Cygwin's original exception handler. */
2104     static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2105    
2106     /* Our exception handler. */
2107     static int
2108     libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2109     {
2110     EXCEPTION_POINTERS ExceptionInfo;
2111     ExceptionInfo.ExceptionRecord = exception;
2112     ExceptionInfo.ContextRecord = context;
2113     if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2114     return cygwin_exception_handler (exception, frame, context, dispatch);
2115     else
2116     return 0;
2117     }
2118    
2119     static void
2120     do_install_main_exception_filter ()
2121     {
2122     /* We cannot insert any handler into the chain, because such handlers
2123     must lie on the stack (?). Instead, we have to replace(!) Cygwin's
2124     global exception handler. */
2125     cygwin_exception_handler = _except_list->handler;
2126     _except_list->handler = libsigsegv_exception_handler;
2127     }
2128    
2129     #else
2130    
2131     static void
2132     do_install_main_exception_filter ()
2133     {
2134     SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2135     }
2136     #endif
2137    
2138     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2139     {
2140     static bool main_exception_filter_installed = false;
2141     if (!main_exception_filter_installed) {
2142     do_install_main_exception_filter();
2143     main_exception_filter_installed = true;
2144     }
2145     sigsegv_fault_handler = handler;
2146     return true;
2147     }
2148     #endif
2149    
2150 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2151 gbeauche 1.1 {
2152 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
2153 gbeauche 1.1 bool success = true;
2154     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
2155     SIGSEGV_ALL_SIGNALS
2156     #undef FAULT_HANDLER
2157 gbeauche 1.27 if (success)
2158     sigsegv_fault_handler = handler;
2159 gbeauche 1.1 return success;
2160 gbeauche 1.48 #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2161 gbeauche 1.27 return sigsegv_do_install_handler(handler);
2162 gbeauche 1.1 #else
2163     // FAIL: no siginfo_t nor sigcontext subterfuge is available
2164     return false;
2165     #endif
2166     }
2167    
2168    
2169     /*
2170     * SIGSEGV handler deinitialization
2171     */
2172    
2173     void sigsegv_deinstall_handler(void)
2174     {
2175 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
2176     // suspended if not already so, and we might mess with other
2177     // exception handlers that came after we registered ours. There is
2178     // no need to remove the exception handler, in fact this function is
2179     // not called anywhere in Basilisk II.
2180 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
2181 gbeauche 1.12 sigsegv_fault_handler = 0;
2182 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2183     SIGSEGV_ALL_SIGNALS
2184     #undef FAULT_HANDLER
2185 gbeauche 1.2 #endif
2186 gbeauche 1.48 #ifdef HAVE_WIN32_EXCEPTIONS
2187     sigsegv_fault_handler = NULL;
2188     #endif
2189 gbeauche 1.1 }
2190    
2191 gbeauche 1.10
2192     /*
2193     * Set callback function when we cannot handle the fault
2194     */
2195    
2196 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
2197 gbeauche 1.10 {
2198 gbeauche 1.12 sigsegv_state_dumper = handler;
2199 gbeauche 1.10 }
2200    
2201    
2202 gbeauche 1.1 /*
2203     * Test program used for configure/test
2204     */
2205    
2206 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
2207 gbeauche 1.1 #include <stdio.h>
2208     #include <stdlib.h>
2209     #include <fcntl.h>
2210 gbeauche 1.48 #ifdef HAVE_SYS_MMAN_H
2211 gbeauche 1.1 #include <sys/mman.h>
2212 gbeauche 1.48 #endif
2213 gbeauche 1.4 #include "vm_alloc.h"
2214 gbeauche 1.1
2215 gbeauche 1.32 const int REF_INDEX = 123;
2216     const int REF_VALUE = 45;
2217    
2218 gbeauche 1.1 static int page_size;
2219 gbeauche 1.3 static volatile char * page = 0;
2220     static volatile int handler_called = 0;
2221 gbeauche 1.1
2222 gbeauche 1.61 /* Barriers */
2223     #ifdef __GNUC__
2224     #define BARRIER() asm volatile ("" : : : "memory")
2225     #else
2226     #define BARRIER() /* nothing */
2227     #endif
2228    
2229 gbeauche 1.32 #ifdef __GNUC__
2230     // Code range where we expect the fault to come from
2231     static void *b_region, *e_region;
2232     #endif
2233    
2234 gbeauche 1.67 static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2235 gbeauche 1.1 {
2236 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2237     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2238 gbeauche 1.39 #if DEBUG
2239     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2240     printf("expected fault at %p\n", page + REF_INDEX);
2241     #ifdef __GNUC__
2242     printf("expected instruction address range: %p-%p\n", b_region, e_region);
2243     #endif
2244     #endif
2245 gbeauche 1.1 handler_called++;
2246 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
2247 gbeauche 1.29 exit(10);
2248 gbeauche 1.32 #ifdef __GNUC__
2249     // Make sure reported fault instruction address falls into
2250     // expected code range
2251 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
2252 gbeauche 1.32 && ((instruction_address < (sigsegv_address_t)b_region) ||
2253     (instruction_address >= (sigsegv_address_t)e_region)))
2254     exit(11);
2255     #endif
2256 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
2257 gbeauche 1.32 exit(12);
2258 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
2259 gbeauche 1.1 }
2260    
2261 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2262 gbeauche 1.67 static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
2263 gbeauche 1.10 {
2264 gbeauche 1.67 const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2265     const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2266 gbeauche 1.44 #if DEBUG
2267     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2268     #endif
2269 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
2270     #ifdef __GNUC__
2271     // Make sure reported fault instruction address falls into
2272     // expected code range
2273 gbeauche 1.67 if (instruction_address != SIGSEGV_INVALID_ADDRESS
2274 gbeauche 1.28 && ((instruction_address < (sigsegv_address_t)b_region) ||
2275     (instruction_address >= (sigsegv_address_t)e_region)))
2276     return SIGSEGV_RETURN_FAILURE;
2277     #endif
2278 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
2279 gbeauche 1.28 }
2280    
2281 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
2282 gbeauche 1.10 }
2283 gbeauche 1.34
2284     // More sophisticated tests for instruction skipper
2285     static bool arch_insn_skipper_tests()
2286     {
2287     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
2288     static const unsigned char code[] = {
2289     0x8a, 0x00, // mov (%eax),%al
2290     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
2291     0x88, 0x20, // mov %ah,(%eax)
2292     0x88, 0x08, // mov %cl,(%eax)
2293     0x66, 0x8b, 0x00, // mov (%eax),%ax
2294     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
2295     0x66, 0x89, 0x00, // mov %ax,(%eax)
2296     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
2297     0x8b, 0x00, // mov (%eax),%eax
2298     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
2299     0x89, 0x00, // mov %eax,(%eax)
2300     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
2301     #if defined(__x86_64__)
2302     0x44, 0x8a, 0x00, // mov (%rax),%r8b
2303     0x44, 0x8a, 0x20, // mov (%rax),%r12b
2304     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
2305     0x44, 0x88, 0x00, // mov %r8b,(%rax)
2306     0x44, 0x88, 0x20, // mov %r12b,(%rax)
2307     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
2308     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
2309     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
2310     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
2311     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
2312     0x44, 0x8b, 0x00, // mov (%rax),%r8d
2313     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
2314     0x44, 0x89, 0x00, // mov %r8d,(%rax)
2315     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
2316     0x48, 0x8b, 0x08, // mov (%rax),%rcx
2317     0x4c, 0x8b, 0x18, // mov (%rax),%r11
2318     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
2319     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
2320     0x48, 0x89, 0x08, // mov %rcx,(%rax)
2321     0x4c, 0x89, 0x18, // mov %r11,(%rax)
2322     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
2323     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
2324 gbeauche 1.62 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax
2325     0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax
2326 gbeauche 1.34 #endif
2327     0 // end
2328     };
2329     const int N_REGS = 20;
2330     unsigned long regs[N_REGS];
2331     for (int i = 0; i < N_REGS; i++)
2332     regs[i] = i;
2333     const unsigned long start_code = (unsigned long)&code;
2334     regs[X86_REG_EIP] = start_code;
2335     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
2336     && ix86_skip_instruction(regs))
2337     ; /* simply iterate */
2338     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
2339     #endif
2340     return true;
2341     }
2342 gbeauche 1.10 #endif
2343    
2344 gbeauche 1.1 int main(void)
2345     {
2346 gbeauche 1.4 if (vm_init() < 0)
2347 gbeauche 1.1 return 1;
2348    
2349 gbeauche 1.54 page_size = vm_get_page_size();
2350 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2351 gbeauche 1.29 return 2;
2352 gbeauche 1.4
2353 gbeauche 1.32 memset((void *)page, 0, page_size);
2354 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
2355 gbeauche 1.29 return 3;
2356 gbeauche 1.1
2357     if (!sigsegv_install_handler(sigsegv_test_handler))
2358 gbeauche 1.29 return 4;
2359 gbeauche 1.1
2360 gbeauche 1.32 #ifdef __GNUC__
2361     b_region = &&L_b_region1;
2362     e_region = &&L_e_region1;
2363     #endif
2364     L_b_region1:
2365     page[REF_INDEX] = REF_VALUE;
2366     if (page[REF_INDEX] != REF_VALUE)
2367     exit(20);
2368     page[REF_INDEX] = REF_VALUE;
2369 gbeauche 1.61 BARRIER();
2370 gbeauche 1.32 L_e_region1:
2371    
2372 gbeauche 1.1 if (handler_called != 1)
2373 gbeauche 1.29 return 5;
2374 gbeauche 1.10
2375     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2376     if (!sigsegv_install_handler(sigsegv_insn_handler))
2377 gbeauche 1.29 return 6;
2378 gbeauche 1.10
2379 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
2380 gbeauche 1.29 return 7;
2381 gbeauche 1.10
2382     for (int i = 0; i < page_size; i++)
2383     page[i] = (i + 1) % page_size;
2384    
2385     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
2386 gbeauche 1.29 return 8;
2387 gbeauche 1.10
2388     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
2389 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
2390     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2391 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2392 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2393 gbeauche 1.10 if (effect != TAG) \
2394 gbeauche 1.29 return 9; \
2395 gbeauche 1.10 } while (0)
2396    
2397 gbeauche 1.28 #ifdef __GNUC__
2398 gbeauche 1.32 b_region = &&L_b_region2;
2399     e_region = &&L_e_region2;
2400 gbeauche 1.28 #endif
2401 gbeauche 1.32 L_b_region2:
2402 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2403     TEST_SKIP_INSTRUCTION(unsigned short);
2404     TEST_SKIP_INSTRUCTION(unsigned int);
2405 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2406 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2407     TEST_SKIP_INSTRUCTION(signed short);
2408     TEST_SKIP_INSTRUCTION(signed int);
2409     TEST_SKIP_INSTRUCTION(signed long);
2410 gbeauche 1.61 BARRIER();
2411 gbeauche 1.32 L_e_region2:
2412 gbeauche 1.1
2413 gbeauche 1.34 if (!arch_insn_skipper_tests())
2414     return 20;
2415 gbeauche 1.35 #endif
2416 gbeauche 1.34
2417 gbeauche 1.4 vm_exit();
2418 gbeauche 1.1 return 0;
2419     }
2420     #endif