ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.56
Committed: 2005-06-12T21:47:46Z (19 years, 3 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-17
Changes since 1.55: +46 -32 lines
Log Message:
Mach exception recovery and instruction skipping for Darwin/x86.

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