ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
Revision: 1.39
Committed: 2003-12-20T21:50:08Z (20 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.38: +20 -1 lines
Log Message:
Add support for Linux/hppa, FreeBSD/alpha. Misc debugging output.

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