ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/sigsegv.cpp (file contents):
Revision 1.3 by gbeauche, 2001-06-05T12:16:34Z vs.
Revision 1.84 by gbeauche, 2008-01-20T17:09:34Z

# Line 4 | Line 4
4   *  Derived from Bruno Haible's work on his SIGSEGV library for clisp
5   *  <http://clisp.sourceforge.net/>
6   *
7 < *  Basilisk II (C) 1997-2001 Christian Bauer
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-2008 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
# Line 29 | Line 35
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 + // Size of an unsigned integer large enough to hold all bits of a pointer
53 + // NOTE: this can be different than SIGSEGV_REGISTER_TYPE. In
54 + // particular, on ILP32 systems with a 64-bit kernel (HP-UX/ia64?)
55 + #ifdef HAVE_WIN32_VM
56 + // Windows is either ILP32 or LLP64
57 + typedef UINT_PTR sigsegv_uintptr_t;
58 + #else
59 + // Other systems are sane enough to follow ILP32 or LP64 models
60 + typedef unsigned long sigsegv_uintptr_t;
61 + #endif
62 +
63   // Type of the system signal handler
64   typedef RETSIGTYPE (*signal_handler)(int);
65  
66   // User's SIGSEGV handler
67 < static sigsegv_handler_t sigsegv_user_handler = 0;
67 > static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
68 >
69 > // Function called to dump state if we can't handle the fault
70 > static sigsegv_state_dumper_t sigsegv_state_dumper = 0;
71  
72   // Actual SIGSEGV handler installer
73   static bool sigsegv_do_install_handler(int sig);
74  
75  
76   /*
77 + *  Instruction decoding aids
78 + */
79 +
80 + // Transfer type
81 + enum transfer_type_t {
82 +        SIGSEGV_TRANSFER_UNKNOWN        = 0,
83 +        SIGSEGV_TRANSFER_LOAD           = 1,
84 +        SIGSEGV_TRANSFER_STORE          = 2
85 + };
86 +
87 + // Transfer size
88 + enum transfer_size_t {
89 +        SIZE_UNKNOWN,
90 +        SIZE_BYTE,
91 +        SIZE_WORD, // 2 bytes
92 +        SIZE_LONG, // 4 bytes
93 +        SIZE_QUAD  // 8 bytes
94 + };
95 +
96 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
97 + // Addressing mode
98 + enum addressing_mode_t {
99 +        MODE_UNKNOWN,
100 +        MODE_NORM,
101 +        MODE_U,
102 +        MODE_X,
103 +        MODE_UX
104 + };
105 +
106 + // Decoded instruction
107 + struct instruction_t {
108 +        transfer_type_t         transfer_type;
109 +        transfer_size_t         transfer_size;
110 +        addressing_mode_t       addr_mode;
111 +        unsigned int            addr;
112 +        char                            ra, rd;
113 + };
114 +
115 + static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
116 + {
117 +        // Get opcode and divide into fields
118 +        unsigned int opcode = *((unsigned int *)(unsigned long)nip);
119 +        unsigned int primop = opcode >> 26;
120 +        unsigned int exop = (opcode >> 1) & 0x3ff;
121 +        unsigned int ra = (opcode >> 16) & 0x1f;
122 +        unsigned int rb = (opcode >> 11) & 0x1f;
123 +        unsigned int rd = (opcode >> 21) & 0x1f;
124 +        signed int imm = (signed short)(opcode & 0xffff);
125 +        
126 +        // Analyze opcode
127 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
128 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
129 +        addressing_mode_t addr_mode = MODE_UNKNOWN;
130 +        switch (primop) {
131 +        case 31:
132 +                switch (exop) {
133 +                case 23:        // lwzx
134 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
135 +                case 55:        // lwzux
136 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
137 +                case 87:        // lbzx
138 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
139 +                case 119:       // lbzux
140 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
141 +                case 151:       // stwx
142 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
143 +                case 183:       // stwux
144 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
145 +                case 215:       // stbx
146 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
147 +                case 247:       // stbux
148 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
149 +                case 279:       // lhzx
150 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
151 +                case 311:       // lhzux
152 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
153 +                case 343:       // lhax
154 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
155 +                case 375:       // lhaux
156 +                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
157 +                case 407:       // sthx
158 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
159 +                case 439:       // sthux
160 +                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
161 +                }
162 +                break;
163 +        
164 +        case 32:        // lwz
165 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
166 +        case 33:        // lwzu
167 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
168 +        case 34:        // lbz
169 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
170 +        case 35:        // lbzu
171 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
172 +        case 36:        // stw
173 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
174 +        case 37:        // stwu
175 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
176 +        case 38:        // stb
177 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
178 +        case 39:        // stbu
179 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
180 +        case 40:        // lhz
181 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
182 +        case 41:        // lhzu
183 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
184 +        case 42:        // lha
185 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
186 +        case 43:        // lhau
187 +                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
188 +        case 44:        // sth
189 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
190 +        case 45:        // sthu
191 +                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
192 +        case 58:        // ld, ldu, lwa
193 +                transfer_type = SIGSEGV_TRANSFER_LOAD;
194 +                transfer_size = SIZE_QUAD;
195 +                addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
196 +                imm &= ~3;
197 +                break;
198 +        case 62:        // std, stdu, stq
199 +                transfer_type = SIGSEGV_TRANSFER_STORE;
200 +                transfer_size = SIZE_QUAD;
201 +                addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
202 +                imm &= ~3;
203 +                break;
204 +        }
205 +        
206 +        // Calculate effective address
207 +        unsigned int addr = 0;
208 +        switch (addr_mode) {
209 +        case MODE_X:
210 +        case MODE_UX:
211 +                if (ra == 0)
212 +                        addr = gpr[rb];
213 +                else
214 +                        addr = gpr[ra] + gpr[rb];
215 +                break;
216 +        case MODE_NORM:
217 +        case MODE_U:
218 +                if (ra == 0)
219 +                        addr = (signed int)(signed short)imm;
220 +                else
221 +                        addr = gpr[ra] + (signed int)(signed short)imm;
222 +                break;
223 +        default:
224 +                break;
225 +        }
226 +        
227 +        // Commit decoded instruction
228 +        instruction->addr = addr;
229 +        instruction->addr_mode = addr_mode;
230 +        instruction->transfer_type = transfer_type;
231 +        instruction->transfer_size = transfer_size;
232 +        instruction->ra = ra;
233 +        instruction->rd = rd;
234 + }
235 + #endif
236 +
237 +
238 + /*
239   *  OS-dependant SIGSEGV signals support section
240   */
241  
242   #if HAVE_SIGINFO_T
243   // Generic extended signal handler
244 + #if defined(__FreeBSD__)
245 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
246 + #elif defined(__hpux)
247 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
248 + #else
249   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
250 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *
250 > #endif
251 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, siginfo_t *sip, void *scp
252 > #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp
253 > #define SIGSEGV_FAULT_HANDLER_ARGS              sip, scp
254   #define SIGSEGV_FAULT_ADDRESS                   sip->si_addr
255 + #if (defined(sgi) || defined(__sgi))
256 + #include <ucontext.h>
257 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
258 + #define SIGSEGV_FAULT_INSTRUCTION               (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
259 + #if (defined(mips) || defined(__mips))
260 + #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0]
261 + #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
262 + #endif
263 + #endif
264 + #if defined(__sun__)
265 + #if (defined(sparc) || defined(__sparc__))
266 + #include <sys/stack.h>
267 + #include <sys/regset.h>
268 + #include <sys/ucontext.h>
269 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
270 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[REG_PC]
271 + #define SIGSEGV_SPARC_GWINDOWS                  (((ucontext_t *)scp)->uc_mcontext.gwins)
272 + #define SIGSEGV_SPARC_RWINDOW                   (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS)
273 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
274 + #define SIGSEGV_SKIP_INSTRUCTION                sparc_skip_instruction
275 + #endif
276 + #if defined(__i386__)
277 + #include <sys/regset.h>
278 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
279 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[EIP]
280 + #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
281 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
282 + #endif
283 + #endif
284 + #if defined(__FreeBSD__) || defined(__OpenBSD__)
285 + #if (defined(i386) || defined(__i386__))
286 + #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_eip)
287 + #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
288 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
289 + #endif
290 + #endif
291 + #if defined(__NetBSD__)
292 + #if (defined(i386) || defined(__i386__))
293 + #include <sys/ucontext.h>
294 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.__gregs)
295 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[_REG_EIP]
296 + #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
297 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
298 + #endif
299 + #if (defined(powerpc) || defined(__powerpc__))
300 + #include <sys/ucontext.h>
301 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.__gregs)
302 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[_REG_PC]
303 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
304 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
305 + #endif
306 + #endif
307 + #if defined(__linux__)
308 + #if (defined(i386) || defined(__i386__))
309 + #include <sys/ucontext.h>
310 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
311 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
312 + #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
313 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
314 + #endif
315 + #if (defined(x86_64) || defined(__x86_64__))
316 + #include <sys/ucontext.h>
317 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
318 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
319 + #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
320 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
321 + #endif
322 + #if (defined(ia64) || defined(__ia64__))
323 + #define SIGSEGV_CONTEXT_REGS                    ((struct sigcontext *)scp)
324 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
325 + #define SIGSEGV_REGISTER_FILE                   SIGSEGV_CONTEXT_REGS
326 + #define SIGSEGV_SKIP_INSTRUCTION                ia64_skip_instruction
327 + #endif
328 + #if (defined(powerpc) || defined(__powerpc__))
329 + #include <sys/ucontext.h>
330 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.regs)
331 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->nip)
332 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
333 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
334 + #endif
335 + #if (defined(hppa) || defined(__hppa__))
336 + #undef  SIGSEGV_FAULT_ADDRESS
337 + #define SIGSEGV_FAULT_ADDRESS                   sip->si_ptr
338 + #endif
339 + #if (defined(arm) || defined(__arm__))
340 + #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
341 + #define SIGSEGV_CONTEXT_REGS                    (((struct ucontext *)scp)->uc_mcontext)
342 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS.arm_pc)
343 + #define SIGSEGV_REGISTER_FILE                   (&SIGSEGV_CONTEXT_REGS.arm_r0)
344 + #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
345 + #endif
346 + #if (defined(mips) || defined(__mips__))
347 + #include <sys/ucontext.h>
348 + #define SIGSEGV_CONTEXT_REGS                    (((struct ucontext *)scp)->uc_mcontext)
349 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS.pc)
350 + #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
351 + #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
352 + #endif
353 + #endif
354 + #if (defined(__hpux) || defined(__hpux__))
355 + #if (defined(__hppa) || defined(__hppa__))
356 + #define SIGSEGV_CONTEXT_REGS                    (&((ucontext_t *)scp)->uc_mcontext)
357 + #define SIGSEGV_FAULT_INSTRUCTION_32    (SIGSEGV_CONTEXT_REGS->ss_narrow.ss_pcoq_head & ~3ul)
358 + #define SIGSEGV_FAULT_INSTRUCTION_64    (SIGSEGV_CONTEXT_REGS->ss_wide.ss_64.ss_pcoq_head & ~3ull)
359 + #if defined(__LP64__)
360 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_FAULT_INSTRUCTION_64
361 + #else
362 + #define SIGSEGV_FAULT_INSTRUCTION               ((SIGSEGV_CONTEXT_REGS->ss_flags & SS_WIDEREGS) ? \
363 +                                                                                 (uint32_t)SIGSEGV_FAULT_INSTRUCTION_64 : \
364 +                                                                                 SIGSEGV_FAULT_INSTRUCTION_32)
365 + #endif
366 + #endif
367 + #if (defined(__ia64) || defined(__ia64__))
368 + #include <sys/ucontext.h>
369 + #define SIGSEGV_CONTEXT_REGS                    ((ucontext_t *)scp)
370 + #define SIGSEGV_FAULT_INSTRUCTION               get_fault_instruction(SIGSEGV_CONTEXT_REGS)
371 + #define SIGSEGV_REGISTER_FILE                   SIGSEGV_CONTEXT_REGS
372 + #define SIGSEGV_SKIP_INSTRUCTION                ia64_skip_instruction
373 +
374 + #include <sys/uc_access.h>
375 + static inline sigsegv_address_t get_fault_instruction(const ucontext_t *ucp)
376 + {
377 +  uint64_t ip;
378 +  if (__uc_get_ip(ucp, &ip) != 0)
379 +        return SIGSEGV_INVALID_ADDRESS;
380 +  return (sigsegv_address_t)(ip & ~3ULL);
381 + }
382 + #endif
383 + #endif
384   #endif
385  
386   #if HAVE_SIGCONTEXT_SUBTERFUGE
# Line 65 | Line 390 | static bool sigsegv_do_install_handler(i
390   #if (defined(i386) || defined(__i386__))
391   #include <asm/sigcontext.h>
392   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext scs
393 < #define SIGSEGV_FAULT_ADDRESS                   scs.cr2
394 < #define SIGSEGV_FAULT_INSTRUCTION               scs.eip
393 > #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
394 > #define SIGSEGV_FAULT_HANDLER_ARGS              &scs
395 > #define SIGSEGV_FAULT_ADDRESS                   scp->cr2
396 > #define SIGSEGV_FAULT_INSTRUCTION               scp->eip
397 > #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)scp
398 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
399   #endif
400   #if (defined(sparc) || defined(__sparc__))
401   #include <asm/sigcontext.h>
402 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext* scp, char* addr
402 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
403 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp, addr
404   #define SIGSEGV_FAULT_ADDRESS                   addr
405   #endif
406   #if (defined(powerpc) || defined(__powerpc__))
407   #include <asm/sigcontext.h>
408 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext* scp
408 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, struct sigcontext *scp
409 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, scp
410   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
411   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
412 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
413 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
414 + #endif
415 + #if (defined(alpha) || defined(__alpha__))
416 + #include <asm/sigcontext.h>
417 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
418 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
419 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
420 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
421 + #endif
422 + #if (defined(arm) || defined(__arm__))
423 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int r1, int r2, int r3, struct sigcontext sc
424 + #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
425 + #define SIGSEGV_FAULT_HANDLER_ARGS              &sc
426 + #define SIGSEGV_FAULT_ADDRESS                   scp->fault_address
427 + #define SIGSEGV_FAULT_INSTRUCTION               scp->arm_pc
428 + #define SIGSEGV_REGISTER_FILE                   &scp->arm_r0
429 + #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
430   #endif
431   #endif
432  
433   // Irix 5 or 6 on MIPS
434 < #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4))
434 > #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4))
435 > #include <ucontext.h>
436   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
437 < #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
437 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
438 > #define SIGSEGV_FAULT_ADDRESS                   (unsigned long)scp->sc_badvaddr
439 > #define SIGSEGV_FAULT_INSTRUCTION               (unsigned long)scp->sc_pc
440   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
441   #endif
442  
443 + // HP-UX
444 + #if (defined(hpux) || defined(__hpux__))
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                   scp->sc_sl.sl_ss.ss_narrow.ss_cr21
448 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
449 + #endif
450 +
451   // OSF/1 on Alpha
452   #if defined(__osf__)
453 + #include <ucontext.h>
454   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
455 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
456   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_traparg_a0
457   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
458   #endif
# Line 98 | Line 460 | static bool sigsegv_do_install_handler(i
460   // AIX
461   #if defined(_AIX)
462   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
463 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
464   #define SIGSEGV_FAULT_ADDRESS                   scp->sc_jmpbuf.jmp_context.o_vaddr
465   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
466   #endif
467  
468 < // NetBSD or FreeBSD
469 < #if defined(__NetBSD__) || defined(__FreeBSD__)
468 > // NetBSD
469 > #if defined(__NetBSD__)
470   #if (defined(m68k) || defined(__m68k__))
471   #include <m68k/frame.h>
472   #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
473 < #define SIGSEGV_FAULT_ADDRESS                   ({                                                                                                                              \
474 <        struct sigstate {                                                                                                                                                                       \
112 <                int ss_flags;                                                                                                                                                                   \
113 <                struct frame ss_frame;                                                                                                                                                  \
114 <        };                                                                                                                                                                                                      \
115 <        struct sigstate *state = (struct sigstate *)scp->sc_ap;                                                                                         \
116 <        char *fault_addr;                                                                                                                                                                       \
117 <        switch (state->ss_frame.f_format) {                                                                                                                                     \
118 <        case 7:         /* 68040 access error */                                                                                                                                \
119 <                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */    \
120 <                fault_addr = state->ss_frame.f_fmt7.f_fa;                                                                                                               \
121 <                break;                                                                                                                                                                                  \
122 <        default:                                                                                                                                                                                        \
123 <                fault_addr = (char *)code;                                                                                                                                              \
124 <                break;                                                                                                                                                                                  \
125 <        }                                                                                                                                                                                                       \
126 <        fault_addr;                                                                                                                                                                                     \
127 < })
473 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
474 > #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
475   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
476 < #else
477 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, void *scp, char *addr
476 >
477 > // Use decoding scheme from BasiliskII/m68k native
478 > static sigsegv_address_t get_fault_address(struct sigcontext *scp)
479 > {
480 >        struct sigstate {
481 >                int ss_flags;
482 >                struct frame ss_frame;
483 >        };
484 >        struct sigstate *state = (struct sigstate *)scp->sc_ap;
485 >        char *fault_addr;
486 >        switch (state->ss_frame.f_format) {
487 >        case 7:         /* 68040 access error */
488 >                /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */
489 >                fault_addr = state->ss_frame.f_fmt7.f_fa;
490 >                break;
491 >        default:
492 >                fault_addr = (char *)code;
493 >                break;
494 >        }
495 >        return (sigsegv_address_t)fault_addr;
496 > }
497 > #endif
498 > #if (defined(alpha) || defined(__alpha__))
499 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
500 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
501 > #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
502 > #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
503 > #endif
504 > #if (defined(i386) || defined(__i386__))
505 > #error "FIXME: need to decode instruction and compute EA"
506 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
507 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
508 > #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
509 > #endif
510 > #endif
511 > #if defined(__FreeBSD__)
512 > #if (defined(i386) || defined(__i386__))
513 > #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
514 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp, char *addr
515 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp, addr
516 > #define SIGSEGV_FAULT_ADDRESS                   addr
517 > #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_eip
518 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&scp->sc_edi)
519 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
520 > #endif
521 > #if (defined(alpha) || defined(__alpha__))
522 > #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
523 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, char *addr, struct sigcontext *scp
524 > #define SIGSEGV_FAULT_HANDLER_ARGS              sig, addr, scp
525   #define SIGSEGV_FAULT_ADDRESS                   addr
526 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
527 + #endif
528 + #endif
529 +
530 + // Extract fault address out of a sigcontext
531 + #if (defined(alpha) || defined(__alpha__))
532 + // From Boehm's GC 6.0alpha8
533 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
534 + {
535 +        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
536 +        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
537 +        fault_address += (signed long)(signed short)(instruction & 0xffff);
538 +        return (sigsegv_address_t)fault_address;
539 + }
540 + #endif
541 +
542 +
543 + // MacOS X, not sure which version this works in. Under 10.1
544 + // vm_protect does not appear to work from a signal handler. Under
545 + // 10.2 signal handlers get siginfo type arguments but the si_addr
546 + // field is the address of the faulting instruction and not the
547 + // address that caused the SIGBUS. Maybe this works in 10.0? In any
548 + // case with Mach exception handlers there is a way to do what this
549 + // was meant to do.
550 + #ifndef HAVE_MACH_EXCEPTIONS
551 + #if defined(__APPLE__) && defined(__MACH__)
552 + #if (defined(ppc) || defined(__ppc__))
553 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct sigcontext *scp
554 + #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp
555 + #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
556 + #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_ir
557   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
558 + #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2]
559 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
560 +
561 + // Use decoding scheme from SheepShaver
562 + static sigsegv_address_t get_fault_address(struct sigcontext *scp)
563 + {
564 +        unsigned int   nip = (unsigned int) scp->sc_ir;
565 +        unsigned int * gpr = &((unsigned int *) scp->sc_regs)[2];
566 +        instruction_t  instr;
567 +
568 +        powerpc_decode_instruction(&instr, nip, gpr);
569 +        return (sigsegv_address_t)instr.addr;
570 + }
571 + #endif
572 + #endif
573 + #endif
574 + #endif
575 +
576 + #if HAVE_WIN32_EXCEPTIONS
577 + #define WIN32_LEAN_AND_MEAN /* avoid including junk */
578 + #include <windows.h>
579 + #include <winerror.h>
580 +
581 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   EXCEPTION_POINTERS *ExceptionInfo
582 + #define SIGSEGV_FAULT_HANDLER_ARGS              ExceptionInfo
583 + #define SIGSEGV_FAULT_ADDRESS                   ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
584 + #define SIGSEGV_CONTEXT_REGS                    ExceptionInfo->ContextRecord
585 + #if defined(_M_IX86)
586 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS->Eip
587 + #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Edi)
588 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
589 + #endif
590 + #if defined(_M_X64)
591 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS->Rip
592 + #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Rax)
593 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
594 + #endif
595 + #if defined(_M_IA64)
596 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS->StIIP
597 + #endif
598 + #endif
599 +
600 + #if HAVE_MACH_EXCEPTIONS
601 +
602 + // This can easily be extended to other Mach systems, but really who
603 + // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU
604 + // Mach 2.5/3.0?
605 + #if defined(__APPLE__) && defined(__MACH__)
606 +
607 + #include <sys/types.h>
608 + #include <stdlib.h>
609 + #include <stdio.h>
610 + #include <pthread.h>
611 +
612 + /*
613 + * If you are familiar with MIG then you will understand the frustration
614 + * that was necessary to get these embedded into C++ code by hand.
615 + */
616 + extern "C" {
617 + #include <mach/mach.h>
618 + #include <mach/mach_error.h>
619 +
620 + extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
621 + extern kern_return_t catch_exception_raise(mach_port_t, mach_port_t,
622 +        mach_port_t, exception_type_t, exception_data_t, mach_msg_type_number_t);
623 + extern kern_return_t exception_raise(mach_port_t, mach_port_t, mach_port_t,
624 +        exception_type_t, exception_data_t, mach_msg_type_number_t);
625 + extern kern_return_t exception_raise_state(mach_port_t, exception_type_t,
626 +        exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
627 +        thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
628 + extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
629 +        exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
630 +        thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
631 + }
632 +
633 + // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
634 + #define HANDLER_COUNT 64
635 +
636 + // structure to tuck away existing exception handlers
637 + typedef struct _ExceptionPorts {
638 +        mach_msg_type_number_t maskCount;
639 +        exception_mask_t masks[HANDLER_COUNT];
640 +        exception_handler_t handlers[HANDLER_COUNT];
641 +        exception_behavior_t behaviors[HANDLER_COUNT];
642 +        thread_state_flavor_t flavors[HANDLER_COUNT];
643 + } ExceptionPorts;
644 +
645 + // exception handler thread
646 + static pthread_t exc_thread;
647 +
648 + // place where old exception handler info is stored
649 + static ExceptionPorts ports;
650 +
651 + // our exception port
652 + static mach_port_t _exceptionPort = MACH_PORT_NULL;
653 +
654 + #define MACH_CHECK_ERROR(name,ret) \
655 + if (ret != KERN_SUCCESS) { \
656 +        mach_error(#name, ret); \
657 +        exit (1); \
658 + }
659 +
660 + #ifdef __ppc__
661 + #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE
662 + #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
663 + #endif
664 + #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state_t
665 + #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE
666 + #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE_COUNT
667 + #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(dar)
668 + #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state_t
669 + #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE
670 + #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE_COUNT
671 + #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(srr0)
672 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
673 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
674 + #endif
675 + #ifdef __ppc64__
676 + #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE64
677 + #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
678 + #endif
679 + #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state64_t
680 + #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE64
681 + #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE64_COUNT
682 + #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(dar)
683 + #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state64_t
684 + #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE64
685 + #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE64_COUNT
686 + #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(srr0)
687 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
688 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
689 + #endif
690 + #ifdef __i386__
691 + #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE32
692 + #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
693 + #endif
694 + #define SIGSEGV_EXCEPTION_STATE_TYPE    i386_exception_state_t
695 + #define SIGSEGV_EXCEPTION_STATE_FLAVOR  i386_EXCEPTION_STATE
696 + #define SIGSEGV_EXCEPTION_STATE_COUNT   i386_EXCEPTION_STATE_COUNT
697 + #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
698 + #define SIGSEGV_THREAD_STATE_TYPE               i386_thread_state_t
699 + #define SIGSEGV_THREAD_STATE_FLAVOR             i386_THREAD_STATE
700 + #define SIGSEGV_THREAD_STATE_COUNT              i386_THREAD_STATE_COUNT
701 + #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(eip)
702 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
703 + #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(eax)) /* EAX is the first GPR we consider */
704 + #endif
705 + #ifdef __x86_64__
706 + #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE64
707 + #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
708 + #endif
709 + #define SIGSEGV_EXCEPTION_STATE_TYPE    x86_exception_state64_t
710 + #define SIGSEGV_EXCEPTION_STATE_FLAVOR  x86_EXCEPTION_STATE64
711 + #define SIGSEGV_EXCEPTION_STATE_COUNT   x86_EXCEPTION_STATE64_COUNT
712 + #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
713 + #define SIGSEGV_THREAD_STATE_TYPE               x86_thread_state64_t
714 + #define SIGSEGV_THREAD_STATE_FLAVOR             x86_THREAD_STATE64
715 + #define SIGSEGV_THREAD_STATE_COUNT              x86_THREAD_STATE64_COUNT
716 + #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(rip)
717 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
718 + #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(rax)) /* RAX is the first GPR we consider */
719 + #endif
720 + #define SIGSEGV_FAULT_ADDRESS_FAST              code[1]
721 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_INVALID_ADDRESS
722 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code
723 + #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code
724 +
725 + #ifndef MACH_FIELD_NAME
726 + #define MACH_FIELD_NAME(X) X
727 + #endif
728 +
729 + // Since there can only be one exception thread running at any time
730 + // this is not a problem.
731 + #define MSG_SIZE 512
732 + static char msgbuf[MSG_SIZE];
733 + static char replybuf[MSG_SIZE];
734 +
735 + /*
736 + * This is the entry point for the exception handler thread. The job
737 + * of this thread is to wait for exception messages on the exception
738 + * port that was setup beforehand and to pass them on to exc_server.
739 + * exc_server is a MIG generated function that is a part of Mach.
740 + * Its job is to decide what to do with the exception message. In our
741 + * case exc_server calls catch_exception_raise on our behalf. After
742 + * exc_server returns, it is our responsibility to send the reply.
743 + */
744 + static void *
745 + handleExceptions(void *priv)
746 + {
747 +        mach_msg_header_t *msg, *reply;
748 +        kern_return_t krc;
749 +
750 +        msg = (mach_msg_header_t *)msgbuf;
751 +        reply = (mach_msg_header_t *)replybuf;
752 +
753 +        for (;;) {
754 +                krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
755 +                                _exceptionPort, 0, MACH_PORT_NULL);
756 +                MACH_CHECK_ERROR(mach_msg, krc);
757 +
758 +                if (!exc_server(msg, reply)) {
759 +                        fprintf(stderr, "exc_server hated the message\n");
760 +                        exit(1);
761 +                }
762 +
763 +                krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
764 +                                 msg->msgh_local_port, 0, MACH_PORT_NULL);
765 +                if (krc != KERN_SUCCESS) {
766 +                        fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
767 +                                krc, mach_error_string(krc));
768 +                        exit(1);
769 +                }
770 +        }
771 + }
772 + #endif
773 + #endif
774 +
775 +
776 + /*
777 + *  Instruction skipping
778 + */
779 +
780 + #ifndef SIGSEGV_REGISTER_TYPE
781 + #define SIGSEGV_REGISTER_TYPE sigsegv_uintptr_t
782 + #endif
783 +
784 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
785 + // Decode and skip X86 instruction
786 + #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
787 + #if defined(__linux__)
788 + enum {
789 + #if (defined(i386) || defined(__i386__))
790 +        X86_REG_EIP = 14,
791 +        X86_REG_EAX = 11,
792 +        X86_REG_ECX = 10,
793 +        X86_REG_EDX = 9,
794 +        X86_REG_EBX = 8,
795 +        X86_REG_ESP = 7,
796 +        X86_REG_EBP = 6,
797 +        X86_REG_ESI = 5,
798 +        X86_REG_EDI = 4
799 + #endif
800 + #if defined(__x86_64__)
801 +        X86_REG_R8  = 0,
802 +        X86_REG_R9  = 1,
803 +        X86_REG_R10 = 2,
804 +        X86_REG_R11 = 3,
805 +        X86_REG_R12 = 4,
806 +        X86_REG_R13 = 5,
807 +        X86_REG_R14 = 6,
808 +        X86_REG_R15 = 7,
809 +        X86_REG_EDI = 8,
810 +        X86_REG_ESI = 9,
811 +        X86_REG_EBP = 10,
812 +        X86_REG_EBX = 11,
813 +        X86_REG_EDX = 12,
814 +        X86_REG_EAX = 13,
815 +        X86_REG_ECX = 14,
816 +        X86_REG_ESP = 15,
817 +        X86_REG_EIP = 16
818 + #endif
819 + };
820 + #endif
821 + #if defined(__NetBSD__)
822 + enum {
823 + #if (defined(i386) || defined(__i386__))
824 +        X86_REG_EIP = _REG_EIP,
825 +        X86_REG_EAX = _REG_EAX,
826 +        X86_REG_ECX = _REG_ECX,
827 +        X86_REG_EDX = _REG_EDX,
828 +        X86_REG_EBX = _REG_EBX,
829 +        X86_REG_ESP = _REG_ESP,
830 +        X86_REG_EBP = _REG_EBP,
831 +        X86_REG_ESI = _REG_ESI,
832 +        X86_REG_EDI = _REG_EDI
833 + #endif
834 + };
835 + #endif
836 + #if defined(__FreeBSD__)
837 + enum {
838 + #if (defined(i386) || defined(__i386__))
839 +        X86_REG_EIP = 10,
840 +        X86_REG_EAX = 7,
841 +        X86_REG_ECX = 6,
842 +        X86_REG_EDX = 5,
843 +        X86_REG_EBX = 4,
844 +        X86_REG_ESP = 13,
845 +        X86_REG_EBP = 2,
846 +        X86_REG_ESI = 1,
847 +        X86_REG_EDI = 0
848 + #endif
849 + };
850 + #endif
851 + #if defined(__OpenBSD__)
852 + enum {
853 + #if defined(__i386__)
854 +        // EDI is the first register we consider
855 + #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
856 + #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
857 +        X86_REG_EIP = DREG(eip), // 7
858 +        X86_REG_EAX = DREG(eax), // 6
859 +        X86_REG_ECX = DREG(ecx), // 5
860 +        X86_REG_EDX = DREG(edx), // 4
861 +        X86_REG_EBX = DREG(ebx), // 3
862 +        X86_REG_ESP = DREG(esp), // 10
863 +        X86_REG_EBP = DREG(ebp), // 2
864 +        X86_REG_ESI = DREG(esi), // 1
865 +        X86_REG_EDI = DREG(edi)  // 0
866 + #undef DREG
867 + #undef OREG
868 + #endif
869 + };
870 + #endif
871 + #if defined(__sun__)
872 + // Same as for Linux, need to check for x86-64
873 + enum {
874 + #if defined(__i386__)
875 +        X86_REG_EIP = EIP,
876 +        X86_REG_EAX = EAX,
877 +        X86_REG_ECX = ECX,
878 +        X86_REG_EDX = EDX,
879 +        X86_REG_EBX = EBX,
880 +        X86_REG_ESP = ESP,
881 +        X86_REG_EBP = EBP,
882 +        X86_REG_ESI = ESI,
883 +        X86_REG_EDI = EDI
884 + #endif
885 + };
886 + #endif
887 + #if defined(__APPLE__) && defined(__MACH__)
888 + enum {
889 + #if (defined(i386) || defined(__i386__))
890 + #ifdef i386_SAVED_STATE
891 +        // same as FreeBSD (in Open Darwin 8.0.1)
892 +        X86_REG_EIP = 10,
893 +        X86_REG_EAX = 7,
894 +        X86_REG_ECX = 6,
895 +        X86_REG_EDX = 5,
896 +        X86_REG_EBX = 4,
897 +        X86_REG_ESP = 13,
898 +        X86_REG_EBP = 2,
899 +        X86_REG_ESI = 1,
900 +        X86_REG_EDI = 0
901 + #else
902 +        // new layout (MacOS X 10.4.4 for x86)
903 +        X86_REG_EIP = 10,
904 +        X86_REG_EAX = 0,
905 +        X86_REG_ECX = 2,
906 +        X86_REG_EDX = 3,
907 +        X86_REG_EBX = 1,
908 +        X86_REG_ESP = 7,
909 +        X86_REG_EBP = 6,
910 +        X86_REG_ESI = 5,
911 +        X86_REG_EDI = 4
912 + #endif
913 + #endif
914 + #if defined(__x86_64__)
915 +        X86_REG_R8  = 8,
916 +        X86_REG_R9  = 9,
917 +        X86_REG_R10 = 10,
918 +        X86_REG_R11 = 11,
919 +        X86_REG_R12 = 12,
920 +        X86_REG_R13 = 13,
921 +        X86_REG_R14 = 14,
922 +        X86_REG_R15 = 15,
923 +        X86_REG_EDI = 4,
924 +        X86_REG_ESI = 5,
925 +        X86_REG_EBP = 6,
926 +        X86_REG_EBX = 1,
927 +        X86_REG_EDX = 3,
928 +        X86_REG_EAX = 0,
929 +        X86_REG_ECX = 2,
930 +        X86_REG_ESP = 7,
931 +        X86_REG_EIP = 16
932 + #endif
933 + };
934 + #endif
935 + #if defined(_WIN32)
936 + enum {
937 + #if defined(_M_IX86)
938 +        X86_REG_EIP = 7,
939 +        X86_REG_EAX = 5,
940 +        X86_REG_ECX = 4,
941 +        X86_REG_EDX = 3,
942 +        X86_REG_EBX = 2,
943 +        X86_REG_ESP = 10,
944 +        X86_REG_EBP = 6,
945 +        X86_REG_ESI = 1,
946 +        X86_REG_EDI = 0
947 + #endif
948 + #if defined(_M_X64)
949 +        X86_REG_EAX = 0,
950 +        X86_REG_ECX = 1,
951 +        X86_REG_EDX = 2,
952 +        X86_REG_EBX = 3,
953 +        X86_REG_ESP = 4,
954 +        X86_REG_EBP = 5,
955 +        X86_REG_ESI = 6,
956 +        X86_REG_EDI = 7,
957 +        X86_REG_R8  = 8,
958 +        X86_REG_R9  = 9,
959 +        X86_REG_R10 = 10,
960 +        X86_REG_R11 = 11,
961 +        X86_REG_R12 = 12,
962 +        X86_REG_R13 = 13,
963 +        X86_REG_R14 = 14,
964 +        X86_REG_R15 = 15,
965 +        X86_REG_EIP = 16
966 + #endif
967 + };
968 + #endif
969 + // FIXME: this is partly redundant with the instruction decoding phase
970 + // to discover transfer type and register number
971 + static inline int ix86_step_over_modrm(unsigned char * p)
972 + {
973 +        int mod = (p[0] >> 6) & 3;
974 +        int rm = p[0] & 7;
975 +        int offset = 0;
976 +
977 +        // ModR/M Byte
978 +        switch (mod) {
979 +        case 0: // [reg]
980 +                if (rm == 5) return 4; // disp32
981 +                break;
982 +        case 1: // disp8[reg]
983 +                offset = 1;
984 +                break;
985 +        case 2: // disp32[reg]
986 +                offset = 4;
987 +                break;
988 +        case 3: // register
989 +                return 0;
990 +        }
991 +        
992 +        // SIB Byte
993 +        if (rm == 4) {
994 +                if (mod == 0 && (p[1] & 7) == 5)
995 +                        offset = 5; // disp32[index]
996 +                else
997 +                        offset++;
998 +        }
999 +
1000 +        return offset;
1001 + }
1002 +
1003 + static bool ix86_skip_instruction(SIGSEGV_REGISTER_TYPE * regs)
1004 + {
1005 +        unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
1006 +
1007 +        if (eip == 0)
1008 +                return false;
1009 + #ifdef _WIN32
1010 +        if (IsBadCodePtr((FARPROC)eip))
1011 +                return false;
1012 + #endif
1013 +        
1014 +        enum instruction_type_t {
1015 +                i_MOV,
1016 +                i_ADD
1017 +        };
1018 +
1019 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1020 +        transfer_size_t transfer_size = SIZE_LONG;
1021 +        instruction_type_t instruction_type = i_MOV;
1022 +        
1023 +        int reg = -1;
1024 +        int len = 0;
1025 +
1026 + #if DEBUG
1027 +        printf("IP: %p [%02x %02x %02x %02x...]\n",
1028 +                   eip, eip[0], eip[1], eip[2], eip[3]);
1029 + #endif
1030 +
1031 +        // Operand size prefix
1032 +        if (*eip == 0x66) {
1033 +                eip++;
1034 +                len++;
1035 +                transfer_size = SIZE_WORD;
1036 +        }
1037 +
1038 +        // REX prefix
1039 + #if defined(__x86_64__) || defined(_M_X64)
1040 +        struct rex_t {
1041 +                unsigned char W;
1042 +                unsigned char R;
1043 +                unsigned char X;
1044 +                unsigned char B;
1045 +        };
1046 +        rex_t rex = { 0, 0, 0, 0 };
1047 +        bool has_rex = false;
1048 +        if ((*eip & 0xf0) == 0x40) {
1049 +                has_rex = true;
1050 +                const unsigned char b = *eip;
1051 +                rex.W = b & (1 << 3);
1052 +                rex.R = b & (1 << 2);
1053 +                rex.X = b & (1 << 1);
1054 +                rex.B = b & (1 << 0);
1055 + #if DEBUG
1056 +                printf("REX: %c,%c,%c,%c\n",
1057 +                           rex.W ? 'W' : '_',
1058 +                           rex.R ? 'R' : '_',
1059 +                           rex.X ? 'X' : '_',
1060 +                           rex.B ? 'B' : '_');
1061 + #endif
1062 +                eip++;
1063 +                len++;
1064 +                if (rex.W)
1065 +                        transfer_size = SIZE_QUAD;
1066 +        }
1067 + #else
1068 +        const bool has_rex = false;
1069 + #endif
1070 +
1071 +        // Decode instruction
1072 +        int op_len = 1;
1073 +        int target_size = SIZE_UNKNOWN;
1074 +        switch (eip[0]) {
1075 +        case 0x0f:
1076 +                target_size = transfer_size;
1077 +            switch (eip[1]) {
1078 +                case 0xbe: // MOVSX r32, r/m8
1079 +            case 0xb6: // MOVZX r32, r/m8
1080 +                        transfer_size = SIZE_BYTE;
1081 +                        goto do_mov_extend;
1082 +                case 0xbf: // MOVSX r32, r/m16
1083 +            case 0xb7: // MOVZX r32, r/m16
1084 +                        transfer_size = SIZE_WORD;
1085 +                        goto do_mov_extend;
1086 +                  do_mov_extend:
1087 +                        op_len = 2;
1088 +                        goto do_transfer_load;
1089 +                }
1090 +                break;
1091 + #if defined(__x86_64__) || defined(_M_X64)
1092 +        case 0x63: // MOVSXD r64, r/m32
1093 +                if (has_rex && rex.W) {
1094 +                        transfer_size = SIZE_LONG;
1095 +                        target_size = SIZE_QUAD;
1096 +                }
1097 +                else if (transfer_size != SIZE_WORD) {
1098 +                        transfer_size = SIZE_LONG;
1099 +                        target_size = SIZE_QUAD;
1100 +                }
1101 +                goto do_transfer_load;
1102 + #endif
1103 +        case 0x02: // ADD r8, r/m8
1104 +                transfer_size = SIZE_BYTE;
1105 +        case 0x03: // ADD r32, r/m32
1106 +                instruction_type = i_ADD;
1107 +                goto do_transfer_load;
1108 +        case 0x8a: // MOV r8, r/m8
1109 +                transfer_size = SIZE_BYTE;
1110 +        case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1111 +          do_transfer_load:
1112 +                switch (eip[op_len] & 0xc0) {
1113 +                case 0x80:
1114 +                        reg = (eip[op_len] >> 3) & 7;
1115 +                        transfer_type = SIGSEGV_TRANSFER_LOAD;
1116 +                        break;
1117 +                case 0x40:
1118 +                        reg = (eip[op_len] >> 3) & 7;
1119 +                        transfer_type = SIGSEGV_TRANSFER_LOAD;
1120 +                        break;
1121 +                case 0x00:
1122 +                        reg = (eip[op_len] >> 3) & 7;
1123 +                        transfer_type = SIGSEGV_TRANSFER_LOAD;
1124 +                        break;
1125 +                }
1126 +                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1127 +                break;
1128 +        case 0x00: // ADD r/m8, r8
1129 +                transfer_size = SIZE_BYTE;
1130 +        case 0x01: // ADD r/m32, r32
1131 +                instruction_type = i_ADD;
1132 +                goto do_transfer_store;
1133 +        case 0x88: // MOV r/m8, r8
1134 +                transfer_size = SIZE_BYTE;
1135 +        case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1136 +          do_transfer_store:
1137 +                switch (eip[op_len] & 0xc0) {
1138 +                case 0x80:
1139 +                        reg = (eip[op_len] >> 3) & 7;
1140 +                        transfer_type = SIGSEGV_TRANSFER_STORE;
1141 +                        break;
1142 +                case 0x40:
1143 +                        reg = (eip[op_len] >> 3) & 7;
1144 +                        transfer_type = SIGSEGV_TRANSFER_STORE;
1145 +                        break;
1146 +                case 0x00:
1147 +                        reg = (eip[op_len] >> 3) & 7;
1148 +                        transfer_type = SIGSEGV_TRANSFER_STORE;
1149 +                        break;
1150 +                }
1151 +                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1152 +                break;
1153 +        }
1154 +        if (target_size == SIZE_UNKNOWN)
1155 +                target_size = transfer_size;
1156 +
1157 +        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1158 +                // Unknown machine code, let it crash. Then patch the decoder
1159 +                return false;
1160 +        }
1161 +
1162 + #if defined(__x86_64__) || defined(_M_X64)
1163 +        if (rex.R)
1164 +                reg += 8;
1165 + #endif
1166 +
1167 +        if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1168 +                static const int x86_reg_map[] = {
1169 +                        X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1170 +                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1171 + #if defined(__x86_64__) || defined(_M_X64)
1172 +                        X86_REG_R8,  X86_REG_R9,  X86_REG_R10, X86_REG_R11,
1173 +                        X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1174 + #endif
1175 +                };
1176 +                
1177 +                if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1178 +                        return false;
1179 +
1180 +                // Set 0 to the relevant register part
1181 +                // NOTE: this is only valid for MOV alike instructions
1182 +                int rloc = x86_reg_map[reg];
1183 +                switch (target_size) {
1184 +                case SIZE_BYTE:
1185 +                        if (has_rex || reg < 4)
1186 +                                regs[rloc] = (regs[rloc] & ~0x00ffL);
1187 +                        else {
1188 +                                rloc = x86_reg_map[reg - 4];
1189 +                                regs[rloc] = (regs[rloc] & ~0xff00L);
1190 +                        }
1191 +                        break;
1192 +                case SIZE_WORD:
1193 +                        regs[rloc] = (regs[rloc] & ~0xffffL);
1194 +                        break;
1195 +                case SIZE_LONG:
1196 +                case SIZE_QUAD: // zero-extension
1197 +                        regs[rloc] = 0;
1198 +                        break;
1199 +                }
1200 +        }
1201 +
1202 + #if DEBUG
1203 +        printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1204 +                   transfer_size == SIZE_BYTE ? "byte" :
1205 +                   transfer_size == SIZE_WORD ? "word" :
1206 +                   transfer_size == SIZE_LONG ? "long" :
1207 +                   transfer_size == SIZE_QUAD ? "quad" : "unknown",
1208 +                   transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1209 +        
1210 +        if (reg != -1) {
1211 +                static const char * x86_byte_reg_str_map[] = {
1212 +                        "al",   "cl",   "dl",   "bl",
1213 +                        "spl",  "bpl",  "sil",  "dil",
1214 +                        "r8b",  "r9b",  "r10b", "r11b",
1215 +                        "r12b", "r13b", "r14b", "r15b",
1216 +                        "ah",   "ch",   "dh",   "bh",
1217 +                };
1218 +                static const char * x86_word_reg_str_map[] = {
1219 +                        "ax",   "cx",   "dx",   "bx",
1220 +                        "sp",   "bp",   "si",   "di",
1221 +                        "r8w",  "r9w",  "r10w", "r11w",
1222 +                        "r12w", "r13w", "r14w", "r15w",
1223 +                };
1224 +                static const char *x86_long_reg_str_map[] = {
1225 +                        "eax",  "ecx",  "edx",  "ebx",
1226 +                        "esp",  "ebp",  "esi",  "edi",
1227 +                        "r8d",  "r9d",  "r10d", "r11d",
1228 +                        "r12d", "r13d", "r14d", "r15d",
1229 +                };
1230 +                static const char *x86_quad_reg_str_map[] = {
1231 +                        "rax", "rcx", "rdx", "rbx",
1232 +                        "rsp", "rbp", "rsi", "rdi",
1233 +                        "r8",  "r9",  "r10", "r11",
1234 +                        "r12", "r13", "r14", "r15",
1235 +                };
1236 +                const char * reg_str = NULL;
1237 +                switch (target_size) {
1238 +                case SIZE_BYTE:
1239 +                        reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1240 +                        break;
1241 +                case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1242 +                case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1243 +                case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1244 +                }
1245 +                if (reg_str)
1246 +                        printf(" %s register %%%s",
1247 +                                   transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1248 +                                   reg_str);
1249 +        }
1250 +        printf(", %d bytes instruction\n", len);
1251 + #endif
1252 +        
1253 +        regs[X86_REG_EIP] += len;
1254 +        return true;
1255 + }
1256 + #endif
1257 +
1258 + // Decode and skip IA-64 instruction
1259 + #if defined(__ia64) || defined(__ia64__)
1260 + typedef uint64_t ia64_bundle_t[2];
1261 + #if defined(__linux__)
1262 + // We can directly patch the slot number
1263 + #define IA64_CAN_PATCH_IP_SLOT  1
1264 + // Helper macros to access the machine context
1265 + #define IA64_CONTEXT_TYPE               struct sigcontext *
1266 + #define IA64_CONTEXT                    scp
1267 + #define IA64_GET_IP()                   (IA64_CONTEXT->sc_ip)
1268 + #define IA64_SET_IP(V)                  (IA64_CONTEXT->sc_ip = (V))
1269 + #define IA64_GET_PR(P)                  ((IA64_CONTEXT->sc_pr >> (P)) & 1)
1270 + #define IA64_GET_NAT(I)                 ((IA64_CONTEXT->sc_nat >> (I)) & 1)
1271 + #define IA64_GET_GR(R)                  (IA64_CONTEXT->sc_gr[(R)])
1272 + #define _IA64_SET_GR(R,V)               (IA64_CONTEXT->sc_gr[(R)] = (V))
1273 + #define _IA64_SET_NAT(I,V)              (IA64_CONTEXT->sc_nat = (IA64_CONTEXT->sc_nat & ~(1ull << (I))) | (((uint64_t)!!(V)) << (I)))
1274 + #define IA64_SET_GR(R,V,N)              (_IA64_SET_GR(R,V), _IA64_SET_NAT(R,N))
1275 +
1276 + // Load bundle (in little-endian)
1277 + static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1278 + {
1279 +        uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1280 +        bundle[0] = ip[0];
1281 +        bundle[1] = ip[1];
1282 + }
1283 + #endif
1284 + #if defined(__hpux) || defined(__hpux__)
1285 + // We can directly patch the slot number
1286 + #define IA64_CAN_PATCH_IP_SLOT  1
1287 + // Helper macros to access the machine context
1288 + #define IA64_CONTEXT_TYPE               ucontext_t *
1289 + #define IA64_CONTEXT                    ucp
1290 + #define IA64_GET_IP()                   ia64_get_ip(IA64_CONTEXT)
1291 + #define IA64_SET_IP(V)                  ia64_set_ip(IA64_CONTEXT, V)
1292 + #define IA64_GET_PR(P)                  ia64_get_pr(IA64_CONTEXT, P)
1293 + #define IA64_GET_NAT(I)                 ia64_get_nat(IA64_CONTEXT, I)
1294 + #define IA64_GET_GR(R)                  ia64_get_gr(IA64_CONTEXT, R)
1295 + #define IA64_SET_GR(R,V,N)              ia64_set_gr(IA64_CONTEXT, R, V, N)
1296 + #define UC_ACCESS(FUNC,ARGS)    do { if (__uc_##FUNC ARGS != 0) abort(); } while (0)
1297 +
1298 + static inline uint64_t ia64_get_ip(IA64_CONTEXT_TYPE IA64_CONTEXT)
1299 +        { uint64_t v; UC_ACCESS(get_ip,(IA64_CONTEXT, &v)); return v; }
1300 + static inline void ia64_set_ip(IA64_CONTEXT_TYPE IA64_CONTEXT, uint64_t v)
1301 +        { UC_ACCESS(set_ip,(IA64_CONTEXT, v)); }
1302 + static inline unsigned int ia64_get_pr(IA64_CONTEXT_TYPE IA64_CONTEXT, int pr)
1303 +        { uint64_t v; UC_ACCESS(get_prs,(IA64_CONTEXT, &v)); return (v >> pr) & 1; }
1304 + static inline unsigned int ia64_get_nat(IA64_CONTEXT_TYPE IA64_CONTEXT, int r)
1305 +        { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return (nat >> r) & 1; }
1306 + static inline uint64_t ia64_get_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r)
1307 +        { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return v; }
1308 +
1309 + static void ia64_set_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r, uint64_t v, unsigned int nat)
1310 + {
1311 +        if (r == 0)
1312 +                return;
1313 +        if (r > 0 && r < 32)
1314 +                UC_ACCESS(set_grs,(IA64_CONTEXT, r, 1, &v, (!!nat) << r));
1315 +        else {
1316 +                uint64_t bsp, bspstore;
1317 +                UC_ACCESS(get_ar_bsp,(IA64_CONTEXT, &bsp));
1318 +                UC_ACCESS(get_ar_bspstore,(IA64_CONTEXT, &bspstore));
1319 +                abort(); /* XXX: use libunwind, this is not fun... */
1320 +        }
1321 + }
1322 +
1323 + // Byte-swapping
1324 + #if defined(__GNUC__)
1325 + #define BSWAP64(V) ({ uint64_t r; __asm__ __volatile__("mux1 %0=%1,@rev;;" : "=r" (r) : "r" (V)); r; })
1326 + #elif defined (__HP_aCC)
1327 + #define BSWAP64(V) _Asm_mux1(_MBTYPE_REV, V)
1328 + #else
1329 + #error "Define byte-swap instruction"
1330 + #endif
1331 +
1332 + // Load bundle (in little-endian)
1333 + static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1334 + {
1335 +        uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1336 +        bundle[0] = BSWAP64(ip[0]);
1337 +        bundle[1] = BSWAP64(ip[1]);
1338 + }
1339 + #endif
1340 +
1341 + // Instruction operations
1342 + enum {
1343 +        IA64_INST_UNKNOWN = 0,
1344 +        IA64_INST_LD1,                          // ld1 op0=[op1]
1345 +        IA64_INST_LD1_UPDATE,           // ld1 op0=[op1],op2
1346 +        IA64_INST_LD2,                          // ld2 op0=[op1]
1347 +        IA64_INST_LD2_UPDATE,           // ld2 op0=[op1],op2
1348 +        IA64_INST_LD4,                          // ld4 op0=[op1]
1349 +        IA64_INST_LD4_UPDATE,           // ld4 op0=[op1],op2
1350 +        IA64_INST_LD8,                          // ld8 op0=[op1]
1351 +        IA64_INST_LD8_UPDATE,           // ld8 op0=[op1],op2
1352 +        IA64_INST_ST1,                          // st1 [op0]=op1
1353 +        IA64_INST_ST1_UPDATE,           // st1 [op0]=op1,op2
1354 +        IA64_INST_ST2,                          // st2 [op0]=op1
1355 +        IA64_INST_ST2_UPDATE,           // st2 [op0]=op1,op2
1356 +        IA64_INST_ST4,                          // st4 [op0]=op1
1357 +        IA64_INST_ST4_UPDATE,           // st4 [op0]=op1,op2
1358 +        IA64_INST_ST8,                          // st8 [op0]=op1
1359 +        IA64_INST_ST8_UPDATE,           // st8 [op0]=op1,op2
1360 +        IA64_INST_ADD,                          // add op0=op1,op2,op3
1361 +        IA64_INST_SUB,                          // sub op0=op1,op2,op3
1362 +        IA64_INST_SHLADD,                       // shladd op0=op1,op3,op2
1363 +        IA64_INST_AND,                          // and op0=op1,op2
1364 +        IA64_INST_ANDCM,                        // andcm op0=op1,op2
1365 +        IA64_INST_OR,                           // or op0=op1,op2
1366 +        IA64_INST_XOR,                          // xor op0=op1,op2
1367 +        IA64_INST_SXT1,                         // sxt1 op0=op1
1368 +        IA64_INST_SXT2,                         // sxt2 op0=op1
1369 +        IA64_INST_SXT4,                         // sxt4 op0=op1
1370 +        IA64_INST_ZXT1,                         // zxt1 op0=op1
1371 +        IA64_INST_ZXT2,                         // zxt2 op0=op1
1372 +        IA64_INST_ZXT4,                         // zxt4 op0=op1
1373 +        IA64_INST_NOP                           // nop op0
1374 + };
1375 +
1376 + const int IA64_N_OPERANDS = 4;
1377 +
1378 + // Decoded operand type
1379 + struct ia64_operand_t {
1380 +        uint8_t commit;                         // commit result of operation to register file?
1381 +        uint8_t valid;                          // XXX: not really used, can be removed (debug)
1382 +        int8_t index;                           // index of GPR, or -1 if immediate value
1383 +        uint8_t nat;                            // NaT state before operation
1384 +        uint64_t value;                         // register contents or immediate value
1385 + };
1386 +
1387 + // Decoded instruction type
1388 + struct ia64_instruction_t {
1389 +        uint8_t mnemo;                          // operation to perform
1390 +        uint8_t pred;                           // predicate register to check
1391 +        uint8_t no_memory;                      // used to emulated main fault instruction
1392 +        uint64_t inst;                          // the raw instruction bits (41-bit wide)
1393 +        ia64_operand_t operands[IA64_N_OPERANDS];
1394 + };
1395 +
1396 + // Get immediate sign-bit
1397 + static inline int ia64_inst_get_sbit(uint64_t inst)
1398 + {
1399 +        return (inst >> 36) & 1;
1400 + }
1401 +
1402 + // Get 8-bit immediate value (A3, A8, I27, M30)
1403 + static inline uint64_t ia64_inst_get_imm8(uint64_t inst)
1404 + {
1405 +        uint64_t value = (inst >> 13) & 0x7full;
1406 +        if (ia64_inst_get_sbit(inst))
1407 +                value |= ~0x7full;
1408 +        return value;
1409 + }
1410 +
1411 + // Get 9-bit immediate value (M3)
1412 + static inline uint64_t ia64_inst_get_imm9b(uint64_t inst)
1413 + {
1414 +        uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1415 +        if (ia64_inst_get_sbit(inst))
1416 +                value |= ~0xffull;
1417 +        return value;
1418 + }
1419 +
1420 + // Get 9-bit immediate value (M5)
1421 + static inline uint64_t ia64_inst_get_imm9a(uint64_t inst)
1422 + {
1423 +        uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1424 +        if (ia64_inst_get_sbit(inst))
1425 +                value |= ~0xffull;
1426 +        return value;
1427 + }
1428 +
1429 + // Get 14-bit immediate value (A4)
1430 + static inline uint64_t ia64_inst_get_imm14(uint64_t inst)
1431 + {
1432 +        uint64_t value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1433 +        if (ia64_inst_get_sbit(inst))
1434 +                value |= ~0x1ffull;
1435 +        return value;
1436 + }
1437 +
1438 + // Get 22-bit immediate value (A5)
1439 + static inline uint64_t ia64_inst_get_imm22(uint64_t inst)
1440 + {
1441 +        uint64_t value = ((((inst >> 22) & 0x1f) << 16) |
1442 +                                          (((inst >> 27) & 0x1ff) << 7) |
1443 +                                          (inst & 0x7f));
1444 +        if (ia64_inst_get_sbit(inst))
1445 +                value |= ~0x1fffffull;
1446 +        return value;
1447 + }
1448 +
1449 + // Get 21-bit immediate value (I19)
1450 + static inline uint64_t ia64_inst_get_imm21(uint64_t inst)
1451 + {
1452 +        return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1453 + }
1454 +
1455 + // Get 2-bit count value (A2)
1456 + static inline int ia64_inst_get_count2(uint64_t inst)
1457 + {
1458 +        return (inst >> 27) & 0x3;
1459 + }
1460 +
1461 + // Get bundle template
1462 + static inline unsigned int ia64_get_template(uint64_t ip)
1463 + {
1464 +        ia64_bundle_t bundle;
1465 +        ia64_load_bundle(bundle, ip);
1466 +        return bundle[0] & 0x1f;
1467 + }
1468 +
1469 + // Get specified instruction in bundle
1470 + static uint64_t ia64_get_instruction(uint64_t ip, int slot)
1471 + {
1472 +        uint64_t inst;
1473 +        ia64_bundle_t bundle;
1474 +        ia64_load_bundle(bundle, ip);
1475 + #if DEBUG
1476 +        printf("Bundle: %016llx%016llx\n", bundle[1], bundle[0]);
1477 + #endif
1478 +
1479 +        switch (slot) {
1480 +        case 0:
1481 +                inst = (bundle[0] >> 5) & 0x1ffffffffffull;
1482 +                break;
1483 +        case 1:
1484 +                inst = ((bundle[1] & 0x7fffffull) << 18) | ((bundle[0] >> 46) & 0x3ffffull);
1485 +                break;
1486 +        case 2:
1487 +                inst = (bundle[1] >> 23) & 0x1ffffffffffull;
1488 +                break;
1489 +        case 3:
1490 +                fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1491 +                abort();
1492 +                break;
1493 +        }
1494 +
1495 + #if DEBUG
1496 +        printf(" Instruction %d: 0x%016llx\n", slot, inst);
1497 + #endif
1498 +        return inst;
1499 + }
1500 +
1501 + // Decode group 0 instructions
1502 + static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1503 + {
1504 +        const int r1 = (inst->inst >>  6) & 0x7f;
1505 +        const int r3 = (inst->inst >> 20) & 0x7f;
1506 +
1507 +        const int x3 = (inst->inst >> 33) & 0x07;
1508 +        const int x6 = (inst->inst >> 27) & 0x3f;
1509 +        const int x2 = (inst->inst >> 31) & 0x03;
1510 +        const int x4 = (inst->inst >> 27) & 0x0f;
1511 +
1512 +        if (x3 == 0) {
1513 +                switch (x6) {
1514 +                case 0x01:                                              // nop.i (I19)
1515 +                        inst->mnemo = IA64_INST_NOP;
1516 +                        inst->operands[0].valid = true;
1517 +                        inst->operands[0].index = -1;
1518 +                        inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1519 +                        return true;
1520 +                case 0x14:                                              // sxt1 (I29)
1521 +                case 0x15:                                              // sxt2 (I29)
1522 +                case 0x16:                                              // sxt4 (I29)
1523 +                case 0x10:                                              // zxt1 (I29)
1524 +                case 0x11:                                              // zxt2 (I29)
1525 +                case 0x12:                                              // zxt4 (I29)
1526 +                        switch (x6) {
1527 +                        case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1528 +                        case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1529 +                        case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1530 +                        case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1531 +                        case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1532 +                        case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1533 +                        default: abort();
1534 +                        }
1535 +                        inst->operands[0].valid = true;
1536 +                        inst->operands[0].index = r1;
1537 +                        inst->operands[1].valid = true;
1538 +                        inst->operands[1].index = r3;
1539 +                        inst->operands[1].value = IA64_GET_GR(r3);
1540 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1541 +                        return true;
1542 +                }
1543 +        }
1544 +        return false;
1545 + }
1546 +
1547 + // Decode group 4 instructions (load/store instructions)
1548 + static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1549 + {
1550 +        const int r1 = (inst->inst >> 6) & 0x7f;
1551 +        const int r2 = (inst->inst >> 13) & 0x7f;
1552 +        const int r3 = (inst->inst >> 20) & 0x7f;
1553 +
1554 +        const int m  = (inst->inst >> 36) & 1;
1555 +        const int x  = (inst->inst >> 27) & 1;
1556 +        const int x6 = (inst->inst >> 30) & 0x3f;
1557 +
1558 +        switch (x6) {
1559 +        case 0x00:
1560 +        case 0x01:
1561 +        case 0x02:
1562 +        case 0x03:
1563 +                if (x == 0) {
1564 +                        inst->operands[0].valid = true;
1565 +                        inst->operands[0].index = r1;
1566 +                        inst->operands[1].valid = true;
1567 +                        inst->operands[1].index = r3;
1568 +                        inst->operands[1].value = IA64_GET_GR(r3);
1569 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1570 +                        if (m == 0) {
1571 +                                switch (x6) {
1572 +                                case 0x00: inst->mnemo = IA64_INST_LD1; break;
1573 +                                case 0x01: inst->mnemo = IA64_INST_LD2; break;
1574 +                                case 0x02: inst->mnemo = IA64_INST_LD4; break;
1575 +                                case 0x03: inst->mnemo = IA64_INST_LD8; break;
1576 +                                }
1577 +                        }
1578 +                        else {
1579 +                                inst->operands[2].valid = true;
1580 +                                inst->operands[2].index = r2;
1581 +                                inst->operands[2].value = IA64_GET_GR(r2);
1582 +                                inst->operands[2].nat   = IA64_GET_NAT(r2);
1583 +                                switch (x6) {
1584 +                                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1585 +                                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1586 +                                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1587 +                                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1588 +                                }
1589 +                        }
1590 +                        return true;
1591 +                }
1592 +                break;
1593 +        case 0x30:
1594 +        case 0x31:
1595 +        case 0x32:
1596 +        case 0x33:
1597 +                if (m == 0 && x == 0) {
1598 +                        inst->operands[0].valid = true;
1599 +                        inst->operands[0].index = r3;
1600 +                        inst->operands[0].value = IA64_GET_GR(r3);
1601 +                        inst->operands[0].nat   = IA64_GET_NAT(r3);
1602 +                        inst->operands[1].valid = true;
1603 +                        inst->operands[1].index = r2;
1604 +                        inst->operands[1].value = IA64_GET_GR(r2);
1605 +                        inst->operands[1].nat   = IA64_GET_NAT(r2);
1606 +                        switch (x6) {
1607 +                        case 0x30: inst->mnemo = IA64_INST_ST1; break;
1608 +                        case 0x31: inst->mnemo = IA64_INST_ST2; break;
1609 +                        case 0x32: inst->mnemo = IA64_INST_ST4; break;
1610 +                        case 0x33: inst->mnemo = IA64_INST_ST8; break;
1611 +                        }
1612 +                        return true;
1613 +                }
1614 +                break;
1615 +        }
1616 +        return false;
1617 + }
1618 +
1619 + // Decode group 5 instructions (load/store instructions)
1620 + static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1621 + {
1622 +        const int r1 = (inst->inst >> 6) & 0x7f;
1623 +        const int r2 = (inst->inst >> 13) & 0x7f;
1624 +        const int r3 = (inst->inst >> 20) & 0x7f;
1625 +
1626 +        const int x6 = (inst->inst >> 30) & 0x3f;
1627 +
1628 +        switch (x6) {
1629 +        case 0x00:
1630 +        case 0x01:
1631 +        case 0x02:
1632 +        case 0x03:
1633 +                inst->operands[0].valid = true;
1634 +                inst->operands[0].index = r1;
1635 +                inst->operands[1].valid = true;
1636 +                inst->operands[1].index = r3;
1637 +                inst->operands[1].value = IA64_GET_GR(r3);
1638 +                inst->operands[1].nat   = IA64_GET_NAT(r3);
1639 +                inst->operands[2].valid = true;
1640 +                inst->operands[2].index = -1;
1641 +                inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1642 +                inst->operands[2].nat   = 0;
1643 +                switch (x6) {
1644 +                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1645 +                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1646 +                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1647 +                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1648 +                }
1649 +                return true;
1650 +        case 0x30:
1651 +        case 0x31:
1652 +        case 0x32:
1653 +        case 0x33:
1654 +                inst->operands[0].valid = true;
1655 +                inst->operands[0].index = r3;
1656 +                inst->operands[0].value = IA64_GET_GR(r3);
1657 +                inst->operands[0].nat   = IA64_GET_NAT(r3);
1658 +                inst->operands[1].valid = true;
1659 +                inst->operands[1].index = r2;
1660 +                inst->operands[1].value = IA64_GET_GR(r2);
1661 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1662 +                inst->operands[2].valid = true;
1663 +                inst->operands[2].index = -1;
1664 +                inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1665 +                inst->operands[2].nat   = 0;
1666 +                switch (x6) {
1667 +                case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1668 +                case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1669 +                case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1670 +                case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1671 +                }
1672 +                return true;
1673 +        }
1674 +        return false;
1675 + }
1676 +
1677 + // Decode group 8 instructions (ALU integer)
1678 + static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1679 + {
1680 +        const int r1  = (inst->inst >> 6) & 0x7f;
1681 +        const int r2  = (inst->inst >> 13) & 0x7f;
1682 +        const int r3  = (inst->inst >> 20) & 0x7f;
1683 +
1684 +        const int x2a = (inst->inst >> 34) & 0x3;
1685 +        const int x2b = (inst->inst >> 27) & 0x3;
1686 +        const int x4  = (inst->inst >> 29) & 0xf;
1687 +        const int ve  = (inst->inst >> 33) & 0x1;
1688 +
1689 +        // destination register (r1) is always valid in this group
1690 +        inst->operands[0].valid = true;
1691 +        inst->operands[0].index = r1;
1692 +
1693 +        // source register (r3) is always valid in this group
1694 +        inst->operands[2].valid = true;
1695 +        inst->operands[2].index = r3;
1696 +        inst->operands[2].value = IA64_GET_GR(r3);
1697 +        inst->operands[2].nat   = IA64_GET_NAT(r3);
1698 +
1699 +        if (x2a == 0 && ve == 0) {
1700 +                inst->operands[1].valid = true;
1701 +                inst->operands[1].index = r2;
1702 +                inst->operands[1].value = IA64_GET_GR(r2);
1703 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1704 +                switch (x4) {
1705 +                case 0x0:                               // add (A1)
1706 +                        inst->mnemo = IA64_INST_ADD;
1707 +                        inst->operands[3].valid = true;
1708 +                        inst->operands[3].index = -1;
1709 +                        inst->operands[3].value = x2b == 1;
1710 +                        return true;
1711 +                case 0x1:                               // add (A1)
1712 +                        inst->mnemo = IA64_INST_SUB;
1713 +                        inst->operands[3].valid = true;
1714 +                        inst->operands[3].index = -1;
1715 +                        inst->operands[3].value = x2b == 0;
1716 +                        return true;
1717 +                case 0x4:                               // shladd (A2)
1718 +                        inst->mnemo = IA64_INST_SHLADD;
1719 +                        inst->operands[3].valid = true;
1720 +                        inst->operands[3].index = -1;
1721 +                        inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1722 +                        return true;
1723 +                case 0x9:
1724 +                        if (x2b == 1) {
1725 +                                inst->mnemo = IA64_INST_SUB;
1726 +                                inst->operands[1].index = -1;
1727 +                                inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1728 +                                inst->operands[1].nat   = 0;
1729 +                                return true;
1730 +                        }
1731 +                        break;
1732 +                case 0xb:
1733 +                        inst->operands[1].index = -1;
1734 +                        inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1735 +                        inst->operands[1].nat   = 0;
1736 +                        // fall-through
1737 +                case 0x3:
1738 +                        switch (x2b) {
1739 +                        case 0: inst->mnemo = IA64_INST_AND;   break;
1740 +                        case 1: inst->mnemo = IA64_INST_ANDCM; break;
1741 +                        case 2: inst->mnemo = IA64_INST_OR;    break;
1742 +                        case 3: inst->mnemo = IA64_INST_XOR;   break;
1743 +                        }
1744 +                        return true;
1745 +                }
1746 +        }
1747 +        return false;
1748 + }
1749 +
1750 + // Decode instruction
1751 + static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1752 + {
1753 +        const int major = (inst->inst >> 37) & 0xf;
1754 +
1755 +        inst->mnemo = IA64_INST_UNKNOWN;
1756 +        inst->pred  = inst->inst & 0x3f;
1757 +        memset(&inst->operands[0], 0, sizeof(inst->operands));
1758 +
1759 +        switch (major) {
1760 +        case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT);
1761 +        case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT);
1762 +        case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT);
1763 +        case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT);
1764 +        }
1765 +        return false;
1766 + }
1767 +
1768 + static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1769 + {
1770 +        // XXX: handle Register NaT Consumption fault?
1771 +        // XXX: this simple emulator assumes instructions in a bundle
1772 +        // don't depend on effects of other instructions in the same
1773 +        // bundle. It probably would be simpler to JIT-generate code to be
1774 +        // executed natively but probably more costly (inject/extract CPU state)
1775 +        if (inst->mnemo == IA64_INST_UNKNOWN)
1776 +                return false;
1777 +        if (inst->pred && !IA64_GET_PR(inst->pred))
1778 +                return true;
1779 +
1780 +        uint8_t nat, nat2;
1781 +        uint64_t dst, dst2, src1, src2, src3;
1782 +
1783 +        switch (inst->mnemo) {
1784 +        case IA64_INST_NOP:
1785 +                break;
1786 +        case IA64_INST_ADD:
1787 +        case IA64_INST_SUB:
1788 +        case IA64_INST_SHLADD:
1789 +                src3 = inst->operands[3].value;
1790 +                // fall-through
1791 +        case IA64_INST_AND:
1792 +        case IA64_INST_ANDCM:
1793 +        case IA64_INST_OR:
1794 +        case IA64_INST_XOR:
1795 +                src1 = inst->operands[1].value;
1796 +                src2 = inst->operands[2].value;
1797 +                switch (inst->mnemo) {
1798 +                case IA64_INST_ADD:   dst = src1 + src2 + src3; break;
1799 +                case IA64_INST_SUB:   dst = src1 - src2 - src3; break;
1800 +                case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1801 +                case IA64_INST_AND:   dst = src1 & src2;                break;
1802 +                case IA64_INST_ANDCM: dst = src1 &~ src2;               break;
1803 +                case IA64_INST_OR:    dst = src1 | src2;                break;
1804 +                case IA64_INST_XOR:   dst = src1 ^ src2;                break;
1805 +                }
1806 +                inst->operands[0].commit = true;
1807 +                inst->operands[0].value  = dst;
1808 +                inst->operands[0].nat    = inst->operands[1].nat | inst->operands[2].nat;
1809 +                break;
1810 +        case IA64_INST_SXT1:
1811 +        case IA64_INST_SXT2:
1812 +        case IA64_INST_SXT4:
1813 +        case IA64_INST_ZXT1:
1814 +        case IA64_INST_ZXT2:
1815 +        case IA64_INST_ZXT4:
1816 +                src1 = inst->operands[1].value;
1817 +                switch (inst->mnemo) {
1818 +                case IA64_INST_SXT1: dst = (int64_t)(int8_t)src1;               break;
1819 +                case IA64_INST_SXT2: dst = (int64_t)(int16_t)src1;              break;
1820 +                case IA64_INST_SXT4: dst = (int64_t)(int32_t)src1;              break;
1821 +                case IA64_INST_ZXT1: dst = (uint8_t)src1;                               break;
1822 +                case IA64_INST_ZXT2: dst = (uint16_t)src1;                              break;
1823 +                case IA64_INST_ZXT4: dst = (uint32_t)src1;                              break;
1824 +                }
1825 +                inst->operands[0].commit = true;
1826 +                inst->operands[0].value  = dst;
1827 +                inst->operands[0].nat    = inst->operands[1].nat;
1828 +                break;
1829 +        case IA64_INST_LD1_UPDATE:
1830 +        case IA64_INST_LD2_UPDATE:
1831 +        case IA64_INST_LD4_UPDATE:
1832 +        case IA64_INST_LD8_UPDATE:
1833 +                inst->operands[1].commit = true;
1834 +                dst2 = inst->operands[1].value + inst->operands[2].value;
1835 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1836 +                // fall-through
1837 +        case IA64_INST_LD1:
1838 +        case IA64_INST_LD2:
1839 +        case IA64_INST_LD4:
1840 +        case IA64_INST_LD8:
1841 +                src1 = inst->operands[1].value;
1842 +                if (inst->no_memory)
1843 +                        dst = 0;
1844 +                else {
1845 +                        switch (inst->mnemo) {
1846 +                        case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((uint8_t *)src1);        break;
1847 +                        case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((uint16_t *)src1);       break;
1848 +                        case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((uint32_t *)src1);       break;
1849 +                        case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((uint64_t *)src1);       break;
1850 +                        }
1851 +                }
1852 +                inst->operands[0].commit = true;
1853 +                inst->operands[0].value  = dst;
1854 +                inst->operands[0].nat    = 0;
1855 +                inst->operands[1].value  = dst2;
1856 +                inst->operands[1].nat    = nat2;
1857 +                break;
1858 +        case IA64_INST_ST1_UPDATE:
1859 +        case IA64_INST_ST2_UPDATE:
1860 +        case IA64_INST_ST4_UPDATE:
1861 +        case IA64_INST_ST8_UPDATE:
1862 +                inst->operands[0].commit = 0;
1863 +                dst2 = inst->operands[0].value + inst->operands[2].value;
1864 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1865 +                // fall-through
1866 +        case IA64_INST_ST1:
1867 +        case IA64_INST_ST2:
1868 +        case IA64_INST_ST4:
1869 +        case IA64_INST_ST8:
1870 +                dst  = inst->operands[0].value;
1871 +                src1 = inst->operands[1].value;
1872 +                if (!inst->no_memory) {
1873 +                        switch (inst->mnemo) {
1874 +                        case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((uint8_t *)dst) = src1;        break;
1875 +                        case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((uint16_t *)dst) = src1;       break;
1876 +                        case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((uint32_t *)dst) = src1;       break;
1877 +                        case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((uint64_t *)dst) = src1;       break;
1878 +                        }
1879 +                }
1880 +                inst->operands[0].value  = dst2;
1881 +                inst->operands[0].nat    = nat2;
1882 +                break;
1883 +        default:
1884 +                return false;
1885 +        }
1886 +
1887 +        for (int i = 0; i < IA64_N_OPERANDS; i++) {
1888 +                ia64_operand_t const & op = inst->operands[i];
1889 +                if (!op.commit)
1890 +                        continue;
1891 +                if (op.index == -1)
1892 +                        return false; // XXX: internal error
1893 +                IA64_SET_GR(op.index, op.value, op.nat);
1894 +        }
1895 +        return true;
1896 + }
1897 +
1898 + static bool ia64_emulate_instruction(uint64_t raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1899 + {
1900 +        ia64_instruction_t inst;
1901 +        memset(&inst, 0, sizeof(inst));
1902 +        inst.inst = raw_inst;
1903 +        if (!ia64_decode_instruction(&inst, IA64_CONTEXT))
1904 +                return false;
1905 +        return ia64_emulate_instruction(&inst, IA64_CONTEXT);
1906 + }
1907 +
1908 + static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT)
1909 + {
1910 +        uint64_t ip = IA64_GET_IP();
1911 + #if DEBUG
1912 +        printf("IP: 0x%016llx\n", ip);
1913 + #if 0
1914 +        printf(" Template 0x%02x\n", ia64_get_template(ip));
1915 +        ia64_get_instruction(ip, 0);
1916 +        ia64_get_instruction(ip, 1);
1917 +        ia64_get_instruction(ip, 2);
1918 + #endif
1919 + #endif
1920 +
1921 +        // Select which decode switch to use
1922 +        ia64_instruction_t inst;
1923 +        inst.inst = ia64_get_instruction(ip, ip & 3);
1924 +        if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) {
1925 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1926 +                return false;
1927 +        }
1928 +
1929 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1930 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
1931 +
1932 +        switch (inst.mnemo) {
1933 +        case IA64_INST_LD1:
1934 +        case IA64_INST_LD2:
1935 +        case IA64_INST_LD4:
1936 +        case IA64_INST_LD8:
1937 +        case IA64_INST_LD1_UPDATE:
1938 +        case IA64_INST_LD2_UPDATE:
1939 +        case IA64_INST_LD4_UPDATE:
1940 +        case IA64_INST_LD8_UPDATE:
1941 +                transfer_type = SIGSEGV_TRANSFER_LOAD;
1942 +                break;
1943 +        case IA64_INST_ST1:
1944 +        case IA64_INST_ST2:
1945 +        case IA64_INST_ST4:
1946 +        case IA64_INST_ST8:
1947 +        case IA64_INST_ST1_UPDATE:
1948 +        case IA64_INST_ST2_UPDATE:
1949 +        case IA64_INST_ST4_UPDATE:
1950 +        case IA64_INST_ST8_UPDATE:
1951 +                transfer_type = SIGSEGV_TRANSFER_STORE;
1952 +                break;
1953 +        }
1954 +
1955 +        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1956 +                // Unknown machine code, let it crash. Then patch the decoder
1957 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1958 +                return false;
1959 +        }
1960 +
1961 +        switch (inst.mnemo) {
1962 +        case IA64_INST_LD1:
1963 +        case IA64_INST_LD1_UPDATE:
1964 +        case IA64_INST_ST1:
1965 +        case IA64_INST_ST1_UPDATE:
1966 +                transfer_size = SIZE_BYTE;
1967 +                break;
1968 +        case IA64_INST_LD2:
1969 +        case IA64_INST_LD2_UPDATE:
1970 +        case IA64_INST_ST2:
1971 +        case IA64_INST_ST2_UPDATE:
1972 +                transfer_size = SIZE_WORD;
1973 +                break;
1974 +        case IA64_INST_LD4:
1975 +        case IA64_INST_LD4_UPDATE:
1976 +        case IA64_INST_ST4:
1977 +        case IA64_INST_ST4_UPDATE:
1978 +                transfer_size = SIZE_LONG;
1979 +                break;
1980 +        case IA64_INST_LD8:
1981 +        case IA64_INST_LD8_UPDATE:
1982 +        case IA64_INST_ST8:
1983 +        case IA64_INST_ST8_UPDATE:
1984 +                transfer_size = SIZE_QUAD;
1985 +                break;
1986 +        }
1987 +
1988 +        if (transfer_size == SIZE_UNKNOWN) {
1989 +                // Unknown machine code, let it crash. Then patch the decoder
1990 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
1991 +                return false;
1992 +        }
1993 +
1994 +        inst.no_memory = true;
1995 +        if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) {
1996 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
1997 +                return false;
1998 +        }
1999 +
2000 +        int slot = ip & 3;
2001 +        bool emulate_next = false;
2002 +        switch (slot) {
2003 +        case 0:
2004 +                switch (ia64_get_template(ip)) {
2005 +                case 0x2: // MI;I
2006 +                case 0x3: // MI;I;
2007 +                        emulate_next = true;
2008 +                        slot = 2;
2009 +                        break;
2010 +                case 0xa: // M;MI
2011 +                case 0xb: // M;MI;
2012 +                        emulate_next = true;
2013 +                        slot = 1;
2014 +                        break;
2015 +                }
2016 +                break;
2017 +        }
2018 +        if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) {
2019 +                while (slot < 3) {
2020 +                        if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) {
2021 +                                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
2022 +                                return false;
2023 +                        }
2024 +                        ++slot;
2025 +                }
2026 +        }
2027 +
2028 + #if IA64_CAN_PATCH_IP_SLOT
2029 +        if ((slot = ip & 3) < 2)
2030 +                IA64_SET_IP((ip & ~3ull) + (slot + 1));
2031 +        else
2032 + #endif
2033 +                IA64_SET_IP((ip & ~3ull) + 16);
2034 + #if DEBUG
2035 +        printf("IP: 0x%016llx\n", IA64_GET_IP());
2036 + #endif
2037 +        return true;
2038 + }
2039 + #endif
2040 +
2041 + // Decode and skip PPC instruction
2042 + #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
2043 + static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
2044 + {
2045 +        instruction_t instr;
2046 +        powerpc_decode_instruction(&instr, *nip_p, regs);
2047 +        
2048 +        if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2049 +                // Unknown machine code, let it crash. Then patch the decoder
2050 +                return false;
2051 +        }
2052 +
2053 + #if DEBUG
2054 +        printf("%08x: %s %s access", *nip_p,
2055 +                   instr.transfer_size == SIZE_BYTE ? "byte" :
2056 +                   instr.transfer_size == SIZE_WORD ? "word" :
2057 +                   instr.transfer_size == SIZE_LONG ? "long" : "quad",
2058 +                   instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
2059 +        
2060 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
2061 +                printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
2062 +        if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
2063 +                printf(" r%d (rd = 0)\n", instr.rd);
2064 + #endif
2065 +        
2066 +        if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
2067 +                regs[instr.ra] = instr.addr;
2068 +        if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
2069 +                regs[instr.rd] = 0;
2070 +        
2071 +        *nip_p += 4;
2072 +        return true;
2073 + }
2074 + #endif
2075 +
2076 + // Decode and skip MIPS instruction
2077 + #if (defined(mips) || defined(__mips))
2078 + static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
2079 + {
2080 +  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
2081 +
2082 +  if (epc == 0)
2083 +        return false;
2084 +
2085 + #if DEBUG
2086 +  printf("IP: %p [%08x]\n", epc, epc[0]);
2087 + #endif
2088 +
2089 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2090 +  transfer_size_t transfer_size = SIZE_LONG;
2091 +  int direction = 0;
2092 +
2093 +  const unsigned int opcode = epc[0];
2094 +  switch (opcode >> 26) {
2095 +  case 32: // Load Byte
2096 +  case 36: // Load Byte Unsigned
2097 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2098 +        transfer_size = SIZE_BYTE;
2099 +        break;
2100 +  case 33: // Load Halfword
2101 +  case 37: // Load Halfword Unsigned
2102 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2103 +        transfer_size = SIZE_WORD;
2104 +        break;
2105 +  case 35: // Load Word
2106 +  case 39: // Load Word Unsigned
2107 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2108 +        transfer_size = SIZE_LONG;
2109 +        break;
2110 +  case 34: // Load Word Left
2111 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2112 +        transfer_size = SIZE_LONG;
2113 +        direction = -1;
2114 +        break;
2115 +  case 38: // Load Word Right
2116 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2117 +        transfer_size = SIZE_LONG;
2118 +        direction = 1;
2119 +        break;
2120 +  case 55: // Load Doubleword
2121 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2122 +        transfer_size = SIZE_QUAD;
2123 +        break;
2124 +  case 26: // Load Doubleword Left
2125 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2126 +        transfer_size = SIZE_QUAD;
2127 +        direction = -1;
2128 +        break;
2129 +  case 27: // Load Doubleword Right
2130 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2131 +        transfer_size = SIZE_QUAD;
2132 +        direction = 1;
2133 +        break;
2134 +  case 40: // Store Byte
2135 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2136 +        transfer_size = SIZE_BYTE;
2137 +        break;
2138 +  case 41: // Store Halfword
2139 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2140 +        transfer_size = SIZE_WORD;
2141 +        break;
2142 +  case 43: // Store Word
2143 +  case 42: // Store Word Left
2144 +  case 46: // Store Word Right
2145 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2146 +        transfer_size = SIZE_LONG;
2147 +        break;
2148 +  case 63: // Store Doubleword
2149 +  case 44: // Store Doubleword Left
2150 +  case 45: // Store Doubleword Right
2151 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2152 +        transfer_size = SIZE_QUAD;
2153 +        break;
2154 +  /* Misc instructions unlikely to be used within CPU emulators */
2155 +  case 48: // Load Linked Word
2156 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2157 +        transfer_size = SIZE_LONG;
2158 +        break;
2159 +  case 52: // Load Linked Doubleword
2160 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2161 +        transfer_size = SIZE_QUAD;
2162 +        break;
2163 +  case 56: // Store Conditional Word
2164 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2165 +        transfer_size = SIZE_LONG;
2166 +        break;
2167 +  case 60: // Store Conditional Doubleword
2168 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2169 +        transfer_size = SIZE_QUAD;
2170 +        break;
2171 +  }
2172 +
2173 +  if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2174 +        // Unknown machine code, let it crash. Then patch the decoder
2175 +        return false;
2176 +  }
2177 +
2178 +  // Zero target register in case of a load operation
2179 +  const int reg = (opcode >> 16) & 0x1f;
2180 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
2181 +        if (direction == 0)
2182 +          regs[reg] = 0;
2183 +        else {
2184 +          // FIXME: untested code
2185 +          unsigned long ea = regs[(opcode >> 21) & 0x1f];
2186 +          ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
2187 +          const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
2188 +          unsigned long value;
2189 +          if (direction > 0) {
2190 +                const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
2191 +                value = regs[reg] & rmask;
2192 +          }
2193 +          else {
2194 +                const unsigned long lmask = (1L << (offset * 8)) - 1;
2195 +                value = regs[reg] & lmask;
2196 +          }
2197 +          // restore most significant bits
2198 +          if (transfer_size == SIZE_LONG)
2199 +                value = (signed long)(signed int)value;
2200 +          regs[reg] = value;
2201 +        }
2202 +  }
2203 +
2204 + #if DEBUG
2205 + #if (defined(_ABIN32) || defined(_ABI64))
2206 +  static const char * mips_gpr_names[32] = {
2207 +        "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
2208 +        "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
2209 +        "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
2210 +        "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
2211 +  };
2212 + #else
2213 +  static const char * mips_gpr_names[32] = {
2214 +        "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
2215 +        "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
2216 +        "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
2217 +        "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
2218 +  };
2219 + #endif
2220 +  printf("%s %s register %s\n",
2221 +                 transfer_size == SIZE_BYTE ? "byte" :
2222 +                 transfer_size == SIZE_WORD ? "word" :
2223 +                 transfer_size == SIZE_LONG ? "long" :
2224 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2225 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2226 +                 mips_gpr_names[reg]);
2227 + #endif
2228 +
2229 +  *pc_p += 4;
2230 +  return true;
2231 + }
2232 + #endif
2233 +
2234 + // Decode and skip SPARC instruction
2235 + #if (defined(sparc) || defined(__sparc__))
2236 + enum {
2237 + #if (defined(__sun__))
2238 +  SPARC_REG_G1 = REG_G1,
2239 +  SPARC_REG_O0 = REG_O0,
2240 +  SPARC_REG_PC = REG_PC,
2241 +  SPARC_REG_nPC = REG_nPC
2242 + #endif
2243 + };
2244 + static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
2245 + {
2246 +  unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
2247 +
2248 +  if (pc == 0)
2249 +        return false;
2250 +
2251 + #if DEBUG
2252 +  printf("IP: %p [%08x]\n", pc, pc[0]);
2253 + #endif
2254 +
2255 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2256 +  transfer_size_t transfer_size = SIZE_LONG;
2257 +  bool register_pair = false;
2258 +
2259 +  const unsigned int opcode = pc[0];
2260 +  if ((opcode >> 30) != 3)
2261 +        return false;
2262 +  switch ((opcode >> 19) & 0x3f) {
2263 +  case 9: // Load Signed Byte
2264 +  case 1: // Load Unsigned Byte
2265 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2266 +        transfer_size = SIZE_BYTE;
2267 +        break;
2268 +  case 10:// Load Signed Halfword
2269 +  case 2: // Load Unsigned Word
2270 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2271 +        transfer_size = SIZE_WORD;
2272 +        break;
2273 +  case 8: // Load Word
2274 +  case 0: // Load Unsigned Word
2275 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2276 +        transfer_size = SIZE_LONG;
2277 +        break;
2278 +  case 11:// Load Extended Word
2279 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2280 +        transfer_size = SIZE_QUAD;
2281 +        break;
2282 +  case 3: // Load Doubleword
2283 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2284 +        transfer_size = SIZE_LONG;
2285 +        register_pair = true;
2286 +        break;
2287 +  case 5: // Store Byte
2288 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2289 +        transfer_size = SIZE_BYTE;
2290 +        break;
2291 +  case 6: // Store Halfword
2292 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2293 +        transfer_size = SIZE_WORD;
2294 +        break;
2295 +  case 4: // Store Word
2296 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2297 +        transfer_size = SIZE_LONG;
2298 +        break;
2299 +  case 14:// Store Extended Word
2300 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2301 +        transfer_size = SIZE_QUAD;
2302 +        break;
2303 +  case 7: // Store Doubleword
2304 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2305 +        transfer_size = SIZE_LONG;
2306 +        register_pair = true;
2307 +        break;
2308 +  }
2309 +
2310 +  if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2311 +        // Unknown machine code, let it crash. Then patch the decoder
2312 +        return false;
2313 +  }
2314 +
2315 +  const int reg = (opcode >> 25) & 0x1f;
2316 +
2317 + #if DEBUG
2318 +  static const char * reg_names[] = {
2319 +        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2320 +        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2321 +        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2322 +        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2323 +  };
2324 +  printf("%s %s register %s\n",
2325 +                 transfer_size == SIZE_BYTE ? "byte" :
2326 +                 transfer_size == SIZE_WORD ? "word" :
2327 +                 transfer_size == SIZE_LONG ? "long" :
2328 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2329 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2330 +                 reg_names[reg]);
2331 + #endif
2332 +
2333 +  // Zero target register in case of a load operation
2334 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2335 +        // FIXME: code to handle local & input registers is not tested
2336 +        if (reg >= 1 && reg < 8) {
2337 +          // global registers
2338 +          regs[reg - 1 + SPARC_REG_G1] = 0;
2339 +        }
2340 +        else if (reg >= 8 && reg < 16) {
2341 +          // output registers
2342 +          regs[reg - 8 + SPARC_REG_O0] = 0;
2343 +        }
2344 +        else if (reg >= 16 && reg < 24) {
2345 +          // local registers (in register windows)
2346 +          if (gwins)
2347 +                gwins->wbuf->rw_local[reg - 16] = 0;
2348 +          else
2349 +                rwin->rw_local[reg - 16] = 0;
2350 +        }
2351 +        else {
2352 +          // input registers (in register windows)
2353 +          if (gwins)
2354 +                gwins->wbuf->rw_in[reg - 24] = 0;
2355 +          else
2356 +                rwin->rw_in[reg - 24] = 0;
2357 +        }
2358 +  }
2359 +
2360 +  regs[SPARC_REG_PC] += 4;
2361 +  regs[SPARC_REG_nPC] += 4;
2362 +  return true;
2363 + }
2364   #endif
2365   #endif
2366 +
2367 + // Decode and skip ARM instruction
2368 + #if (defined(arm) || defined(__arm__))
2369 + enum {
2370 + #if (defined(__linux__))
2371 +  ARM_REG_PC = 15,
2372 +  ARM_REG_CPSR = 16
2373   #endif
2374 + };
2375 + static bool arm_skip_instruction(unsigned long * regs)
2376 + {
2377 +  unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
2378 +
2379 +  if (pc == 0)
2380 +        return false;
2381 +
2382 + #if DEBUG
2383 +  printf("IP: %p [%08x]\n", pc, pc[0]);
2384 + #endif
2385 +
2386 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2387 +  transfer_size_t transfer_size = SIZE_UNKNOWN;
2388 +  enum { op_sdt = 1, op_sdth = 2 };
2389 +  int op = 0;
2390 +
2391 +  // Handle load/store instructions only
2392 +  const unsigned int opcode = pc[0];
2393 +  switch ((opcode >> 25) & 7) {
2394 +  case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
2395 +        op = op_sdth;
2396 +        // Determine transfer size (S/H bits)
2397 +        switch ((opcode >> 5) & 3) {
2398 +        case 0: // SWP instruction
2399 +          break;
2400 +        case 1: // Unsigned halfwords
2401 +        case 3: // Signed halfwords
2402 +          transfer_size = SIZE_WORD;
2403 +          break;
2404 +        case 2: // Signed byte
2405 +          transfer_size = SIZE_BYTE;
2406 +          break;
2407 +        }
2408 +        break;
2409 +  case 2:
2410 +  case 3: // Single Data Transfer (LDR, STR)
2411 +        op = op_sdt;
2412 +        // Determine transfer size (B bit)
2413 +        if (((opcode >> 22) & 1) == 1)
2414 +          transfer_size = SIZE_BYTE;
2415 +        else
2416 +          transfer_size = SIZE_LONG;
2417 +        break;
2418 +  default:
2419 +        // FIXME: support load/store mutliple?
2420 +        return false;
2421 +  }
2422 +
2423 +  // Check for invalid transfer size (SWP instruction?)
2424 +  if (transfer_size == SIZE_UNKNOWN)
2425 +        return false;
2426 +
2427 +  // Determine transfer type (L bit)
2428 +  if (((opcode >> 20) & 1) == 1)
2429 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2430 +  else
2431 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2432 +
2433 +  // Compute offset
2434 +  int offset;
2435 +  if (((opcode >> 25) & 1) == 0) {
2436 +        if (op == op_sdt)
2437 +          offset = opcode & 0xfff;
2438 +        else if (op == op_sdth) {
2439 +          int rm = opcode & 0xf;
2440 +          if (((opcode >> 22) & 1) == 0) {
2441 +                // register offset
2442 +                offset = regs[rm];
2443 +          }
2444 +          else {
2445 +                // immediate offset
2446 +                offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
2447 +          }
2448 +        }
2449 +  }
2450 +  else {
2451 +        const int rm = opcode & 0xf;
2452 +        const int sh = (opcode >> 7) & 0x1f;
2453 +        if (((opcode >> 4) & 1) == 1) {
2454 +          // we expect only legal load/store instructions
2455 +          printf("FATAL: invalid shift operand\n");
2456 +          return false;
2457 +        }
2458 +        const unsigned int v = regs[rm];
2459 +        switch ((opcode >> 5) & 3) {
2460 +        case 0: // logical shift left
2461 +          offset = sh ? v << sh : v;
2462 +          break;
2463 +        case 1: // logical shift right
2464 +          offset = sh ? v >> sh : 0;
2465 +          break;
2466 +        case 2: // arithmetic shift right
2467 +          if (sh)
2468 +                offset = ((signed int)v) >> sh;
2469 +          else
2470 +                offset = (v & 0x80000000) ? 0xffffffff : 0;
2471 +          break;
2472 +        case 3: // rotate right
2473 +          if (sh)
2474 +                offset = (v >> sh) | (v << (32 - sh));
2475 +          else
2476 +                offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
2477 +          break;
2478 +        }
2479 +  }
2480 +  if (((opcode >> 23) & 1) == 0)
2481 +        offset = -offset;
2482 +
2483 +  int rd = (opcode >> 12) & 0xf;
2484 +  int rn = (opcode >> 16) & 0xf;
2485 + #if DEBUG
2486 +  static const char * reg_names[] = {
2487 +        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2488 +        "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
2489 +  };
2490 +  printf("%s %s register %s\n",
2491 +                 transfer_size == SIZE_BYTE ? "byte" :
2492 +                 transfer_size == SIZE_WORD ? "word" :
2493 +                 transfer_size == SIZE_LONG ? "long" : "unknown",
2494 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2495 +                 reg_names[rd]);
2496 + #endif
2497 +
2498 +  unsigned int base = regs[rn];
2499 +  if (((opcode >> 24) & 1) == 1)
2500 +        base += offset;
2501 +
2502 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD)
2503 +        regs[rd] = 0;
2504 +
2505 +  if (((opcode >> 24) & 1) == 0)                // post-index addressing
2506 +        regs[rn] += offset;
2507 +  else if (((opcode >> 21) & 1) == 1)   // write-back address into base
2508 +        regs[rn] = base;
2509 +
2510 +  regs[ARM_REG_PC] += 4;
2511 +  return true;
2512 + }
2513 + #endif
2514 +
2515  
2516   // Fallbacks
2517 + #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2518 + #define SIGSEGV_FAULT_ADDRESS_FAST              SIGSEGV_FAULT_ADDRESS
2519 + #endif
2520 + #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2521 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_FAULT_INSTRUCTION
2522 + #endif
2523   #ifndef SIGSEGV_FAULT_INSTRUCTION
2524 < #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
2524 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_ADDRESS
2525 > #endif
2526 > #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2527 > #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2528 > #endif
2529 > #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2530 > #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2531   #endif
2532  
2533   // SIGSEGV recovery supported ?
# Line 149 | Line 2540 | static bool sigsegv_do_install_handler(i
2540   *  SIGSEGV global handler
2541   */
2542  
2543 + struct sigsegv_info_t {
2544 +        sigsegv_address_t addr;
2545 +        sigsegv_address_t pc;
2546 + #ifdef HAVE_MACH_EXCEPTIONS
2547 +        mach_port_t thread;
2548 +        bool has_exc_state;
2549 +        SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2550 +        mach_msg_type_number_t exc_state_count;
2551 +        bool has_thr_state;
2552 +        SIGSEGV_THREAD_STATE_TYPE thr_state;
2553 +        mach_msg_type_number_t thr_state_count;
2554 + #endif
2555 + };
2556 +
2557 + #ifdef HAVE_MACH_EXCEPTIONS
2558 + static void mach_get_exception_state(sigsegv_info_t *SIP)
2559 + {
2560 +        SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2561 +        kern_return_t krc = thread_get_state(SIP->thread,
2562 +                                                                                 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2563 +                                                                                 (natural_t *)&SIP->exc_state,
2564 +                                                                                 &SIP->exc_state_count);
2565 +        MACH_CHECK_ERROR(thread_get_state, krc);
2566 +        SIP->has_exc_state = true;
2567 + }
2568 +
2569 + static void mach_get_thread_state(sigsegv_info_t *SIP)
2570 + {
2571 +        SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2572 +        kern_return_t krc = thread_get_state(SIP->thread,
2573 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2574 +                                                                                 (natural_t *)&SIP->thr_state,
2575 +                                                                                 &SIP->thr_state_count);
2576 +        MACH_CHECK_ERROR(thread_get_state, krc);
2577 +        SIP->has_thr_state = true;
2578 + }
2579 +
2580 + static void mach_set_thread_state(sigsegv_info_t *SIP)
2581 + {
2582 +        kern_return_t krc = thread_set_state(SIP->thread,
2583 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2584 +                                                                                 (natural_t *)&SIP->thr_state,
2585 +                                                                                 SIP->thr_state_count);
2586 +        MACH_CHECK_ERROR(thread_set_state, krc);
2587 + }
2588 + #endif
2589 +
2590 + // Return the address of the invalid memory reference
2591 + sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2592 + {
2593 + #ifdef HAVE_MACH_EXCEPTIONS
2594 +        static int use_fast_path = -1;
2595 +        if (use_fast_path != 1 && !SIP->has_exc_state) {
2596 +                mach_get_exception_state(SIP);
2597 +
2598 +                sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2599 +                if (use_fast_path < 0) {
2600 +                        const char *machfault = getenv("SIGSEGV_MACH_FAULT");
2601 +                        if (machfault) {
2602 +                                if (strcmp(machfault, "fast") == 0)
2603 +                                        use_fast_path = 1;
2604 +                                else if (strcmp(machfault, "slow") == 0)
2605 +                                        use_fast_path = 0;
2606 +                        }
2607 +                        if (use_fast_path < 0)
2608 +                                use_fast_path = addr == SIP->addr;
2609 +                }
2610 +                SIP->addr = addr;
2611 +        }
2612 + #endif
2613 +        return SIP->addr;
2614 + }
2615 +
2616 + // Return the address of the instruction that caused the fault, or
2617 + // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2618 + sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2619 + {
2620 + #ifdef HAVE_MACH_EXCEPTIONS
2621 +        if (!SIP->has_thr_state) {
2622 +                mach_get_thread_state(SIP);
2623 +
2624 +                SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2625 +        }
2626 + #endif
2627 +        return SIP->pc;
2628 + }
2629 +
2630 + // This function handles the badaccess to memory.
2631 + // It is called from the signal handler or the exception handler.
2632 + static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2633 + {
2634 +        sigsegv_info_t SI;
2635 +        SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2636 +        SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2637 + #ifdef HAVE_MACH_EXCEPTIONS
2638 +        SI.thread = thread;
2639 +        SI.has_exc_state = false;
2640 +        SI.has_thr_state = false;
2641 + #endif
2642 +        sigsegv_info_t * const SIP = &SI;
2643 +
2644 +        // Call user's handler and reinstall the global handler, if required
2645 +        switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2646 +        case SIGSEGV_RETURN_SUCCESS:
2647 +                return true;
2648 +
2649 + #if HAVE_SIGSEGV_SKIP_INSTRUCTION
2650 +        case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2651 +                // Call the instruction skipper with the register file
2652 +                // available
2653 + #ifdef HAVE_MACH_EXCEPTIONS
2654 +                if (!SIP->has_thr_state)
2655 +                        mach_get_thread_state(SIP);
2656 + #endif
2657 +                if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2658 + #ifdef HAVE_MACH_EXCEPTIONS
2659 +                        // Unlike UNIX signals where the thread state
2660 +                        // is modified off of the stack, in Mach we
2661 +                        // need to actually call thread_set_state to
2662 +                        // have the register values updated.
2663 +                        mach_set_thread_state(SIP);
2664 + #endif
2665 +                        return true;
2666 +                }
2667 +                break;
2668 + #endif
2669 +        case SIGSEGV_RETURN_FAILURE:
2670 +                // We can't do anything with the fault_address, dump state?
2671 +                if (sigsegv_state_dumper != 0)
2672 +                        sigsegv_state_dumper(SIP);
2673 +                break;
2674 +        }
2675 +
2676 +        return false;
2677 + }
2678 +
2679 +
2680 + /*
2681 + * There are two mechanisms for handling a bad memory access,
2682 + * Mach exceptions and UNIX signals. The implementation specific
2683 + * code appears below. Its reponsibility is to call handle_badaccess
2684 + * which is the routine that handles the fault in an implementation
2685 + * agnostic manner. The implementation specific code below is then
2686 + * reponsible for checking whether handle_badaccess was able
2687 + * to handle the memory access error and perform any implementation
2688 + * specific tasks necessary afterwards.
2689 + */
2690 +
2691 + #ifdef HAVE_MACH_EXCEPTIONS
2692 + /*
2693 + * We need to forward all exceptions that we do not handle.
2694 + * This is important, there are many exceptions that may be
2695 + * handled by other exception handlers. For example debuggers
2696 + * use exceptions and the exception hander is in another
2697 + * process in such a case. (Timothy J. Wood states in his
2698 + * message to the list that he based this code on that from
2699 + * gdb for Darwin.)
2700 + */
2701 + static inline kern_return_t
2702 + forward_exception(mach_port_t thread_port,
2703 +                                  mach_port_t task_port,
2704 +                                  exception_type_t exception_type,
2705 +                                  exception_data_t exception_data,
2706 +                                  mach_msg_type_number_t data_count,
2707 +                                  ExceptionPorts *oldExceptionPorts)
2708 + {
2709 +        kern_return_t kret;
2710 +        unsigned int portIndex;
2711 +        mach_port_t port;
2712 +        exception_behavior_t behavior;
2713 +        thread_state_flavor_t flavor;
2714 +        thread_state_data_t thread_state;
2715 +        mach_msg_type_number_t thread_state_count;
2716 +
2717 +        for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
2718 +                if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
2719 +                        // This handler wants the exception
2720 +                        break;
2721 +                }
2722 +        }
2723 +
2724 +        if (portIndex >= oldExceptionPorts->maskCount) {
2725 +                fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type);
2726 +                return KERN_FAILURE;
2727 +        }
2728 +
2729 +        port = oldExceptionPorts->handlers[portIndex];
2730 +        behavior = oldExceptionPorts->behaviors[portIndex];
2731 +        flavor = oldExceptionPorts->flavors[portIndex];
2732 +
2733 +        if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2734 +                fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2735 +                return KERN_FAILURE;
2736 +        }
2737 +
2738 +        /*
2739 +         fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2740 +         */
2741 +
2742 +        if (behavior != EXCEPTION_DEFAULT) {
2743 +                thread_state_count = THREAD_STATE_MAX;
2744 +                kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2745 +                                                                 &thread_state_count);
2746 +                MACH_CHECK_ERROR (thread_get_state, kret);
2747 +        }
2748 +
2749 +        switch (behavior) {
2750 +        case EXCEPTION_DEFAULT:
2751 +          // fprintf(stderr, "forwarding to exception_raise\n");
2752 +          kret = exception_raise(port, thread_port, task_port, exception_type,
2753 +                                                         exception_data, data_count);
2754 +          MACH_CHECK_ERROR (exception_raise, kret);
2755 +          break;
2756 +        case EXCEPTION_STATE:
2757 +          // fprintf(stderr, "forwarding to exception_raise_state\n");
2758 +          kret = exception_raise_state(port, exception_type, exception_data,
2759 +                                                                   data_count, &flavor,
2760 +                                                                   (natural_t *)&thread_state, thread_state_count,
2761 +                                                                   (natural_t *)&thread_state, &thread_state_count);
2762 +          MACH_CHECK_ERROR (exception_raise_state, kret);
2763 +          break;
2764 +        case EXCEPTION_STATE_IDENTITY:
2765 +          // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2766 +          kret = exception_raise_state_identity(port, thread_port, task_port,
2767 +                                                                                        exception_type, exception_data,
2768 +                                                                                        data_count, &flavor,
2769 +                                                                                        (natural_t *)&thread_state, thread_state_count,
2770 +                                                                                        (natural_t *)&thread_state, &thread_state_count);
2771 +          MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2772 +          break;
2773 +        default:
2774 +          fprintf(stderr, "forward_exception got unknown behavior\n");
2775 +          kret = KERN_FAILURE;
2776 +          break;
2777 +        }
2778 +
2779 +        if (behavior != EXCEPTION_DEFAULT) {
2780 +                kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2781 +                                                                 thread_state_count);
2782 +                MACH_CHECK_ERROR (thread_set_state, kret);
2783 +        }
2784 +
2785 +        return kret;
2786 + }
2787 +
2788 + /*
2789 + * This is the code that actually handles the exception.
2790 + * It is called by exc_server. For Darwin 5 Apple changed
2791 + * this a bit from how this family of functions worked in
2792 + * Mach. If you are familiar with that it is a little
2793 + * different. The main variation that concerns us here is
2794 + * that code is an array of exception specific codes and
2795 + * codeCount is a count of the number of codes in the code
2796 + * array. In typical Mach all exceptions have a code
2797 + * and sub-code. It happens to be the case that for a
2798 + * EXC_BAD_ACCESS exception the first entry is the type of
2799 + * bad access that occurred and the second entry is the
2800 + * faulting address so these entries correspond exactly to
2801 + * how the code and sub-code are used on Mach.
2802 + *
2803 + * This is a MIG interface. No code in Basilisk II should
2804 + * call this directley. This has to have external C
2805 + * linkage because that is what exc_server expects.
2806 + */
2807 + kern_return_t
2808 + catch_exception_raise(mach_port_t exception_port,
2809 +                                          mach_port_t thread,
2810 +                                          mach_port_t task,
2811 +                                          exception_type_t exception,
2812 +                                          exception_data_t code,
2813 +                                          mach_msg_type_number_t code_count)
2814 + {
2815 +        kern_return_t krc;
2816 +
2817 +        if (exception == EXC_BAD_ACCESS) {
2818 +                switch (code[0]) {
2819 +                case KERN_PROTECTION_FAILURE:
2820 +                case KERN_INVALID_ADDRESS:
2821 +                        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2822 +                                return KERN_SUCCESS;
2823 +                        break;
2824 +                }
2825 +        }
2826 +
2827 +        // In Mach we do not need to remove the exception handler.
2828 +        // If we forward the exception, eventually some exception handler
2829 +        // will take care of this exception.
2830 +        krc = forward_exception(thread, task, exception, code, code_count, &ports);
2831 +
2832 +        return krc;
2833 + }
2834 + #endif
2835 +
2836   #ifdef HAVE_SIGSEGV_RECOVERY
2837 + // Handle bad memory accesses with signal handler
2838   static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST)
2839   {
2840 <        // Call user's handler and reinstall the global handler, if required
2841 <        if (sigsegv_user_handler((sigsegv_address_t)SIGSEGV_FAULT_ADDRESS, (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION)) {
2840 >        // Call handler and reinstall the global handler, if required
2841 >        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) {
2842   #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL))
2843                  sigsegv_do_install_handler(sig);
2844   #endif
2845 +                return;
2846          }
2847 <        else {
2848 <                // FAIL: reinstall default handler for "safe" crash
2847 >
2848 >        // Failure: reinstall default handler for "safe" crash
2849   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
2850 <                SIGSEGV_ALL_SIGNALS
2850 >        SIGSEGV_ALL_SIGNALS
2851   #undef FAULT_HANDLER
166        }
2852   }
2853   #endif
2854  
# Line 177 | Line 2862 | static bool sigsegv_do_install_handler(i
2862   {
2863          // Setup SIGSEGV handler to process writes to frame buffer
2864   #ifdef HAVE_SIGACTION
2865 <        struct sigaction vosf_sa;
2866 <        sigemptyset(&vosf_sa.sa_mask);
2867 <        vosf_sa.sa_sigaction = sigsegv_handler;
2868 <        vosf_sa.sa_flags = SA_SIGINFO;
2869 <        return (sigaction(sig, &vosf_sa, 0) == 0);
2865 >        struct sigaction sigsegv_sa;
2866 >        sigemptyset(&sigsegv_sa.sa_mask);
2867 >        sigsegv_sa.sa_sigaction = sigsegv_handler;
2868 >        sigsegv_sa.sa_flags = SA_SIGINFO;
2869 >        return (sigaction(sig, &sigsegv_sa, 0) == 0);
2870   #else
2871          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2872   #endif
# Line 193 | Line 2878 | static bool sigsegv_do_install_handler(i
2878   {
2879          // Setup SIGSEGV handler to process writes to frame buffer
2880   #ifdef HAVE_SIGACTION
2881 <        struct sigaction vosf_sa;
2882 <        sigemptyset(&vosf_sa.sa_mask);
2883 <        vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
2881 >        struct sigaction sigsegv_sa;
2882 >        sigemptyset(&sigsegv_sa.sa_mask);
2883 >        sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
2884 >        sigsegv_sa.sa_flags = 0;
2885   #if !EMULATED_68K && defined(__NetBSD__)
2886 <        sigaddset(&vosf_sa.sa_mask, SIGALRM);
2887 <        vosf_sa.sa_flags = SA_ONSTACK;
202 < #else
203 <        vosf_sa.sa_flags = 0;
2886 >        sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
2887 >        sigsegv_sa.sa_flags |= SA_ONSTACK;
2888   #endif
2889 <        return (sigaction(sig, &vosf_sa, 0) == 0);
2889 >        return (sigaction(sig, &sigsegv_sa, 0) == 0);
2890   #else
2891          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
2892   #endif
2893   }
2894   #endif
2895  
2896 < bool sigsegv_install_handler(sigsegv_handler_t handler)
2896 > #if defined(HAVE_MACH_EXCEPTIONS)
2897 > static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2898   {
2899 < #ifdef HAVE_SIGSEGV_RECOVERY
2900 <        sigsegv_user_handler = handler;
2899 >        /*
2900 >         * Except for the exception port functions, this should be
2901 >         * pretty much stock Mach. If later you choose to support
2902 >         * other Mach's besides Darwin, just check for __MACH__
2903 >         * here and __APPLE__ where the actual differences are.
2904 >         */
2905 > #if defined(__APPLE__) && defined(__MACH__)
2906 >        if (sigsegv_fault_handler != NULL) {
2907 >                sigsegv_fault_handler = handler;
2908 >                return true;
2909 >        }
2910 >
2911 >        kern_return_t krc;
2912 >
2913 >        // create the the exception port
2914 >        krc = mach_port_allocate(mach_task_self(),
2915 >                          MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
2916 >        if (krc != KERN_SUCCESS) {
2917 >                mach_error("mach_port_allocate", krc);
2918 >                return false;
2919 >        }
2920 >
2921 >        // add a port send right
2922 >        krc = mach_port_insert_right(mach_task_self(),
2923 >                              _exceptionPort, _exceptionPort,
2924 >                              MACH_MSG_TYPE_MAKE_SEND);
2925 >        if (krc != KERN_SUCCESS) {
2926 >                mach_error("mach_port_insert_right", krc);
2927 >                return false;
2928 >        }
2929 >
2930 >        // get the old exception ports
2931 >        ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
2932 >        krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
2933 >                                &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
2934 >        if (krc != KERN_SUCCESS) {
2935 >                mach_error("thread_get_exception_ports", krc);
2936 >                return false;
2937 >        }
2938 >
2939 >        // set the new exception port
2940 >        //
2941 >        // We could have used EXCEPTION_STATE_IDENTITY instead of
2942 >        // EXCEPTION_DEFAULT to get the thread state in the initial
2943 >        // message, but it turns out that in the common case this is not
2944 >        // neccessary. If we need it we can later ask for it from the
2945 >        // suspended thread.
2946 >        //
2947 >        // Even with THREAD_STATE_NONE, Darwin provides the program
2948 >        // counter in the thread state.  The comments in the header file
2949 >        // seem to imply that you can count on the GPR's on an exception
2950 >        // as well but just to be safe I use MACHINE_THREAD_STATE because
2951 >        // you have to ask for all of the GPR's anyway just to get the
2952 >        // program counter. In any case because of update effective
2953 >        // address from immediate and update address from effective
2954 >        // addresses of ra and rb modes (as good an name as any for these
2955 >        // addressing modes) used in PPC instructions, you will need the
2956 >        // GPR state anyway.
2957 >        krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2958 >                                EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2959 >        if (krc != KERN_SUCCESS) {
2960 >                mach_error("thread_set_exception_ports", krc);
2961 >                return false;
2962 >        }
2963 >
2964 >        // create the exception handler thread
2965 >        if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
2966 >                (void)fprintf(stderr, "creation of exception thread failed\n");
2967 >                return false;
2968 >        }
2969 >
2970 >        // do not care about the exception thread any longer, let is run standalone
2971 >        (void)pthread_detach(exc_thread);
2972 >
2973 >        sigsegv_fault_handler = handler;
2974 >        return true;
2975 > #else
2976 >        return false;
2977 > #endif
2978 > }
2979 > #endif
2980 >
2981 > #ifdef HAVE_WIN32_EXCEPTIONS
2982 > static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
2983 > {
2984 >        if (sigsegv_fault_handler != NULL
2985 >                && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
2986 >                && ExceptionInfo->ExceptionRecord->NumberParameters >= 2
2987 >                && handle_badaccess(ExceptionInfo))
2988 >                return EXCEPTION_CONTINUE_EXECUTION;
2989 >
2990 >        return EXCEPTION_CONTINUE_SEARCH;
2991 > }
2992 >
2993 > #if defined __CYGWIN__ && defined __i386__
2994 > /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
2995 >   installs a global exception handler.  We have to dig deep in order to install
2996 >   our main_exception_filter.  */
2997 >
2998 > /* Data structures for the current thread's exception handler chain.
2999 >   On the x86 Windows uses register fs, offset 0 to point to the current
3000 >   exception handler; Cygwin mucks with it, so we must do the same... :-/ */
3001 >
3002 > /* Magic taken from winsup/cygwin/include/exceptions.h.  */
3003 >
3004 > struct exception_list {
3005 >    struct exception_list *prev;
3006 >    int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
3007 > };
3008 > typedef struct exception_list exception_list;
3009 >
3010 > /* Magic taken from winsup/cygwin/exceptions.cc.  */
3011 >
3012 > __asm__ (".equ __except_list,0");
3013 >
3014 > extern exception_list *_except_list __asm__ ("%fs:__except_list");
3015 >
3016 > /* For debugging.  _except_list is not otherwise accessible from gdb.  */
3017 > static exception_list *
3018 > debug_get_except_list ()
3019 > {
3020 >  return _except_list;
3021 > }
3022 >
3023 > /* Cygwin's original exception handler.  */
3024 > static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
3025 >
3026 > /* Our exception handler.  */
3027 > static int
3028 > libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
3029 > {
3030 >  EXCEPTION_POINTERS ExceptionInfo;
3031 >  ExceptionInfo.ExceptionRecord = exception;
3032 >  ExceptionInfo.ContextRecord = context;
3033 >  if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
3034 >    return cygwin_exception_handler (exception, frame, context, dispatch);
3035 >  else
3036 >    return 0;
3037 > }
3038 >
3039 > static void
3040 > do_install_main_exception_filter ()
3041 > {
3042 >  /* We cannot insert any handler into the chain, because such handlers
3043 >     must lie on the stack (?).  Instead, we have to replace(!) Cygwin's
3044 >     global exception handler.  */
3045 >  cygwin_exception_handler = _except_list->handler;
3046 >  _except_list->handler = libsigsegv_exception_handler;
3047 > }
3048 >
3049 > #else
3050 >
3051 > static void
3052 > do_install_main_exception_filter ()
3053 > {
3054 >  SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
3055 > }
3056 > #endif
3057 >
3058 > static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
3059 > {
3060 >        static bool main_exception_filter_installed = false;
3061 >        if (!main_exception_filter_installed) {
3062 >                do_install_main_exception_filter();
3063 >                main_exception_filter_installed = true;
3064 >        }
3065 >        sigsegv_fault_handler = handler;
3066 >        return true;
3067 > }
3068 > #endif
3069 >
3070 > bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
3071 > {
3072 > #if defined(HAVE_SIGSEGV_RECOVERY)
3073          bool success = true;
3074   #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig);
3075          SIGSEGV_ALL_SIGNALS
3076   #undef FAULT_HANDLER
3077 +        if (success)
3078 +            sigsegv_fault_handler = handler;
3079          return success;
3080 + #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
3081 +        return sigsegv_do_install_handler(handler);
3082   #else
3083          // FAIL: no siginfo_t nor sigcontext subterfuge is available
3084          return false;
# Line 231 | Line 3092 | bool sigsegv_install_handler(sigsegv_han
3092  
3093   void sigsegv_deinstall_handler(void)
3094   {
3095 +  // We do nothing for Mach exceptions, the thread would need to be
3096 +  // suspended if not already so, and we might mess with other
3097 +  // exception handlers that came after we registered ours. There is
3098 +  // no need to remove the exception handler, in fact this function is
3099 +  // not called anywhere in Basilisk II.
3100   #ifdef HAVE_SIGSEGV_RECOVERY
3101 <        sigsegv_user_handler = 0;
3101 >        sigsegv_fault_handler = 0;
3102   #define FAULT_HANDLER(sig) signal(sig, SIG_DFL);
3103          SIGSEGV_ALL_SIGNALS
3104   #undef FAULT_HANDLER
3105   #endif
3106 + #ifdef HAVE_WIN32_EXCEPTIONS
3107 +        sigsegv_fault_handler = NULL;
3108 + #endif
3109 + }
3110 +
3111 +
3112 + /*
3113 + *  Set callback function when we cannot handle the fault
3114 + */
3115 +
3116 + void sigsegv_set_dump_state(sigsegv_state_dumper_t handler)
3117 + {
3118 +        sigsegv_state_dumper = handler;
3119   }
3120  
3121 +
3122   /*
3123   *  Test program used for configure/test
3124   */
3125  
3126 < #ifdef CONFIGURE_TEST
3126 > #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY
3127   #include <stdio.h>
3128   #include <stdlib.h>
249 #include <unistd.h>
3129   #include <fcntl.h>
3130 + #ifdef HAVE_SYS_MMAN_H
3131   #include <sys/mman.h>
3132 + #endif
3133 + #include "vm_alloc.h"
3134 +
3135 + const int REF_INDEX = 123;
3136 + const int REF_VALUE = 45;
3137  
3138 < static int page_size;
3138 > static sigsegv_uintptr_t page_size;
3139   static volatile char * page = 0;
3140   static volatile int handler_called = 0;
3141  
3142 < static bool sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
3142 > /* Barriers */
3143 > #ifdef __GNUC__
3144 > #define BARRIER() asm volatile ("" : : : "memory")
3145 > #else
3146 > #define BARRIER() /* nothing */
3147 > #endif
3148 >
3149 > #ifdef __GNUC__
3150 > // Code range where we expect the fault to come from
3151 > static void *b_region, *e_region;
3152 > #endif
3153 >
3154 > static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
3155   {
3156 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3157 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3158 + #if DEBUG
3159 +        printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
3160 +        printf("expected fault at %p\n", page + REF_INDEX);
3161 + #ifdef __GNUC__
3162 +        printf("expected instruction address range: %p-%p\n", b_region, e_region);
3163 + #endif
3164 + #endif
3165          handler_called++;
3166 <        if ((fault_address - 123) != page)
3167 <                exit(1);
3168 <        if (mprotect((char *)((unsigned long)fault_address & -page_size), page_size, PROT_READ | PROT_WRITE) != 0)
3169 <                exit(1);
3166 >        if ((fault_address - REF_INDEX) != page)
3167 >                exit(10);
3168 > #ifdef __GNUC__
3169 >        // Make sure reported fault instruction address falls into
3170 >        // expected code range
3171 >        if (instruction_address != SIGSEGV_INVALID_ADDRESS
3172 >                && ((instruction_address <  (sigsegv_address_t)b_region) ||
3173 >                        (instruction_address >= (sigsegv_address_t)e_region)))
3174 >                exit(11);
3175 > #endif
3176 >        if (vm_protect((char *)((sigsegv_uintptr_t)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3177 >                exit(12);
3178 >        return SIGSEGV_RETURN_SUCCESS;
3179 > }
3180 >
3181 > #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3182 > static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3183 > {
3184 >        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3185 >        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3186 > #if DEBUG
3187 >        printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3188 > #endif
3189 >        if (((sigsegv_uintptr_t)fault_address - (sigsegv_uintptr_t)page) < page_size) {
3190 > #ifdef __GNUC__
3191 >                // Make sure reported fault instruction address falls into
3192 >                // expected code range
3193 >                if (instruction_address != SIGSEGV_INVALID_ADDRESS
3194 >                        && ((instruction_address <  (sigsegv_address_t)b_region) ||
3195 >                                (instruction_address >= (sigsegv_address_t)e_region)))
3196 >                        return SIGSEGV_RETURN_FAILURE;
3197 > #endif
3198 >                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
3199 >        }
3200 >
3201 >        return SIGSEGV_RETURN_FAILURE;
3202 > }
3203 >
3204 > // More sophisticated tests for instruction skipper
3205 > static bool arch_insn_skipper_tests()
3206 > {
3207 > #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
3208 >        static const unsigned char code[] = {
3209 >                0x8a, 0x00,                    // mov    (%eax),%al
3210 >                0x8a, 0x2c, 0x18,              // mov    (%eax,%ebx,1),%ch
3211 >                0x88, 0x20,                    // mov    %ah,(%eax)
3212 >                0x88, 0x08,                    // mov    %cl,(%eax)
3213 >                0x66, 0x8b, 0x00,              // mov    (%eax),%ax
3214 >                0x66, 0x8b, 0x0c, 0x18,        // mov    (%eax,%ebx,1),%cx
3215 >                0x66, 0x89, 0x00,              // mov    %ax,(%eax)
3216 >                0x66, 0x89, 0x0c, 0x18,        // mov    %cx,(%eax,%ebx,1)
3217 >                0x8b, 0x00,                    // mov    (%eax),%eax
3218 >                0x8b, 0x0c, 0x18,              // mov    (%eax,%ebx,1),%ecx
3219 >                0x89, 0x00,                    // mov    %eax,(%eax)
3220 >                0x89, 0x0c, 0x18,              // mov    %ecx,(%eax,%ebx,1)
3221 > #if defined(__x86_64__) || defined(_M_X64)
3222 >                0x44, 0x8a, 0x00,              // mov    (%rax),%r8b
3223 >                0x44, 0x8a, 0x20,              // mov    (%rax),%r12b
3224 >                0x42, 0x8a, 0x3c, 0x10,        // mov    (%rax,%r10,1),%dil
3225 >                0x44, 0x88, 0x00,              // mov    %r8b,(%rax)
3226 >                0x44, 0x88, 0x20,              // mov    %r12b,(%rax)
3227 >                0x42, 0x88, 0x3c, 0x10,        // mov    %dil,(%rax,%r10,1)
3228 >                0x66, 0x44, 0x8b, 0x00,        // mov    (%rax),%r8w
3229 >                0x66, 0x42, 0x8b, 0x0c, 0x10,  // mov    (%rax,%r10,1),%cx
3230 >                0x66, 0x44, 0x89, 0x00,        // mov    %r8w,(%rax)
3231 >                0x66, 0x42, 0x89, 0x0c, 0x10,  // mov    %cx,(%rax,%r10,1)
3232 >                0x44, 0x8b, 0x00,              // mov    (%rax),%r8d
3233 >                0x42, 0x8b, 0x0c, 0x10,        // mov    (%rax,%r10,1),%ecx
3234 >                0x44, 0x89, 0x00,              // mov    %r8d,(%rax)
3235 >                0x42, 0x89, 0x0c, 0x10,        // mov    %ecx,(%rax,%r10,1)
3236 >                0x48, 0x8b, 0x08,              // mov    (%rax),%rcx
3237 >                0x4c, 0x8b, 0x18,              // mov    (%rax),%r11
3238 >                0x4a, 0x8b, 0x0c, 0x10,        // mov    (%rax,%r10,1),%rcx
3239 >                0x4e, 0x8b, 0x1c, 0x10,        // mov    (%rax,%r10,1),%r11
3240 >                0x48, 0x89, 0x08,              // mov    %rcx,(%rax)
3241 >                0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
3242 >                0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
3243 >                0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
3244 >                0x63, 0x47, 0x04,              // movslq 4(%rdi),%eax
3245 >                0x48, 0x63, 0x47, 0x04,        // movslq 4(%rdi),%rax
3246 > #endif
3247 >                0                              // end
3248 >        };
3249 >        const int N_REGS = 20;
3250 >        SIGSEGV_REGISTER_TYPE regs[N_REGS];
3251 >        for (int i = 0; i < N_REGS; i++)
3252 >                regs[i] = i;
3253 >        const sigsegv_uintptr_t start_code = (sigsegv_uintptr_t)&code;
3254 >        regs[X86_REG_EIP] = start_code;
3255 >        while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3256 >                   && ix86_skip_instruction(regs))
3257 >                ; /* simply iterate */
3258 >        return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3259 > #endif
3260          return true;
3261   }
3262 + #endif
3263  
3264   int main(void)
3265   {
3266 <        int zero_fd = open("/dev/zero", O_RDWR);
270 <        if (zero_fd < 0)
3266 >        if (vm_init() < 0)
3267                  return 1;
3268  
3269 <        page_size = getpagesize();
3270 <        page = (char *)mmap(0, page_size, PROT_READ, MAP_PRIVATE, zero_fd, 0);
3271 <        if (page == MAP_FAILED)
3272 <                return 1;
3269 >        page_size = vm_get_page_size();
3270 >        if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3271 >                return 2;
3272 >        
3273 >        memset((void *)page, 0, page_size);
3274 >        if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3275 >                return 3;
3276          
3277          if (!sigsegv_install_handler(sigsegv_test_handler))
3278 <                return 1;
3278 >                return 4;
3279 >
3280 > #ifdef __GNUC__
3281 >        b_region = &&L_b_region1;
3282 >        e_region = &&L_e_region1;
3283 > #endif
3284 >        /* This is a really awful hack but otherwise gcc is smart enough
3285 >         * (or bug'ous enough?) to optimize the labels and place them
3286 >         * e.g. at the "main" entry point, which is wrong.
3287 >         */
3288 >        volatile int label_hack = 1;
3289 >        switch (label_hack) {
3290 >        case 1:
3291 >        L_b_region1:
3292 >                page[REF_INDEX] = REF_VALUE;
3293 >                if (page[REF_INDEX] != REF_VALUE)
3294 >                        exit(20);
3295 >                page[REF_INDEX] = REF_VALUE;
3296 >                BARRIER();
3297 >                // fall-through
3298 >        case 2:
3299 >        L_e_region1:
3300 >                BARRIER();
3301 >                break;
3302 >        }
3303 >
3304 >        if (handler_called != 1)
3305 >                return 5;
3306 >
3307 > #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3308 >        if (!sigsegv_install_handler(sigsegv_insn_handler))
3309 >                return 6;
3310          
3311 <        page[123] = 45;
3312 <        page[123] = 45;
3311 >        if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
3312 >                return 7;
3313          
3314 <        if (handler_called != 1)
3315 <                return 1;
3314 >        for (int i = 0; i < page_size; i++)
3315 >                page[i] = (i + 1) % page_size;
3316 >        
3317 >        if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
3318 >                return 8;
3319 >        
3320 > #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
3321 >                const unsigned long TAG = 0x12345678 |                  \
3322 >                (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0);   \
3323 >                TYPE data = *((TYPE *)(page + sizeof(TYPE)));   \
3324 >                volatile unsigned long effect = data + TAG;             \
3325 >                if (effect != TAG)                                                              \
3326 >                        return 9;                                                                       \
3327 >        } while (0)
3328 >        
3329 > #ifdef __GNUC__
3330 >        b_region = &&L_b_region2;
3331 >        e_region = &&L_e_region2;
3332 > #endif
3333 >        switch (label_hack) {
3334 >        case 1:
3335 >        L_b_region2:
3336 >                TEST_SKIP_INSTRUCTION(unsigned char);
3337 >                TEST_SKIP_INSTRUCTION(unsigned short);
3338 >                TEST_SKIP_INSTRUCTION(unsigned int);
3339 >                TEST_SKIP_INSTRUCTION(unsigned long);
3340 >                TEST_SKIP_INSTRUCTION(signed char);
3341 >                TEST_SKIP_INSTRUCTION(signed short);
3342 >                TEST_SKIP_INSTRUCTION(signed int);
3343 >                TEST_SKIP_INSTRUCTION(signed long);
3344 >                BARRIER();
3345 >                // fall-through
3346 >        case 2:
3347 >        L_e_region2:
3348 >                BARRIER();
3349 >                break;
3350 >        }
3351 >        if (!arch_insn_skipper_tests())
3352 >                return 20;
3353 > #endif
3354  
3355 +        vm_exit();
3356          return 0;
3357   }
3358   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines