ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.41
Committed: 2004-01-12T15:29:25Z (20 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.40: +1 -1 lines
Log Message:
Happy New Year! :)

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-2004 Christian Bauer
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <list>
39 #include <stdio.h>
40 #include <signal.h>
41 #include "sigsegv.h"
42
43 #ifndef NO_STD_NAMESPACE
44 using std::list;
45 #endif
46
47 // Return value type of a signal handler (standard type if not defined)
48 #ifndef RETSIGTYPE
49 #define RETSIGTYPE void
50 #endif
51
52 // Type of the system signal handler
53 typedef RETSIGTYPE (*signal_handler)(int);
54
55 // User's SIGSEGV handler
56 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
57
58 // Function called to dump state if we can't handle the fault
59 static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
60
61 // Actual SIGSEGV handler installer
62 static bool sigsegv_do_install_handler(int sig);
63
64
65 /*
66 * Instruction decoding aids
67 */
68
69 // Transfer size
70 enum transfer_size_t {
71 SIZE_UNKNOWN,
72 SIZE_BYTE,
73 SIZE_WORD, // 2 bytes
74 SIZE_LONG, // 4 bytes
75 SIZE_QUAD, // 8 bytes
76 };
77
78 // Transfer type
79 typedef sigsegv_transfer_type_t transfer_type_t;
80
81 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
82 // Addressing mode
83 enum addressing_mode_t {
84 MODE_UNKNOWN,
85 MODE_NORM,
86 MODE_U,
87 MODE_X,
88 MODE_UX
89 };
90
91 // Decoded instruction
92 struct instruction_t {
93 transfer_type_t transfer_type;
94 transfer_size_t transfer_size;
95 addressing_mode_t addr_mode;
96 unsigned int addr;
97 char ra, rd;
98 };
99
100 static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
101 {
102 // Get opcode and divide into fields
103 unsigned int opcode = *((unsigned int *)nip);
104 unsigned int primop = opcode >> 26;
105 unsigned int exop = (opcode >> 1) & 0x3ff;
106 unsigned int ra = (opcode >> 16) & 0x1f;
107 unsigned int rb = (opcode >> 11) & 0x1f;
108 unsigned int rd = (opcode >> 21) & 0x1f;
109 signed int imm = (signed short)(opcode & 0xffff);
110
111 // Analyze opcode
112 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
113 transfer_size_t transfer_size = SIZE_UNKNOWN;
114 addressing_mode_t addr_mode = MODE_UNKNOWN;
115 switch (primop) {
116 case 31:
117 switch (exop) {
118 case 23: // lwzx
119 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
120 case 55: // lwzux
121 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
122 case 87: // lbzx
123 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
124 case 119: // lbzux
125 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
126 case 151: // stwx
127 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
128 case 183: // stwux
129 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
130 case 215: // stbx
131 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
132 case 247: // stbux
133 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
134 case 279: // lhzx
135 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
136 case 311: // lhzux
137 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
138 case 343: // lhax
139 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
140 case 375: // lhaux
141 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
142 case 407: // sthx
143 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
144 case 439: // sthux
145 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
146 }
147 break;
148
149 case 32: // lwz
150 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
151 case 33: // lwzu
152 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
153 case 34: // lbz
154 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
155 case 35: // lbzu
156 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
157 case 36: // stw
158 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
159 case 37: // stwu
160 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
161 case 38: // stb
162 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
163 case 39: // stbu
164 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
165 case 40: // lhz
166 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
167 case 41: // lhzu
168 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
169 case 42: // lha
170 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
171 case 43: // lhau
172 transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
173 case 44: // sth
174 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
175 case 45: // sthu
176 transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
177 }
178
179 // Calculate effective address
180 unsigned int addr = 0;
181 switch (addr_mode) {
182 case MODE_X:
183 case MODE_UX:
184 if (ra == 0)
185 addr = gpr[rb];
186 else
187 addr = gpr[ra] + gpr[rb];
188 break;
189 case MODE_NORM:
190 case MODE_U:
191 if (ra == 0)
192 addr = (signed int)(signed short)imm;
193 else
194 addr = gpr[ra] + (signed int)(signed short)imm;
195 break;
196 default:
197 break;
198 }
199
200 // Commit decoded instruction
201 instruction->addr = addr;
202 instruction->addr_mode = addr_mode;
203 instruction->transfer_type = transfer_type;
204 instruction->transfer_size = transfer_size;
205 instruction->ra = ra;
206 instruction->rd = rd;
207 }
208 #endif
209
210
211 /*
212 * OS-dependant SIGSEGV signals support section
213 */
214
215 #if HAVE_SIGINFO_T
216 // Generic extended signal handler
217 #if defined(__NetBSD__) || defined(__FreeBSD__)
218 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
219 #else
220 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
221 #endif
222 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp
223 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
224 #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp
225 #define SIGSEGV_FAULT_ADDRESS sip->si_addr
226 #if (defined(sgi) || defined(__sgi))
227 #include <ucontext.h>
228 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
229 #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
230 #if (defined(mips) || defined(__mips))
231 #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS
232 #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction
233 #endif
234 #endif
235 #if defined(__sun__)
236 #if (defined(sparc) || defined(__sparc__))
237 #include <sys/stack.h>
238 #include <sys/regset.h>
239 #include <sys/ucontext.h>
240 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
241 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC]
242 #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins)
243 #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
244 #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
245 #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction
246 #endif
247 #endif
248 #if defined(__FreeBSD__)
249 #if (defined(i386) || defined(__i386__))
250 #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip)
251 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
252 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
253 #endif
254 #endif
255 #if defined(__linux__)
256 #if (defined(i386) || defined(__i386__))
257 #include <sys/ucontext.h>
258 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
259 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
260 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
261 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
262 #endif
263 #if (defined(x86_64) || defined(__x86_64__))
264 #include <sys/ucontext.h>
265 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs)
266 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
267 #define SIGSEGV_REGISTER_FILE (unsigned long *)SIGSEGV_CONTEXT_REGS
268 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
269 #endif
270 #if (defined(ia64) || defined(__ia64__))
271 #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
272 #endif
273 #if (defined(powerpc) || defined(__powerpc__))
274 #include <sys/ucontext.h>
275 #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs)
276 #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip)
277 #define SIGSEGV_REGISTER_FILE (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
278 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
279 #endif
280 #if (defined(hppa) || defined(__hppa__))
281 #undef SIGSEGV_FAULT_ADDRESS
282 #define SIGSEGV_FAULT_ADDRESS sip->si_ptr
283 #endif
284 #endif
285 #endif
286
287 #if HAVE_SIGCONTEXT_SUBTERFUGE
288 // Linux kernels prior to 2.4 ?
289 #if defined(__linux__)
290 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
291 #if (defined(i386) || defined(__i386__))
292 #include <asm/sigcontext.h>
293 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs
294 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
295 #define SIGSEGV_FAULT_HANDLER_ARGS &scs
296 #define SIGSEGV_FAULT_ADDRESS scp->cr2
297 #define SIGSEGV_FAULT_INSTRUCTION scp->eip
298 #define SIGSEGV_REGISTER_FILE (unsigned long *)scp
299 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
300 #endif
301 #if (defined(sparc) || defined(__sparc__))
302 #include <asm/sigcontext.h>
303 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
304 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
305 #define SIGSEGV_FAULT_ADDRESS addr
306 #endif
307 #if (defined(powerpc) || defined(__powerpc__))
308 #include <asm/sigcontext.h>
309 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp
310 #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp
311 #define SIGSEGV_FAULT_ADDRESS scp->regs->dar
312 #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip
313 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
314 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
315 #endif
316 #if (defined(alpha) || defined(__alpha__))
317 #include <asm/sigcontext.h>
318 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
319 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
320 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
321 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
322 #endif
323 #endif
324
325 // Irix 5 or 6 on MIPS
326 #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
327 #include <ucontext.h>
328 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
329 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
330 #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr
331 #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc
332 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
333 #endif
334
335 // HP-UX
336 #if (defined(hpux) || defined(__hpux__))
337 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
338 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
339 #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21
340 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
341 #endif
342
343 // OSF/1 on Alpha
344 #if defined(__osf__)
345 #include <ucontext.h>
346 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
347 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
348 #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0
349 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
350 #endif
351
352 // AIX
353 #if defined(_AIX)
354 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
355 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
356 #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr
357 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
358 #endif
359
360 // NetBSD
361 #if defined(__NetBSD__)
362 #if (defined(m68k) || defined(__m68k__))
363 #include <m68k/frame.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_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
368
369 // Use decoding scheme from BasiliskII/m68k native
370 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
371 {
372 struct sigstate {
373 int ss_flags;
374 struct frame ss_frame;
375 };
376 struct sigstate *state = (struct sigstate *)scp->sc_ap;
377 char *fault_addr;
378 switch (state->ss_frame.f_format) {
379 case 7: /* 68040 access error */
380 /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
381 fault_addr = state->ss_frame.f_fmt7.f_fa;
382 break;
383 default:
384 fault_addr = (char *)code;
385 break;
386 }
387 return (sigsegv_address_t)fault_addr;
388 }
389 #endif
390 #if (defined(alpha) || defined(__alpha__))
391 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
392 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
393 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
394 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
395 #endif
396 #if (defined(i386) || defined(__i386__))
397 #error "FIXME: need to decode instruction and compute EA"
398 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
399 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
400 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
401 #endif
402 #endif
403 #if defined(__FreeBSD__)
404 #if (defined(i386) || defined(__i386__))
405 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
406 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr
407 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr
408 #define SIGSEGV_FAULT_ADDRESS addr
409 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip
410 #define SIGSEGV_REGISTER_FILE ((unsigned long *)&scp->sc_edi)
411 #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction
412 #endif
413 #if (defined(alpha) || defined(__alpha__))
414 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV)
415 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp
416 #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp
417 #define SIGSEGV_FAULT_ADDRESS addr
418 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc
419 #endif
420 #endif
421
422 // Extract fault address out of a sigcontext
423 #if (defined(alpha) || defined(__alpha__))
424 // From Boehm's GC 6.0alpha8
425 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
426 {
427 unsigned int instruction = *((unsigned int *)(scp->sc_pc));
428 unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
429 fault_address += (signed long)(signed short)(instruction & 0xffff);
430 return (sigsegv_address_t)fault_address;
431 }
432 #endif
433
434
435 // MacOS X, not sure which version this works in. Under 10.1
436 // vm_protect does not appear to work from a signal handler. Under
437 // 10.2 signal handlers get siginfo type arguments but the si_addr
438 // field is the address of the faulting instruction and not the
439 // address that caused the SIGBUS. Maybe this works in 10.0? In any
440 // case with Mach exception handlers there is a way to do what this
441 // was meant to do.
442 #ifndef HAVE_MACH_EXCEPTIONS
443 #if defined(__APPLE__) && defined(__MACH__)
444 #if (defined(ppc) || defined(__ppc__))
445 #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp
446 #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp
447 #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp)
448 #define SIGSEGV_FAULT_INSTRUCTION scp->sc_ir
449 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS)
450 #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
451 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
452
453 // Use decoding scheme from SheepShaver
454 static sigsegv_address_t get_fault_address(struct sigcontext *scp)
455 {
456 unsigned int nip = (unsigned int) scp->sc_ir;
457 unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
458 instruction_t instr;
459
460 powerpc_decode_instruction(&instr, nip, gpr);
461 return (sigsegv_address_t)instr.addr;
462 }
463 #endif
464 #endif
465 #endif
466 #endif
467
468 #if HAVE_MACH_EXCEPTIONS
469
470 // This can easily be extended to other Mach systems, but really who
471 // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
472 // Mach 2.5/3.0?
473 #if defined(__APPLE__) && defined(__MACH__)
474
475 #include <sys/types.h>
476 #include <stdlib.h>
477 #include <stdio.h>
478 #include <pthread.h>
479
480 /*
481 * If you are familiar with MIG then you will understand the frustration
482 * that was necessary to get these embedded into C++ code by hand.
483 */
484 extern "C" {
485 #include <mach/mach.h>
486 #include <mach/mach_error.h>
487
488 extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
489 extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
490 mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
491 extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
492 exception_type_t, exception_data_t, mach_msg_type_number_t);
493 extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
494 exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
495 thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
496 extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
497 exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
498 thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
499 }
500
501 // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
502 #define HANDLER_COUNT 64
503
504 // structure to tuck away existing exception handlers
505 typedef struct _ExceptionPorts {
506 mach_msg_type_number_t maskCount;
507 exception_mask_t masks[HANDLER_COUNT];
508 exception_handler_t handlers[HANDLER_COUNT];
509 exception_behavior_t behaviors[HANDLER_COUNT];
510 thread_state_flavor_t flavors[HANDLER_COUNT];
511 } ExceptionPorts;
512
513 // exception handler thread
514 static pthread_t exc_thread;
515
516 // place where old exception handler info is stored
517 static ExceptionPorts ports;
518
519 // our exception port
520 static mach_port_t _exceptionPort = MACH_PORT_NULL;
521
522 #define MACH_CHECK_ERROR(name,ret) \
523 if (ret != KERN_SUCCESS) { \
524 mach_error(#name, ret); \
525 exit (1); \
526 }
527
528 #define SIGSEGV_FAULT_ADDRESS code[1]
529 #define SIGSEGV_FAULT_INSTRUCTION get_fault_instruction(thread, state)
530 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
531 #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
532 #define SIGSEGV_FAULT_HANDLER_ARGS thread, code, &state
533 #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction
534 #define SIGSEGV_REGISTER_FILE &state->srr0, &state->r0
535
536 // Given a suspended thread, stuff the current instruction and
537 // registers into state.
538 //
539 // It would have been nice to have this be ppc/x86 independant which
540 // could have been done easily with a thread_state_t instead of
541 // ppc_thread_state_t, but because of the way this is called it is
542 // easier to do it this way.
543 #if (defined(ppc) || defined(__ppc__))
544 static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
545 {
546 kern_return_t krc;
547 mach_msg_type_number_t count;
548
549 count = MACHINE_THREAD_STATE_COUNT;
550 krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
551 MACH_CHECK_ERROR (thread_get_state, krc);
552
553 return (sigsegv_address_t)state->srr0;
554 }
555 #endif
556
557 // Since there can only be one exception thread running at any time
558 // this is not a problem.
559 #define MSG_SIZE 512
560 static char msgbuf[MSG_SIZE];
561 static char replybuf[MSG_SIZE];
562
563 /*
564 * This is the entry point for the exception handler thread. The job
565 * of this thread is to wait for exception messages on the exception
566 * port that was setup beforehand and to pass them on to exc_server.
567 * exc_server is a MIG generated function that is a part of Mach.
568 * Its job is to decide what to do with the exception message. In our
569 * case exc_server calls catch_exception_raise on our behalf. After
570 * exc_server returns, it is our responsibility to send the reply.
571 */
572 static void *
573 handleExceptions(void *priv)
574 {
575 mach_msg_header_t *msg, *reply;
576 kern_return_t krc;
577
578 msg = (mach_msg_header_t *)msgbuf;
579 reply = (mach_msg_header_t *)replybuf;
580
581 for (;;) {
582 krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
583 _exceptionPort, 0, MACH_PORT_NULL);
584 MACH_CHECK_ERROR(mach_msg, krc);
585
586 if (!exc_server(msg, reply)) {
587 fprintf(stderr, "exc_server hated the message\n");
588 exit(1);
589 }
590
591 krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
592 msg->msgh_local_port, 0, MACH_PORT_NULL);
593 if (krc != KERN_SUCCESS) {
594 fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
595 krc, mach_error_string(krc));
596 exit(1);
597 }
598 }
599 }
600 #endif
601 #endif
602
603
604 /*
605 * Instruction skipping
606 */
607
608 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
609 // Decode and skip X86 instruction
610 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
611 #if defined(__linux__)
612 enum {
613 #if (defined(i386) || defined(__i386__))
614 X86_REG_EIP = 14,
615 X86_REG_EAX = 11,
616 X86_REG_ECX = 10,
617 X86_REG_EDX = 9,
618 X86_REG_EBX = 8,
619 X86_REG_ESP = 7,
620 X86_REG_EBP = 6,
621 X86_REG_ESI = 5,
622 X86_REG_EDI = 4
623 #endif
624 #if defined(__x86_64__)
625 X86_REG_R8 = 0,
626 X86_REG_R9 = 1,
627 X86_REG_R10 = 2,
628 X86_REG_R11 = 3,
629 X86_REG_R12 = 4,
630 X86_REG_R13 = 5,
631 X86_REG_R14 = 6,
632 X86_REG_R15 = 7,
633 X86_REG_EDI = 8,
634 X86_REG_ESI = 9,
635 X86_REG_EBP = 10,
636 X86_REG_EBX = 11,
637 X86_REG_EDX = 12,
638 X86_REG_EAX = 13,
639 X86_REG_ECX = 14,
640 X86_REG_ESP = 15,
641 X86_REG_EIP = 16
642 #endif
643 };
644 #endif
645 #if defined(__NetBSD__) || defined(__FreeBSD__)
646 enum {
647 #if (defined(i386) || defined(__i386__))
648 X86_REG_EIP = 10,
649 X86_REG_EAX = 7,
650 X86_REG_ECX = 6,
651 X86_REG_EDX = 5,
652 X86_REG_EBX = 4,
653 X86_REG_ESP = 13,
654 X86_REG_EBP = 2,
655 X86_REG_ESI = 1,
656 X86_REG_EDI = 0
657 #endif
658 };
659 #endif
660 // FIXME: this is partly redundant with the instruction decoding phase
661 // to discover transfer type and register number
662 static inline int ix86_step_over_modrm(unsigned char * p)
663 {
664 int mod = (p[0] >> 6) & 3;
665 int rm = p[0] & 7;
666 int offset = 0;
667
668 // ModR/M Byte
669 switch (mod) {
670 case 0: // [reg]
671 if (rm == 5) return 4; // disp32
672 break;
673 case 1: // disp8[reg]
674 offset = 1;
675 break;
676 case 2: // disp32[reg]
677 offset = 4;
678 break;
679 case 3: // register
680 return 0;
681 }
682
683 // SIB Byte
684 if (rm == 4) {
685 if (mod == 0 && (p[1] & 7) == 5)
686 offset = 5; // disp32[index]
687 else
688 offset++;
689 }
690
691 return offset;
692 }
693
694 static bool ix86_skip_instruction(unsigned long * regs)
695 {
696 unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
697
698 if (eip == 0)
699 return false;
700
701 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
702 transfer_size_t transfer_size = SIZE_LONG;
703
704 int reg = -1;
705 int len = 0;
706
707 #if DEBUG
708 printf("IP: %p [%02x %02x %02x %02x...]\n",
709 eip, eip[0], eip[1], eip[2], eip[3]);
710 #endif
711
712 // Operand size prefix
713 if (*eip == 0x66) {
714 eip++;
715 len++;
716 transfer_size = SIZE_WORD;
717 }
718
719 // REX prefix
720 #if defined(__x86_64__)
721 struct rex_t {
722 unsigned char W;
723 unsigned char R;
724 unsigned char X;
725 unsigned char B;
726 };
727 rex_t rex = { 0, 0, 0, 0 };
728 bool has_rex = false;
729 if ((*eip & 0xf0) == 0x40) {
730 has_rex = true;
731 const unsigned char b = *eip;
732 rex.W = b & (1 << 3);
733 rex.R = b & (1 << 2);
734 rex.X = b & (1 << 1);
735 rex.B = b & (1 << 0);
736 #if DEBUG
737 printf("REX: %c,%c,%c,%c\n",
738 rex.W ? 'W' : '_',
739 rex.R ? 'R' : '_',
740 rex.X ? 'X' : '_',
741 rex.B ? 'B' : '_');
742 #endif
743 eip++;
744 len++;
745 if (rex.W)
746 transfer_size = SIZE_QUAD;
747 }
748 #else
749 const bool has_rex = false;
750 #endif
751
752 // Decode instruction
753 switch (eip[0]) {
754 case 0x0f:
755 switch (eip[1]) {
756 case 0xb6: // MOVZX r32, r/m8
757 case 0xb7: // MOVZX r32, r/m16
758 switch (eip[2] & 0xc0) {
759 case 0x80:
760 reg = (eip[2] >> 3) & 7;
761 transfer_type = SIGSEGV_TRANSFER_LOAD;
762 break;
763 case 0x40:
764 reg = (eip[2] >> 3) & 7;
765 transfer_type = SIGSEGV_TRANSFER_LOAD;
766 break;
767 case 0x00:
768 reg = (eip[2] >> 3) & 7;
769 transfer_type = SIGSEGV_TRANSFER_LOAD;
770 break;
771 }
772 len += 3 + ix86_step_over_modrm(eip + 2);
773 break;
774 }
775 break;
776 case 0x8a: // MOV r8, r/m8
777 transfer_size = SIZE_BYTE;
778 case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
779 switch (eip[1] & 0xc0) {
780 case 0x80:
781 reg = (eip[1] >> 3) & 7;
782 transfer_type = SIGSEGV_TRANSFER_LOAD;
783 break;
784 case 0x40:
785 reg = (eip[1] >> 3) & 7;
786 transfer_type = SIGSEGV_TRANSFER_LOAD;
787 break;
788 case 0x00:
789 reg = (eip[1] >> 3) & 7;
790 transfer_type = SIGSEGV_TRANSFER_LOAD;
791 break;
792 }
793 len += 2 + ix86_step_over_modrm(eip + 1);
794 break;
795 case 0x88: // MOV r/m8, r8
796 transfer_size = SIZE_BYTE;
797 case 0x89: // MOV r/m32, r32 (or 16-bit operation)
798 switch (eip[1] & 0xc0) {
799 case 0x80:
800 reg = (eip[1] >> 3) & 7;
801 transfer_type = SIGSEGV_TRANSFER_STORE;
802 break;
803 case 0x40:
804 reg = (eip[1] >> 3) & 7;
805 transfer_type = SIGSEGV_TRANSFER_STORE;
806 break;
807 case 0x00:
808 reg = (eip[1] >> 3) & 7;
809 transfer_type = SIGSEGV_TRANSFER_STORE;
810 break;
811 }
812 len += 2 + ix86_step_over_modrm(eip + 1);
813 break;
814 }
815
816 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
817 // Unknown machine code, let it crash. Then patch the decoder
818 return false;
819 }
820
821 #if defined(__x86_64__)
822 if (rex.R)
823 reg += 8;
824 #endif
825
826 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
827 static const int x86_reg_map[] = {
828 X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
829 X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
830 #if defined(__x86_64__)
831 X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11,
832 X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
833 #endif
834 };
835
836 if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
837 return false;
838
839 // Set 0 to the relevant register part
840 // NOTE: this is only valid for MOV alike instructions
841 int rloc = x86_reg_map[reg];
842 switch (transfer_size) {
843 case SIZE_BYTE:
844 if (has_rex || reg < 4)
845 regs[rloc] = (regs[rloc] & ~0x00ffL);
846 else {
847 rloc = x86_reg_map[reg - 4];
848 regs[rloc] = (regs[rloc] & ~0xff00L);
849 }
850 break;
851 case SIZE_WORD:
852 regs[rloc] = (regs[rloc] & ~0xffffL);
853 break;
854 case SIZE_LONG:
855 case SIZE_QUAD: // zero-extension
856 regs[rloc] = 0;
857 break;
858 }
859 }
860
861 #if DEBUG
862 printf("%08x: %s %s access", regs[X86_REG_EIP],
863 transfer_size == SIZE_BYTE ? "byte" :
864 transfer_size == SIZE_WORD ? "word" :
865 transfer_size == SIZE_LONG ? "long" :
866 transfer_size == SIZE_QUAD ? "quad" : "unknown",
867 transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
868
869 if (reg != -1) {
870 static const char * x86_byte_reg_str_map[] = {
871 "al", "cl", "dl", "bl",
872 "spl", "bpl", "sil", "dil",
873 "r8b", "r9b", "r10b", "r11b",
874 "r12b", "r13b", "r14b", "r15b",
875 "ah", "ch", "dh", "bh",
876 };
877 static const char * x86_word_reg_str_map[] = {
878 "ax", "cx", "dx", "bx",
879 "sp", "bp", "si", "di",
880 "r8w", "r9w", "r10w", "r11w",
881 "r12w", "r13w", "r14w", "r15w",
882 };
883 static const char *x86_long_reg_str_map[] = {
884 "eax", "ecx", "edx", "ebx",
885 "esp", "ebp", "esi", "edi",
886 "r8d", "r9d", "r10d", "r11d",
887 "r12d", "r13d", "r14d", "r15d",
888 };
889 static const char *x86_quad_reg_str_map[] = {
890 "rax", "rcx", "rdx", "rbx",
891 "rsp", "rbp", "rsi", "rdi",
892 "r8", "r9", "r10", "r11",
893 "r12", "r13", "r14", "r15",
894 };
895 const char * reg_str = NULL;
896 switch (transfer_size) {
897 case SIZE_BYTE:
898 reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
899 break;
900 case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
901 case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
902 case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
903 }
904 if (reg_str)
905 printf(" %s register %%%s",
906 transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
907 reg_str);
908 }
909 printf(", %d bytes instruction\n", len);
910 #endif
911
912 regs[X86_REG_EIP] += len;
913 return true;
914 }
915 #endif
916
917 // Decode and skip PPC instruction
918 #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
919 static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
920 {
921 instruction_t instr;
922 powerpc_decode_instruction(&instr, *nip_p, regs);
923
924 if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
925 // Unknown machine code, let it crash. Then patch the decoder
926 return false;
927 }
928
929 #if DEBUG
930 printf("%08x: %s %s access", *nip_p,
931 instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
932 instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
933
934 if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
935 printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
936 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
937 printf(" r%d (rd = 0)\n", instr.rd);
938 #endif
939
940 if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
941 regs[instr.ra] = instr.addr;
942 if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
943 regs[instr.rd] = 0;
944
945 *nip_p += 4;
946 return true;
947 }
948 #endif
949
950 // Decode and skip MIPS instruction
951 #if (defined(mips) || defined(__mips))
952 enum {
953 #if (defined(sgi) || defined(__sgi))
954 MIPS_REG_EPC = 35,
955 #endif
956 };
957 static bool mips_skip_instruction(greg_t * regs)
958 {
959 unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
960
961 if (epc == 0)
962 return false;
963
964 #if DEBUG
965 printf("IP: %p [%08x]\n", epc, epc[0]);
966 #endif
967
968 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
969 transfer_size_t transfer_size = SIZE_LONG;
970 int direction = 0;
971
972 const unsigned int opcode = epc[0];
973 switch (opcode >> 26) {
974 case 32: // Load Byte
975 case 36: // Load Byte Unsigned
976 transfer_type = SIGSEGV_TRANSFER_LOAD;
977 transfer_size = SIZE_BYTE;
978 break;
979 case 33: // Load Halfword
980 case 37: // Load Halfword Unsigned
981 transfer_type = SIGSEGV_TRANSFER_LOAD;
982 transfer_size = SIZE_WORD;
983 break;
984 case 35: // Load Word
985 case 39: // Load Word Unsigned
986 transfer_type = SIGSEGV_TRANSFER_LOAD;
987 transfer_size = SIZE_LONG;
988 break;
989 case 34: // Load Word Left
990 transfer_type = SIGSEGV_TRANSFER_LOAD;
991 transfer_size = SIZE_LONG;
992 direction = -1;
993 break;
994 case 38: // Load Word Right
995 transfer_type = SIGSEGV_TRANSFER_LOAD;
996 transfer_size = SIZE_LONG;
997 direction = 1;
998 break;
999 case 55: // Load Doubleword
1000 transfer_type = SIGSEGV_TRANSFER_LOAD;
1001 transfer_size = SIZE_QUAD;
1002 break;
1003 case 26: // Load Doubleword Left
1004 transfer_type = SIGSEGV_TRANSFER_LOAD;
1005 transfer_size = SIZE_QUAD;
1006 direction = -1;
1007 break;
1008 case 27: // Load Doubleword Right
1009 transfer_type = SIGSEGV_TRANSFER_LOAD;
1010 transfer_size = SIZE_QUAD;
1011 direction = 1;
1012 break;
1013 case 40: // Store Byte
1014 transfer_type = SIGSEGV_TRANSFER_STORE;
1015 transfer_size = SIZE_BYTE;
1016 break;
1017 case 41: // Store Halfword
1018 transfer_type = SIGSEGV_TRANSFER_STORE;
1019 transfer_size = SIZE_WORD;
1020 break;
1021 case 43: // Store Word
1022 case 42: // Store Word Left
1023 case 46: // Store Word Right
1024 transfer_type = SIGSEGV_TRANSFER_STORE;
1025 transfer_size = SIZE_LONG;
1026 break;
1027 case 63: // Store Doubleword
1028 case 44: // Store Doubleword Left
1029 case 45: // Store Doubleword Right
1030 transfer_type = SIGSEGV_TRANSFER_STORE;
1031 transfer_size = SIZE_QUAD;
1032 break;
1033 /* Misc instructions unlikely to be used within CPU emulators */
1034 case 48: // Load Linked Word
1035 transfer_type = SIGSEGV_TRANSFER_LOAD;
1036 transfer_size = SIZE_LONG;
1037 break;
1038 case 52: // Load Linked Doubleword
1039 transfer_type = SIGSEGV_TRANSFER_LOAD;
1040 transfer_size = SIZE_QUAD;
1041 break;
1042 case 56: // Store Conditional Word
1043 transfer_type = SIGSEGV_TRANSFER_STORE;
1044 transfer_size = SIZE_LONG;
1045 break;
1046 case 60: // Store Conditional Doubleword
1047 transfer_type = SIGSEGV_TRANSFER_STORE;
1048 transfer_size = SIZE_QUAD;
1049 break;
1050 }
1051
1052 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1053 // Unknown machine code, let it crash. Then patch the decoder
1054 return false;
1055 }
1056
1057 // Zero target register in case of a load operation
1058 const int reg = (opcode >> 16) & 0x1f;
1059 if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
1060 if (direction == 0)
1061 regs[reg] = 0;
1062 else {
1063 // FIXME: untested code
1064 unsigned long ea = regs[(opcode >> 21) & 0x1f];
1065 ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
1066 const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
1067 unsigned long value;
1068 if (direction > 0) {
1069 const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
1070 value = regs[reg] & rmask;
1071 }
1072 else {
1073 const unsigned long lmask = (1L << (offset * 8)) - 1;
1074 value = regs[reg] & lmask;
1075 }
1076 // restore most significant bits
1077 if (transfer_size == SIZE_LONG)
1078 value = (signed long)(signed int)value;
1079 regs[reg] = value;
1080 }
1081 }
1082
1083 #if DEBUG
1084 #if (defined(_ABIN32) || defined(_ABI64))
1085 static const char * mips_gpr_names[32] = {
1086 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1087 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
1088 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1089 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1090 };
1091 #else
1092 static const char * mips_gpr_names[32] = {
1093 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
1094 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
1095 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
1096 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
1097 };
1098 #endif
1099 printf("%s %s register %s\n",
1100 transfer_size == SIZE_BYTE ? "byte" :
1101 transfer_size == SIZE_WORD ? "word" :
1102 transfer_size == SIZE_LONG ? "long" :
1103 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1104 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1105 mips_gpr_names[reg]);
1106 #endif
1107
1108 regs[MIPS_REG_EPC] += 4;
1109 return true;
1110 }
1111 #endif
1112
1113 // Decode and skip SPARC instruction
1114 #if (defined(sparc) || defined(__sparc__))
1115 enum {
1116 #if (defined(__sun__))
1117 SPARC_REG_G1 = REG_G1,
1118 SPARC_REG_O0 = REG_O0,
1119 SPARC_REG_PC = REG_PC,
1120 #endif
1121 };
1122 static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
1123 {
1124 unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
1125
1126 if (pc == 0)
1127 return false;
1128
1129 #if DEBUG
1130 printf("IP: %p [%08x]\n", pc, pc[0]);
1131 #endif
1132
1133 transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1134 transfer_size_t transfer_size = SIZE_LONG;
1135 bool register_pair = false;
1136
1137 const unsigned int opcode = pc[0];
1138 if ((opcode >> 30) != 3)
1139 return false;
1140 switch ((opcode >> 19) & 0x3f) {
1141 case 9: // Load Signed Byte
1142 case 1: // Load Unsigned Byte
1143 transfer_type = SIGSEGV_TRANSFER_LOAD;
1144 transfer_size = SIZE_BYTE;
1145 break;
1146 case 10:// Load Signed Halfword
1147 case 2: // Load Unsigned Word
1148 transfer_type = SIGSEGV_TRANSFER_LOAD;
1149 transfer_size = SIZE_WORD;
1150 break;
1151 case 8: // Load Word
1152 case 0: // Load Unsigned Word
1153 transfer_type = SIGSEGV_TRANSFER_LOAD;
1154 transfer_size = SIZE_LONG;
1155 break;
1156 case 11:// Load Extended Word
1157 transfer_type = SIGSEGV_TRANSFER_LOAD;
1158 transfer_size = SIZE_QUAD;
1159 break;
1160 case 3: // Load Doubleword
1161 transfer_type = SIGSEGV_TRANSFER_LOAD;
1162 transfer_size = SIZE_LONG;
1163 register_pair = true;
1164 break;
1165 case 5: // Store Byte
1166 transfer_type = SIGSEGV_TRANSFER_STORE;
1167 transfer_size = SIZE_BYTE;
1168 break;
1169 case 6: // Store Halfword
1170 transfer_type = SIGSEGV_TRANSFER_STORE;
1171 transfer_size = SIZE_WORD;
1172 break;
1173 case 4: // Store Word
1174 transfer_type = SIGSEGV_TRANSFER_STORE;
1175 transfer_size = SIZE_LONG;
1176 break;
1177 case 14:// Store Extended Word
1178 transfer_type = SIGSEGV_TRANSFER_STORE;
1179 transfer_size = SIZE_QUAD;
1180 break;
1181 case 7: // Store Doubleword
1182 transfer_type = SIGSEGV_TRANSFER_STORE;
1183 transfer_size = SIZE_WORD;
1184 register_pair = true;
1185 break;
1186 }
1187
1188 if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1189 // Unknown machine code, let it crash. Then patch the decoder
1190 return false;
1191 }
1192
1193 // Zero target register in case of a load operation
1194 const int reg = (opcode >> 25) & 0x1f;
1195 if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1196 // FIXME: code to handle local & input registers is not tested
1197 if (reg >= 1 && reg <= 7) {
1198 // global registers
1199 regs[reg - 1 + SPARC_REG_G1] = 0;
1200 }
1201 else if (reg >= 8 && reg <= 15) {
1202 // output registers
1203 regs[reg - 8 + SPARC_REG_O0] = 0;
1204 }
1205 else if (reg >= 16 && reg <= 23) {
1206 // local registers (in register windows)
1207 if (gwins)
1208 gwins->wbuf->rw_local[reg - 16] = 0;
1209 else
1210 rwin->rw_local[reg - 16] = 0;
1211 }
1212 else {
1213 // input registers (in register windows)
1214 if (gwins)
1215 gwins->wbuf->rw_in[reg - 24] = 0;
1216 else
1217 rwin->rw_in[reg - 24] = 0;
1218 }
1219 }
1220
1221 #if DEBUG
1222 static const char * reg_names[] = {
1223 "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1224 "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1225 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1226 "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1227 };
1228 printf("%s %s register %s\n",
1229 transfer_size == SIZE_BYTE ? "byte" :
1230 transfer_size == SIZE_WORD ? "word" :
1231 transfer_size == SIZE_LONG ? "long" :
1232 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1233 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1234 reg_names[reg]);
1235 #endif
1236
1237 regs[SPARC_REG_PC] += 4;
1238 return true;
1239 }
1240 #endif
1241 #endif
1242
1243 // Fallbacks
1244 #ifndef SIGSEGV_FAULT_INSTRUCTION
1245 #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_PC
1246 #endif
1247 #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1248 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1249 #endif
1250 #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1251 #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP) sigsegv_fault_handler(ADDR, IP)
1252 #endif
1253
1254 // SIGSEGV recovery supported ?
1255 #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
1256 #define HAVE_SIGSEGV_RECOVERY
1257 #endif
1258
1259
1260 /*
1261 * SIGSEGV global handler
1262 */
1263
1264 #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
1265 // This function handles the badaccess to memory.
1266 // It is called from the signal handler or the exception handler.
1267 static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1268 {
1269 sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1270 sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1271
1272 // Call user's handler and reinstall the global handler, if required
1273 switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1274 case SIGSEGV_RETURN_SUCCESS:
1275 return true;
1276
1277 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
1278 case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1279 // Call the instruction skipper with the register file
1280 // available
1281 if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1282 #ifdef HAVE_MACH_EXCEPTIONS
1283 // Unlike UNIX signals where the thread state
1284 // is modified off of the stack, in Mach we
1285 // need to actually call thread_set_state to
1286 // have the register values updated.
1287 kern_return_t krc;
1288
1289 krc = thread_set_state(thread,
1290 MACHINE_THREAD_STATE, (thread_state_t)state,
1291 MACHINE_THREAD_STATE_COUNT);
1292 MACH_CHECK_ERROR (thread_get_state, krc);
1293 #endif
1294 return true;
1295 }
1296 break;
1297 #endif
1298 }
1299
1300 // We can't do anything with the fault_address, dump state?
1301 if (sigsegv_state_dumper != 0)
1302 sigsegv_state_dumper(fault_address, fault_instruction);
1303
1304 return false;
1305 }
1306 #endif
1307
1308
1309 /*
1310 * There are two mechanisms for handling a bad memory access,
1311 * Mach exceptions and UNIX signals. The implementation specific
1312 * code appears below. Its reponsibility is to call handle_badaccess
1313 * which is the routine that handles the fault in an implementation
1314 * agnostic manner. The implementation specific code below is then
1315 * reponsible for checking whether handle_badaccess was able
1316 * to handle the memory access error and perform any implementation
1317 * specific tasks necessary afterwards.
1318 */
1319
1320 #ifdef HAVE_MACH_EXCEPTIONS
1321 /*
1322 * We need to forward all exceptions that we do not handle.
1323 * This is important, there are many exceptions that may be
1324 * handled by other exception handlers. For example debuggers
1325 * use exceptions and the exception hander is in another
1326 * process in such a case. (Timothy J. Wood states in his
1327 * message to the list that he based this code on that from
1328 * gdb for Darwin.)
1329 */
1330 static inline kern_return_t
1331 forward_exception(mach_port_t thread_port,
1332 mach_port_t task_port,
1333 exception_type_t exception_type,
1334 exception_data_t exception_data,
1335 mach_msg_type_number_t data_count,
1336 ExceptionPorts *oldExceptionPorts)
1337 {
1338 kern_return_t kret;
1339 unsigned int portIndex;
1340 mach_port_t port;
1341 exception_behavior_t behavior;
1342 thread_state_flavor_t flavor;
1343 thread_state_t thread_state;
1344 mach_msg_type_number_t thread_state_count;
1345
1346 for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
1347 if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
1348 // This handler wants the exception
1349 break;
1350 }
1351 }
1352
1353 if (portIndex >= oldExceptionPorts->maskCount) {
1354 fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
1355 return KERN_FAILURE;
1356 }
1357
1358 port = oldExceptionPorts->handlers[portIndex];
1359 behavior = oldExceptionPorts->behaviors[portIndex];
1360 flavor = oldExceptionPorts->flavors[portIndex];
1361
1362 /*
1363 fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1364 */
1365
1366 if (behavior != EXCEPTION_DEFAULT) {
1367 thread_state_count = THREAD_STATE_MAX;
1368 kret = thread_get_state (thread_port, flavor, thread_state,
1369 &thread_state_count);
1370 MACH_CHECK_ERROR (thread_get_state, kret);
1371 }
1372
1373 switch (behavior) {
1374 case EXCEPTION_DEFAULT:
1375 // fprintf(stderr, "forwarding to exception_raise\n");
1376 kret = exception_raise(port, thread_port, task_port, exception_type,
1377 exception_data, data_count);
1378 MACH_CHECK_ERROR (exception_raise, kret);
1379 break;
1380 case EXCEPTION_STATE:
1381 // fprintf(stderr, "forwarding to exception_raise_state\n");
1382 kret = exception_raise_state(port, exception_type, exception_data,
1383 data_count, &flavor,
1384 thread_state, thread_state_count,
1385 thread_state, &thread_state_count);
1386 MACH_CHECK_ERROR (exception_raise_state, kret);
1387 break;
1388 case EXCEPTION_STATE_IDENTITY:
1389 // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
1390 kret = exception_raise_state_identity(port, thread_port, task_port,
1391 exception_type, exception_data,
1392 data_count, &flavor,
1393 thread_state, thread_state_count,
1394 thread_state, &thread_state_count);
1395 MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1396 break;
1397 default:
1398 fprintf(stderr, "forward_exception got unknown behavior\n");
1399 break;
1400 }
1401
1402 if (behavior != EXCEPTION_DEFAULT) {
1403 kret = thread_set_state (thread_port, flavor, thread_state,
1404 thread_state_count);
1405 MACH_CHECK_ERROR (thread_set_state, kret);
1406 }
1407
1408 return KERN_SUCCESS;
1409 }
1410
1411 /*
1412 * This is the code that actually handles the exception.
1413 * It is called by exc_server. For Darwin 5 Apple changed
1414 * this a bit from how this family of functions worked in
1415 * Mach. If you are familiar with that it is a little
1416 * different. The main variation that concerns us here is
1417 * that code is an array of exception specific codes and
1418 * codeCount is a count of the number of codes in the code
1419 * array. In typical Mach all exceptions have a code
1420 * and sub-code. It happens to be the case that for a
1421 * EXC_BAD_ACCESS exception the first entry is the type of
1422 * bad access that occurred and the second entry is the
1423 * faulting address so these entries correspond exactly to
1424 * how the code and sub-code are used on Mach.
1425 *
1426 * This is a MIG interface. No code in Basilisk II should
1427 * call this directley. This has to have external C
1428 * linkage because that is what exc_server expects.
1429 */
1430 kern_return_t
1431 catch_exception_raise(mach_port_t exception_port,
1432 mach_port_t thread,
1433 mach_port_t task,
1434 exception_type_t exception,
1435 exception_data_t code,
1436 mach_msg_type_number_t codeCount)
1437 {
1438 ppc_thread_state_t state;
1439 kern_return_t krc;
1440
1441 if ((exception == EXC_BAD_ACCESS) && (codeCount >= 2)) {
1442 if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1443 return KERN_SUCCESS;
1444 }
1445
1446 // In Mach we do not need to remove the exception handler.
1447 // If we forward the exception, eventually some exception handler
1448 // will take care of this exception.
1449 krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1450
1451 return krc;
1452 }
1453 #endif
1454
1455 #ifdef HAVE_SIGSEGV_RECOVERY
1456 // Handle bad memory accesses with signal handler
1457 static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
1458 {
1459 // Call handler and reinstall the global handler, if required
1460 if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
1461 #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
1462 sigsegv_do_install_handler(sig);
1463 #endif
1464 return;
1465 }
1466
1467 // Failure: reinstall default handler for "safe" crash
1468 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1469 SIGSEGV_ALL_SIGNALS
1470 #undef FAULT_HANDLER
1471 }
1472 #endif
1473
1474
1475 /*
1476 * SIGSEGV handler initialization
1477 */
1478
1479 #if defined(HAVE_SIGINFO_T)
1480 static bool sigsegv_do_install_handler(int sig)
1481 {
1482 // Setup SIGSEGV handler to process writes to frame buffer
1483 #ifdef HAVE_SIGACTION
1484 struct sigaction sigsegv_sa;
1485 sigemptyset(&sigsegv_sa.sa_mask);
1486 sigsegv_sa.sa_sigaction = sigsegv_handler;
1487 sigsegv_sa.sa_flags = SA_SIGINFO;
1488 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1489 #else
1490 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1491 #endif
1492 }
1493 #endif
1494
1495 #if defined(HAVE_SIGCONTEXT_SUBTERFUGE)
1496 static bool sigsegv_do_install_handler(int sig)
1497 {
1498 // Setup SIGSEGV handler to process writes to frame buffer
1499 #ifdef HAVE_SIGACTION
1500 struct sigaction sigsegv_sa;
1501 sigemptyset(&sigsegv_sa.sa_mask);
1502 sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
1503 sigsegv_sa.sa_flags = 0;
1504 #if !EMULATED_68K && defined(__NetBSD__)
1505 sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
1506 sigsegv_sa.sa_flags |= SA_ONSTACK;
1507 #endif
1508 return (sigaction(sig, &sigsegv_sa, 0) == 0);
1509 #else
1510 return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
1511 #endif
1512 }
1513 #endif
1514
1515 #if defined(HAVE_MACH_EXCEPTIONS)
1516 static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
1517 {
1518 /*
1519 * Except for the exception port functions, this should be
1520 * pretty much stock Mach. If later you choose to support
1521 * other Mach's besides Darwin, just check for __MACH__
1522 * here and __APPLE__ where the actual differences are.
1523 */
1524 #if defined(__APPLE__) && defined(__MACH__)
1525 if (sigsegv_fault_handler != NULL) {
1526 sigsegv_fault_handler = handler;
1527 return true;
1528 }
1529
1530 kern_return_t krc;
1531
1532 // create the the exception port
1533 krc = mach_port_allocate(mach_task_self(),
1534 MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
1535 if (krc != KERN_SUCCESS) {
1536 mach_error("mach_port_allocate", krc);
1537 return false;
1538 }
1539
1540 // add a port send right
1541 krc = mach_port_insert_right(mach_task_self(),
1542 _exceptionPort, _exceptionPort,
1543 MACH_MSG_TYPE_MAKE_SEND);
1544 if (krc != KERN_SUCCESS) {
1545 mach_error("mach_port_insert_right", krc);
1546 return false;
1547 }
1548
1549 // get the old exception ports
1550 ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
1551 krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
1552 &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
1553 if (krc != KERN_SUCCESS) {
1554 mach_error("thread_get_exception_ports", krc);
1555 return false;
1556 }
1557
1558 // set the new exception port
1559 //
1560 // We could have used EXCEPTION_STATE_IDENTITY instead of
1561 // EXCEPTION_DEFAULT to get the thread state in the initial
1562 // message, but it turns out that in the common case this is not
1563 // neccessary. If we need it we can later ask for it from the
1564 // suspended thread.
1565 //
1566 // Even with THREAD_STATE_NONE, Darwin provides the program
1567 // counter in the thread state. The comments in the header file
1568 // seem to imply that you can count on the GPR's on an exception
1569 // as well but just to be safe I use MACHINE_THREAD_STATE because
1570 // you have to ask for all of the GPR's anyway just to get the
1571 // program counter. In any case because of update effective
1572 // address from immediate and update address from effective
1573 // addresses of ra and rb modes (as good an name as any for these
1574 // addressing modes) used in PPC instructions, you will need the
1575 // GPR state anyway.
1576 krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1577 EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
1578 if (krc != KERN_SUCCESS) {
1579 mach_error("thread_set_exception_ports", krc);
1580 return false;
1581 }
1582
1583 // create the exception handler thread
1584 if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
1585 (void)fprintf(stderr, "creation of exception thread failed\n");
1586 return false;
1587 }
1588
1589 // do not care about the exception thread any longer, let is run standalone
1590 (void)pthread_detach(exc_thread);
1591
1592 sigsegv_fault_handler = handler;
1593 return true;
1594 #else
1595 return false;
1596 #endif
1597 }
1598 #endif
1599
1600 bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
1601 {
1602 #if defined(HAVE_SIGSEGV_RECOVERY)
1603 bool success = true;
1604 #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
1605 SIGSEGV_ALL_SIGNALS
1606 #undef FAULT_HANDLER
1607 if (success)
1608 sigsegv_fault_handler = handler;
1609 return success;
1610 #elif defined(HAVE_MACH_EXCEPTIONS)
1611 return sigsegv_do_install_handler(handler);
1612 #else
1613 // FAIL: no siginfo_t nor sigcontext subterfuge is available
1614 return false;
1615 #endif
1616 }
1617
1618
1619 /*
1620 * SIGSEGV handler deinitialization
1621 */
1622
1623 void sigsegv_deinstall_handler(void)
1624 {
1625 // We do nothing for Mach exceptions, the thread would need to be
1626 // suspended if not already so, and we might mess with other
1627 // exception handlers that came after we registered ours. There is
1628 // no need to remove the exception handler, in fact this function is
1629 // not called anywhere in Basilisk II.
1630 #ifdef HAVE_SIGSEGV_RECOVERY
1631 sigsegv_fault_handler = 0;
1632 #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
1633 SIGSEGV_ALL_SIGNALS
1634 #undef FAULT_HANDLER
1635 #endif
1636 }
1637
1638
1639 /*
1640 * Set callback function when we cannot handle the fault
1641 */
1642
1643 void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
1644 {
1645 sigsegv_state_dumper = handler;
1646 }
1647
1648
1649 /*
1650 * Test program used for configure/test
1651 */
1652
1653 #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
1654 #include <stdio.h>
1655 #include <stdlib.h>
1656 #include <fcntl.h>
1657 #include <sys/mman.h>
1658 #include "vm_alloc.h"
1659
1660 const int REF_INDEX = 123;
1661 const int REF_VALUE = 45;
1662
1663 static int page_size;
1664 static volatile char * page = 0;
1665 static volatile int handler_called = 0;
1666
1667 #ifdef __GNUC__
1668 // Code range where we expect the fault to come from
1669 static void *b_region, *e_region;
1670 #endif
1671
1672 static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1673 {
1674 #if DEBUG
1675 printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
1676 printf("expected fault at %p\n", page + REF_INDEX);
1677 #ifdef __GNUC__
1678 printf("expected instruction address range: %p-%p\n", b_region, e_region);
1679 #endif
1680 #endif
1681 handler_called++;
1682 if ((fault_address - REF_INDEX) != page)
1683 exit(10);
1684 #ifdef __GNUC__
1685 // Make sure reported fault instruction address falls into
1686 // expected code range
1687 if (instruction_address != SIGSEGV_INVALID_PC
1688 && ((instruction_address < (sigsegv_address_t)b_region) ||
1689 (instruction_address >= (sigsegv_address_t)e_region)))
1690 exit(11);
1691 #endif
1692 if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
1693 exit(12);
1694 return SIGSEGV_RETURN_SUCCESS;
1695 }
1696
1697 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1698 static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1699 {
1700 if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
1701 #ifdef __GNUC__
1702 // Make sure reported fault instruction address falls into
1703 // expected code range
1704 if (instruction_address != SIGSEGV_INVALID_PC
1705 && ((instruction_address < (sigsegv_address_t)b_region) ||
1706 (instruction_address >= (sigsegv_address_t)e_region)))
1707 return SIGSEGV_RETURN_FAILURE;
1708 #endif
1709 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
1710 }
1711
1712 return SIGSEGV_RETURN_FAILURE;
1713 }
1714
1715 // More sophisticated tests for instruction skipper
1716 static bool arch_insn_skipper_tests()
1717 {
1718 #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
1719 static const unsigned char code[] = {
1720 0x8a, 0x00, // mov (%eax),%al
1721 0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch
1722 0x88, 0x20, // mov %ah,(%eax)
1723 0x88, 0x08, // mov %cl,(%eax)
1724 0x66, 0x8b, 0x00, // mov (%eax),%ax
1725 0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx
1726 0x66, 0x89, 0x00, // mov %ax,(%eax)
1727 0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1)
1728 0x8b, 0x00, // mov (%eax),%eax
1729 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx
1730 0x89, 0x00, // mov %eax,(%eax)
1731 0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1)
1732 #if defined(__x86_64__)
1733 0x44, 0x8a, 0x00, // mov (%rax),%r8b
1734 0x44, 0x8a, 0x20, // mov (%rax),%r12b
1735 0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil
1736 0x44, 0x88, 0x00, // mov %r8b,(%rax)
1737 0x44, 0x88, 0x20, // mov %r12b,(%rax)
1738 0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1)
1739 0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w
1740 0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx
1741 0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax)
1742 0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1)
1743 0x44, 0x8b, 0x00, // mov (%rax),%r8d
1744 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx
1745 0x44, 0x89, 0x00, // mov %r8d,(%rax)
1746 0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1)
1747 0x48, 0x8b, 0x08, // mov (%rax),%rcx
1748 0x4c, 0x8b, 0x18, // mov (%rax),%r11
1749 0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx
1750 0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11
1751 0x48, 0x89, 0x08, // mov %rcx,(%rax)
1752 0x4c, 0x89, 0x18, // mov %r11,(%rax)
1753 0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1)
1754 0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1)
1755 #endif
1756 0 // end
1757 };
1758 const int N_REGS = 20;
1759 unsigned long regs[N_REGS];
1760 for (int i = 0; i < N_REGS; i++)
1761 regs[i] = i;
1762 const unsigned long start_code = (unsigned long)&code;
1763 regs[X86_REG_EIP] = start_code;
1764 while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
1765 && ix86_skip_instruction(regs))
1766 ; /* simply iterate */
1767 return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
1768 #endif
1769 return true;
1770 }
1771 #endif
1772
1773 int main(void)
1774 {
1775 if (vm_init() < 0)
1776 return 1;
1777
1778 page_size = getpagesize();
1779 if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
1780 return 2;
1781
1782 memset((void *)page, 0, page_size);
1783 if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
1784 return 3;
1785
1786 if (!sigsegv_install_handler(sigsegv_test_handler))
1787 return 4;
1788
1789 #ifdef __GNUC__
1790 b_region = &&L_b_region1;
1791 e_region = &&L_e_region1;
1792 #endif
1793 L_b_region1:
1794 page[REF_INDEX] = REF_VALUE;
1795 if (page[REF_INDEX] != REF_VALUE)
1796 exit(20);
1797 page[REF_INDEX] = REF_VALUE;
1798 L_e_region1:
1799
1800 if (handler_called != 1)
1801 return 5;
1802
1803 #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1804 if (!sigsegv_install_handler(sigsegv_insn_handler))
1805 return 6;
1806
1807 if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
1808 return 7;
1809
1810 for (int i = 0; i < page_size; i++)
1811 page[i] = (i + 1) % page_size;
1812
1813 if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
1814 return 8;
1815
1816 #define TEST_SKIP_INSTRUCTION(TYPE) do { \
1817 const unsigned long TAG = 0x12345678 | \
1818 (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \
1819 TYPE data = *((TYPE *)(page + sizeof(TYPE))); \
1820 volatile unsigned long effect = data + TAG; \
1821 if (effect != TAG) \
1822 return 9; \
1823 } while (0)
1824
1825 #ifdef __GNUC__
1826 b_region = &&L_b_region2;
1827 e_region = &&L_e_region2;
1828 #endif
1829 L_b_region2:
1830 TEST_SKIP_INSTRUCTION(unsigned char);
1831 TEST_SKIP_INSTRUCTION(unsigned short);
1832 TEST_SKIP_INSTRUCTION(unsigned int);
1833 TEST_SKIP_INSTRUCTION(unsigned long);
1834 L_e_region2:
1835
1836 if (!arch_insn_skipper_tests())
1837 return 20;
1838 #endif
1839
1840 vm_exit();
1841 return 0;
1842 }
1843 #endif