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.30 by gbeauche, 2003-10-13T19:56:17Z vs.
Revision 1.86 by asvitkine, 2009-02-11T19:23:53Z

# Line 10 | Line 10
10   *    tjw@omnigroup.com Sun, 4 Jun 2000
11   *    www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
12   *
13 < *  Basilisk II (C) 1997-2002 Christian Bauer
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 36 | Line 36
36   #endif
37  
38   #include <list>
39 + #include <stdio.h>
40   #include <signal.h>
41   #include "sigsegv.h"
42  
# Line 48 | Line 49 | using std::list;
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  
# Line 65 | Line 77 | static bool sigsegv_do_install_handler(i
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,
92 <        SIZE_LONG
91 >        SIZE_WORD, // 2 bytes
92 >        SIZE_LONG, // 4 bytes
93 >        SIZE_QUAD  // 8 bytes
94   };
95  
96 < // Transfer type
77 < typedef sigsegv_transfer_type_t transfer_type_t;
78 <
79 < #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
96 > #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
97   // Addressing mode
98   enum addressing_mode_t {
99          MODE_UNKNOWN,
# Line 95 | Line 112 | struct instruction_t {
112          char                            ra, rd;
113   };
114  
115 < static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
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 *)nip);
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;
# Line 172 | Line 189 | static void powerpc_decode_instruction(i
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
# Line 212 | Line 241 | static void powerpc_decode_instruction(i
241  
242   #if HAVE_SIGINFO_T
243   // Generic extended signal handler
244 < #define SIGSEGV_FAULT_HANDLER                   sigsegv_fault_handler
216 < #if defined(__NetBSD__) || defined(__FreeBSD__)
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   #endif
# Line 222 | Line 252 | static void powerpc_decode_instruction(i
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(__NetBSD__) || defined(__FreeBSD__)
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                   ((unsigned int *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
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                   (unsigned int *)SIGSEGV_CONTEXT_REGS
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                   (unsigned long *)SIGSEGV_CONTEXT_REGS
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_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
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 int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
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
260 #define SIGSEGV_FAULT_HANDLER                   sigsegv_fault_handler
387   // Linux kernels prior to 2.4 ?
388   #if defined(__linux__)
389   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
# Line 268 | Line 394 | static void powerpc_decode_instruction(i
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                   (unsigned int *)scp
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__))
# Line 283 | Line 409 | static void powerpc_decode_instruction(i
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 int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
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__))
# Line 292 | Line 418 | static void powerpc_decode_instruction(i
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 <
422 < // From Boehm's GC 6.0alpha8
423 < static sigsegv_address_t get_fault_address(struct sigcontext *scp)
424 < {
425 <        unsigned int instruction = *((unsigned int *)(scp->sc_pc));
426 <        unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f];
427 <        fault_address += (signed long)(signed short)(instruction & 0xffff);
428 <        return (sigsegv_address_t)fault_address;
429 < }
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_HANDLER_ARGS              sig, code, scp
438 < #define SIGSEGV_FAULT_ADDRESS                   scp->sc_badvaddr
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  
# Line 338 | Line 465 | static sigsegv_address_t get_fault_addre
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
# Line 367 | Line 494 | static sigsegv_address_t get_fault_addre
494          }
495          return (sigsegv_address_t)fault_addr;
496   }
497 < #else
498 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, void *scp, char *addr
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_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
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
# Line 385 | Line 550 | static sigsegv_address_t get_fault_addre
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
553 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int code, struct __darwin_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
556 > #define SIGSEGV_FAULT_INSTRUCTION               scp->MACH_FIELD_NAME(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
# Line 396 | Line 561 | static sigsegv_address_t get_fault_addre
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];
564 >        unsigned int   nip = (unsigned int) scp->MACH_FIELD_NAME(sc_ir);
565 >        unsigned int * gpr = &((unsigned int *) scp->MACH_FIELD_NAME(sc_regs))[2];
566          instruction_t  instr;
567  
568 <        powerpc_decode_instruction(&instr, nip, gpr);
568 >        powerpc_decode_instruction(&instr, nip, (long unsigned int*)gpr);
569          return (sigsegv_address_t)instr.addr;
570   }
571   #endif
# Line 408 | Line 573 | static sigsegv_address_t get_fault_addre
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
# Line 428 | Line 617 | 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 *,
620 > #ifndef HAVE_MACH64_VM
621 >
622 > // Undefine this to prevent a preprocessor warning when compiling on a
623 > // 32-bit machine with Mac OS X 10.5.
624 > #undef  MACH_EXCEPTION_CODES
625 >
626 > #define MACH_EXCEPTION_CODES                                    0
627 > #define mach_exception_data_t                                   exception_data_t
628 > #define mach_exception_data_type_t                              exception_data_type_t
629 > #define mach_exc_server                                                 exc_server
630 > #define catch_mach_exception_raise                              catch_exception_raise
631 > #define mach_exception_raise                                    exception_raise
632 > #define mach_exception_raise_state                              exception_raise_state
633 > #define mach_exception_raise_state_identity             exception_raise_state_identity
634 > #endif
635 >
636 > extern boolean_t mach_exc_server(mach_msg_header_t *, mach_msg_header_t *);
637 > extern kern_return_t catch_mach_exception_raise(mach_port_t, mach_port_t,
638 >        mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t);
639 > extern kern_return_t catch_mach_exception_raise_state(mach_port_t exception_port,
640 >        exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count,
641 >        int *flavor,
642 >        thread_state_t old_state, mach_msg_type_number_t old_state_count,
643 >        thread_state_t new_state, mach_msg_type_number_t *new_state_count);
644 > extern kern_return_t catch_mach_exception_raise_state_identity(mach_port_t exception_port,
645 >        mach_port_t thread_port, mach_port_t task_port, exception_type_t exception,
646 >        mach_exception_data_t code, mach_msg_type_number_t code_count,
647 >        int *flavor,
648 >        thread_state_t old_state, mach_msg_type_number_t old_state_count,
649 >        thread_state_t new_state, mach_msg_type_number_t *new_state_count);
650 > extern kern_return_t mach_exception_raise(mach_port_t, mach_port_t, mach_port_t,
651 >        exception_type_t, mach_exception_data_t, mach_msg_type_number_t);
652 > extern kern_return_t mach_exception_raise_state(mach_port_t, exception_type_t,
653 >        mach_exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
654          thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
655 < extern kern_return_t exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
656 <        exception_type_t, exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
655 > extern kern_return_t mach_exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
656 >        exception_type_t, mach_exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *,
657          thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
658   }
659  
# Line 468 | Line 684 | if (ret != KERN_SUCCESS) { \
684          exit (1); \
685   }
686  
687 < #define SIGSEGV_FAULT_ADDRESS                   code[1]
688 < #define SIGSEGV_FAULT_INSTRUCTION               get_fault_instruction(thread, state)
689 < #define SIGSEGV_FAULT_HANDLER                   (code[0] == KERN_PROTECTION_FAILURE) && sigsegv_fault_handler
690 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
691 < #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
687 > #ifdef __ppc__
688 > #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE
689 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
690 > #endif
691 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state_t
692 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE
693 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE_COUNT
694 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(dar)
695 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state_t
696 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE
697 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE_COUNT
698 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(srr0)
699   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
700 < #define SIGSEGV_REGISTER_FILE                   &state->srr0, &state->r0
701 <
702 < // Given a suspended thread, stuff the current instruction and
703 < // registers into state.
704 < //
705 < // It would have been nice to have this be ppc/x86 independant which
706 < // could have been done easily with a thread_state_t instead of
707 < // ppc_thread_state_t, but because of the way this is called it is
708 < // easier to do it this way.
709 < #if (defined(ppc) || defined(__ppc__))
710 < static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
711 < {
712 <        kern_return_t krc;
713 <        mach_msg_type_number_t count;
714 <
715 <        count = MACHINE_THREAD_STATE_COUNT;
716 <        krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
717 <        MACH_CHECK_ERROR (thread_get_state, krc);
700 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
701 > #endif
702 > #ifdef __ppc64__
703 > #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE64
704 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
705 > #endif
706 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state64_t
707 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE64
708 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE64_COUNT
709 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(dar)
710 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state64_t
711 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE64
712 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE64_COUNT
713 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(srr0)
714 > #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
715 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
716 > #endif
717 > #ifdef __i386__
718 > #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE32
719 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
720 > #endif
721 > #define SIGSEGV_EXCEPTION_STATE_TYPE    i386_exception_state_t
722 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  i386_EXCEPTION_STATE
723 > #define SIGSEGV_EXCEPTION_STATE_COUNT   i386_EXCEPTION_STATE_COUNT
724 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
725 > #define SIGSEGV_THREAD_STATE_TYPE               i386_thread_state_t
726 > #define SIGSEGV_THREAD_STATE_FLAVOR             i386_THREAD_STATE
727 > #define SIGSEGV_THREAD_STATE_COUNT              i386_THREAD_STATE_COUNT
728 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(eip)
729 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
730 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(eax)) /* EAX is the first GPR we consider */
731 > #endif
732 > #ifdef __x86_64__
733 > #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE64
734 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
735 > #endif
736 > #define SIGSEGV_EXCEPTION_STATE_TYPE    x86_exception_state64_t
737 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  x86_EXCEPTION_STATE64
738 > #define SIGSEGV_EXCEPTION_STATE_COUNT   x86_EXCEPTION_STATE64_COUNT
739 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
740 > #define SIGSEGV_THREAD_STATE_TYPE               x86_thread_state64_t
741 > #define SIGSEGV_THREAD_STATE_FLAVOR             x86_THREAD_STATE64
742 > #define SIGSEGV_THREAD_STATE_COUNT              x86_THREAD_STATE64_COUNT
743 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(rip)
744 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
745 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(rax)) /* RAX is the first GPR we consider */
746 > #endif
747 > #define SIGSEGV_FAULT_ADDRESS_FAST              code[1]
748 > #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_INVALID_ADDRESS
749 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, mach_exception_data_t code
750 > #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code
751  
752 <        return (sigsegv_address_t)state->srr0;
753 < }
752 > #ifndef MACH_FIELD_NAME
753 > #define MACH_FIELD_NAME(X) X
754   #endif
755  
756   // Since there can only be one exception thread running at any time
# Line 526 | Line 782 | handleExceptions(void *priv)
782                                  _exceptionPort, 0, MACH_PORT_NULL);
783                  MACH_CHECK_ERROR(mach_msg, krc);
784  
785 <                if (!exc_server(msg, reply)) {
785 >                if (!mach_exc_server(msg, reply)) {
786                          fprintf(stderr, "exc_server hated the message\n");
787                          exit(1);
788                  }
# Line 548 | Line 804 | handleExceptions(void *priv)
804   *  Instruction skipping
805   */
806  
807 + #ifndef SIGSEGV_REGISTER_TYPE
808 + #define SIGSEGV_REGISTER_TYPE sigsegv_uintptr_t
809 + #endif
810 +
811   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
812   // Decode and skip X86 instruction
813 < #if (defined(i386) || defined(__i386__))
813 > #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
814   #if defined(__linux__)
815   enum {
816 + #if (defined(i386) || defined(__i386__))
817          X86_REG_EIP = 14,
818          X86_REG_EAX = 11,
819          X86_REG_ECX = 10,
# Line 562 | Line 823 | enum {
823          X86_REG_EBP = 6,
824          X86_REG_ESI = 5,
825          X86_REG_EDI = 4
826 + #endif
827 + #if defined(__x86_64__)
828 +        X86_REG_R8  = 0,
829 +        X86_REG_R9  = 1,
830 +        X86_REG_R10 = 2,
831 +        X86_REG_R11 = 3,
832 +        X86_REG_R12 = 4,
833 +        X86_REG_R13 = 5,
834 +        X86_REG_R14 = 6,
835 +        X86_REG_R15 = 7,
836 +        X86_REG_EDI = 8,
837 +        X86_REG_ESI = 9,
838 +        X86_REG_EBP = 10,
839 +        X86_REG_EBX = 11,
840 +        X86_REG_EDX = 12,
841 +        X86_REG_EAX = 13,
842 +        X86_REG_ECX = 14,
843 +        X86_REG_ESP = 15,
844 +        X86_REG_EIP = 16
845 + #endif
846 + };
847 + #endif
848 + #if defined(__NetBSD__)
849 + enum {
850 + #if (defined(i386) || defined(__i386__))
851 +        X86_REG_EIP = _REG_EIP,
852 +        X86_REG_EAX = _REG_EAX,
853 +        X86_REG_ECX = _REG_ECX,
854 +        X86_REG_EDX = _REG_EDX,
855 +        X86_REG_EBX = _REG_EBX,
856 +        X86_REG_ESP = _REG_ESP,
857 +        X86_REG_EBP = _REG_EBP,
858 +        X86_REG_ESI = _REG_ESI,
859 +        X86_REG_EDI = _REG_EDI
860 + #endif
861   };
862   #endif
863 < #if defined(__NetBSD__) || defined(__FreeBSD__)
863 > #if defined(__FreeBSD__)
864   enum {
865 + #if (defined(i386) || defined(__i386__))
866          X86_REG_EIP = 10,
867          X86_REG_EAX = 7,
868          X86_REG_ECX = 6,
# Line 575 | Line 872 | enum {
872          X86_REG_EBP = 2,
873          X86_REG_ESI = 1,
874          X86_REG_EDI = 0
875 + #endif
876 + };
877 + #endif
878 + #if defined(__OpenBSD__)
879 + enum {
880 + #if defined(__i386__)
881 +        // EDI is the first register we consider
882 + #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
883 + #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
884 +        X86_REG_EIP = DREG(eip), // 7
885 +        X86_REG_EAX = DREG(eax), // 6
886 +        X86_REG_ECX = DREG(ecx), // 5
887 +        X86_REG_EDX = DREG(edx), // 4
888 +        X86_REG_EBX = DREG(ebx), // 3
889 +        X86_REG_ESP = DREG(esp), // 10
890 +        X86_REG_EBP = DREG(ebp), // 2
891 +        X86_REG_ESI = DREG(esi), // 1
892 +        X86_REG_EDI = DREG(edi)  // 0
893 + #undef DREG
894 + #undef OREG
895 + #endif
896 + };
897 + #endif
898 + #if defined(__sun__)
899 + // Same as for Linux, need to check for x86-64
900 + enum {
901 + #if defined(__i386__)
902 +        X86_REG_EIP = EIP,
903 +        X86_REG_EAX = EAX,
904 +        X86_REG_ECX = ECX,
905 +        X86_REG_EDX = EDX,
906 +        X86_REG_EBX = EBX,
907 +        X86_REG_ESP = ESP,
908 +        X86_REG_EBP = EBP,
909 +        X86_REG_ESI = ESI,
910 +        X86_REG_EDI = EDI
911 + #endif
912 + };
913 + #endif
914 + #if defined(__APPLE__) && defined(__MACH__)
915 + enum {
916 + #if (defined(i386) || defined(__i386__))
917 + #ifdef i386_SAVED_STATE
918 +        // same as FreeBSD (in Open Darwin 8.0.1)
919 +        X86_REG_EIP = 10,
920 +        X86_REG_EAX = 7,
921 +        X86_REG_ECX = 6,
922 +        X86_REG_EDX = 5,
923 +        X86_REG_EBX = 4,
924 +        X86_REG_ESP = 13,
925 +        X86_REG_EBP = 2,
926 +        X86_REG_ESI = 1,
927 +        X86_REG_EDI = 0
928 + #else
929 +        // new layout (MacOS X 10.4.4 for x86)
930 +        X86_REG_EIP = 10,
931 +        X86_REG_EAX = 0,
932 +        X86_REG_ECX = 2,
933 +        X86_REG_EDX = 3,
934 +        X86_REG_EBX = 1,
935 +        X86_REG_ESP = 7,
936 +        X86_REG_EBP = 6,
937 +        X86_REG_ESI = 5,
938 +        X86_REG_EDI = 4
939 + #endif
940 + #endif
941 + #if defined(__x86_64__)
942 +        X86_REG_R8  = 8,
943 +        X86_REG_R9  = 9,
944 +        X86_REG_R10 = 10,
945 +        X86_REG_R11 = 11,
946 +        X86_REG_R12 = 12,
947 +        X86_REG_R13 = 13,
948 +        X86_REG_R14 = 14,
949 +        X86_REG_R15 = 15,
950 +        X86_REG_EDI = 4,
951 +        X86_REG_ESI = 5,
952 +        X86_REG_EBP = 6,
953 +        X86_REG_EBX = 1,
954 +        X86_REG_EDX = 3,
955 +        X86_REG_EAX = 0,
956 +        X86_REG_ECX = 2,
957 +        X86_REG_ESP = 7,
958 +        X86_REG_EIP = 16
959 + #endif
960 + };
961 + #endif
962 + #if defined(_WIN32)
963 + enum {
964 + #if defined(_M_IX86)
965 +        X86_REG_EIP = 7,
966 +        X86_REG_EAX = 5,
967 +        X86_REG_ECX = 4,
968 +        X86_REG_EDX = 3,
969 +        X86_REG_EBX = 2,
970 +        X86_REG_ESP = 10,
971 +        X86_REG_EBP = 6,
972 +        X86_REG_ESI = 1,
973 +        X86_REG_EDI = 0
974 + #endif
975 + #if defined(_M_X64)
976 +        X86_REG_EAX = 0,
977 +        X86_REG_ECX = 1,
978 +        X86_REG_EDX = 2,
979 +        X86_REG_EBX = 3,
980 +        X86_REG_ESP = 4,
981 +        X86_REG_EBP = 5,
982 +        X86_REG_ESI = 6,
983 +        X86_REG_EDI = 7,
984 +        X86_REG_R8  = 8,
985 +        X86_REG_R9  = 9,
986 +        X86_REG_R10 = 10,
987 +        X86_REG_R11 = 11,
988 +        X86_REG_R12 = 12,
989 +        X86_REG_R13 = 13,
990 +        X86_REG_R14 = 14,
991 +        X86_REG_R15 = 15,
992 +        X86_REG_EIP = 16
993 + #endif
994   };
995   #endif
996   // FIXME: this is partly redundant with the instruction decoding phase
# Line 611 | Line 1027 | static inline int ix86_step_over_modrm(u
1027          return offset;
1028   }
1029  
1030 < static bool ix86_skip_instruction(unsigned int * regs)
1030 > static bool ix86_skip_instruction(SIGSEGV_REGISTER_TYPE * regs)
1031   {
1032          unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
1033  
1034          if (eip == 0)
1035                  return false;
1036 + #ifdef _WIN32
1037 +        if (IsBadCodePtr((FARPROC)eip))
1038 +                return false;
1039 + #endif
1040          
1041 +        enum instruction_type_t {
1042 +                i_MOV,
1043 +                i_ADD
1044 +        };
1045 +
1046          transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1047          transfer_size_t transfer_size = SIZE_LONG;
1048 +        instruction_type_t instruction_type = i_MOV;
1049          
1050          int reg = -1;
1051          int len = 0;
1052 <        
1052 >
1053 > #if DEBUG
1054 >        printf("IP: %p [%02x %02x %02x %02x...]\n",
1055 >                   eip, eip[0], eip[1], eip[2], eip[3]);
1056 > #endif
1057 >
1058          // Operand size prefix
1059          if (*eip == 0x66) {
1060                  eip++;
# Line 631 | Line 1062 | static bool ix86_skip_instruction(unsign
1062                  transfer_size = SIZE_WORD;
1063          }
1064  
1065 +        // REX prefix
1066 + #if defined(__x86_64__) || defined(_M_X64)
1067 +        struct rex_t {
1068 +                unsigned char W;
1069 +                unsigned char R;
1070 +                unsigned char X;
1071 +                unsigned char B;
1072 +        };
1073 +        rex_t rex = { 0, 0, 0, 0 };
1074 +        bool has_rex = false;
1075 +        if ((*eip & 0xf0) == 0x40) {
1076 +                has_rex = true;
1077 +                const unsigned char b = *eip;
1078 +                rex.W = b & (1 << 3);
1079 +                rex.R = b & (1 << 2);
1080 +                rex.X = b & (1 << 1);
1081 +                rex.B = b & (1 << 0);
1082 + #if DEBUG
1083 +                printf("REX: %c,%c,%c,%c\n",
1084 +                           rex.W ? 'W' : '_',
1085 +                           rex.R ? 'R' : '_',
1086 +                           rex.X ? 'X' : '_',
1087 +                           rex.B ? 'B' : '_');
1088 + #endif
1089 +                eip++;
1090 +                len++;
1091 +                if (rex.W)
1092 +                        transfer_size = SIZE_QUAD;
1093 +        }
1094 + #else
1095 +        const bool has_rex = false;
1096 + #endif
1097 +
1098          // Decode instruction
1099 +        int op_len = 1;
1100 +        int target_size = SIZE_UNKNOWN;
1101          switch (eip[0]) {
1102          case 0x0f:
1103 +                target_size = transfer_size;
1104              switch (eip[1]) {
1105 +                case 0xbe: // MOVSX r32, r/m8
1106              case 0xb6: // MOVZX r32, r/m8
1107 +                        transfer_size = SIZE_BYTE;
1108 +                        goto do_mov_extend;
1109 +                case 0xbf: // MOVSX r32, r/m16
1110              case 0xb7: // MOVZX r32, r/m16
1111 <                switch (eip[2] & 0xc0) {
1112 <                case 0x80:
1113 <                    reg = (eip[2] >> 3) & 7;
1114 <                    transfer_type = SIGSEGV_TRANSFER_LOAD;
1115 <                    break;
645 <                case 0x40:
646 <                    reg = (eip[2] >> 3) & 7;
647 <                    transfer_type = SIGSEGV_TRANSFER_LOAD;
648 <                    break;
649 <                case 0x00:
650 <                    reg = (eip[2] >> 3) & 7;
651 <                    transfer_type = SIGSEGV_TRANSFER_LOAD;
652 <                    break;
1111 >                        transfer_size = SIZE_WORD;
1112 >                        goto do_mov_extend;
1113 >                  do_mov_extend:
1114 >                        op_len = 2;
1115 >                        goto do_transfer_load;
1116                  }
654                len += 3 + ix86_step_over_modrm(eip + 2);
1117                  break;
1118 <            }
1119 <          break;
1118 > #if defined(__x86_64__) || defined(_M_X64)
1119 >        case 0x63: // MOVSXD r64, r/m32
1120 >                if (has_rex && rex.W) {
1121 >                        transfer_size = SIZE_LONG;
1122 >                        target_size = SIZE_QUAD;
1123 >                }
1124 >                else if (transfer_size != SIZE_WORD) {
1125 >                        transfer_size = SIZE_LONG;
1126 >                        target_size = SIZE_QUAD;
1127 >                }
1128 >                goto do_transfer_load;
1129 > #endif
1130 >        case 0x02: // ADD r8, r/m8
1131 >                transfer_size = SIZE_BYTE;
1132 >        case 0x03: // ADD r32, r/m32
1133 >                instruction_type = i_ADD;
1134 >                goto do_transfer_load;
1135          case 0x8a: // MOV r8, r/m8
1136                  transfer_size = SIZE_BYTE;
1137          case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1138 <                switch (eip[1] & 0xc0) {
1138 >          do_transfer_load:
1139 >                switch (eip[op_len] & 0xc0) {
1140                  case 0x80:
1141 <                        reg = (eip[1] >> 3) & 7;
1141 >                        reg = (eip[op_len] >> 3) & 7;
1142                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1143                          break;
1144                  case 0x40:
1145 <                        reg = (eip[1] >> 3) & 7;
1145 >                        reg = (eip[op_len] >> 3) & 7;
1146                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1147                          break;
1148                  case 0x00:
1149 <                        reg = (eip[1] >> 3) & 7;
1149 >                        reg = (eip[op_len] >> 3) & 7;
1150                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1151                          break;
1152                  }
1153 <                len += 2 + ix86_step_over_modrm(eip + 1);
1153 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1154                  break;
1155 +        case 0x00: // ADD r/m8, r8
1156 +                transfer_size = SIZE_BYTE;
1157 +        case 0x01: // ADD r/m32, r32
1158 +                instruction_type = i_ADD;
1159 +                goto do_transfer_store;
1160          case 0x88: // MOV r/m8, r8
1161                  transfer_size = SIZE_BYTE;
1162          case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1163 <                switch (eip[1] & 0xc0) {
1163 >          do_transfer_store:
1164 >                switch (eip[op_len] & 0xc0) {
1165                  case 0x80:
1166 <                        reg = (eip[1] >> 3) & 7;
1166 >                        reg = (eip[op_len] >> 3) & 7;
1167                          transfer_type = SIGSEGV_TRANSFER_STORE;
1168                          break;
1169                  case 0x40:
1170 <                        reg = (eip[1] >> 3) & 7;
1170 >                        reg = (eip[op_len] >> 3) & 7;
1171                          transfer_type = SIGSEGV_TRANSFER_STORE;
1172                          break;
1173                  case 0x00:
1174 <                        reg = (eip[1] >> 3) & 7;
1174 >                        reg = (eip[op_len] >> 3) & 7;
1175                          transfer_type = SIGSEGV_TRANSFER_STORE;
1176                          break;
1177                  }
1178 <                len += 2 + ix86_step_over_modrm(eip + 1);
1178 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1179                  break;
1180          }
1181 +        if (target_size == SIZE_UNKNOWN)
1182 +                target_size = transfer_size;
1183  
1184          if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1185                  // Unknown machine code, let it crash. Then patch the decoder
1186                  return false;
1187          }
1188  
1189 <        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1190 <                static const int x86_reg_map[8] = {
1189 > #if defined(__x86_64__) || defined(_M_X64)
1190 >        if (rex.R)
1191 >                reg += 8;
1192 > #endif
1193 >
1194 >        if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1195 >                static const int x86_reg_map[] = {
1196                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1197 <                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
1197 >                        X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1198 > #if defined(__x86_64__) || defined(_M_X64)
1199 >                        X86_REG_R8,  X86_REG_R9,  X86_REG_R10, X86_REG_R11,
1200 >                        X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1201 > #endif
1202                  };
1203                  
1204 <                if (reg < 0 || reg >= 8)
1204 >                if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1))
1205                          return false;
1206  
1207 +                // Set 0 to the relevant register part
1208 +                // NOTE: this is only valid for MOV alike instructions
1209                  int rloc = x86_reg_map[reg];
1210 <                switch (transfer_size) {
1210 >                switch (target_size) {
1211                  case SIZE_BYTE:
1212 <                        regs[rloc] = (regs[rloc] & ~0xff);
1212 >                        if (has_rex || reg < 4)
1213 >                                regs[rloc] = (regs[rloc] & ~0x00ffL);
1214 >                        else {
1215 >                                rloc = x86_reg_map[reg - 4];
1216 >                                regs[rloc] = (regs[rloc] & ~0xff00L);
1217 >                        }
1218                          break;
1219                  case SIZE_WORD:
1220 <                        regs[rloc] = (regs[rloc] & ~0xffff);
1220 >                        regs[rloc] = (regs[rloc] & ~0xffffL);
1221                          break;
1222                  case SIZE_LONG:
1223 +                case SIZE_QUAD: // zero-extension
1224                          regs[rloc] = 0;
1225                          break;
1226                  }
1227          }
1228  
1229   #if DEBUG
1230 <        printf("%08x: %s %s access", regs[X86_REG_EIP],
1231 <                   transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
1230 >        printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1231 >                   transfer_size == SIZE_BYTE ? "byte" :
1232 >                   transfer_size == SIZE_WORD ? "word" :
1233 >                   transfer_size == SIZE_LONG ? "long" :
1234 >                   transfer_size == SIZE_QUAD ? "quad" : "unknown",
1235                     transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1236          
1237          if (reg != -1) {
1238 <                static const char * x86_reg_str_map[8] = {
1239 <                        "eax", "ecx", "edx", "ebx",
1240 <                        "esp", "ebp", "esi", "edi"
1238 >                static const char * x86_byte_reg_str_map[] = {
1239 >                        "al",   "cl",   "dl",   "bl",
1240 >                        "spl",  "bpl",  "sil",  "dil",
1241 >                        "r8b",  "r9b",  "r10b", "r11b",
1242 >                        "r12b", "r13b", "r14b", "r15b",
1243 >                        "ah",   "ch",   "dh",   "bh",
1244 >                };
1245 >                static const char * x86_word_reg_str_map[] = {
1246 >                        "ax",   "cx",   "dx",   "bx",
1247 >                        "sp",   "bp",   "si",   "di",
1248 >                        "r8w",  "r9w",  "r10w", "r11w",
1249 >                        "r12w", "r13w", "r14w", "r15w",
1250                  };
1251 <                printf(" %s register %%%s", transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from", x86_reg_str_map[reg]);
1251 >                static const char *x86_long_reg_str_map[] = {
1252 >                        "eax",  "ecx",  "edx",  "ebx",
1253 >                        "esp",  "ebp",  "esi",  "edi",
1254 >                        "r8d",  "r9d",  "r10d", "r11d",
1255 >                        "r12d", "r13d", "r14d", "r15d",
1256 >                };
1257 >                static const char *x86_quad_reg_str_map[] = {
1258 >                        "rax", "rcx", "rdx", "rbx",
1259 >                        "rsp", "rbp", "rsi", "rdi",
1260 >                        "r8",  "r9",  "r10", "r11",
1261 >                        "r12", "r13", "r14", "r15",
1262 >                };
1263 >                const char * reg_str = NULL;
1264 >                switch (target_size) {
1265 >                case SIZE_BYTE:
1266 >                        reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1267 >                        break;
1268 >                case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break;
1269 >                case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break;
1270 >                case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break;
1271 >                }
1272 >                if (reg_str)
1273 >                        printf(" %s register %%%s",
1274 >                                   transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from",
1275 >                                   reg_str);
1276          }
1277          printf(", %d bytes instruction\n", len);
1278   #endif
# Line 743 | Line 1282 | static bool ix86_skip_instruction(unsign
1282   }
1283   #endif
1284  
1285 + // Decode and skip IA-64 instruction
1286 + #if defined(__ia64) || defined(__ia64__)
1287 + typedef uint64_t ia64_bundle_t[2];
1288 + #if defined(__linux__)
1289 + // We can directly patch the slot number
1290 + #define IA64_CAN_PATCH_IP_SLOT  1
1291 + // Helper macros to access the machine context
1292 + #define IA64_CONTEXT_TYPE               struct sigcontext *
1293 + #define IA64_CONTEXT                    scp
1294 + #define IA64_GET_IP()                   (IA64_CONTEXT->sc_ip)
1295 + #define IA64_SET_IP(V)                  (IA64_CONTEXT->sc_ip = (V))
1296 + #define IA64_GET_PR(P)                  ((IA64_CONTEXT->sc_pr >> (P)) & 1)
1297 + #define IA64_GET_NAT(I)                 ((IA64_CONTEXT->sc_nat >> (I)) & 1)
1298 + #define IA64_GET_GR(R)                  (IA64_CONTEXT->sc_gr[(R)])
1299 + #define _IA64_SET_GR(R,V)               (IA64_CONTEXT->sc_gr[(R)] = (V))
1300 + #define _IA64_SET_NAT(I,V)              (IA64_CONTEXT->sc_nat = (IA64_CONTEXT->sc_nat & ~(1ull << (I))) | (((uint64_t)!!(V)) << (I)))
1301 + #define IA64_SET_GR(R,V,N)              (_IA64_SET_GR(R,V), _IA64_SET_NAT(R,N))
1302 +
1303 + // Load bundle (in little-endian)
1304 + static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1305 + {
1306 +        uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1307 +        bundle[0] = ip[0];
1308 +        bundle[1] = ip[1];
1309 + }
1310 + #endif
1311 + #if defined(__hpux) || defined(__hpux__)
1312 + // We can directly patch the slot number
1313 + #define IA64_CAN_PATCH_IP_SLOT  1
1314 + // Helper macros to access the machine context
1315 + #define IA64_CONTEXT_TYPE               ucontext_t *
1316 + #define IA64_CONTEXT                    ucp
1317 + #define IA64_GET_IP()                   ia64_get_ip(IA64_CONTEXT)
1318 + #define IA64_SET_IP(V)                  ia64_set_ip(IA64_CONTEXT, V)
1319 + #define IA64_GET_PR(P)                  ia64_get_pr(IA64_CONTEXT, P)
1320 + #define IA64_GET_NAT(I)                 ia64_get_nat(IA64_CONTEXT, I)
1321 + #define IA64_GET_GR(R)                  ia64_get_gr(IA64_CONTEXT, R)
1322 + #define IA64_SET_GR(R,V,N)              ia64_set_gr(IA64_CONTEXT, R, V, N)
1323 + #define UC_ACCESS(FUNC,ARGS)    do { if (__uc_##FUNC ARGS != 0) abort(); } while (0)
1324 +
1325 + static inline uint64_t ia64_get_ip(IA64_CONTEXT_TYPE IA64_CONTEXT)
1326 +        { uint64_t v; UC_ACCESS(get_ip,(IA64_CONTEXT, &v)); return v; }
1327 + static inline void ia64_set_ip(IA64_CONTEXT_TYPE IA64_CONTEXT, uint64_t v)
1328 +        { UC_ACCESS(set_ip,(IA64_CONTEXT, v)); }
1329 + static inline unsigned int ia64_get_pr(IA64_CONTEXT_TYPE IA64_CONTEXT, int pr)
1330 +        { uint64_t v; UC_ACCESS(get_prs,(IA64_CONTEXT, &v)); return (v >> pr) & 1; }
1331 + static inline unsigned int ia64_get_nat(IA64_CONTEXT_TYPE IA64_CONTEXT, int r)
1332 +        { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return (nat >> r) & 1; }
1333 + static inline uint64_t ia64_get_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r)
1334 +        { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return v; }
1335 +
1336 + static void ia64_set_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r, uint64_t v, unsigned int nat)
1337 + {
1338 +        if (r == 0)
1339 +                return;
1340 +        if (r > 0 && r < 32)
1341 +                UC_ACCESS(set_grs,(IA64_CONTEXT, r, 1, &v, (!!nat) << r));
1342 +        else {
1343 +                uint64_t bsp, bspstore;
1344 +                UC_ACCESS(get_ar_bsp,(IA64_CONTEXT, &bsp));
1345 +                UC_ACCESS(get_ar_bspstore,(IA64_CONTEXT, &bspstore));
1346 +                abort(); /* XXX: use libunwind, this is not fun... */
1347 +        }
1348 + }
1349 +
1350 + // Byte-swapping
1351 + #if defined(__GNUC__)
1352 + #define BSWAP64(V) ({ uint64_t r; __asm__ __volatile__("mux1 %0=%1,@rev;;" : "=r" (r) : "r" (V)); r; })
1353 + #elif defined (__HP_aCC)
1354 + #define BSWAP64(V) _Asm_mux1(_MBTYPE_REV, V)
1355 + #else
1356 + #error "Define byte-swap instruction"
1357 + #endif
1358 +
1359 + // Load bundle (in little-endian)
1360 + static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip)
1361 + {
1362 +        uint64_t *ip = (uint64_t *)(raw_ip & ~3ull);
1363 +        bundle[0] = BSWAP64(ip[0]);
1364 +        bundle[1] = BSWAP64(ip[1]);
1365 + }
1366 + #endif
1367 +
1368 + // Instruction operations
1369 + enum {
1370 +        IA64_INST_UNKNOWN = 0,
1371 +        IA64_INST_LD1,                          // ld1 op0=[op1]
1372 +        IA64_INST_LD1_UPDATE,           // ld1 op0=[op1],op2
1373 +        IA64_INST_LD2,                          // ld2 op0=[op1]
1374 +        IA64_INST_LD2_UPDATE,           // ld2 op0=[op1],op2
1375 +        IA64_INST_LD4,                          // ld4 op0=[op1]
1376 +        IA64_INST_LD4_UPDATE,           // ld4 op0=[op1],op2
1377 +        IA64_INST_LD8,                          // ld8 op0=[op1]
1378 +        IA64_INST_LD8_UPDATE,           // ld8 op0=[op1],op2
1379 +        IA64_INST_ST1,                          // st1 [op0]=op1
1380 +        IA64_INST_ST1_UPDATE,           // st1 [op0]=op1,op2
1381 +        IA64_INST_ST2,                          // st2 [op0]=op1
1382 +        IA64_INST_ST2_UPDATE,           // st2 [op0]=op1,op2
1383 +        IA64_INST_ST4,                          // st4 [op0]=op1
1384 +        IA64_INST_ST4_UPDATE,           // st4 [op0]=op1,op2
1385 +        IA64_INST_ST8,                          // st8 [op0]=op1
1386 +        IA64_INST_ST8_UPDATE,           // st8 [op0]=op1,op2
1387 +        IA64_INST_ADD,                          // add op0=op1,op2,op3
1388 +        IA64_INST_SUB,                          // sub op0=op1,op2,op3
1389 +        IA64_INST_SHLADD,                       // shladd op0=op1,op3,op2
1390 +        IA64_INST_AND,                          // and op0=op1,op2
1391 +        IA64_INST_ANDCM,                        // andcm op0=op1,op2
1392 +        IA64_INST_OR,                           // or op0=op1,op2
1393 +        IA64_INST_XOR,                          // xor op0=op1,op2
1394 +        IA64_INST_SXT1,                         // sxt1 op0=op1
1395 +        IA64_INST_SXT2,                         // sxt2 op0=op1
1396 +        IA64_INST_SXT4,                         // sxt4 op0=op1
1397 +        IA64_INST_ZXT1,                         // zxt1 op0=op1
1398 +        IA64_INST_ZXT2,                         // zxt2 op0=op1
1399 +        IA64_INST_ZXT4,                         // zxt4 op0=op1
1400 +        IA64_INST_NOP                           // nop op0
1401 + };
1402 +
1403 + const int IA64_N_OPERANDS = 4;
1404 +
1405 + // Decoded operand type
1406 + struct ia64_operand_t {
1407 +        uint8_t commit;                         // commit result of operation to register file?
1408 +        uint8_t valid;                          // XXX: not really used, can be removed (debug)
1409 +        int8_t index;                           // index of GPR, or -1 if immediate value
1410 +        uint8_t nat;                            // NaT state before operation
1411 +        uint64_t value;                         // register contents or immediate value
1412 + };
1413 +
1414 + // Decoded instruction type
1415 + struct ia64_instruction_t {
1416 +        uint8_t mnemo;                          // operation to perform
1417 +        uint8_t pred;                           // predicate register to check
1418 +        uint8_t no_memory;                      // used to emulated main fault instruction
1419 +        uint64_t inst;                          // the raw instruction bits (41-bit wide)
1420 +        ia64_operand_t operands[IA64_N_OPERANDS];
1421 + };
1422 +
1423 + // Get immediate sign-bit
1424 + static inline int ia64_inst_get_sbit(uint64_t inst)
1425 + {
1426 +        return (inst >> 36) & 1;
1427 + }
1428 +
1429 + // Get 8-bit immediate value (A3, A8, I27, M30)
1430 + static inline uint64_t ia64_inst_get_imm8(uint64_t inst)
1431 + {
1432 +        uint64_t value = (inst >> 13) & 0x7full;
1433 +        if (ia64_inst_get_sbit(inst))
1434 +                value |= ~0x7full;
1435 +        return value;
1436 + }
1437 +
1438 + // Get 9-bit immediate value (M3)
1439 + static inline uint64_t ia64_inst_get_imm9b(uint64_t inst)
1440 + {
1441 +        uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1442 +        if (ia64_inst_get_sbit(inst))
1443 +                value |= ~0xffull;
1444 +        return value;
1445 + }
1446 +
1447 + // Get 9-bit immediate value (M5)
1448 + static inline uint64_t ia64_inst_get_imm9a(uint64_t inst)
1449 + {
1450 +        uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1451 +        if (ia64_inst_get_sbit(inst))
1452 +                value |= ~0xffull;
1453 +        return value;
1454 + }
1455 +
1456 + // Get 14-bit immediate value (A4)
1457 + static inline uint64_t ia64_inst_get_imm14(uint64_t inst)
1458 + {
1459 +        uint64_t value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1460 +        if (ia64_inst_get_sbit(inst))
1461 +                value |= ~0x1ffull;
1462 +        return value;
1463 + }
1464 +
1465 + // Get 22-bit immediate value (A5)
1466 + static inline uint64_t ia64_inst_get_imm22(uint64_t inst)
1467 + {
1468 +        uint64_t value = ((((inst >> 22) & 0x1f) << 16) |
1469 +                                          (((inst >> 27) & 0x1ff) << 7) |
1470 +                                          (inst & 0x7f));
1471 +        if (ia64_inst_get_sbit(inst))
1472 +                value |= ~0x1fffffull;
1473 +        return value;
1474 + }
1475 +
1476 + // Get 21-bit immediate value (I19)
1477 + static inline uint64_t ia64_inst_get_imm21(uint64_t inst)
1478 + {
1479 +        return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1480 + }
1481 +
1482 + // Get 2-bit count value (A2)
1483 + static inline int ia64_inst_get_count2(uint64_t inst)
1484 + {
1485 +        return (inst >> 27) & 0x3;
1486 + }
1487 +
1488 + // Get bundle template
1489 + static inline unsigned int ia64_get_template(uint64_t ip)
1490 + {
1491 +        ia64_bundle_t bundle;
1492 +        ia64_load_bundle(bundle, ip);
1493 +        return bundle[0] & 0x1f;
1494 + }
1495 +
1496 + // Get specified instruction in bundle
1497 + static uint64_t ia64_get_instruction(uint64_t ip, int slot)
1498 + {
1499 +        uint64_t inst;
1500 +        ia64_bundle_t bundle;
1501 +        ia64_load_bundle(bundle, ip);
1502 + #if DEBUG
1503 +        printf("Bundle: %016llx%016llx\n", bundle[1], bundle[0]);
1504 + #endif
1505 +
1506 +        switch (slot) {
1507 +        case 0:
1508 +                inst = (bundle[0] >> 5) & 0x1ffffffffffull;
1509 +                break;
1510 +        case 1:
1511 +                inst = ((bundle[1] & 0x7fffffull) << 18) | ((bundle[0] >> 46) & 0x3ffffull);
1512 +                break;
1513 +        case 2:
1514 +                inst = (bundle[1] >> 23) & 0x1ffffffffffull;
1515 +                break;
1516 +        case 3:
1517 +                fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1518 +                abort();
1519 +                break;
1520 +        }
1521 +
1522 + #if DEBUG
1523 +        printf(" Instruction %d: 0x%016llx\n", slot, inst);
1524 + #endif
1525 +        return inst;
1526 + }
1527 +
1528 + // Decode group 0 instructions
1529 + static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1530 + {
1531 +        const int r1 = (inst->inst >>  6) & 0x7f;
1532 +        const int r3 = (inst->inst >> 20) & 0x7f;
1533 +
1534 +        const int x3 = (inst->inst >> 33) & 0x07;
1535 +        const int x6 = (inst->inst >> 27) & 0x3f;
1536 +        const int x2 = (inst->inst >> 31) & 0x03;
1537 +        const int x4 = (inst->inst >> 27) & 0x0f;
1538 +
1539 +        if (x3 == 0) {
1540 +                switch (x6) {
1541 +                case 0x01:                                              // nop.i (I19)
1542 +                        inst->mnemo = IA64_INST_NOP;
1543 +                        inst->operands[0].valid = true;
1544 +                        inst->operands[0].index = -1;
1545 +                        inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1546 +                        return true;
1547 +                case 0x14:                                              // sxt1 (I29)
1548 +                case 0x15:                                              // sxt2 (I29)
1549 +                case 0x16:                                              // sxt4 (I29)
1550 +                case 0x10:                                              // zxt1 (I29)
1551 +                case 0x11:                                              // zxt2 (I29)
1552 +                case 0x12:                                              // zxt4 (I29)
1553 +                        switch (x6) {
1554 +                        case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1555 +                        case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1556 +                        case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1557 +                        case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1558 +                        case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1559 +                        case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1560 +                        default: abort();
1561 +                        }
1562 +                        inst->operands[0].valid = true;
1563 +                        inst->operands[0].index = r1;
1564 +                        inst->operands[1].valid = true;
1565 +                        inst->operands[1].index = r3;
1566 +                        inst->operands[1].value = IA64_GET_GR(r3);
1567 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1568 +                        return true;
1569 +                }
1570 +        }
1571 +        return false;
1572 + }
1573 +
1574 + // Decode group 4 instructions (load/store instructions)
1575 + static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1576 + {
1577 +        const int r1 = (inst->inst >> 6) & 0x7f;
1578 +        const int r2 = (inst->inst >> 13) & 0x7f;
1579 +        const int r3 = (inst->inst >> 20) & 0x7f;
1580 +
1581 +        const int m  = (inst->inst >> 36) & 1;
1582 +        const int x  = (inst->inst >> 27) & 1;
1583 +        const int x6 = (inst->inst >> 30) & 0x3f;
1584 +
1585 +        switch (x6) {
1586 +        case 0x00:
1587 +        case 0x01:
1588 +        case 0x02:
1589 +        case 0x03:
1590 +                if (x == 0) {
1591 +                        inst->operands[0].valid = true;
1592 +                        inst->operands[0].index = r1;
1593 +                        inst->operands[1].valid = true;
1594 +                        inst->operands[1].index = r3;
1595 +                        inst->operands[1].value = IA64_GET_GR(r3);
1596 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1597 +                        if (m == 0) {
1598 +                                switch (x6) {
1599 +                                case 0x00: inst->mnemo = IA64_INST_LD1; break;
1600 +                                case 0x01: inst->mnemo = IA64_INST_LD2; break;
1601 +                                case 0x02: inst->mnemo = IA64_INST_LD4; break;
1602 +                                case 0x03: inst->mnemo = IA64_INST_LD8; break;
1603 +                                }
1604 +                        }
1605 +                        else {
1606 +                                inst->operands[2].valid = true;
1607 +                                inst->operands[2].index = r2;
1608 +                                inst->operands[2].value = IA64_GET_GR(r2);
1609 +                                inst->operands[2].nat   = IA64_GET_NAT(r2);
1610 +                                switch (x6) {
1611 +                                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1612 +                                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1613 +                                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1614 +                                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1615 +                                }
1616 +                        }
1617 +                        return true;
1618 +                }
1619 +                break;
1620 +        case 0x30:
1621 +        case 0x31:
1622 +        case 0x32:
1623 +        case 0x33:
1624 +                if (m == 0 && x == 0) {
1625 +                        inst->operands[0].valid = true;
1626 +                        inst->operands[0].index = r3;
1627 +                        inst->operands[0].value = IA64_GET_GR(r3);
1628 +                        inst->operands[0].nat   = IA64_GET_NAT(r3);
1629 +                        inst->operands[1].valid = true;
1630 +                        inst->operands[1].index = r2;
1631 +                        inst->operands[1].value = IA64_GET_GR(r2);
1632 +                        inst->operands[1].nat   = IA64_GET_NAT(r2);
1633 +                        switch (x6) {
1634 +                        case 0x30: inst->mnemo = IA64_INST_ST1; break;
1635 +                        case 0x31: inst->mnemo = IA64_INST_ST2; break;
1636 +                        case 0x32: inst->mnemo = IA64_INST_ST4; break;
1637 +                        case 0x33: inst->mnemo = IA64_INST_ST8; break;
1638 +                        }
1639 +                        return true;
1640 +                }
1641 +                break;
1642 +        }
1643 +        return false;
1644 + }
1645 +
1646 + // Decode group 5 instructions (load/store instructions)
1647 + static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1648 + {
1649 +        const int r1 = (inst->inst >> 6) & 0x7f;
1650 +        const int r2 = (inst->inst >> 13) & 0x7f;
1651 +        const int r3 = (inst->inst >> 20) & 0x7f;
1652 +
1653 +        const int x6 = (inst->inst >> 30) & 0x3f;
1654 +
1655 +        switch (x6) {
1656 +        case 0x00:
1657 +        case 0x01:
1658 +        case 0x02:
1659 +        case 0x03:
1660 +                inst->operands[0].valid = true;
1661 +                inst->operands[0].index = r1;
1662 +                inst->operands[1].valid = true;
1663 +                inst->operands[1].index = r3;
1664 +                inst->operands[1].value = IA64_GET_GR(r3);
1665 +                inst->operands[1].nat   = IA64_GET_NAT(r3);
1666 +                inst->operands[2].valid = true;
1667 +                inst->operands[2].index = -1;
1668 +                inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1669 +                inst->operands[2].nat   = 0;
1670 +                switch (x6) {
1671 +                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1672 +                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1673 +                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1674 +                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1675 +                }
1676 +                return true;
1677 +        case 0x30:
1678 +        case 0x31:
1679 +        case 0x32:
1680 +        case 0x33:
1681 +                inst->operands[0].valid = true;
1682 +                inst->operands[0].index = r3;
1683 +                inst->operands[0].value = IA64_GET_GR(r3);
1684 +                inst->operands[0].nat   = IA64_GET_NAT(r3);
1685 +                inst->operands[1].valid = true;
1686 +                inst->operands[1].index = r2;
1687 +                inst->operands[1].value = IA64_GET_GR(r2);
1688 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1689 +                inst->operands[2].valid = true;
1690 +                inst->operands[2].index = -1;
1691 +                inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1692 +                inst->operands[2].nat   = 0;
1693 +                switch (x6) {
1694 +                case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1695 +                case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1696 +                case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1697 +                case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1698 +                }
1699 +                return true;
1700 +        }
1701 +        return false;
1702 + }
1703 +
1704 + // Decode group 8 instructions (ALU integer)
1705 + static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1706 + {
1707 +        const int r1  = (inst->inst >> 6) & 0x7f;
1708 +        const int r2  = (inst->inst >> 13) & 0x7f;
1709 +        const int r3  = (inst->inst >> 20) & 0x7f;
1710 +
1711 +        const int x2a = (inst->inst >> 34) & 0x3;
1712 +        const int x2b = (inst->inst >> 27) & 0x3;
1713 +        const int x4  = (inst->inst >> 29) & 0xf;
1714 +        const int ve  = (inst->inst >> 33) & 0x1;
1715 +
1716 +        // destination register (r1) is always valid in this group
1717 +        inst->operands[0].valid = true;
1718 +        inst->operands[0].index = r1;
1719 +
1720 +        // source register (r3) is always valid in this group
1721 +        inst->operands[2].valid = true;
1722 +        inst->operands[2].index = r3;
1723 +        inst->operands[2].value = IA64_GET_GR(r3);
1724 +        inst->operands[2].nat   = IA64_GET_NAT(r3);
1725 +
1726 +        if (x2a == 0 && ve == 0) {
1727 +                inst->operands[1].valid = true;
1728 +                inst->operands[1].index = r2;
1729 +                inst->operands[1].value = IA64_GET_GR(r2);
1730 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1731 +                switch (x4) {
1732 +                case 0x0:                               // add (A1)
1733 +                        inst->mnemo = IA64_INST_ADD;
1734 +                        inst->operands[3].valid = true;
1735 +                        inst->operands[3].index = -1;
1736 +                        inst->operands[3].value = x2b == 1;
1737 +                        return true;
1738 +                case 0x1:                               // add (A1)
1739 +                        inst->mnemo = IA64_INST_SUB;
1740 +                        inst->operands[3].valid = true;
1741 +                        inst->operands[3].index = -1;
1742 +                        inst->operands[3].value = x2b == 0;
1743 +                        return true;
1744 +                case 0x4:                               // shladd (A2)
1745 +                        inst->mnemo = IA64_INST_SHLADD;
1746 +                        inst->operands[3].valid = true;
1747 +                        inst->operands[3].index = -1;
1748 +                        inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1749 +                        return true;
1750 +                case 0x9:
1751 +                        if (x2b == 1) {
1752 +                                inst->mnemo = IA64_INST_SUB;
1753 +                                inst->operands[1].index = -1;
1754 +                                inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1755 +                                inst->operands[1].nat   = 0;
1756 +                                return true;
1757 +                        }
1758 +                        break;
1759 +                case 0xb:
1760 +                        inst->operands[1].index = -1;
1761 +                        inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1762 +                        inst->operands[1].nat   = 0;
1763 +                        // fall-through
1764 +                case 0x3:
1765 +                        switch (x2b) {
1766 +                        case 0: inst->mnemo = IA64_INST_AND;   break;
1767 +                        case 1: inst->mnemo = IA64_INST_ANDCM; break;
1768 +                        case 2: inst->mnemo = IA64_INST_OR;    break;
1769 +                        case 3: inst->mnemo = IA64_INST_XOR;   break;
1770 +                        }
1771 +                        return true;
1772 +                }
1773 +        }
1774 +        return false;
1775 + }
1776 +
1777 + // Decode instruction
1778 + static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1779 + {
1780 +        const int major = (inst->inst >> 37) & 0xf;
1781 +
1782 +        inst->mnemo = IA64_INST_UNKNOWN;
1783 +        inst->pred  = inst->inst & 0x3f;
1784 +        memset(&inst->operands[0], 0, sizeof(inst->operands));
1785 +
1786 +        switch (major) {
1787 +        case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT);
1788 +        case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT);
1789 +        case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT);
1790 +        case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT);
1791 +        }
1792 +        return false;
1793 + }
1794 +
1795 + static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1796 + {
1797 +        // XXX: handle Register NaT Consumption fault?
1798 +        // XXX: this simple emulator assumes instructions in a bundle
1799 +        // don't depend on effects of other instructions in the same
1800 +        // bundle. It probably would be simpler to JIT-generate code to be
1801 +        // executed natively but probably more costly (inject/extract CPU state)
1802 +        if (inst->mnemo == IA64_INST_UNKNOWN)
1803 +                return false;
1804 +        if (inst->pred && !IA64_GET_PR(inst->pred))
1805 +                return true;
1806 +
1807 +        uint8_t nat, nat2;
1808 +        uint64_t dst, dst2, src1, src2, src3;
1809 +
1810 +        switch (inst->mnemo) {
1811 +        case IA64_INST_NOP:
1812 +                break;
1813 +        case IA64_INST_ADD:
1814 +        case IA64_INST_SUB:
1815 +        case IA64_INST_SHLADD:
1816 +                src3 = inst->operands[3].value;
1817 +                // fall-through
1818 +        case IA64_INST_AND:
1819 +        case IA64_INST_ANDCM:
1820 +        case IA64_INST_OR:
1821 +        case IA64_INST_XOR:
1822 +                src1 = inst->operands[1].value;
1823 +                src2 = inst->operands[2].value;
1824 +                switch (inst->mnemo) {
1825 +                case IA64_INST_ADD:   dst = src1 + src2 + src3; break;
1826 +                case IA64_INST_SUB:   dst = src1 - src2 - src3; break;
1827 +                case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1828 +                case IA64_INST_AND:   dst = src1 & src2;                break;
1829 +                case IA64_INST_ANDCM: dst = src1 &~ src2;               break;
1830 +                case IA64_INST_OR:    dst = src1 | src2;                break;
1831 +                case IA64_INST_XOR:   dst = src1 ^ src2;                break;
1832 +                }
1833 +                inst->operands[0].commit = true;
1834 +                inst->operands[0].value  = dst;
1835 +                inst->operands[0].nat    = inst->operands[1].nat | inst->operands[2].nat;
1836 +                break;
1837 +        case IA64_INST_SXT1:
1838 +        case IA64_INST_SXT2:
1839 +        case IA64_INST_SXT4:
1840 +        case IA64_INST_ZXT1:
1841 +        case IA64_INST_ZXT2:
1842 +        case IA64_INST_ZXT4:
1843 +                src1 = inst->operands[1].value;
1844 +                switch (inst->mnemo) {
1845 +                case IA64_INST_SXT1: dst = (int64_t)(int8_t)src1;               break;
1846 +                case IA64_INST_SXT2: dst = (int64_t)(int16_t)src1;              break;
1847 +                case IA64_INST_SXT4: dst = (int64_t)(int32_t)src1;              break;
1848 +                case IA64_INST_ZXT1: dst = (uint8_t)src1;                               break;
1849 +                case IA64_INST_ZXT2: dst = (uint16_t)src1;                              break;
1850 +                case IA64_INST_ZXT4: dst = (uint32_t)src1;                              break;
1851 +                }
1852 +                inst->operands[0].commit = true;
1853 +                inst->operands[0].value  = dst;
1854 +                inst->operands[0].nat    = inst->operands[1].nat;
1855 +                break;
1856 +        case IA64_INST_LD1_UPDATE:
1857 +        case IA64_INST_LD2_UPDATE:
1858 +        case IA64_INST_LD4_UPDATE:
1859 +        case IA64_INST_LD8_UPDATE:
1860 +                inst->operands[1].commit = true;
1861 +                dst2 = inst->operands[1].value + inst->operands[2].value;
1862 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1863 +                // fall-through
1864 +        case IA64_INST_LD1:
1865 +        case IA64_INST_LD2:
1866 +        case IA64_INST_LD4:
1867 +        case IA64_INST_LD8:
1868 +                src1 = inst->operands[1].value;
1869 +                if (inst->no_memory)
1870 +                        dst = 0;
1871 +                else {
1872 +                        switch (inst->mnemo) {
1873 +                        case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((uint8_t *)src1);        break;
1874 +                        case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((uint16_t *)src1);       break;
1875 +                        case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((uint32_t *)src1);       break;
1876 +                        case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((uint64_t *)src1);       break;
1877 +                        }
1878 +                }
1879 +                inst->operands[0].commit = true;
1880 +                inst->operands[0].value  = dst;
1881 +                inst->operands[0].nat    = 0;
1882 +                inst->operands[1].value  = dst2;
1883 +                inst->operands[1].nat    = nat2;
1884 +                break;
1885 +        case IA64_INST_ST1_UPDATE:
1886 +        case IA64_INST_ST2_UPDATE:
1887 +        case IA64_INST_ST4_UPDATE:
1888 +        case IA64_INST_ST8_UPDATE:
1889 +                inst->operands[0].commit = 0;
1890 +                dst2 = inst->operands[0].value + inst->operands[2].value;
1891 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1892 +                // fall-through
1893 +        case IA64_INST_ST1:
1894 +        case IA64_INST_ST2:
1895 +        case IA64_INST_ST4:
1896 +        case IA64_INST_ST8:
1897 +                dst  = inst->operands[0].value;
1898 +                src1 = inst->operands[1].value;
1899 +                if (!inst->no_memory) {
1900 +                        switch (inst->mnemo) {
1901 +                        case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((uint8_t *)dst) = src1;        break;
1902 +                        case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((uint16_t *)dst) = src1;       break;
1903 +                        case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((uint32_t *)dst) = src1;       break;
1904 +                        case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((uint64_t *)dst) = src1;       break;
1905 +                        }
1906 +                }
1907 +                inst->operands[0].value  = dst2;
1908 +                inst->operands[0].nat    = nat2;
1909 +                break;
1910 +        default:
1911 +                return false;
1912 +        }
1913 +
1914 +        for (int i = 0; i < IA64_N_OPERANDS; i++) {
1915 +                ia64_operand_t const & op = inst->operands[i];
1916 +                if (!op.commit)
1917 +                        continue;
1918 +                if (op.index == -1)
1919 +                        return false; // XXX: internal error
1920 +                IA64_SET_GR(op.index, op.value, op.nat);
1921 +        }
1922 +        return true;
1923 + }
1924 +
1925 + static bool ia64_emulate_instruction(uint64_t raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1926 + {
1927 +        ia64_instruction_t inst;
1928 +        memset(&inst, 0, sizeof(inst));
1929 +        inst.inst = raw_inst;
1930 +        if (!ia64_decode_instruction(&inst, IA64_CONTEXT))
1931 +                return false;
1932 +        return ia64_emulate_instruction(&inst, IA64_CONTEXT);
1933 + }
1934 +
1935 + static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT)
1936 + {
1937 +        uint64_t ip = IA64_GET_IP();
1938 + #if DEBUG
1939 +        printf("IP: 0x%016llx\n", ip);
1940 + #if 0
1941 +        printf(" Template 0x%02x\n", ia64_get_template(ip));
1942 +        ia64_get_instruction(ip, 0);
1943 +        ia64_get_instruction(ip, 1);
1944 +        ia64_get_instruction(ip, 2);
1945 + #endif
1946 + #endif
1947 +
1948 +        // Select which decode switch to use
1949 +        ia64_instruction_t inst;
1950 +        inst.inst = ia64_get_instruction(ip, ip & 3);
1951 +        if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) {
1952 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1953 +                return false;
1954 +        }
1955 +
1956 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1957 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
1958 +
1959 +        switch (inst.mnemo) {
1960 +        case IA64_INST_LD1:
1961 +        case IA64_INST_LD2:
1962 +        case IA64_INST_LD4:
1963 +        case IA64_INST_LD8:
1964 +        case IA64_INST_LD1_UPDATE:
1965 +        case IA64_INST_LD2_UPDATE:
1966 +        case IA64_INST_LD4_UPDATE:
1967 +        case IA64_INST_LD8_UPDATE:
1968 +                transfer_type = SIGSEGV_TRANSFER_LOAD;
1969 +                break;
1970 +        case IA64_INST_ST1:
1971 +        case IA64_INST_ST2:
1972 +        case IA64_INST_ST4:
1973 +        case IA64_INST_ST8:
1974 +        case IA64_INST_ST1_UPDATE:
1975 +        case IA64_INST_ST2_UPDATE:
1976 +        case IA64_INST_ST4_UPDATE:
1977 +        case IA64_INST_ST8_UPDATE:
1978 +                transfer_type = SIGSEGV_TRANSFER_STORE;
1979 +                break;
1980 +        }
1981 +
1982 +        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1983 +                // Unknown machine code, let it crash. Then patch the decoder
1984 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1985 +                return false;
1986 +        }
1987 +
1988 +        switch (inst.mnemo) {
1989 +        case IA64_INST_LD1:
1990 +        case IA64_INST_LD1_UPDATE:
1991 +        case IA64_INST_ST1:
1992 +        case IA64_INST_ST1_UPDATE:
1993 +                transfer_size = SIZE_BYTE;
1994 +                break;
1995 +        case IA64_INST_LD2:
1996 +        case IA64_INST_LD2_UPDATE:
1997 +        case IA64_INST_ST2:
1998 +        case IA64_INST_ST2_UPDATE:
1999 +                transfer_size = SIZE_WORD;
2000 +                break;
2001 +        case IA64_INST_LD4:
2002 +        case IA64_INST_LD4_UPDATE:
2003 +        case IA64_INST_ST4:
2004 +        case IA64_INST_ST4_UPDATE:
2005 +                transfer_size = SIZE_LONG;
2006 +                break;
2007 +        case IA64_INST_LD8:
2008 +        case IA64_INST_LD8_UPDATE:
2009 +        case IA64_INST_ST8:
2010 +        case IA64_INST_ST8_UPDATE:
2011 +                transfer_size = SIZE_QUAD;
2012 +                break;
2013 +        }
2014 +
2015 +        if (transfer_size == SIZE_UNKNOWN) {
2016 +                // Unknown machine code, let it crash. Then patch the decoder
2017 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
2018 +                return false;
2019 +        }
2020 +
2021 +        inst.no_memory = true;
2022 +        if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) {
2023 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
2024 +                return false;
2025 +        }
2026 +
2027 +        int slot = ip & 3;
2028 +        bool emulate_next = false;
2029 +        switch (slot) {
2030 +        case 0:
2031 +                switch (ia64_get_template(ip)) {
2032 +                case 0x2: // MI;I
2033 +                case 0x3: // MI;I;
2034 +                        emulate_next = true;
2035 +                        slot = 2;
2036 +                        break;
2037 +                case 0xa: // M;MI
2038 +                case 0xb: // M;MI;
2039 +                        emulate_next = true;
2040 +                        slot = 1;
2041 +                        break;
2042 +                }
2043 +                break;
2044 +        }
2045 +        if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) {
2046 +                while (slot < 3) {
2047 +                        if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) {
2048 +                                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
2049 +                                return false;
2050 +                        }
2051 +                        ++slot;
2052 +                }
2053 +        }
2054 +
2055 + #if IA64_CAN_PATCH_IP_SLOT
2056 +        if ((slot = ip & 3) < 2)
2057 +                IA64_SET_IP((ip & ~3ull) + (slot + 1));
2058 +        else
2059 + #endif
2060 +                IA64_SET_IP((ip & ~3ull) + 16);
2061 + #if DEBUG
2062 +        printf("IP: 0x%016llx\n", IA64_GET_IP());
2063 + #endif
2064 +        return true;
2065 + }
2066 + #endif
2067 +
2068   // Decode and skip PPC instruction
2069 < #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
2070 < static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
2069 > #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
2070 > static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
2071   {
2072          instruction_t instr;
2073          powerpc_decode_instruction(&instr, *nip_p, regs);
# Line 757 | Line 2079 | static bool powerpc_skip_instruction(uns
2079  
2080   #if DEBUG
2081          printf("%08x: %s %s access", *nip_p,
2082 <                   instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
2082 >                   instr.transfer_size == SIZE_BYTE ? "byte" :
2083 >                   instr.transfer_size == SIZE_WORD ? "word" :
2084 >                   instr.transfer_size == SIZE_LONG ? "long" : "quad",
2085                     instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
2086          
2087          if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
# Line 775 | Line 2099 | static bool powerpc_skip_instruction(uns
2099          return true;
2100   }
2101   #endif
2102 +
2103 + // Decode and skip MIPS instruction
2104 + #if (defined(mips) || defined(__mips))
2105 + static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
2106 + {
2107 +  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
2108 +
2109 +  if (epc == 0)
2110 +        return false;
2111 +
2112 + #if DEBUG
2113 +  printf("IP: %p [%08x]\n", epc, epc[0]);
2114 + #endif
2115 +
2116 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2117 +  transfer_size_t transfer_size = SIZE_LONG;
2118 +  int direction = 0;
2119 +
2120 +  const unsigned int opcode = epc[0];
2121 +  switch (opcode >> 26) {
2122 +  case 32: // Load Byte
2123 +  case 36: // Load Byte Unsigned
2124 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2125 +        transfer_size = SIZE_BYTE;
2126 +        break;
2127 +  case 33: // Load Halfword
2128 +  case 37: // Load Halfword Unsigned
2129 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2130 +        transfer_size = SIZE_WORD;
2131 +        break;
2132 +  case 35: // Load Word
2133 +  case 39: // Load Word Unsigned
2134 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2135 +        transfer_size = SIZE_LONG;
2136 +        break;
2137 +  case 34: // Load Word Left
2138 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2139 +        transfer_size = SIZE_LONG;
2140 +        direction = -1;
2141 +        break;
2142 +  case 38: // Load Word Right
2143 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2144 +        transfer_size = SIZE_LONG;
2145 +        direction = 1;
2146 +        break;
2147 +  case 55: // Load Doubleword
2148 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2149 +        transfer_size = SIZE_QUAD;
2150 +        break;
2151 +  case 26: // Load Doubleword Left
2152 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2153 +        transfer_size = SIZE_QUAD;
2154 +        direction = -1;
2155 +        break;
2156 +  case 27: // Load Doubleword Right
2157 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2158 +        transfer_size = SIZE_QUAD;
2159 +        direction = 1;
2160 +        break;
2161 +  case 40: // Store Byte
2162 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2163 +        transfer_size = SIZE_BYTE;
2164 +        break;
2165 +  case 41: // Store Halfword
2166 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2167 +        transfer_size = SIZE_WORD;
2168 +        break;
2169 +  case 43: // Store Word
2170 +  case 42: // Store Word Left
2171 +  case 46: // Store Word Right
2172 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2173 +        transfer_size = SIZE_LONG;
2174 +        break;
2175 +  case 63: // Store Doubleword
2176 +  case 44: // Store Doubleword Left
2177 +  case 45: // Store Doubleword Right
2178 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2179 +        transfer_size = SIZE_QUAD;
2180 +        break;
2181 +  /* Misc instructions unlikely to be used within CPU emulators */
2182 +  case 48: // Load Linked Word
2183 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2184 +        transfer_size = SIZE_LONG;
2185 +        break;
2186 +  case 52: // Load Linked Doubleword
2187 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2188 +        transfer_size = SIZE_QUAD;
2189 +        break;
2190 +  case 56: // Store Conditional Word
2191 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2192 +        transfer_size = SIZE_LONG;
2193 +        break;
2194 +  case 60: // Store Conditional Doubleword
2195 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2196 +        transfer_size = SIZE_QUAD;
2197 +        break;
2198 +  }
2199 +
2200 +  if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2201 +        // Unknown machine code, let it crash. Then patch the decoder
2202 +        return false;
2203 +  }
2204 +
2205 +  // Zero target register in case of a load operation
2206 +  const int reg = (opcode >> 16) & 0x1f;
2207 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD) {
2208 +        if (direction == 0)
2209 +          regs[reg] = 0;
2210 +        else {
2211 +          // FIXME: untested code
2212 +          unsigned long ea = regs[(opcode >> 21) & 0x1f];
2213 +          ea += (signed long)(signed int)(signed short)(opcode & 0xffff);
2214 +          const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7);
2215 +          unsigned long value;
2216 +          if (direction > 0) {
2217 +                const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1);
2218 +                value = regs[reg] & rmask;
2219 +          }
2220 +          else {
2221 +                const unsigned long lmask = (1L << (offset * 8)) - 1;
2222 +                value = regs[reg] & lmask;
2223 +          }
2224 +          // restore most significant bits
2225 +          if (transfer_size == SIZE_LONG)
2226 +                value = (signed long)(signed int)value;
2227 +          regs[reg] = value;
2228 +        }
2229 +  }
2230 +
2231 + #if DEBUG
2232 + #if (defined(_ABIN32) || defined(_ABI64))
2233 +  static const char * mips_gpr_names[32] = {
2234 +        "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
2235 +        "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
2236 +        "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
2237 +        "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
2238 +  };
2239 + #else
2240 +  static const char * mips_gpr_names[32] = {
2241 +        "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
2242 +        "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
2243 +        "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
2244 +        "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
2245 +  };
2246 + #endif
2247 +  printf("%s %s register %s\n",
2248 +                 transfer_size == SIZE_BYTE ? "byte" :
2249 +                 transfer_size == SIZE_WORD ? "word" :
2250 +                 transfer_size == SIZE_LONG ? "long" :
2251 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2252 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2253 +                 mips_gpr_names[reg]);
2254 + #endif
2255 +
2256 +  *pc_p += 4;
2257 +  return true;
2258 + }
2259 + #endif
2260 +
2261 + // Decode and skip SPARC instruction
2262 + #if (defined(sparc) || defined(__sparc__))
2263 + enum {
2264 + #if (defined(__sun__))
2265 +  SPARC_REG_G1 = REG_G1,
2266 +  SPARC_REG_O0 = REG_O0,
2267 +  SPARC_REG_PC = REG_PC,
2268 +  SPARC_REG_nPC = REG_nPC
2269 + #endif
2270 + };
2271 + static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
2272 + {
2273 +  unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC];
2274 +
2275 +  if (pc == 0)
2276 +        return false;
2277 +
2278 + #if DEBUG
2279 +  printf("IP: %p [%08x]\n", pc, pc[0]);
2280 + #endif
2281 +
2282 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2283 +  transfer_size_t transfer_size = SIZE_LONG;
2284 +  bool register_pair = false;
2285 +
2286 +  const unsigned int opcode = pc[0];
2287 +  if ((opcode >> 30) != 3)
2288 +        return false;
2289 +  switch ((opcode >> 19) & 0x3f) {
2290 +  case 9: // Load Signed Byte
2291 +  case 1: // Load Unsigned Byte
2292 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2293 +        transfer_size = SIZE_BYTE;
2294 +        break;
2295 +  case 10:// Load Signed Halfword
2296 +  case 2: // Load Unsigned Word
2297 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2298 +        transfer_size = SIZE_WORD;
2299 +        break;
2300 +  case 8: // Load Word
2301 +  case 0: // Load Unsigned Word
2302 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2303 +        transfer_size = SIZE_LONG;
2304 +        break;
2305 +  case 11:// Load Extended Word
2306 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2307 +        transfer_size = SIZE_QUAD;
2308 +        break;
2309 +  case 3: // Load Doubleword
2310 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2311 +        transfer_size = SIZE_LONG;
2312 +        register_pair = true;
2313 +        break;
2314 +  case 5: // Store Byte
2315 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2316 +        transfer_size = SIZE_BYTE;
2317 +        break;
2318 +  case 6: // Store Halfword
2319 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2320 +        transfer_size = SIZE_WORD;
2321 +        break;
2322 +  case 4: // Store Word
2323 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2324 +        transfer_size = SIZE_LONG;
2325 +        break;
2326 +  case 14:// Store Extended Word
2327 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2328 +        transfer_size = SIZE_QUAD;
2329 +        break;
2330 +  case 7: // Store Doubleword
2331 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2332 +        transfer_size = SIZE_LONG;
2333 +        register_pair = true;
2334 +        break;
2335 +  }
2336 +
2337 +  if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
2338 +        // Unknown machine code, let it crash. Then patch the decoder
2339 +        return false;
2340 +  }
2341 +
2342 +  const int reg = (opcode >> 25) & 0x1f;
2343 +
2344 + #if DEBUG
2345 +  static const char * reg_names[] = {
2346 +        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2347 +        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2348 +        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2349 +        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2350 +  };
2351 +  printf("%s %s register %s\n",
2352 +                 transfer_size == SIZE_BYTE ? "byte" :
2353 +                 transfer_size == SIZE_WORD ? "word" :
2354 +                 transfer_size == SIZE_LONG ? "long" :
2355 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2356 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2357 +                 reg_names[reg]);
2358 + #endif
2359 +
2360 +  // Zero target register in case of a load operation
2361 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2362 +        // FIXME: code to handle local & input registers is not tested
2363 +        if (reg >= 1 && reg < 8) {
2364 +          // global registers
2365 +          regs[reg - 1 + SPARC_REG_G1] = 0;
2366 +        }
2367 +        else if (reg >= 8 && reg < 16) {
2368 +          // output registers
2369 +          regs[reg - 8 + SPARC_REG_O0] = 0;
2370 +        }
2371 +        else if (reg >= 16 && reg < 24) {
2372 +          // local registers (in register windows)
2373 +          if (gwins)
2374 +                gwins->wbuf->rw_local[reg - 16] = 0;
2375 +          else
2376 +                rwin->rw_local[reg - 16] = 0;
2377 +        }
2378 +        else {
2379 +          // input registers (in register windows)
2380 +          if (gwins)
2381 +                gwins->wbuf->rw_in[reg - 24] = 0;
2382 +          else
2383 +                rwin->rw_in[reg - 24] = 0;
2384 +        }
2385 +  }
2386 +
2387 +  regs[SPARC_REG_PC] += 4;
2388 +  regs[SPARC_REG_nPC] += 4;
2389 +  return true;
2390 + }
2391 + #endif
2392 + #endif
2393 +
2394 + // Decode and skip ARM instruction
2395 + #if (defined(arm) || defined(__arm__))
2396 + enum {
2397 + #if (defined(__linux__))
2398 +  ARM_REG_PC = 15,
2399 +  ARM_REG_CPSR = 16
2400 + #endif
2401 + };
2402 + static bool arm_skip_instruction(unsigned long * regs)
2403 + {
2404 +  unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
2405 +
2406 +  if (pc == 0)
2407 +        return false;
2408 +
2409 + #if DEBUG
2410 +  printf("IP: %p [%08x]\n", pc, pc[0]);
2411 + #endif
2412 +
2413 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
2414 +  transfer_size_t transfer_size = SIZE_UNKNOWN;
2415 +  enum { op_sdt = 1, op_sdth = 2 };
2416 +  int op = 0;
2417 +
2418 +  // Handle load/store instructions only
2419 +  const unsigned int opcode = pc[0];
2420 +  switch ((opcode >> 25) & 7) {
2421 +  case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
2422 +        op = op_sdth;
2423 +        // Determine transfer size (S/H bits)
2424 +        switch ((opcode >> 5) & 3) {
2425 +        case 0: // SWP instruction
2426 +          break;
2427 +        case 1: // Unsigned halfwords
2428 +        case 3: // Signed halfwords
2429 +          transfer_size = SIZE_WORD;
2430 +          break;
2431 +        case 2: // Signed byte
2432 +          transfer_size = SIZE_BYTE;
2433 +          break;
2434 +        }
2435 +        break;
2436 +  case 2:
2437 +  case 3: // Single Data Transfer (LDR, STR)
2438 +        op = op_sdt;
2439 +        // Determine transfer size (B bit)
2440 +        if (((opcode >> 22) & 1) == 1)
2441 +          transfer_size = SIZE_BYTE;
2442 +        else
2443 +          transfer_size = SIZE_LONG;
2444 +        break;
2445 +  default:
2446 +        // FIXME: support load/store mutliple?
2447 +        return false;
2448 +  }
2449 +
2450 +  // Check for invalid transfer size (SWP instruction?)
2451 +  if (transfer_size == SIZE_UNKNOWN)
2452 +        return false;
2453 +
2454 +  // Determine transfer type (L bit)
2455 +  if (((opcode >> 20) & 1) == 1)
2456 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
2457 +  else
2458 +        transfer_type = SIGSEGV_TRANSFER_STORE;
2459 +
2460 +  // Compute offset
2461 +  int offset;
2462 +  if (((opcode >> 25) & 1) == 0) {
2463 +        if (op == op_sdt)
2464 +          offset = opcode & 0xfff;
2465 +        else if (op == op_sdth) {
2466 +          int rm = opcode & 0xf;
2467 +          if (((opcode >> 22) & 1) == 0) {
2468 +                // register offset
2469 +                offset = regs[rm];
2470 +          }
2471 +          else {
2472 +                // immediate offset
2473 +                offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
2474 +          }
2475 +        }
2476 +  }
2477 +  else {
2478 +        const int rm = opcode & 0xf;
2479 +        const int sh = (opcode >> 7) & 0x1f;
2480 +        if (((opcode >> 4) & 1) == 1) {
2481 +          // we expect only legal load/store instructions
2482 +          printf("FATAL: invalid shift operand\n");
2483 +          return false;
2484 +        }
2485 +        const unsigned int v = regs[rm];
2486 +        switch ((opcode >> 5) & 3) {
2487 +        case 0: // logical shift left
2488 +          offset = sh ? v << sh : v;
2489 +          break;
2490 +        case 1: // logical shift right
2491 +          offset = sh ? v >> sh : 0;
2492 +          break;
2493 +        case 2: // arithmetic shift right
2494 +          if (sh)
2495 +                offset = ((signed int)v) >> sh;
2496 +          else
2497 +                offset = (v & 0x80000000) ? 0xffffffff : 0;
2498 +          break;
2499 +        case 3: // rotate right
2500 +          if (sh)
2501 +                offset = (v >> sh) | (v << (32 - sh));
2502 +          else
2503 +                offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
2504 +          break;
2505 +        }
2506 +  }
2507 +  if (((opcode >> 23) & 1) == 0)
2508 +        offset = -offset;
2509 +
2510 +  int rd = (opcode >> 12) & 0xf;
2511 +  int rn = (opcode >> 16) & 0xf;
2512 + #if DEBUG
2513 +  static const char * reg_names[] = {
2514 +        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2515 +        "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
2516 +  };
2517 +  printf("%s %s register %s\n",
2518 +                 transfer_size == SIZE_BYTE ? "byte" :
2519 +                 transfer_size == SIZE_WORD ? "word" :
2520 +                 transfer_size == SIZE_LONG ? "long" : "unknown",
2521 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2522 +                 reg_names[rd]);
2523 + #endif
2524 +
2525 +  unsigned int base = regs[rn];
2526 +  if (((opcode >> 24) & 1) == 1)
2527 +        base += offset;
2528 +
2529 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD)
2530 +        regs[rd] = 0;
2531 +
2532 +  if (((opcode >> 24) & 1) == 0)                // post-index addressing
2533 +        regs[rn] += offset;
2534 +  else if (((opcode >> 21) & 1) == 1)   // write-back address into base
2535 +        regs[rn] = base;
2536 +
2537 +  regs[ARM_REG_PC] += 4;
2538 +  return true;
2539 + }
2540   #endif
2541  
2542 +
2543   // Fallbacks
2544 + #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2545 + #define SIGSEGV_FAULT_ADDRESS_FAST              SIGSEGV_FAULT_ADDRESS
2546 + #endif
2547 + #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2548 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_FAULT_INSTRUCTION
2549 + #endif
2550   #ifndef SIGSEGV_FAULT_INSTRUCTION
2551 < #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
2551 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_ADDRESS
2552   #endif
2553   #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2554   #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2555   #endif
2556 + #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2557 + #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2558 + #endif
2559  
2560   // SIGSEGV recovery supported ?
2561   #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS)
# Line 795 | Line 2567 | static bool powerpc_skip_instruction(uns
2567   *  SIGSEGV global handler
2568   */
2569  
2570 < #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
2570 > struct sigsegv_info_t {
2571 >        sigsegv_address_t addr;
2572 >        sigsegv_address_t pc;
2573 > #ifdef HAVE_MACH_EXCEPTIONS
2574 >        mach_port_t thread;
2575 >        bool has_exc_state;
2576 >        SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2577 >        mach_msg_type_number_t exc_state_count;
2578 >        bool has_thr_state;
2579 >        SIGSEGV_THREAD_STATE_TYPE thr_state;
2580 >        mach_msg_type_number_t thr_state_count;
2581 > #endif
2582 > };
2583 >
2584 > #ifdef HAVE_MACH_EXCEPTIONS
2585 > static void mach_get_exception_state(sigsegv_info_t *SIP)
2586 > {
2587 >        SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2588 >        kern_return_t krc = thread_get_state(SIP->thread,
2589 >                                                                                 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2590 >                                                                                 (natural_t *)&SIP->exc_state,
2591 >                                                                                 &SIP->exc_state_count);
2592 >        MACH_CHECK_ERROR(thread_get_state, krc);
2593 >        SIP->has_exc_state = true;
2594 > }
2595 >
2596 > static void mach_get_thread_state(sigsegv_info_t *SIP)
2597 > {
2598 >        SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2599 >        kern_return_t krc = thread_get_state(SIP->thread,
2600 >                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2601 >                                                                                 (natural_t *)&SIP->thr_state,
2602 >                                                                                 &SIP->thr_state_count);
2603 >        MACH_CHECK_ERROR(thread_get_state, krc);
2604 >        SIP->has_thr_state = true;
2605 > }
2606 >
2607 > static void mach_set_thread_state(sigsegv_info_t *SIP)
2608 > {
2609 >        kern_return_t krc = thread_set_state(SIP->thread,
2610 >                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2611 >                                                                                 (natural_t *)&SIP->thr_state,
2612 >                                                                                 SIP->thr_state_count);
2613 >        MACH_CHECK_ERROR(thread_set_state, krc);
2614 > }
2615 > #endif
2616 >
2617 > // Return the address of the invalid memory reference
2618 > sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2619 > {
2620 > #ifdef HAVE_MACH_EXCEPTIONS
2621 > #ifdef EMULATED_PPC
2622 >        static int use_fast_path = -1;
2623 >        if (use_fast_path != 1 && !SIP->has_exc_state) {
2624 >                mach_get_exception_state(SIP);
2625 >
2626 >                sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2627 >                if (use_fast_path < 0) {
2628 >                        const char *machfault = getenv("SIGSEGV_MACH_FAULT");
2629 >                        if (machfault) {
2630 >                                if (strcmp(machfault, "fast") == 0)
2631 >                                        use_fast_path = 1;
2632 >                                else if (strcmp(machfault, "slow") == 0)
2633 >                                        use_fast_path = 0;
2634 >                        }
2635 >                        if (use_fast_path < 0)
2636 >                                use_fast_path = addr == SIP->addr;
2637 >                }
2638 >                SIP->addr = addr;
2639 >        }
2640 > #endif
2641 > #endif
2642 >        return SIP->addr;
2643 > }
2644 >
2645 > // Return the address of the instruction that caused the fault, or
2646 > // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2647 > sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2648 > {
2649 > #ifdef HAVE_MACH_EXCEPTIONS
2650 > #ifdef EMULATED_PPC
2651 >        if (!SIP->has_thr_state) {
2652 >                mach_get_thread_state(SIP);
2653 >
2654 >                SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2655 >        }
2656 > #endif
2657 > #endif
2658 >        return SIP->pc;
2659 > }
2660 >
2661   // This function handles the badaccess to memory.
2662   // It is called from the signal handler or the exception handler.
2663   static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2664   {
2665 <        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2666 <        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2667 <        
2665 >        sigsegv_info_t SI;
2666 >        SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2667 >        SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2668 > #ifdef HAVE_MACH_EXCEPTIONS
2669 >        SI.thread = thread;
2670 >        SI.has_exc_state = false;
2671 >        SI.has_thr_state = false;
2672 > #endif
2673 >        sigsegv_info_t * const SIP = &SI;
2674 >
2675          // Call user's handler and reinstall the global handler, if required
2676 <        switch (sigsegv_fault_handler(fault_address, fault_instruction)) {
2676 >        switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2677          case SIGSEGV_RETURN_SUCCESS:
2678                  return true;
2679  
# Line 812 | Line 2681 | static bool handle_badaccess(SIGSEGV_FAU
2681          case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2682                  // Call the instruction skipper with the register file
2683                  // available
2684 + #ifdef HAVE_MACH_EXCEPTIONS
2685 +                if (!SIP->has_thr_state)
2686 +                        mach_get_thread_state(SIP);
2687 + #endif
2688                  if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2689   #ifdef HAVE_MACH_EXCEPTIONS
2690                          // Unlike UNIX signals where the thread state
2691                          // is modified off of the stack, in Mach we
2692                          // need to actually call thread_set_state to
2693                          // have the register values updated.
2694 <                        kern_return_t krc;
822 <
823 <                        krc = thread_set_state(thread,
824 <                                                                   MACHINE_THREAD_STATE, (thread_state_t)state,
825 <                                                                   MACHINE_THREAD_STATE_COUNT);
826 <                        MACH_CHECK_ERROR (thread_get_state, krc);
2694 >                        mach_set_thread_state(SIP);
2695   #endif
2696                          return true;
2697                  }
2698                  break;
2699   #endif
2700 +        case SIGSEGV_RETURN_FAILURE:
2701 +                // We can't do anything with the fault_address, dump state?
2702 +                if (sigsegv_state_dumper != 0)
2703 +                        sigsegv_state_dumper(SIP);
2704 +                break;
2705          }
833        
834        // We can't do anything with the fault_address, dump state?
835        if (sigsegv_state_dumper != 0)
836                sigsegv_state_dumper(fault_address, fault_instruction);
2706  
2707          return false;
2708   }
840 #endif
2709  
2710  
2711   /*
# Line 865 | Line 2733 | static inline kern_return_t
2733   forward_exception(mach_port_t thread_port,
2734                                    mach_port_t task_port,
2735                                    exception_type_t exception_type,
2736 <                                  exception_data_t exception_data,
2736 >                                  mach_exception_data_t exception_data,
2737                                    mach_msg_type_number_t data_count,
2738                                    ExceptionPorts *oldExceptionPorts)
2739   {
# Line 874 | Line 2742 | forward_exception(mach_port_t thread_por
2742          mach_port_t port;
2743          exception_behavior_t behavior;
2744          thread_state_flavor_t flavor;
2745 <        thread_state_t thread_state;
2745 >        thread_state_data_t thread_state;
2746          mach_msg_type_number_t thread_state_count;
2747  
2748          for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
# Line 893 | Line 2761 | forward_exception(mach_port_t thread_por
2761          behavior = oldExceptionPorts->behaviors[portIndex];
2762          flavor = oldExceptionPorts->flavors[portIndex];
2763  
2764 +        if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2765 +                fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2766 +                return KERN_FAILURE;
2767 +        }
2768 +
2769          /*
2770           fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2771           */
2772  
2773          if (behavior != EXCEPTION_DEFAULT) {
2774                  thread_state_count = THREAD_STATE_MAX;
2775 <                kret = thread_get_state (thread_port, flavor, thread_state,
2775 >                kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2776                                                                   &thread_state_count);
2777                  MACH_CHECK_ERROR (thread_get_state, kret);
2778          }
# Line 907 | Line 2780 | forward_exception(mach_port_t thread_por
2780          switch (behavior) {
2781          case EXCEPTION_DEFAULT:
2782            // fprintf(stderr, "forwarding to exception_raise\n");
2783 <          kret = exception_raise(port, thread_port, task_port, exception_type,
2784 <                                                         exception_data, data_count);
2785 <          MACH_CHECK_ERROR (exception_raise, kret);
2783 >          kret = mach_exception_raise(port, thread_port, task_port, exception_type,
2784 >                                                                  exception_data, data_count);
2785 >          MACH_CHECK_ERROR (mach_exception_raise, kret);
2786            break;
2787          case EXCEPTION_STATE:
2788            // fprintf(stderr, "forwarding to exception_raise_state\n");
2789 <          kret = exception_raise_state(port, exception_type, exception_data,
2790 <                                                                   data_count, &flavor,
2791 <                                                                   thread_state, thread_state_count,
2792 <                                                                   thread_state, &thread_state_count);
2793 <          MACH_CHECK_ERROR (exception_raise_state, kret);
2789 >          kret = mach_exception_raise_state(port, exception_type, exception_data,
2790 >                                                                                data_count, &flavor,
2791 >                                                                                (natural_t *)&thread_state, thread_state_count,
2792 >                                                                                (natural_t *)&thread_state, &thread_state_count);
2793 >          MACH_CHECK_ERROR (mach_exception_raise_state, kret);
2794            break;
2795          case EXCEPTION_STATE_IDENTITY:
2796            // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
2797 <          kret = exception_raise_state_identity(port, thread_port, task_port,
2798 <                                                                                        exception_type, exception_data,
2799 <                                                                                        data_count, &flavor,
2800 <                                                                                        thread_state, thread_state_count,
2801 <                                                                                        thread_state, &thread_state_count);
2802 <          MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2797 >          kret = mach_exception_raise_state_identity(port, thread_port, task_port,
2798 >                                                                                                 exception_type, exception_data,
2799 >                                                                                                 data_count, &flavor,
2800 >                                                                                                 (natural_t *)&thread_state, thread_state_count,
2801 >                                                                                                 (natural_t *)&thread_state, &thread_state_count);
2802 >          MACH_CHECK_ERROR (mach_exception_raise_state_identity, kret);
2803            break;
2804          default:
2805            fprintf(stderr, "forward_exception got unknown behavior\n");
2806 +          kret = KERN_FAILURE;
2807            break;
2808          }
2809  
2810          if (behavior != EXCEPTION_DEFAULT) {
2811 <                kret = thread_set_state (thread_port, flavor, thread_state,
2811 >                kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2812                                                                   thread_state_count);
2813                  MACH_CHECK_ERROR (thread_set_state, kret);
2814          }
2815  
2816 <        return KERN_SUCCESS;
2816 >        return kret;
2817   }
2818  
2819   /*
# Line 962 | Line 2836 | forward_exception(mach_port_t thread_por
2836   * linkage because that is what exc_server expects.
2837   */
2838   kern_return_t
2839 < catch_exception_raise(mach_port_t exception_port,
2840 <                                          mach_port_t thread,
2841 <                                          mach_port_t task,
2842 <                                          exception_type_t exception,
2843 <                                          exception_data_t code,
2844 <                                          mach_msg_type_number_t codeCount)
2839 > catch_mach_exception_raise(mach_port_t exception_port,
2840 >                                                   mach_port_t thread,
2841 >                                                   mach_port_t task,
2842 >                                                   exception_type_t exception,
2843 >                                                   mach_exception_data_t code,
2844 >                                                   mach_msg_type_number_t code_count)
2845   {
972        ppc_thread_state_t state;
2846          kern_return_t krc;
2847  
2848 <        if ((exception == EXC_BAD_ACCESS)  && (codeCount >= 2)) {
2849 <                if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2850 <                        return KERN_SUCCESS;
2848 >        if (exception == EXC_BAD_ACCESS) {
2849 >                switch (code[0]) {
2850 >                case KERN_PROTECTION_FAILURE:
2851 >                case KERN_INVALID_ADDRESS:
2852 >                        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2853 >                                return KERN_SUCCESS;
2854 >                        break;
2855 >                }
2856          }
2857  
2858          // In Mach we do not need to remove the exception handler.
2859          // If we forward the exception, eventually some exception handler
2860          // will take care of this exception.
2861 <        krc = forward_exception(thread, task, exception, code, codeCount, &ports);
2861 >        krc = forward_exception(thread, task, exception, code, code_count, &ports);
2862  
2863          return krc;
2864   }
2865 +
2866 + /* XXX: borrowed from launchd and gdb */
2867 + kern_return_t
2868 + catch_mach_exception_raise_state(mach_port_t exception_port,
2869 +                                                                 exception_type_t exception,
2870 +                                                                 mach_exception_data_t code,
2871 +                                                                 mach_msg_type_number_t code_count,
2872 +                                                                 int *flavor,
2873 +                                                                 thread_state_t old_state,
2874 +                                                                 mach_msg_type_number_t old_state_count,
2875 +                                                                 thread_state_t new_state,
2876 +                                                                 mach_msg_type_number_t *new_state_count)
2877 + {
2878 +        memcpy(new_state, old_state, old_state_count * sizeof(old_state[0]));
2879 +        *new_state_count = old_state_count;
2880 +        return KERN_SUCCESS;
2881 + }
2882 +
2883 + /* XXX: borrowed from launchd and gdb */
2884 + kern_return_t
2885 + catch_mach_exception_raise_state_identity(mach_port_t exception_port,
2886 +                                                                                  mach_port_t thread_port,
2887 +                                                                                  mach_port_t task_port,
2888 +                                                                                  exception_type_t exception,
2889 +                                                                                  mach_exception_data_t code,
2890 +                                                                                  mach_msg_type_number_t code_count,
2891 +                                                                                  int *flavor,
2892 +                                                                                  thread_state_t old_state,
2893 +                                                                                  mach_msg_type_number_t old_state_count,
2894 +                                                                                  thread_state_t new_state,
2895 +                                                                                  mach_msg_type_number_t *new_state_count)
2896 + {
2897 +        kern_return_t kret;
2898 +
2899 +        memcpy(new_state, old_state, old_state_count * sizeof(old_state[0]));
2900 +        *new_state_count = old_state_count;
2901 +
2902 +        kret = mach_port_deallocate(mach_task_self(), task_port);
2903 +        MACH_CHECK_ERROR(mach_port_deallocate, kret);
2904 +        kret = mach_port_deallocate(mach_task_self(), thread_port);
2905 +        MACH_CHECK_ERROR(mach_port_deallocate, kret);
2906 +
2907 +        return KERN_SUCCESS;
2908 + }
2909   #endif
2910  
2911   #ifdef HAVE_SIGSEGV_RECOVERY
# Line 1108 | Line 3030 | static bool sigsegv_do_install_handler(s
3030          // addressing modes) used in PPC instructions, you will need the
3031          // GPR state anyway.
3032          krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
3033 <                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
3033 >                                EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, SIGSEGV_THREAD_STATE_FLAVOR);
3034          if (krc != KERN_SUCCESS) {
3035                  mach_error("thread_set_exception_ports", krc);
3036                  return false;
# Line 1131 | Line 3053 | static bool sigsegv_do_install_handler(s
3053   }
3054   #endif
3055  
3056 + #ifdef HAVE_WIN32_EXCEPTIONS
3057 + static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
3058 + {
3059 +        if (sigsegv_fault_handler != NULL
3060 +                && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
3061 +                && ExceptionInfo->ExceptionRecord->NumberParameters >= 2
3062 +                && handle_badaccess(ExceptionInfo))
3063 +                return EXCEPTION_CONTINUE_EXECUTION;
3064 +
3065 +        return EXCEPTION_CONTINUE_SEARCH;
3066 + }
3067 +
3068 + #if defined __CYGWIN__ && defined __i386__
3069 + /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
3070 +   installs a global exception handler.  We have to dig deep in order to install
3071 +   our main_exception_filter.  */
3072 +
3073 + /* Data structures for the current thread's exception handler chain.
3074 +   On the x86 Windows uses register fs, offset 0 to point to the current
3075 +   exception handler; Cygwin mucks with it, so we must do the same... :-/ */
3076 +
3077 + /* Magic taken from winsup/cygwin/include/exceptions.h.  */
3078 +
3079 + struct exception_list {
3080 +    struct exception_list *prev;
3081 +    int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
3082 + };
3083 + typedef struct exception_list exception_list;
3084 +
3085 + /* Magic taken from winsup/cygwin/exceptions.cc.  */
3086 +
3087 + __asm__ (".equ __except_list,0");
3088 +
3089 + extern exception_list *_except_list __asm__ ("%fs:__except_list");
3090 +
3091 + /* For debugging.  _except_list is not otherwise accessible from gdb.  */
3092 + static exception_list *
3093 + debug_get_except_list ()
3094 + {
3095 +  return _except_list;
3096 + }
3097 +
3098 + /* Cygwin's original exception handler.  */
3099 + static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
3100 +
3101 + /* Our exception handler.  */
3102 + static int
3103 + libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
3104 + {
3105 +  EXCEPTION_POINTERS ExceptionInfo;
3106 +  ExceptionInfo.ExceptionRecord = exception;
3107 +  ExceptionInfo.ContextRecord = context;
3108 +  if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
3109 +    return cygwin_exception_handler (exception, frame, context, dispatch);
3110 +  else
3111 +    return 0;
3112 + }
3113 +
3114 + static void
3115 + do_install_main_exception_filter ()
3116 + {
3117 +  /* We cannot insert any handler into the chain, because such handlers
3118 +     must lie on the stack (?).  Instead, we have to replace(!) Cygwin's
3119 +     global exception handler.  */
3120 +  cygwin_exception_handler = _except_list->handler;
3121 +  _except_list->handler = libsigsegv_exception_handler;
3122 + }
3123 +
3124 + #else
3125 +
3126 + static void
3127 + do_install_main_exception_filter ()
3128 + {
3129 +  SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
3130 + }
3131 + #endif
3132 +
3133 + static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
3134 + {
3135 +        static bool main_exception_filter_installed = false;
3136 +        if (!main_exception_filter_installed) {
3137 +                do_install_main_exception_filter();
3138 +                main_exception_filter_installed = true;
3139 +        }
3140 +        sigsegv_fault_handler = handler;
3141 +        return true;
3142 + }
3143 + #endif
3144 +
3145   bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
3146   {
3147   #if defined(HAVE_SIGSEGV_RECOVERY)
# Line 1141 | Line 3152 | bool sigsegv_install_handler(sigsegv_fau
3152          if (success)
3153              sigsegv_fault_handler = handler;
3154          return success;
3155 < #elif defined(HAVE_MACH_EXCEPTIONS)
3155 > #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
3156          return sigsegv_do_install_handler(handler);
3157   #else
3158          // FAIL: no siginfo_t nor sigcontext subterfuge is available
# Line 1167 | Line 3178 | void sigsegv_deinstall_handler(void)
3178          SIGSEGV_ALL_SIGNALS
3179   #undef FAULT_HANDLER
3180   #endif
3181 + #ifdef HAVE_WIN32_EXCEPTIONS
3182 +        sigsegv_fault_handler = NULL;
3183 + #endif
3184   }
3185  
3186  
# Line 1188 | Line 3202 | void sigsegv_set_dump_state(sigsegv_stat
3202   #include <stdio.h>
3203   #include <stdlib.h>
3204   #include <fcntl.h>
3205 + #ifdef HAVE_SYS_MMAN_H
3206   #include <sys/mman.h>
3207 + #endif
3208   #include "vm_alloc.h"
3209  
3210 < static int page_size;
3210 > const int REF_INDEX = 123;
3211 > const int REF_VALUE = 45;
3212 >
3213 > static sigsegv_uintptr_t page_size;
3214   static volatile char * page = 0;
3215   static volatile int handler_called = 0;
3216  
3217 < static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
3217 > /* Barriers */
3218 > #ifdef __GNUC__
3219 > #define BARRIER() asm volatile ("" : : : "memory")
3220 > #else
3221 > #define BARRIER() /* nothing */
3222 > #endif
3223 >
3224 > #ifdef __GNUC__
3225 > // Code range where we expect the fault to come from
3226 > static void *b_region, *e_region;
3227 > #endif
3228 >
3229 > static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
3230   {
3231 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3232 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3233 + #if DEBUG
3234 +        printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
3235 +        printf("expected fault at %p\n", page + REF_INDEX);
3236 + #ifdef __GNUC__
3237 +        printf("expected instruction address range: %p-%p\n", b_region, e_region);
3238 + #endif
3239 + #endif
3240          handler_called++;
3241 <        if ((fault_address - 123) != page)
3241 >        if ((fault_address - REF_INDEX) != page)
3242                  exit(10);
3243 <        if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3243 > #ifdef __GNUC__
3244 >        // Make sure reported fault instruction address falls into
3245 >        // expected code range
3246 >        if (instruction_address != SIGSEGV_INVALID_ADDRESS
3247 >                && ((instruction_address <  (sigsegv_address_t)b_region) ||
3248 >                        (instruction_address >= (sigsegv_address_t)e_region)))
3249                  exit(11);
3250 + #endif
3251 +        if (vm_protect((char *)((sigsegv_uintptr_t)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3252 +                exit(12);
3253          return SIGSEGV_RETURN_SUCCESS;
3254   }
3255  
3256   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3257 < #ifdef __GNUC__
1210 < // Code range where we expect the fault to come from
1211 < static void *b_region, *e_region;
1212 < #endif
1213 <
1214 < static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
3257 > static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3258   {
3259 <        if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
3259 >        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3260 >        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3261 > #if DEBUG
3262 >        printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3263 > #endif
3264 >        if (((sigsegv_uintptr_t)fault_address - (sigsegv_uintptr_t)page) < page_size) {
3265   #ifdef __GNUC__
3266                  // Make sure reported fault instruction address falls into
3267                  // expected code range
3268 <                if (instruction_address != SIGSEGV_INVALID_PC
3268 >                if (instruction_address != SIGSEGV_INVALID_ADDRESS
3269                          && ((instruction_address <  (sigsegv_address_t)b_region) ||
3270                                  (instruction_address >= (sigsegv_address_t)e_region)))
3271                          return SIGSEGV_RETURN_FAILURE;
# Line 1227 | Line 3275 | static sigsegv_return_t sigsegv_insn_han
3275  
3276          return SIGSEGV_RETURN_FAILURE;
3277   }
3278 +
3279 + // More sophisticated tests for instruction skipper
3280 + static bool arch_insn_skipper_tests()
3281 + {
3282 + #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
3283 +        static const unsigned char code[] = {
3284 +                0x8a, 0x00,                    // mov    (%eax),%al
3285 +                0x8a, 0x2c, 0x18,              // mov    (%eax,%ebx,1),%ch
3286 +                0x88, 0x20,                    // mov    %ah,(%eax)
3287 +                0x88, 0x08,                    // mov    %cl,(%eax)
3288 +                0x66, 0x8b, 0x00,              // mov    (%eax),%ax
3289 +                0x66, 0x8b, 0x0c, 0x18,        // mov    (%eax,%ebx,1),%cx
3290 +                0x66, 0x89, 0x00,              // mov    %ax,(%eax)
3291 +                0x66, 0x89, 0x0c, 0x18,        // mov    %cx,(%eax,%ebx,1)
3292 +                0x8b, 0x00,                    // mov    (%eax),%eax
3293 +                0x8b, 0x0c, 0x18,              // mov    (%eax,%ebx,1),%ecx
3294 +                0x89, 0x00,                    // mov    %eax,(%eax)
3295 +                0x89, 0x0c, 0x18,              // mov    %ecx,(%eax,%ebx,1)
3296 + #if defined(__x86_64__) || defined(_M_X64)
3297 +                0x44, 0x8a, 0x00,              // mov    (%rax),%r8b
3298 +                0x44, 0x8a, 0x20,              // mov    (%rax),%r12b
3299 +                0x42, 0x8a, 0x3c, 0x10,        // mov    (%rax,%r10,1),%dil
3300 +                0x44, 0x88, 0x00,              // mov    %r8b,(%rax)
3301 +                0x44, 0x88, 0x20,              // mov    %r12b,(%rax)
3302 +                0x42, 0x88, 0x3c, 0x10,        // mov    %dil,(%rax,%r10,1)
3303 +                0x66, 0x44, 0x8b, 0x00,        // mov    (%rax),%r8w
3304 +                0x66, 0x42, 0x8b, 0x0c, 0x10,  // mov    (%rax,%r10,1),%cx
3305 +                0x66, 0x44, 0x89, 0x00,        // mov    %r8w,(%rax)
3306 +                0x66, 0x42, 0x89, 0x0c, 0x10,  // mov    %cx,(%rax,%r10,1)
3307 +                0x44, 0x8b, 0x00,              // mov    (%rax),%r8d
3308 +                0x42, 0x8b, 0x0c, 0x10,        // mov    (%rax,%r10,1),%ecx
3309 +                0x44, 0x89, 0x00,              // mov    %r8d,(%rax)
3310 +                0x42, 0x89, 0x0c, 0x10,        // mov    %ecx,(%rax,%r10,1)
3311 +                0x48, 0x8b, 0x08,              // mov    (%rax),%rcx
3312 +                0x4c, 0x8b, 0x18,              // mov    (%rax),%r11
3313 +                0x4a, 0x8b, 0x0c, 0x10,        // mov    (%rax,%r10,1),%rcx
3314 +                0x4e, 0x8b, 0x1c, 0x10,        // mov    (%rax,%r10,1),%r11
3315 +                0x48, 0x89, 0x08,              // mov    %rcx,(%rax)
3316 +                0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
3317 +                0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
3318 +                0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
3319 +                0x63, 0x47, 0x04,              // movslq 4(%rdi),%eax
3320 +                0x48, 0x63, 0x47, 0x04,        // movslq 4(%rdi),%rax
3321 + #endif
3322 +                0                              // end
3323 +        };
3324 +        const int N_REGS = 20;
3325 +        SIGSEGV_REGISTER_TYPE regs[N_REGS];
3326 +        for (int i = 0; i < N_REGS; i++)
3327 +                regs[i] = i;
3328 +        const sigsegv_uintptr_t start_code = (sigsegv_uintptr_t)&code;
3329 +        regs[X86_REG_EIP] = start_code;
3330 +        while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3331 +                   && ix86_skip_instruction(regs))
3332 +                ; /* simply iterate */
3333 +        return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1);
3334 + #endif
3335 +        return true;
3336 + }
3337   #endif
3338  
3339   int main(void)
# Line 1234 | Line 3341 | int main(void)
3341          if (vm_init() < 0)
3342                  return 1;
3343  
3344 <        page_size = getpagesize();
3344 >        page_size = vm_get_page_size();
3345          if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3346                  return 2;
3347          
3348 +        memset((void *)page, 0, page_size);
3349          if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0)
3350                  return 3;
3351          
3352          if (!sigsegv_install_handler(sigsegv_test_handler))
3353                  return 4;
3354 <        
3355 <        page[123] = 45;
3356 <        page[123] = 45;
3357 <        
3354 >
3355 > #ifdef __GNUC__
3356 >        b_region = &&L_b_region1;
3357 >        e_region = &&L_e_region1;
3358 > #endif
3359 >        /* This is a really awful hack but otherwise gcc is smart enough
3360 >         * (or bug'ous enough?) to optimize the labels and place them
3361 >         * e.g. at the "main" entry point, which is wrong.
3362 >         */
3363 >        volatile int label_hack = 1;
3364 >        switch (label_hack) {
3365 >        case 1:
3366 >        L_b_region1:
3367 >                page[REF_INDEX] = REF_VALUE;
3368 >                if (page[REF_INDEX] != REF_VALUE)
3369 >                        exit(20);
3370 >                page[REF_INDEX] = REF_VALUE;
3371 >                BARRIER();
3372 >                // fall-through
3373 >        case 2:
3374 >        L_e_region1:
3375 >                BARRIER();
3376 >                break;
3377 >        }
3378 >
3379          if (handler_called != 1)
3380                  return 5;
3381  
# Line 1264 | Line 3393 | int main(void)
3393                  return 8;
3394          
3395   #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
3396 <                const unsigned int TAG = 0x12345678;                    \
3396 >                const unsigned long TAG = 0x12345678 |                  \
3397 >                (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0);   \
3398                  TYPE data = *((TYPE *)(page + sizeof(TYPE)));   \
3399 <                volatile unsigned int effect = data + TAG;              \
3399 >                volatile unsigned long effect = data + TAG;             \
3400                  if (effect != TAG)                                                              \
3401                          return 9;                                                                       \
3402          } while (0)
3403          
3404   #ifdef __GNUC__
3405 <        b_region = &&L_b_region;
3406 <        e_region = &&L_e_region;
3405 >        b_region = &&L_b_region2;
3406 >        e_region = &&L_e_region2;
3407   #endif
3408 < L_b_region:
3409 <        TEST_SKIP_INSTRUCTION(unsigned char);
3410 <        TEST_SKIP_INSTRUCTION(unsigned short);
3411 <        TEST_SKIP_INSTRUCTION(unsigned int);
3412 < L_e_region:
3408 >        switch (label_hack) {
3409 >        case 1:
3410 >        L_b_region2:
3411 >                TEST_SKIP_INSTRUCTION(unsigned char);
3412 >                TEST_SKIP_INSTRUCTION(unsigned short);
3413 >                TEST_SKIP_INSTRUCTION(unsigned int);
3414 >                TEST_SKIP_INSTRUCTION(unsigned long);
3415 >                TEST_SKIP_INSTRUCTION(signed char);
3416 >                TEST_SKIP_INSTRUCTION(signed short);
3417 >                TEST_SKIP_INSTRUCTION(signed int);
3418 >                TEST_SKIP_INSTRUCTION(signed long);
3419 >                BARRIER();
3420 >                // fall-through
3421 >        case 2:
3422 >        L_e_region2:
3423 >                BARRIER();
3424 >                break;
3425 >        }
3426 >        if (!arch_insn_skipper_tests())
3427 >                return 20;
3428   #endif
3429  
3430          vm_exit();

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines