ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.60
Committed: 2006-01-24T21:33:26Z (18 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.59: +6 -6 lines
Log Message:
ugly cast games

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