ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.47
Committed: 2004-02-16T16:02:48Z (20 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.46: +1 -0 lines
Log Message:
Decode MOVSX r32, r/m16 (generated by icc v8.0 on x86)

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 gbeauche 1.45 int target_size = SIZE_UNKNOWN;
770 gbeauche 1.10 switch (eip[0]) {
771 gbeauche 1.17 case 0x0f:
772 gbeauche 1.45 target_size = transfer_size;
773 gbeauche 1.18 switch (eip[1]) {
774 gbeauche 1.45 case 0xbe: // MOVSX r32, r/m8
775 gbeauche 1.18 case 0xb6: // MOVZX r32, r/m8
776 gbeauche 1.45 transfer_size = SIZE_BYTE;
777     goto do_mov_extend;
778 gbeauche 1.47 case 0xbf: // MOVSX r32, r/m16
779 gbeauche 1.18 case 0xb7: // MOVZX r32, r/m16
780 gbeauche 1.45 transfer_size = SIZE_WORD;
781     goto do_mov_extend;
782     do_mov_extend:
783     switch (eip[2] & 0xc0) {
784     case 0x80:
785     reg = (eip[2] >> 3) & 7;
786     transfer_type = SIGSEGV_TRANSFER_LOAD;
787     break;
788     case 0x40:
789     reg = (eip[2] >> 3) & 7;
790     transfer_type = SIGSEGV_TRANSFER_LOAD;
791     break;
792     case 0x00:
793     reg = (eip[2] >> 3) & 7;
794     transfer_type = SIGSEGV_TRANSFER_LOAD;
795     break;
796     }
797     len += 3 + ix86_step_over_modrm(eip + 2);
798     break;
799 gbeauche 1.17 }
800     break;
801 gbeauche 1.10 case 0x8a: // MOV r8, r/m8
802     transfer_size = SIZE_BYTE;
803     case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
804     switch (eip[1] & 0xc0) {
805     case 0x80:
806     reg = (eip[1] >> 3) & 7;
807 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
808 gbeauche 1.10 break;
809     case 0x40:
810     reg = (eip[1] >> 3) & 7;
811 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
812 gbeauche 1.10 break;
813     case 0x00:
814     reg = (eip[1] >> 3) & 7;
815 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_LOAD;
816 gbeauche 1.10 break;
817     }
818     len += 2 + ix86_step_over_modrm(eip + 1);
819     break;
820     case 0x88: // MOV r/m8, r8
821     transfer_size = SIZE_BYTE;
822     case 0x89: // MOV r/m32, r32 (or 16-bit operation)
823     switch (eip[1] & 0xc0) {
824     case 0x80:
825     reg = (eip[1] >> 3) & 7;
826 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
827 gbeauche 1.10 break;
828     case 0x40:
829     reg = (eip[1] >> 3) & 7;
830 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
831 gbeauche 1.10 break;
832     case 0x00:
833     reg = (eip[1] >> 3) & 7;
834 gbeauche 1.22 transfer_type = SIGSEGV_TRANSFER_STORE;
835 gbeauche 1.10 break;
836     }
837     len += 2 + ix86_step_over_modrm(eip + 1);
838     break;
839     }
840 gbeauche 1.45 if (target_size == SIZE_UNKNOWN)
841     target_size = transfer_size;
842 gbeauche 1.10
843 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
844 gbeauche 1.10 // Unknown machine code, let it crash. Then patch the decoder
845     return false;
846     }
847    
848 gbeauche 1.34 #if defined(__x86_64__)
849     if (rex.R)
850     reg += 8;
851     #endif
852    
853 gbeauche 1.22 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
854 gbeauche 1.34 static const int x86_reg_map[] = {
855 gbeauche 1.10 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
856 gbeauche 1.34 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
857     #if defined(__x86_64__)
858     X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
859     X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
860     #endif
861 gbeauche 1.10 };
862    
863 gbeauche 1.34 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
864 gbeauche 1.10 return false;
865    
866 gbeauche 1.34 // Set 0 to the relevant register part
867     // NOTE: this is only valid for MOV alike instructions
868 gbeauche 1.10 int rloc = x86_reg_map[reg];
869 gbeauche 1.45 switch (target_size) {
870 gbeauche 1.10 case SIZE_BYTE:
871 gbeauche 1.36 if (has_rex || reg < 4)
872     regs[rloc] = (regs[rloc] & ~0x00ffL);
873     else {
874     rloc = x86_reg_map[reg - 4];
875     regs[rloc] = (regs[rloc] & ~0xff00L);
876     }
877 gbeauche 1.10 break;
878     case SIZE_WORD:
879 gbeauche 1.34 regs[rloc] = (regs[rloc] & ~0xffffL);
880 gbeauche 1.10 break;
881     case SIZE_LONG:
882 gbeauche 1.34 case SIZE_QUAD: // zero-extension
883 gbeauche 1.10 regs[rloc] = 0;
884     break;
885     }
886     }
887    
888     #if DEBUG
889 gbeauche 1.15 printf("%08x: %s %s access", regs[X86_REG_EIP],
890 gbeauche 1.34 transfer_size == SIZE_BYTE ? "byte" :
891     transfer_size == SIZE_WORD ? "word" :
892     transfer_size == SIZE_LONG ? "long" :
893     transfer_size == SIZE_QUAD ? "quad" : "unknown",
894 gbeauche 1.22 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
895 gbeauche 1.10
896     if (reg != -1) {
897 gbeauche 1.34 static const char * x86_byte_reg_str_map[] = {
898     "al", "cl", "dl", "bl",
899     "spl", "bpl", "sil", "dil",
900     "r8b", "r9b", "r10b", "r11b",
901     "r12b", "r13b", "r14b", "r15b",
902     "ah", "ch", "dh", "bh",
903     };
904     static const char * x86_word_reg_str_map[] = {
905     "ax", "cx", "dx", "bx",
906     "sp", "bp", "si", "di",
907     "r8w", "r9w", "r10w", "r11w",
908     "r12w", "r13w", "r14w", "r15w",
909     };
910     static const char *x86_long_reg_str_map[] = {
911     "eax", "ecx", "edx", "ebx",
912     "esp", "ebp", "esi", "edi",
913     "r8d", "r9d", "r10d", "r11d",
914     "r12d", "r13d", "r14d", "r15d",
915     };
916     static const char *x86_quad_reg_str_map[] = {
917     "rax", "rcx", "rdx", "rbx",
918     "rsp", "rbp", "rsi", "rdi",
919     "r8", "r9", "r10", "r11",
920     "r12", "r13", "r14", "r15",
921 gbeauche 1.10 };
922 gbeauche 1.34 const char * reg_str = NULL;
923 gbeauche 1.46 switch (target_size) {
924 gbeauche 1.34 case SIZE_BYTE:
925     reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
926     break;
927     case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
928     case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
929     case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
930     }
931     if (reg_str)
932     printf(" %s register %%%s",
933     transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
934     reg_str);
935 gbeauche 1.10 }
936     printf(", %d bytes instruction\n", len);
937     #endif
938    
939     regs[X86_REG_EIP] += len;
940 gbeauche 1.13 return true;
941     }
942     #endif
943 gbeauche 1.14
944 gbeauche 1.13 // Decode and skip PPC instruction
945 gbeauche 1.14 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
946     static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
947 gbeauche 1.13 {
948 gbeauche 1.14 instruction_t instr;
949     powerpc_decode_instruction(&instr, *nip_p, regs);
950 gbeauche 1.13
951 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
952 gbeauche 1.13 // Unknown machine code, let it crash. Then patch the decoder
953     return false;
954     }
955    
956     #if DEBUG
957 gbeauche 1.14 printf("%08x: %s %s access", *nip_p,
958     instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
959 gbeauche 1.22 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
960 gbeauche 1.14
961     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
962     printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
963 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
964 gbeauche 1.14 printf(" r%d (rd = 0)\n", instr.rd);
965     #endif
966    
967     if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
968     regs[instr.ra] = instr.addr;
969 gbeauche 1.22 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
970 gbeauche 1.14 regs[instr.rd] = 0;
971 gbeauche 1.13
972 gbeauche 1.14 *nip_p += 4;
973 gbeauche 1.10 return true;
974 gbeauche 1.38 }
975     #endif
976    
977     // Decode and skip MIPS instruction
978     #if (defined(mips) || defined(__mips))
979     enum {
980     #if (defined(sgi) || defined(__sgi))
981     MIPS_REG_EPC = 35,
982     #endif
983     };
984     static bool mips_skip_instruction(greg_t * regs)
985     {
986     unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
987    
988     if (epc == 0)
989     return false;
990    
991     #if DEBUG
992     printf("IP: %p [%08x]\n", epc, epc[0]);
993     #endif
994    
995     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
996     transfer_size_t transfer_size = SIZE_LONG;
997     int direction = 0;
998    
999     const unsigned int opcode = epc[0];
1000     switch (opcode >> 26) {
1001     case 32: // Load Byte
1002     case 36: // Load Byte Unsigned
1003     transfer_type = SIGSEGV_TRANSFER_LOAD;
1004     transfer_size = SIZE_BYTE;
1005     break;
1006     case 33: // Load Halfword
1007     case 37: // Load Halfword Unsigned
1008     transfer_type = SIGSEGV_TRANSFER_LOAD;
1009     transfer_size = SIZE_WORD;
1010     break;
1011     case 35: // Load Word
1012     case 39: // Load Word Unsigned
1013     transfer_type = SIGSEGV_TRANSFER_LOAD;
1014     transfer_size = SIZE_LONG;
1015     break;
1016     case 34: // Load Word Left
1017     transfer_type = SIGSEGV_TRANSFER_LOAD;
1018     transfer_size = SIZE_LONG;
1019     direction = -1;
1020     break;
1021     case 38: // Load Word Right
1022     transfer_type = SIGSEGV_TRANSFER_LOAD;
1023     transfer_size = SIZE_LONG;
1024     direction = 1;
1025     break;
1026     case 55: // Load Doubleword
1027     transfer_type = SIGSEGV_TRANSFER_LOAD;
1028     transfer_size = SIZE_QUAD;
1029     break;
1030     case 26: // Load Doubleword Left
1031     transfer_type = SIGSEGV_TRANSFER_LOAD;
1032     transfer_size = SIZE_QUAD;
1033     direction = -1;
1034     break;
1035     case 27: // Load Doubleword Right
1036     transfer_type = SIGSEGV_TRANSFER_LOAD;
1037     transfer_size = SIZE_QUAD;
1038     direction = 1;
1039     break;
1040     case 40: // Store Byte
1041     transfer_type = SIGSEGV_TRANSFER_STORE;
1042     transfer_size = SIZE_BYTE;
1043     break;
1044     case 41: // Store Halfword
1045     transfer_type = SIGSEGV_TRANSFER_STORE;
1046     transfer_size = SIZE_WORD;
1047     break;
1048     case 43: // Store Word
1049     case 42: // Store Word Left
1050     case 46: // Store Word Right
1051     transfer_type = SIGSEGV_TRANSFER_STORE;
1052     transfer_size = SIZE_LONG;
1053     break;
1054     case 63: // Store Doubleword
1055     case 44: // Store Doubleword Left
1056     case 45: // Store Doubleword Right
1057     transfer_type = SIGSEGV_TRANSFER_STORE;
1058     transfer_size = SIZE_QUAD;
1059     break;
1060     /* Misc instructions unlikely to be used within CPU emulators */
1061     case 48: // Load Linked Word
1062     transfer_type = SIGSEGV_TRANSFER_LOAD;
1063     transfer_size = SIZE_LONG;
1064     break;
1065     case 52: // Load Linked Doubleword
1066     transfer_type = SIGSEGV_TRANSFER_LOAD;
1067     transfer_size = SIZE_QUAD;
1068     break;
1069     case 56: // Store Conditional Word
1070     transfer_type = SIGSEGV_TRANSFER_STORE;
1071     transfer_size = SIZE_LONG;
1072     break;
1073     case 60: // Store Conditional Doubleword
1074     transfer_type = SIGSEGV_TRANSFER_STORE;
1075     transfer_size = SIZE_QUAD;
1076     break;
1077     }
1078    
1079     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1080     // Unknown machine code, let it crash. Then patch the decoder
1081     return false;
1082     }
1083    
1084     // Zero target register in case of a load operation
1085     const int reg = (opcode >> 16) & 0x1f;
1086     if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1087     if (direction == 0)
1088     regs[reg] = 0;
1089     else {
1090     // FIXME: untested code
1091     unsigned long ea = regs[(opcode >> 21) & 0x1f];
1092     ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1093     const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1094     unsigned long value;
1095     if (direction > 0) {
1096     const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1097     value = regs[reg] & rmask;
1098     }
1099     else {
1100     const unsigned long lmask = (1L << (offset * 8)) - 1;
1101     value = regs[reg] & lmask;
1102     }
1103     // restore most significant bits
1104     if (transfer_size == SIZE_LONG)
1105     value = (signed long)(signed int)value;
1106     regs[reg] = value;
1107     }
1108     }
1109    
1110     #if DEBUG
1111     #if (defined(_ABIN32) || defined(_ABI64))
1112     static const char * mips_gpr_names[32] = {
1113     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1114     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1115     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1116     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1117     };
1118     #else
1119     static const char * mips_gpr_names[32] = {
1120     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1121     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1122     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1123     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1124     };
1125     #endif
1126     printf("%s %s register %s\n",
1127     transfer_size == SIZE_BYTE ? "byte" :
1128     transfer_size == SIZE_WORD ? "word" :
1129     transfer_size == SIZE_LONG ? "long" :
1130     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1131     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1132     mips_gpr_names[reg]);
1133     #endif
1134    
1135     regs[MIPS_REG_EPC] += 4;
1136 gbeauche 1.40 return true;
1137     }
1138     #endif
1139    
1140     // Decode and skip SPARC instruction
1141     #if (defined(sparc) || defined(__sparc__))
1142     enum {
1143     #if (defined(__sun__))
1144     SPARC_REG_G1 = REG_G1,
1145     SPARC_REG_O0 = REG_O0,
1146     SPARC_REG_PC = REG_PC,
1147     #endif
1148     };
1149     static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1150     {
1151     unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1152    
1153     if (pc == 0)
1154     return false;
1155    
1156     #if DEBUG
1157     printf("IP: %p [%08x]\n", pc, pc[0]);
1158     #endif
1159    
1160     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1161     transfer_size_t transfer_size = SIZE_LONG;
1162     bool register_pair = false;
1163    
1164     const unsigned int opcode = pc[0];
1165     if ((opcode >> 30) != 3)
1166     return false;
1167     switch ((opcode >> 19) & 0x3f) {
1168     case 9: // Load Signed Byte
1169     case 1: // Load Unsigned Byte
1170     transfer_type = SIGSEGV_TRANSFER_LOAD;
1171     transfer_size = SIZE_BYTE;
1172     break;
1173     case 10:// Load Signed Halfword
1174     case 2: // Load Unsigned Word
1175     transfer_type = SIGSEGV_TRANSFER_LOAD;
1176     transfer_size = SIZE_WORD;
1177     break;
1178     case 8: // Load Word
1179     case 0: // Load Unsigned Word
1180     transfer_type = SIGSEGV_TRANSFER_LOAD;
1181     transfer_size = SIZE_LONG;
1182     break;
1183     case 11:// Load Extended Word
1184     transfer_type = SIGSEGV_TRANSFER_LOAD;
1185     transfer_size = SIZE_QUAD;
1186     break;
1187     case 3: // Load Doubleword
1188     transfer_type = SIGSEGV_TRANSFER_LOAD;
1189     transfer_size = SIZE_LONG;
1190     register_pair = true;
1191     break;
1192     case 5: // Store Byte
1193     transfer_type = SIGSEGV_TRANSFER_STORE;
1194     transfer_size = SIZE_BYTE;
1195     break;
1196     case 6: // Store Halfword
1197     transfer_type = SIGSEGV_TRANSFER_STORE;
1198     transfer_size = SIZE_WORD;
1199     break;
1200     case 4: // Store Word
1201     transfer_type = SIGSEGV_TRANSFER_STORE;
1202     transfer_size = SIZE_LONG;
1203     break;
1204     case 14:// Store Extended Word
1205     transfer_type = SIGSEGV_TRANSFER_STORE;
1206     transfer_size = SIZE_QUAD;
1207     break;
1208     case 7: // Store Doubleword
1209     transfer_type = SIGSEGV_TRANSFER_STORE;
1210     transfer_size = SIZE_WORD;
1211     register_pair = true;
1212     break;
1213     }
1214    
1215     if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1216     // Unknown machine code, let it crash. Then patch the decoder
1217     return false;
1218     }
1219    
1220     // Zero target register in case of a load operation
1221     const int reg = (opcode >> 25) & 0x1f;
1222     if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1223     // FIXME: code to handle local & input registers is not tested
1224     if (reg >= 1 && reg <= 7) {
1225     // global registers
1226     regs[reg - 1 + SPARC_REG_G1] = 0;
1227     }
1228     else if (reg >= 8 && reg <= 15) {
1229     // output registers
1230     regs[reg - 8 + SPARC_REG_O0] = 0;
1231     }
1232     else if (reg >= 16 && reg <= 23) {
1233     // local registers (in register windows)
1234     if (gwins)
1235     gwins->wbuf->rw_local[reg - 16] = 0;
1236     else
1237     rwin->rw_local[reg - 16] = 0;
1238     }
1239     else {
1240     // input registers (in register windows)
1241     if (gwins)
1242     gwins->wbuf->rw_in[reg - 24] = 0;
1243     else
1244     rwin->rw_in[reg - 24] = 0;
1245     }
1246     }
1247    
1248     #if DEBUG
1249     static const char * reg_names[] = {
1250     "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1251     "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1252     "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1253     "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1254     };
1255     printf("%s %s register %s\n",
1256     transfer_size == SIZE_BYTE ? "byte" :
1257     transfer_size == SIZE_WORD ? "word" :
1258     transfer_size == SIZE_LONG ? "long" :
1259     transfer_size == SIZE_QUAD ? "quad" : "unknown",
1260     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1261     reg_names[reg]);
1262     #endif
1263    
1264     regs[SPARC_REG_PC] += 4;
1265 gbeauche 1.38 return true;
1266 gbeauche 1.10 }
1267     #endif
1268     #endif
1269    
1270 gbeauche 1.44 // Decode and skip ARM instruction
1271     #if (defined(arm) || defined(__arm__))
1272     enum {
1273     #if (defined(__linux__))
1274     ARM_REG_PC = 15,
1275     ARM_REG_CPSR = 16
1276     #endif
1277     };
1278     static bool arm_skip_instruction(unsigned long * regs)
1279     {
1280     unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1281    
1282     if (pc == 0)
1283     return false;
1284    
1285     #if DEBUG
1286     printf("IP: %p [%08x]\n", pc, pc[0]);
1287     #endif
1288    
1289     transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1290     transfer_size_t transfer_size = SIZE_UNKNOWN;
1291     enum { op_sdt = 1, op_sdth = 2 };
1292     int op = 0;
1293    
1294     // Handle load/store instructions only
1295     const unsigned int opcode = pc[0];
1296     switch ((opcode >> 25) & 7) {
1297     case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1298     op = op_sdth;
1299     // Determine transfer size (S/H bits)
1300     switch ((opcode >> 5) & 3) {
1301     case 0: // SWP instruction
1302     break;
1303     case 1: // Unsigned halfwords
1304     case 3: // Signed halfwords
1305     transfer_size = SIZE_WORD;
1306     break;
1307     case 2: // Signed byte
1308     transfer_size = SIZE_BYTE;
1309     break;
1310     }
1311     break;
1312     case 2:
1313     case 3: // Single Data Transfer (LDR, STR)
1314     op = op_sdt;
1315     // Determine transfer size (B bit)
1316     if (((opcode >> 22) & 1) == 1)
1317     transfer_size = SIZE_BYTE;
1318     else
1319     transfer_size = SIZE_LONG;
1320     break;
1321     default:
1322     // FIXME: support load/store mutliple?
1323     return false;
1324     }
1325    
1326     // Check for invalid transfer size (SWP instruction?)
1327     if (transfer_size == SIZE_UNKNOWN)
1328     return false;
1329    
1330     // Determine transfer type (L bit)
1331     if (((opcode >> 20) & 1) == 1)
1332     transfer_type = SIGSEGV_TRANSFER_LOAD;
1333     else
1334     transfer_type = SIGSEGV_TRANSFER_STORE;
1335    
1336     // Compute offset
1337     int offset;
1338     if (((opcode >> 25) & 1) == 0) {
1339     if (op == op_sdt)
1340     offset = opcode & 0xfff;
1341     else if (op == op_sdth) {
1342     int rm = opcode & 0xf;
1343     if (((opcode >> 22) & 1) == 0) {
1344     // register offset
1345     offset = regs[rm];
1346     }
1347     else {
1348     // immediate offset
1349     offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1350     }
1351     }
1352     }
1353     else {
1354     const int rm = opcode & 0xf;
1355     const int sh = (opcode >> 7) & 0x1f;
1356     if (((opcode >> 4) & 1) == 1) {
1357     // we expect only legal load/store instructions
1358     printf("FATAL: invalid shift operand\n");
1359     return false;
1360     }
1361     const unsigned int v = regs[rm];
1362     switch ((opcode >> 5) & 3) {
1363     case 0: // logical shift left
1364     offset = sh ? v << sh : v;
1365     break;
1366     case 1: // logical shift right
1367     offset = sh ? v >> sh : 0;
1368     break;
1369     case 2: // arithmetic shift right
1370     if (sh)
1371     offset = ((signed int)v) >> sh;
1372     else
1373     offset = (v & 0x80000000) ? 0xffffffff : 0;
1374     break;
1375     case 3: // rotate right
1376     if (sh)
1377     offset = (v >> sh) | (v << (32 - sh));
1378     else
1379     offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1380     break;
1381     }
1382     }
1383     if (((opcode >> 23) & 1) == 0)
1384     offset = -offset;
1385    
1386     int rd = (opcode >> 12) & 0xf;
1387     int rn = (opcode >> 16) & 0xf;
1388     #if DEBUG
1389     static const char * reg_names[] = {
1390     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1391     "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1392     };
1393     printf("%s %s register %s\n",
1394     transfer_size == SIZE_BYTE ? "byte" :
1395     transfer_size == SIZE_WORD ? "word" :
1396     transfer_size == SIZE_LONG ? "long" : "unknown",
1397     transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1398     reg_names[rd]);
1399     #endif
1400    
1401     unsigned int base = regs[rn];
1402     if (((opcode >> 24) & 1) == 1)
1403     base += offset;
1404    
1405     if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1406     regs[rd] = 0;
1407    
1408     if (((opcode >> 24) & 1) == 0) // post-index addressing
1409     regs[rn] += offset;
1410     else if (((opcode >> 21) & 1) == 1) // write-back address into base
1411     regs[rn] = base;
1412    
1413     regs[ARM_REG_PC] += 4;
1414     return true;
1415     }
1416     #endif
1417    
1418    
1419 gbeauche 1.1 // Fallbacks
1420     #ifndef SIGSEGV_FAULT_INSTRUCTION
1421     #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1422     #endif
1423 gbeauche 1.30 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1424     #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1425     #endif
1426 gbeauche 1.31 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1427     #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1428     #endif
1429 gbeauche 1.1
1430 gbeauche 1.2 // SIGSEGV recovery supported ?
1431     #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1432     #define HAVE_SIGSEGV_RECOVERY
1433     #endif
1434    
1435 gbeauche 1.1
1436     /*
1437     * SIGSEGV global handler
1438     */
1439    
1440 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
1441     // This function handles the badaccess to memory.
1442     // It is called from the signal handler or the exception handler.
1443 gbeauche 1.30 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1444 gbeauche 1.1 {
1445 gbeauche 1.10 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1446     sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1447    
1448 gbeauche 1.1 // Call user's handler and reinstall the global handler, if required
1449 gbeauche 1.31 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1450 gbeauche 1.24 case SIGSEGV_RETURN_SUCCESS:
1451 gbeauche 1.27 return true;
1452    
1453 gbeauche 1.10 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1454 gbeauche 1.24 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1455 gbeauche 1.27 // Call the instruction skipper with the register file
1456     // available
1457     if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1458     #ifdef HAVE_MACH_EXCEPTIONS
1459     // Unlike UNIX signals where the thread state
1460     // is modified off of the stack, in Mach we
1461     // need to actually call thread_set_state to
1462     // have the register values updated.
1463     kern_return_t krc;
1464    
1465     krc = thread_set_state(thread,
1466     MACHINE_THREAD_STATE, (thread_state_t)state,
1467     MACHINE_THREAD_STATE_COUNT);
1468     MACH_CHECK_ERROR (thread_get_state, krc);
1469     #endif
1470     return true;
1471     }
1472 gbeauche 1.24 break;
1473     #endif
1474 nigel 1.43 case SIGSEGV_RETURN_FAILURE:
1475     return false;
1476 gbeauche 1.10 }
1477 gbeauche 1.27
1478     // We can't do anything with the fault_address, dump state?
1479     if (sigsegv_state_dumper != 0)
1480     sigsegv_state_dumper(fault_address, fault_instruction);
1481    
1482     return false;
1483     }
1484     #endif
1485    
1486    
1487     /*
1488     * There are two mechanisms for handling a bad memory access,
1489     * Mach exceptions and UNIX signals. The implementation specific
1490     * code appears below. Its reponsibility is to call handle_badaccess
1491     * which is the routine that handles the fault in an implementation
1492     * agnostic manner. The implementation specific code below is then
1493     * reponsible for checking whether handle_badaccess was able
1494     * to handle the memory access error and perform any implementation
1495     * specific tasks necessary afterwards.
1496     */
1497    
1498     #ifdef HAVE_MACH_EXCEPTIONS
1499     /*
1500     * We need to forward all exceptions that we do not handle.
1501     * This is important, there are many exceptions that may be
1502     * handled by other exception handlers. For example debuggers
1503     * use exceptions and the exception hander is in another
1504     * process in such a case. (Timothy J. Wood states in his
1505     * message to the list that he based this code on that from
1506     * gdb for Darwin.)
1507     */
1508     static inline kern_return_t
1509     forward_exception(mach_port_t thread_port,
1510     mach_port_t task_port,
1511     exception_type_t exception_type,
1512     exception_data_t exception_data,
1513     mach_msg_type_number_t data_count,
1514     ExceptionPorts *oldExceptionPorts)
1515     {
1516     kern_return_t kret;
1517     unsigned int portIndex;
1518     mach_port_t port;
1519     exception_behavior_t behavior;
1520     thread_state_flavor_t flavor;
1521     thread_state_t thread_state;
1522     mach_msg_type_number_t thread_state_count;
1523    
1524     for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1525     if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1526     // This handler wants the exception
1527     break;
1528     }
1529     }
1530    
1531     if (portIndex >= oldExceptionPorts->maskCount) {
1532     fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1533     return KERN_FAILURE;
1534     }
1535    
1536     port = oldExceptionPorts->handlers[portIndex];
1537     behavior = oldExceptionPorts->behaviors[portIndex];
1538     flavor = oldExceptionPorts->flavors[portIndex];
1539    
1540     /*
1541     fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1542     */
1543    
1544     if (behavior != EXCEPTION_DEFAULT) {
1545     thread_state_count = THREAD_STATE_MAX;
1546     kret = thread_get_state (thread_port, flavor, thread_state,
1547     &thread_state_count);
1548     MACH_CHECK_ERROR (thread_get_state, kret);
1549     }
1550    
1551     switch (behavior) {
1552     case EXCEPTION_DEFAULT:
1553     // fprintf(stderr, "forwarding to exception_raise\n");
1554     kret = exception_raise(port, thread_port, task_port, exception_type,
1555     exception_data, data_count);
1556     MACH_CHECK_ERROR (exception_raise, kret);
1557     break;
1558     case EXCEPTION_STATE:
1559     // fprintf(stderr, "forwarding to exception_raise_state\n");
1560     kret = exception_raise_state(port, exception_type, exception_data,
1561     data_count, &flavor,
1562     thread_state, thread_state_count,
1563     thread_state, &thread_state_count);
1564     MACH_CHECK_ERROR (exception_raise_state, kret);
1565     break;
1566     case EXCEPTION_STATE_IDENTITY:
1567     // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1568     kret = exception_raise_state_identity(port, thread_port, task_port,
1569     exception_type, exception_data,
1570     data_count, &flavor,
1571     thread_state, thread_state_count,
1572     thread_state, &thread_state_count);
1573     MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1574     break;
1575     default:
1576     fprintf(stderr, "forward_exception got unknown behavior\n");
1577     break;
1578     }
1579    
1580     if (behavior != EXCEPTION_DEFAULT) {
1581     kret = thread_set_state (thread_port, flavor, thread_state,
1582     thread_state_count);
1583     MACH_CHECK_ERROR (thread_set_state, kret);
1584     }
1585    
1586     return KERN_SUCCESS;
1587     }
1588    
1589     /*
1590     * This is the code that actually handles the exception.
1591     * It is called by exc_server. For Darwin 5 Apple changed
1592     * this a bit from how this family of functions worked in
1593     * Mach. If you are familiar with that it is a little
1594     * different. The main variation that concerns us here is
1595     * that code is an array of exception specific codes and
1596     * codeCount is a count of the number of codes in the code
1597     * array. In typical Mach all exceptions have a code
1598     * and sub-code. It happens to be the case that for a
1599     * EXC_BAD_ACCESS exception the first entry is the type of
1600     * bad access that occurred and the second entry is the
1601     * faulting address so these entries correspond exactly to
1602     * how the code and sub-code are used on Mach.
1603     *
1604     * This is a MIG interface. No code in Basilisk II should
1605     * call this directley. This has to have external C
1606     * linkage because that is what exc_server expects.
1607     */
1608     kern_return_t
1609     catch_exception_raise(mach_port_t exception_port,
1610     mach_port_t thread,
1611     mach_port_t task,
1612     exception_type_t exception,
1613     exception_data_t code,
1614     mach_msg_type_number_t codeCount)
1615     {
1616     ppc_thread_state_t state;
1617     kern_return_t krc;
1618    
1619     if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1620     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1621     return KERN_SUCCESS;
1622     }
1623    
1624     // In Mach we do not need to remove the exception handler.
1625     // If we forward the exception, eventually some exception handler
1626     // will take care of this exception.
1627     krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1628    
1629     return krc;
1630     }
1631     #endif
1632    
1633     #ifdef HAVE_SIGSEGV_RECOVERY
1634     // Handle bad memory accesses with signal handler
1635     static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1636     {
1637     // Call handler and reinstall the global handler, if required
1638     if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1639     #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1640     sigsegv_do_install_handler(sig);
1641     #endif
1642     return;
1643     }
1644 gbeauche 1.10
1645 gbeauche 1.27 // Failure: reinstall default handler for "safe" crash
1646 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1647 gbeauche 1.27 SIGSEGV_ALL_SIGNALS
1648 gbeauche 1.1 #undef FAULT_HANDLER
1649     }
1650 gbeauche 1.2 #endif
1651 gbeauche 1.1
1652    
1653     /*
1654     * SIGSEGV handler initialization
1655     */
1656    
1657     #if defined(HAVE_SIGINFO_T)
1658     static bool sigsegv_do_install_handler(int sig)
1659     {
1660     // Setup SIGSEGV handler to process writes to frame buffer
1661     #ifdef HAVE_SIGACTION
1662 gbeauche 1.22 struct sigaction sigsegv_sa;
1663     sigemptyset(&sigsegv_sa.sa_mask);
1664     sigsegv_sa.sa_sigaction = sigsegv_handler;
1665     sigsegv_sa.sa_flags = SA_SIGINFO;
1666     return (sigaction(sig, &sigsegv_sa, 0) == 0);
1667 gbeauche 1.1 #else
1668     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1669     #endif
1670     }
1671 gbeauche 1.2 #endif
1672    
1673     #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1674 gbeauche 1.1 static bool sigsegv_do_install_handler(int sig)
1675     {
1676     // Setup SIGSEGV handler to process writes to frame buffer
1677     #ifdef HAVE_SIGACTION
1678 gbeauche 1.22 struct sigaction sigsegv_sa;
1679     sigemptyset(&sigsegv_sa.sa_mask);
1680     sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1681     sigsegv_sa.sa_flags = 0;
1682 gbeauche 1.1 #if !EMULATED_68K && defined(__NetBSD__)
1683 gbeauche 1.22 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1684     sigsegv_sa.sa_flags |= SA_ONSTACK;
1685 gbeauche 1.1 #endif
1686 gbeauche 1.22 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1687 gbeauche 1.1 #else
1688     return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1689     #endif
1690     }
1691     #endif
1692    
1693 gbeauche 1.27 #if defined(HAVE_MACH_EXCEPTIONS)
1694     static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1695     {
1696     /*
1697     * Except for the exception port functions, this should be
1698     * pretty much stock Mach. If later you choose to support
1699     * other Mach's besides Darwin, just check for __MACH__
1700     * here and __APPLE__ where the actual differences are.
1701     */
1702     #if defined(__APPLE__) && defined(__MACH__)
1703     if (sigsegv_fault_handler != NULL) {
1704     sigsegv_fault_handler = handler;
1705     return true;
1706     }
1707    
1708     kern_return_t krc;
1709    
1710     // create the the exception port
1711     krc = mach_port_allocate(mach_task_self(),
1712     MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1713     if (krc != KERN_SUCCESS) {
1714     mach_error("mach_port_allocate", krc);
1715     return false;
1716     }
1717    
1718     // add a port send right
1719     krc = mach_port_insert_right(mach_task_self(),
1720     _exceptionPort, _exceptionPort,
1721     MACH_MSG_TYPE_MAKE_SEND);
1722     if (krc != KERN_SUCCESS) {
1723     mach_error("mach_port_insert_right", krc);
1724     return false;
1725     }
1726    
1727     // get the old exception ports
1728     ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1729     krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1730     &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1731     if (krc != KERN_SUCCESS) {
1732     mach_error("thread_get_exception_ports", krc);
1733     return false;
1734     }
1735    
1736     // set the new exception port
1737     //
1738     // We could have used EXCEPTION_STATE_IDENTITY instead of
1739     // EXCEPTION_DEFAULT to get the thread state in the initial
1740     // message, but it turns out that in the common case this is not
1741     // neccessary. If we need it we can later ask for it from the
1742     // suspended thread.
1743     //
1744     // Even with THREAD_STATE_NONE, Darwin provides the program
1745     // counter in the thread state. The comments in the header file
1746     // seem to imply that you can count on the GPR's on an exception
1747     // as well but just to be safe I use MACHINE_THREAD_STATE because
1748     // you have to ask for all of the GPR's anyway just to get the
1749     // program counter. In any case because of update effective
1750     // address from immediate and update address from effective
1751     // addresses of ra and rb modes (as good an name as any for these
1752     // addressing modes) used in PPC instructions, you will need the
1753     // GPR state anyway.
1754     krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1755     EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
1756     if (krc != KERN_SUCCESS) {
1757     mach_error("thread_set_exception_ports", krc);
1758     return false;
1759     }
1760    
1761     // create the exception handler thread
1762     if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1763     (void)fprintf(stderr, "creation of exception thread failed\n");
1764     return false;
1765     }
1766    
1767     // do not care about the exception thread any longer, let is run standalone
1768     (void)pthread_detach(exc_thread);
1769    
1770     sigsegv_fault_handler = handler;
1771     return true;
1772     #else
1773     return false;
1774     #endif
1775     }
1776     #endif
1777    
1778 gbeauche 1.12 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
1779 gbeauche 1.1 {
1780 gbeauche 1.27 #if defined(HAVE_SIGSEGV_RECOVERY)
1781 gbeauche 1.1 bool success = true;
1782     #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
1783     SIGSEGV_ALL_SIGNALS
1784     #undef FAULT_HANDLER
1785 gbeauche 1.27 if (success)
1786     sigsegv_fault_handler = handler;
1787 gbeauche 1.1 return success;
1788 gbeauche 1.27 #elif defined(HAVE_MACH_EXCEPTIONS)
1789     return sigsegv_do_install_handler(handler);
1790 gbeauche 1.1 #else
1791     // FAIL: no siginfo_t nor sigcontext subterfuge is available
1792     return false;
1793     #endif
1794     }
1795    
1796    
1797     /*
1798     * SIGSEGV handler deinitialization
1799     */
1800    
1801     void sigsegv_deinstall_handler(void)
1802     {
1803 gbeauche 1.27 // We do nothing for Mach exceptions, the thread would need to be
1804     // suspended if not already so, and we might mess with other
1805     // exception handlers that came after we registered ours. There is
1806     // no need to remove the exception handler, in fact this function is
1807     // not called anywhere in Basilisk II.
1808 gbeauche 1.2 #ifdef HAVE_SIGSEGV_RECOVERY
1809 gbeauche 1.12 sigsegv_fault_handler = 0;
1810 gbeauche 1.1 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1811     SIGSEGV_ALL_SIGNALS
1812     #undef FAULT_HANDLER
1813 gbeauche 1.2 #endif
1814 gbeauche 1.1 }
1815    
1816 gbeauche 1.10
1817     /*
1818     * Set callback function when we cannot handle the fault
1819     */
1820    
1821 gbeauche 1.12 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
1822 gbeauche 1.10 {
1823 gbeauche 1.12 sigsegv_state_dumper = handler;
1824 gbeauche 1.10 }
1825    
1826    
1827 gbeauche 1.1 /*
1828     * Test program used for configure/test
1829     */
1830    
1831 gbeauche 1.4 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
1832 gbeauche 1.1 #include <stdio.h>
1833     #include <stdlib.h>
1834     #include <fcntl.h>
1835     #include <sys/mman.h>
1836 gbeauche 1.4 #include "vm_alloc.h"
1837 gbeauche 1.1
1838 gbeauche 1.32 const int REF_INDEX = 123;
1839     const int REF_VALUE = 45;
1840    
1841 gbeauche 1.1 static int page_size;
1842 gbeauche 1.3 static volatile char * page = 0;
1843     static volatile int handler_called = 0;
1844 gbeauche 1.1
1845 gbeauche 1.32 #ifdef __GNUC__
1846     // Code range where we expect the fault to come from
1847     static void *b_region, *e_region;
1848     #endif
1849    
1850 gbeauche 1.24 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1851 gbeauche 1.1 {
1852 gbeauche 1.39 #if DEBUG
1853     printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
1854     printf("expected fault at %p\n", page + REF_INDEX);
1855     #ifdef __GNUC__
1856     printf("expected instruction address range: %p-%p\n", b_region, e_region);
1857     #endif
1858     #endif
1859 gbeauche 1.1 handler_called++;
1860 gbeauche 1.32 if ((fault_address - REF_INDEX) != page)
1861 gbeauche 1.29 exit(10);
1862 gbeauche 1.32 #ifdef __GNUC__
1863     // Make sure reported fault instruction address falls into
1864     // expected code range
1865     if (instruction_address != SIGSEGV_INVALID_PC
1866     && ((instruction_address < (sigsegv_address_t)b_region) ||
1867     (instruction_address >= (sigsegv_address_t)e_region)))
1868     exit(11);
1869     #endif
1870 gbeauche 1.4 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
1871 gbeauche 1.32 exit(12);
1872 gbeauche 1.24 return SIGSEGV_RETURN_SUCCESS;
1873 gbeauche 1.1 }
1874    
1875 gbeauche 1.10 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1876 gbeauche 1.24 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1877 gbeauche 1.10 {
1878 gbeauche 1.44 #if DEBUG
1879     printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
1880     #endif
1881 gbeauche 1.28 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
1882     #ifdef __GNUC__
1883     // Make sure reported fault instruction address falls into
1884     // expected code range
1885     if (instruction_address != SIGSEGV_INVALID_PC
1886     && ((instruction_address < (sigsegv_address_t)b_region) ||
1887     (instruction_address >= (sigsegv_address_t)e_region)))
1888     return SIGSEGV_RETURN_FAILURE;
1889     #endif
1890 gbeauche 1.26 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
1891 gbeauche 1.28 }
1892    
1893 gbeauche 1.24 return SIGSEGV_RETURN_FAILURE;
1894 gbeauche 1.10 }
1895 gbeauche 1.34
1896     // More sophisticated tests for instruction skipper
1897     static bool arch_insn_skipper_tests()
1898     {
1899     #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
1900     static const unsigned char code[] = {
1901     0x8a, 0x00, // mov (%eax),%al
1902     0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
1903     0x88, 0x20, // mov %ah,(%eax)
1904     0x88, 0x08, // mov %cl,(%eax)
1905     0x66, 0x8b, 0x00, // mov (%eax),%ax
1906     0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
1907     0x66, 0x89, 0x00, // mov %ax,(%eax)
1908     0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
1909     0x8b, 0x00, // mov (%eax),%eax
1910     0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
1911     0x89, 0x00, // mov %eax,(%eax)
1912     0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
1913     #if defined(__x86_64__)
1914     0x44, 0x8a, 0x00, // mov (%rax),%r8b
1915     0x44, 0x8a, 0x20, // mov (%rax),%r12b
1916     0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
1917     0x44, 0x88, 0x00, // mov %r8b,(%rax)
1918     0x44, 0x88, 0x20, // mov %r12b,(%rax)
1919     0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
1920     0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
1921     0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
1922     0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
1923     0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
1924     0x44, 0x8b, 0x00, // mov (%rax),%r8d
1925     0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
1926     0x44, 0x89, 0x00, // mov %r8d,(%rax)
1927     0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
1928     0x48, 0x8b, 0x08, // mov (%rax),%rcx
1929     0x4c, 0x8b, 0x18, // mov (%rax),%r11
1930     0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
1931     0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
1932     0x48, 0x89, 0x08, // mov %rcx,(%rax)
1933     0x4c, 0x89, 0x18, // mov %r11,(%rax)
1934     0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
1935     0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
1936     #endif
1937     0 // end
1938     };
1939     const int N_REGS = 20;
1940     unsigned long regs[N_REGS];
1941     for (int i = 0; i < N_REGS; i++)
1942     regs[i] = i;
1943     const unsigned long start_code = (unsigned long)&code;
1944     regs[X86_REG_EIP] = start_code;
1945     while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
1946     && ix86_skip_instruction(regs))
1947     ; /* simply iterate */
1948     return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
1949     #endif
1950     return true;
1951     }
1952 gbeauche 1.10 #endif
1953    
1954 gbeauche 1.1 int main(void)
1955     {
1956 gbeauche 1.4 if (vm_init() < 0)
1957 gbeauche 1.1 return 1;
1958    
1959     page_size = getpagesize();
1960 gbeauche 1.4 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
1961 gbeauche 1.29 return 2;
1962 gbeauche 1.4
1963 gbeauche 1.32 memset((void *)page, 0, page_size);
1964 gbeauche 1.4 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
1965 gbeauche 1.29 return 3;
1966 gbeauche 1.1
1967     if (!sigsegv_install_handler(sigsegv_test_handler))
1968 gbeauche 1.29 return 4;
1969 gbeauche 1.1
1970 gbeauche 1.32 #ifdef __GNUC__
1971     b_region = &&L_b_region1;
1972     e_region = &&L_e_region1;
1973     #endif
1974     L_b_region1:
1975     page[REF_INDEX] = REF_VALUE;
1976     if (page[REF_INDEX] != REF_VALUE)
1977     exit(20);
1978     page[REF_INDEX] = REF_VALUE;
1979     L_e_region1:
1980    
1981 gbeauche 1.1 if (handler_called != 1)
1982 gbeauche 1.29 return 5;
1983 gbeauche 1.10
1984     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1985     if (!sigsegv_install_handler(sigsegv_insn_handler))
1986 gbeauche 1.29 return 6;
1987 gbeauche 1.10
1988 gbeauche 1.17 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
1989 gbeauche 1.29 return 7;
1990 gbeauche 1.10
1991     for (int i = 0; i < page_size; i++)
1992     page[i] = (i + 1) % page_size;
1993    
1994     if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
1995 gbeauche 1.29 return 8;
1996 gbeauche 1.10
1997     #define TEST_SKIP_INSTRUCTION(TYPE) do { \
1998 gbeauche 1.34 const unsigned long TAG = 0x12345678 | \
1999     (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
2000 gbeauche 1.10 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
2001 gbeauche 1.34 volatile unsigned long effect = data + TAG; \
2002 gbeauche 1.10 if (effect != TAG) \
2003 gbeauche 1.29 return 9; \
2004 gbeauche 1.10 } while (0)
2005    
2006 gbeauche 1.28 #ifdef __GNUC__
2007 gbeauche 1.32 b_region = &&L_b_region2;
2008     e_region = &&L_e_region2;
2009 gbeauche 1.28 #endif
2010 gbeauche 1.32 L_b_region2:
2011 gbeauche 1.10 TEST_SKIP_INSTRUCTION(unsigned char);
2012     TEST_SKIP_INSTRUCTION(unsigned short);
2013     TEST_SKIP_INSTRUCTION(unsigned int);
2014 gbeauche 1.34 TEST_SKIP_INSTRUCTION(unsigned long);
2015 gbeauche 1.44 TEST_SKIP_INSTRUCTION(signed char);
2016     TEST_SKIP_INSTRUCTION(signed short);
2017     TEST_SKIP_INSTRUCTION(signed int);
2018     TEST_SKIP_INSTRUCTION(signed long);
2019 gbeauche 1.32 L_e_region2:
2020 gbeauche 1.1
2021 gbeauche 1.34 if (!arch_insn_skipper_tests())
2022     return 20;
2023 gbeauche 1.35 #endif
2024 gbeauche 1.34
2025 gbeauche 1.4 vm_exit();
2026 gbeauche 1.1 return 0;
2027     }
2028     #endif