ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.55
Committed: 2005-03-23T22:00:06Z (19 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.54: +21 -1 lines
Log Message:
Enable instruction skipping for OpenBSD 3.4 on i386

File Contents

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