ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.44
Committed: 2004-01-21T23:14:28Z (20 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.43: +160 -0 lines
Log Message:
Summary: possible support of SheepShaver on Zaurus PDAs

Add Linux/ARM instruction skipping, includes support for ARMv4+ halfword
and signed data transfer instructions. Note that load/store multiple are
not handled and someone has to make sure post-incr/write-back logic is
correctly implemented.

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