ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.54
Committed: 2005-03-23T21:37:24Z (19 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.53: +24 -5 lines
Log Message:
instruction skipper for Solaris/i386 (Solaris 9)

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