ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.64
Committed: 2006-07-19T21:31:10Z (18 years, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19
Changes since 1.63: +43 -49 lines
Log Message:
A few fixlets to the SIGSEGV library:
- Don't export transfer types definitions (formerly used by older API)
- Handle ADD instructions in ix86_skip_instruction() (generated by icc 9.1)
- Use "%p" format for EIP/RIP addresses

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