ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.38
Committed: 2003-12-20T10:06:18Z (20 years, 11 months ago) by gbeauche
Branch: MAIN
Changes since 1.37: +167 -0 lines
Log Message:
MIPS instruction skipper. TODO: check LWL/LWR semantics.

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