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.52 by gbeauche, 2005-01-30T21:42:14Z 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-2005 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 49 | 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 66 | 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, // 2 bytes
92          SIZE_LONG, // 4 bytes
93 <        SIZE_QUAD, // 8 bytes
93 >        SIZE_QUAD  // 8 bytes
94   };
95  
96 < // Transfer type
79 < typedef sigsegv_transfer_type_t transfer_type_t;
80 <
81 < #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 228 | Line 243 | static void powerpc_decode_instruction(i
243   // Generic extended signal handler
244   #if defined(__FreeBSD__)
245   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
246 + #elif defined(__hpux)
247 + #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS)
248   #else
249   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
250   #endif
# Line 240 | Line 257 | static void powerpc_decode_instruction(i
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
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
# Line 256 | Line 273 | static void powerpc_decode_instruction(i
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 < #if defined(__FreeBSD__)
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 long *)&(((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
# Line 269 | Line 293 | static void powerpc_decode_instruction(i
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                   (unsigned long *)SIGSEGV_CONTEXT_REGS
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 long *)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>
# Line 309 | Line 343 | static void powerpc_decode_instruction(i
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  
# Line 323 | 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 long *)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 444 | Line 515 | static sigsegv_address_t get_fault_addre
515   #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp, addr
516   #define SIGSEGV_FAULT_ADDRESS                   addr
517   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_eip
518 < #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&scp->sc_edi)
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__))
# Line 479 | 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 490 | 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 511 | Line 582 | static sigsegv_address_t get_fault_addre
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                   ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
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  
# Line 536 | 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 576 | 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_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
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 634 | 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 656 | 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__)) || defined(__x86_64__)
813 > #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
814   #if defined(__linux__)
815   enum {
816   #if (defined(i386) || defined(__i386__))
# Line 723 | Line 875 | enum {
875   #endif
876   };
877   #endif
878 < #if defined(_WIN32)
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,
# Line 736 | Line 972 | enum {
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 772 | Line 1027 | static inline int ix86_step_over_modrm(u
1027          return offset;
1028   }
1029  
1030 < static bool ix86_skip_instruction(unsigned long * regs)
1030 > static bool ix86_skip_instruction(SIGSEGV_REGISTER_TYPE * regs)
1031   {
1032          unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
1033  
# Line 783 | Line 1038 | static bool ix86_skip_instruction(unsign
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;
# Line 802 | Line 1063 | static bool ix86_skip_instruction(unsign
1063          }
1064  
1065          // REX prefix
1066 < #if defined(__x86_64__)
1066 > #if defined(__x86_64__) || defined(_M_X64)
1067          struct rex_t {
1068                  unsigned char W;
1069                  unsigned char R;
# Line 835 | Line 1096 | static bool ix86_skip_instruction(unsign
1096   #endif
1097  
1098          // Decode instruction
1099 +        int op_len = 1;
1100          int target_size = SIZE_UNKNOWN;
1101          switch (eip[0]) {
1102          case 0x0f:
# Line 849 | Line 1111 | static bool ix86_skip_instruction(unsign
1111                          transfer_size = SIZE_WORD;
1112                          goto do_mov_extend;
1113                    do_mov_extend:
1114 <                        switch (eip[2] & 0xc0) {
1115 <                        case 0x80:
1116 <                                reg = (eip[2] >> 3) & 7;
1117 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1118 <                                break;
1119 <                        case 0x40:
1120 <                                reg = (eip[2] >> 3) & 7;
1121 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1122 <                                break;
1123 <                        case 0x00:
1124 <                                reg = (eip[2] >> 3) & 7;
1125 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1126 <                                break;
1127 <                        }
1128 <                        len += 3 + ix86_step_over_modrm(eip + 2);
1129 <                        break;
1130 <            }
1131 <          break;
1114 >                        op_len = 2;
1115 >                        goto do_transfer_load;
1116 >                }
1117 >                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)
# Line 914 | Line 1186 | static bool ix86_skip_instruction(unsign
1186                  return false;
1187          }
1188  
1189 < #if defined(__x86_64__)
1189 > #if defined(__x86_64__) || defined(_M_X64)
1190          if (rex.R)
1191                  reg += 8;
1192   #endif
1193  
1194 <        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
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,
1198 < #if defined(__x86_64__)
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
# Line 955 | Line 1227 | static bool ix86_skip_instruction(unsign
1227          }
1228  
1229   #if DEBUG
1230 <        printf("%08x: %s %s access", regs[X86_REG_EIP],
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" :
# Line 1010 | 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__))
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;
# Line 1047 | Line 2102 | static bool powerpc_skip_instruction(uns
2102  
2103   // Decode and skip MIPS instruction
2104   #if (defined(mips) || defined(__mips))
2105 < enum {
1051 < #if (defined(sgi) || defined(__sgi))
1052 <  MIPS_REG_EPC = 35,
1053 < #endif
1054 < };
1055 < static bool mips_skip_instruction(greg_t * regs)
2105 > static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
2106   {
2107 <  unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
2107 >  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
2108  
2109    if (epc == 0)
2110          return false;
# Line 1203 | Line 2253 | static bool mips_skip_instruction(greg_t
2253                   mips_gpr_names[reg]);
2254   #endif
2255  
2256 <  regs[MIPS_REG_EPC] += 4;
2256 >  *pc_p += 4;
2257    return true;
2258   }
2259   #endif
# Line 1215 | Line 2265 | enum {
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)
# Line 1278 | Line 2329 | static bool sparc_skip_instruction(unsig
2329          break;
2330    case 7: // Store Doubleword
2331          transfer_type = SIGSEGV_TRANSFER_STORE;
2332 <        transfer_size = SIZE_WORD;
2332 >        transfer_size = SIZE_LONG;
2333          register_pair = true;
2334          break;
2335    }
# Line 1288 | Line 2339 | static bool sparc_skip_instruction(unsig
2339          return false;
2340    }
2341  
1291  // Zero target register in case of a load operation
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 <= 7) {
2363 >        if (reg >= 1 && reg < 8) {
2364            // global registers
2365            regs[reg - 1 + SPARC_REG_G1] = 0;
2366          }
2367 <        else if (reg >= 8 && reg <= 15) {
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 <= 23) {
2371 >        else if (reg >= 16 && reg < 24) {
2372            // local registers (in register windows)
2373            if (gwins)
2374                  gwins->wbuf->rw_local[reg - 16] = 0;
# Line 1316 | Line 2384 | static bool sparc_skip_instruction(unsig
2384          }
2385    }
2386  
1319 #if DEBUG
1320  static const char * reg_names[] = {
1321        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1322        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1323        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1324        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1325  };
1326  printf("%s %s register %s\n",
1327                 transfer_size == SIZE_BYTE ? "byte" :
1328                 transfer_size == SIZE_WORD ? "word" :
1329                 transfer_size == SIZE_LONG ? "long" :
1330                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1331                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1332                 reg_names[reg]);
1333 #endif
1334
2387    regs[SPARC_REG_PC] += 4;
2388 +  regs[SPARC_REG_nPC] += 4;
2389    return true;
2390   }
2391   #endif
# Line 1488 | Line 2541 | static bool arm_skip_instruction(unsigne
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(ADDR, IP)  sigsegv_fault_handler(ADDR, IP)
2557 > #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2558   #endif
2559  
2560   // SIGSEGV recovery supported ?
# Line 1508 | Line 2567 | static bool arm_skip_instruction(unsigne
2567   *  SIGSEGV global handler
2568   */
2569  
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_INVOKE(fault_address, fault_instruction)) {
2676 >        switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2677          case SIGSEGV_RETURN_SUCCESS:
2678                  return true;
2679  
# Line 1524 | 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;
1534 <
1535 <                        krc = thread_set_state(thread,
1536 <                                                                   MACHINE_THREAD_STATE, (thread_state_t)state,
1537 <                                                                   MACHINE_THREAD_STATE_COUNT);
1538 <                        MACH_CHECK_ERROR (thread_get_state, krc);
2694 >                        mach_set_thread_state(SIP);
2695   #endif
2696                          return true;
2697                  }
# Line 1544 | Line 2700 | static bool handle_badaccess(SIGSEGV_FAU
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(fault_address, fault_instruction);
2703 >                        sigsegv_state_dumper(SIP);
2704                  break;
2705          }
2706  
# Line 1577 | 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 1586 | 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 1605 | 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 1619 | 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 1674 | 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   {
1684        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 1820 | 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 1848 | Line 3058 | static LONG WINAPI main_exception_filter
3058   {
3059          if (sigsegv_fault_handler != NULL
3060                  && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
3061 <                && ExceptionInfo->ExceptionRecord->NumberParameters == 2
3061 >                && ExceptionInfo->ExceptionRecord->NumberParameters >= 2
3062                  && handle_badaccess(ExceptionInfo))
3063                  return EXCEPTION_CONTINUE_EXECUTION;
3064  
# Line 2000 | Line 3210 | void sigsegv_set_dump_state(sigsegv_stat
3210   const int REF_INDEX = 123;
3211   const int REF_VALUE = 45;
3212  
3213 < static int page_size;
3213 > static sigsegv_uintptr_t page_size;
3214   static volatile char * page = 0;
3215   static volatile int handler_called = 0;
3216  
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_address_t fault_address, sigsegv_address_t instruction_address)
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);
# Line 2024 | Line 3243 | static sigsegv_return_t sigsegv_test_han
3243   #ifdef __GNUC__
3244          // Make sure reported fault instruction address falls into
3245          // expected code range
3246 <        if (instruction_address != SIGSEGV_INVALID_PC
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 *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
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 < 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 +        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 (((unsigned long)fault_address - (unsigned long)page) < page_size) {
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 2058 | Line 3279 | static sigsegv_return_t sigsegv_insn_han
3279   // More sophisticated tests for instruction skipper
3280   static bool arch_insn_skipper_tests()
3281   {
3282 < #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
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
# Line 2072 | Line 3293 | static bool arch_insn_skipper_tests()
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__)
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
# Line 2095 | Line 3316 | static bool arch_insn_skipper_tests()
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 <        unsigned long regs[N_REGS];
3325 >        SIGSEGV_REGISTER_TYPE regs[N_REGS];
3326          for (int i = 0; i < N_REGS; i++)
3327                  regs[i] = i;
3328 <        const unsigned long start_code = (unsigned long)&code;
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))
# Line 2118 | Line 3341 | int main(void)
3341          if (vm_init() < 0)
3342                  return 1;
3343  
3344 < #ifdef _WIN32
2122 <        page_size = 4096;
2123 < #else
2124 <        page_size = getpagesize();
2125 < #endif
3344 >        page_size = vm_get_page_size();
3345          if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3346                  return 2;
3347          
# Line 2132 | Line 3351 | int main(void)
3351          
3352          if (!sigsegv_install_handler(sigsegv_test_handler))
3353                  return 4;
3354 <        
3354 >
3355   #ifdef __GNUC__
3356          b_region = &&L_b_region1;
3357          e_region = &&L_e_region1;
3358   #endif
3359 < L_b_region1:
3360 <        page[REF_INDEX] = REF_VALUE;
3361 <        if (page[REF_INDEX] != REF_VALUE)
3362 <          exit(20);
3363 <        page[REF_INDEX] = REF_VALUE;
3364 < L_e_region1:
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;
# Line 2173 | Line 3405 | int main(void)
3405          b_region = &&L_b_region2;
3406          e_region = &&L_e_region2;
3407   #endif
3408 < L_b_region2:
3409 <        TEST_SKIP_INSTRUCTION(unsigned char);
3410 <        TEST_SKIP_INSTRUCTION(unsigned short);
3411 <        TEST_SKIP_INSTRUCTION(unsigned int);
3412 <        TEST_SKIP_INSTRUCTION(unsigned long);
3413 <        TEST_SKIP_INSTRUCTION(signed char);
3414 <        TEST_SKIP_INSTRUCTION(signed short);
3415 <        TEST_SKIP_INSTRUCTION(signed int);
3416 <        TEST_SKIP_INSTRUCTION(signed long);
3417 < L_e_region2:
3418 <
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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines