ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.66
Committed: 2007-06-16T06:21:57Z (17 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.65: +77 -17 lines
Log Message:
Add Darwin/x86_64 support. Fix EDX register index for i386 insn decoder.

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