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.55 by gbeauche, 2005-03-23T22:00:06Z vs.
Revision 1.80 by gbeauche, 2008-01-14T19:29:29Z

# 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 240 | Line 255 | static void powerpc_decode_instruction(i
255   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
256   #define SIGSEGV_FAULT_INSTRUCTION               (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
257   #if (defined(mips) || defined(__mips))
258 < #define SIGSEGV_REGISTER_FILE                   SIGSEGV_CONTEXT_REGS
258 > #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0]
259   #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
260   #endif
261   #endif
# Line 260 | Line 275 | static void powerpc_decode_instruction(i
275   #include <sys/regset.h>
276   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
277   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[EIP]
278 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
278 > #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
279   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
280   #endif
281   #endif
282   #if defined(__FreeBSD__) || defined(__OpenBSD__)
283   #if (defined(i386) || defined(__i386__))
284   #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_eip)
285 < #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
285 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
286   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
287   #endif
288   #endif
# Line 276 | Line 291 | static void powerpc_decode_instruction(i
291   #include <sys/ucontext.h>
292   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.__gregs)
293   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[_REG_EIP]
294 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
294 > #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
295   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
296   #endif
297   #if (defined(powerpc) || defined(__powerpc__))
# Line 292 | Line 307 | static void powerpc_decode_instruction(i
307   #include <sys/ucontext.h>
308   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
309   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */
310 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
310 > #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
311   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
312   #endif
313   #if (defined(x86_64) || defined(__x86_64__))
314   #include <sys/ucontext.h>
315   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
316   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */
317 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
317 > #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS
318   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
319   #endif
320   #if (defined(ia64) || defined(__ia64__))
321 < #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
321 > #define SIGSEGV_CONTEXT_REGS                    ((struct sigcontext *)scp)
322 > #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
323 > #define SIGSEGV_REGISTER_FILE                   SIGSEGV_CONTEXT_REGS
324 > #define SIGSEGV_SKIP_INSTRUCTION                ia64_skip_instruction
325   #endif
326   #if (defined(powerpc) || defined(__powerpc__))
327   #include <sys/ucontext.h>
# Line 323 | Line 341 | static void powerpc_decode_instruction(i
341   #define SIGSEGV_REGISTER_FILE                   (&SIGSEGV_CONTEXT_REGS.arm_r0)
342   #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
343   #endif
344 + #if (defined(mips) || defined(__mips__))
345 + #include <sys/ucontext.h>
346 + #define SIGSEGV_CONTEXT_REGS                    (((struct ucontext *)scp)->uc_mcontext)
347 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS.pc)
348 + #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
349 + #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
350 + #endif
351   #endif
352   #endif
353  
# Line 337 | Line 362 | static void powerpc_decode_instruction(i
362   #define SIGSEGV_FAULT_HANDLER_ARGS              &scs
363   #define SIGSEGV_FAULT_ADDRESS                   scp->cr2
364   #define SIGSEGV_FAULT_INSTRUCTION               scp->eip
365 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)scp
365 > #define SIGSEGV_REGISTER_FILE                   (SIGSEGV_REGISTER_TYPE *)scp
366   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
367   #endif
368   #if (defined(sparc) || defined(__sparc__))
# Line 458 | Line 483 | static sigsegv_address_t get_fault_addre
483   #define SIGSEGV_FAULT_HANDLER_ARGS              sig, code, scp, addr
484   #define SIGSEGV_FAULT_ADDRESS                   addr
485   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_eip
486 < #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&scp->sc_edi)
486 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&scp->sc_edi)
487   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
488   #endif
489   #if (defined(alpha) || defined(__alpha__))
# Line 521 | Line 546 | static sigsegv_address_t get_fault_addre
546   #include <windows.h>
547   #include <winerror.h>
548  
549 + #if defined(_M_IX86)
550   #define SIGSEGV_FAULT_HANDLER_ARGLIST   EXCEPTION_POINTERS *ExceptionInfo
551   #define SIGSEGV_FAULT_HANDLER_ARGS              ExceptionInfo
552   #define SIGSEGV_FAULT_ADDRESS                   ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
553   #define SIGSEGV_CONTEXT_REGS                    ExceptionInfo->ContextRecord
554   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS->Eip
555 < #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
555 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Edi)
556 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
557 > #endif
558 > #if defined(_M_X64)
559 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   EXCEPTION_POINTERS *ExceptionInfo
560 > #define SIGSEGV_FAULT_HANDLER_ARGS              ExceptionInfo
561 > #define SIGSEGV_FAULT_ADDRESS                   ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
562 > #define SIGSEGV_CONTEXT_REGS                    ExceptionInfo->ContextRecord
563 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS->Rip
564 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Rax)
565   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
566   #endif
567 + #endif
568  
569   #if HAVE_MACH_EXCEPTIONS
570  
# Line 590 | Line 626 | if (ret != KERN_SUCCESS) { \
626          exit (1); \
627   }
628  
629 < #define SIGSEGV_FAULT_ADDRESS                   code[1]
630 < #define SIGSEGV_FAULT_INSTRUCTION               get_fault_instruction(thread, state)
631 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
632 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
633 < #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
629 > #ifdef __ppc__
630 > #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE
631 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
632 > #endif
633 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state_t
634 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE
635 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE_COUNT
636 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(dar)
637 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state_t
638 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE
639 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE_COUNT
640 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(srr0)
641   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
642 < #define SIGSEGV_REGISTER_FILE                   &state->srr0, &state->r0
643 <
644 < // Given a suspended thread, stuff the current instruction and
645 < // registers into state.
646 < //
647 < // It would have been nice to have this be ppc/x86 independant which
648 < // could have been done easily with a thread_state_t instead of
649 < // ppc_thread_state_t, but because of the way this is called it is
650 < // easier to do it this way.
651 < #if (defined(ppc) || defined(__ppc__))
652 < static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
653 < {
654 <        kern_return_t krc;
655 <        mach_msg_type_number_t count;
656 <
657 <        count = MACHINE_THREAD_STATE_COUNT;
658 <        krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
659 <        MACH_CHECK_ERROR (thread_get_state, krc);
642 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
643 > #endif
644 > #ifdef __ppc64__
645 > #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE64
646 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
647 > #endif
648 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state64_t
649 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE64
650 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE64_COUNT
651 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(dar)
652 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state64_t
653 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE64
654 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE64_COUNT
655 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(srr0)
656 > #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
657 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0)
658 > #endif
659 > #ifdef __i386__
660 > #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE32
661 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
662 > #endif
663 > #define SIGSEGV_EXCEPTION_STATE_TYPE    i386_exception_state_t
664 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  i386_EXCEPTION_STATE
665 > #define SIGSEGV_EXCEPTION_STATE_COUNT   i386_EXCEPTION_STATE_COUNT
666 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
667 > #define SIGSEGV_THREAD_STATE_TYPE               i386_thread_state_t
668 > #define SIGSEGV_THREAD_STATE_FLAVOR             i386_THREAD_STATE
669 > #define SIGSEGV_THREAD_STATE_COUNT              i386_THREAD_STATE_COUNT
670 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(eip)
671 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
672 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(eax)) /* EAX is the first GPR we consider */
673 > #endif
674 > #ifdef __x86_64__
675 > #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE64
676 > #define MACH_FIELD_NAME(X)                              __CONCAT(__,X)
677 > #endif
678 > #define SIGSEGV_EXCEPTION_STATE_TYPE    x86_exception_state64_t
679 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  x86_EXCEPTION_STATE64
680 > #define SIGSEGV_EXCEPTION_STATE_COUNT   x86_EXCEPTION_STATE64_COUNT
681 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.MACH_FIELD_NAME(faultvaddr)
682 > #define SIGSEGV_THREAD_STATE_TYPE               x86_thread_state64_t
683 > #define SIGSEGV_THREAD_STATE_FLAVOR             x86_THREAD_STATE64
684 > #define SIGSEGV_THREAD_STATE_COUNT              x86_THREAD_STATE64_COUNT
685 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.MACH_FIELD_NAME(rip)
686 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
687 > #define SIGSEGV_REGISTER_FILE                   ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(rax)) /* RAX is the first GPR we consider */
688 > #endif
689 > #define SIGSEGV_FAULT_ADDRESS_FAST              code[1]
690 > #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_INVALID_ADDRESS
691 > #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code
692 > #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code
693  
694 <        return (sigsegv_address_t)state->srr0;
695 < }
694 > #ifndef MACH_FIELD_NAME
695 > #define MACH_FIELD_NAME(X) X
696   #endif
697  
698   // Since there can only be one exception thread running at any time
# Line 670 | Line 746 | handleExceptions(void *priv)
746   *  Instruction skipping
747   */
748  
749 + #ifndef SIGSEGV_REGISTER_TYPE
750 + #define SIGSEGV_REGISTER_TYPE sigsegv_uintptr_t
751 + #endif
752 +
753   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
754   // Decode and skip X86 instruction
755 < #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
755 > #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
756   #if defined(__linux__)
757   enum {
758   #if (defined(i386) || defined(__i386__))
# Line 773 | Line 853 | enum {
853   #endif
854   };
855   #endif
856 < #if defined(_WIN32)
856 > #if defined(__APPLE__) && defined(__MACH__)
857   enum {
858   #if (defined(i386) || defined(__i386__))
859 + #ifdef i386_SAVED_STATE
860 +        // same as FreeBSD (in Open Darwin 8.0.1)
861 +        X86_REG_EIP = 10,
862 +        X86_REG_EAX = 7,
863 +        X86_REG_ECX = 6,
864 +        X86_REG_EDX = 5,
865 +        X86_REG_EBX = 4,
866 +        X86_REG_ESP = 13,
867 +        X86_REG_EBP = 2,
868 +        X86_REG_ESI = 1,
869 +        X86_REG_EDI = 0
870 + #else
871 +        // new layout (MacOS X 10.4.4 for x86)
872 +        X86_REG_EIP = 10,
873 +        X86_REG_EAX = 0,
874 +        X86_REG_ECX = 2,
875 +        X86_REG_EDX = 3,
876 +        X86_REG_EBX = 1,
877 +        X86_REG_ESP = 7,
878 +        X86_REG_EBP = 6,
879 +        X86_REG_ESI = 5,
880 +        X86_REG_EDI = 4
881 + #endif
882 + #endif
883 + #if defined(__x86_64__)
884 +        X86_REG_R8  = 8,
885 +        X86_REG_R9  = 9,
886 +        X86_REG_R10 = 10,
887 +        X86_REG_R11 = 11,
888 +        X86_REG_R12 = 12,
889 +        X86_REG_R13 = 13,
890 +        X86_REG_R14 = 14,
891 +        X86_REG_R15 = 15,
892 +        X86_REG_EDI = 4,
893 +        X86_REG_ESI = 5,
894 +        X86_REG_EBP = 6,
895 +        X86_REG_EBX = 1,
896 +        X86_REG_EDX = 3,
897 +        X86_REG_EAX = 0,
898 +        X86_REG_ECX = 2,
899 +        X86_REG_ESP = 7,
900 +        X86_REG_EIP = 16
901 + #endif
902 + };
903 + #endif
904 + #if defined(_WIN32)
905 + enum {
906 + #if defined(_M_IX86)
907          X86_REG_EIP = 7,
908          X86_REG_EAX = 5,
909          X86_REG_ECX = 4,
# Line 786 | Line 914 | enum {
914          X86_REG_ESI = 1,
915          X86_REG_EDI = 0
916   #endif
917 + #if defined(_M_X64)
918 +        X86_REG_EAX = 0,
919 +        X86_REG_ECX = 1,
920 +        X86_REG_EDX = 2,
921 +        X86_REG_EBX = 3,
922 +        X86_REG_ESP = 4,
923 +        X86_REG_EBP = 5,
924 +        X86_REG_ESI = 6,
925 +        X86_REG_EDI = 7,
926 +        X86_REG_R8  = 8,
927 +        X86_REG_R9  = 9,
928 +        X86_REG_R10 = 10,
929 +        X86_REG_R11 = 11,
930 +        X86_REG_R12 = 12,
931 +        X86_REG_R13 = 13,
932 +        X86_REG_R14 = 14,
933 +        X86_REG_R15 = 15,
934 +        X86_REG_EIP = 16
935 + #endif
936   };
937   #endif
938   // FIXME: this is partly redundant with the instruction decoding phase
# Line 822 | Line 969 | static inline int ix86_step_over_modrm(u
969          return offset;
970   }
971  
972 < static bool ix86_skip_instruction(unsigned long * regs)
972 > static bool ix86_skip_instruction(SIGSEGV_REGISTER_TYPE * regs)
973   {
974          unsigned char * eip = (unsigned char *)regs[X86_REG_EIP];
975  
# Line 833 | Line 980 | static bool ix86_skip_instruction(unsign
980                  return false;
981   #endif
982          
983 +        enum instruction_type_t {
984 +                i_MOV,
985 +                i_ADD
986 +        };
987 +
988          transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
989          transfer_size_t transfer_size = SIZE_LONG;
990 +        instruction_type_t instruction_type = i_MOV;
991          
992          int reg = -1;
993          int len = 0;
# Line 852 | Line 1005 | static bool ix86_skip_instruction(unsign
1005          }
1006  
1007          // REX prefix
1008 < #if defined(__x86_64__)
1008 > #if defined(__x86_64__) || defined(_M_X64)
1009          struct rex_t {
1010                  unsigned char W;
1011                  unsigned char R;
# Line 885 | Line 1038 | static bool ix86_skip_instruction(unsign
1038   #endif
1039  
1040          // Decode instruction
1041 +        int op_len = 1;
1042          int target_size = SIZE_UNKNOWN;
1043          switch (eip[0]) {
1044          case 0x0f:
# Line 899 | Line 1053 | static bool ix86_skip_instruction(unsign
1053                          transfer_size = SIZE_WORD;
1054                          goto do_mov_extend;
1055                    do_mov_extend:
1056 <                        switch (eip[2] & 0xc0) {
1057 <                        case 0x80:
1058 <                                reg = (eip[2] >> 3) & 7;
1059 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1060 <                                break;
1061 <                        case 0x40:
1062 <                                reg = (eip[2] >> 3) & 7;
1063 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1064 <                                break;
1065 <                        case 0x00:
1066 <                                reg = (eip[2] >> 3) & 7;
1067 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1068 <                                break;
1069 <                        }
1070 <                        len += 3 + ix86_step_over_modrm(eip + 2);
1071 <                        break;
1072 <            }
1073 <          break;
1056 >                        op_len = 2;
1057 >                        goto do_transfer_load;
1058 >                }
1059 >                break;
1060 > #if defined(__x86_64__) || defined(_M_X64)
1061 >        case 0x63: // MOVSXD r64, r/m32
1062 >                if (has_rex && rex.W) {
1063 >                        transfer_size = SIZE_LONG;
1064 >                        target_size = SIZE_QUAD;
1065 >                }
1066 >                else if (transfer_size != SIZE_WORD) {
1067 >                        transfer_size = SIZE_LONG;
1068 >                        target_size = SIZE_QUAD;
1069 >                }
1070 >                goto do_transfer_load;
1071 > #endif
1072 >        case 0x02: // ADD r8, r/m8
1073 >                transfer_size = SIZE_BYTE;
1074 >        case 0x03: // ADD r32, r/m32
1075 >                instruction_type = i_ADD;
1076 >                goto do_transfer_load;
1077          case 0x8a: // MOV r8, r/m8
1078                  transfer_size = SIZE_BYTE;
1079          case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1080 <                switch (eip[1] & 0xc0) {
1080 >          do_transfer_load:
1081 >                switch (eip[op_len] & 0xc0) {
1082                  case 0x80:
1083 <                        reg = (eip[1] >> 3) & 7;
1083 >                        reg = (eip[op_len] >> 3) & 7;
1084                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1085                          break;
1086                  case 0x40:
1087 <                        reg = (eip[1] >> 3) & 7;
1087 >                        reg = (eip[op_len] >> 3) & 7;
1088                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1089                          break;
1090                  case 0x00:
1091 <                        reg = (eip[1] >> 3) & 7;
1091 >                        reg = (eip[op_len] >> 3) & 7;
1092                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1093                          break;
1094                  }
1095 <                len += 2 + ix86_step_over_modrm(eip + 1);
1095 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1096                  break;
1097 +        case 0x00: // ADD r/m8, r8
1098 +                transfer_size = SIZE_BYTE;
1099 +        case 0x01: // ADD r/m32, r32
1100 +                instruction_type = i_ADD;
1101 +                goto do_transfer_store;
1102          case 0x88: // MOV r/m8, r8
1103                  transfer_size = SIZE_BYTE;
1104          case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1105 <                switch (eip[1] & 0xc0) {
1105 >          do_transfer_store:
1106 >                switch (eip[op_len] & 0xc0) {
1107                  case 0x80:
1108 <                        reg = (eip[1] >> 3) & 7;
1108 >                        reg = (eip[op_len] >> 3) & 7;
1109                          transfer_type = SIGSEGV_TRANSFER_STORE;
1110                          break;
1111                  case 0x40:
1112 <                        reg = (eip[1] >> 3) & 7;
1112 >                        reg = (eip[op_len] >> 3) & 7;
1113                          transfer_type = SIGSEGV_TRANSFER_STORE;
1114                          break;
1115                  case 0x00:
1116 <                        reg = (eip[1] >> 3) & 7;
1116 >                        reg = (eip[op_len] >> 3) & 7;
1117                          transfer_type = SIGSEGV_TRANSFER_STORE;
1118                          break;
1119                  }
1120 <                len += 2 + ix86_step_over_modrm(eip + 1);
1120 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1121                  break;
1122          }
1123          if (target_size == SIZE_UNKNOWN)
# Line 964 | Line 1128 | static bool ix86_skip_instruction(unsign
1128                  return false;
1129          }
1130  
1131 < #if defined(__x86_64__)
1131 > #if defined(__x86_64__) || defined(_M_X64)
1132          if (rex.R)
1133                  reg += 8;
1134   #endif
1135  
1136 <        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1136 >        if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1137                  static const int x86_reg_map[] = {
1138                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1139                          X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
1140 < #if defined(__x86_64__)
1140 > #if defined(__x86_64__) || defined(_M_X64)
1141                          X86_REG_R8,  X86_REG_R9,  X86_REG_R10, X86_REG_R11,
1142                          X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15,
1143   #endif
# Line 1005 | Line 1169 | static bool ix86_skip_instruction(unsign
1169          }
1170  
1171   #if DEBUG
1172 <        printf("%08x: %s %s access", regs[X86_REG_EIP],
1172 >        printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1173                     transfer_size == SIZE_BYTE ? "byte" :
1174                     transfer_size == SIZE_WORD ? "word" :
1175                     transfer_size == SIZE_LONG ? "long" :
# Line 1060 | Line 1224 | static bool ix86_skip_instruction(unsign
1224   }
1225   #endif
1226  
1227 + // Decode and skip IA-64 instruction
1228 + #if defined(__ia64__)
1229 + #if defined(__linux__)
1230 + // We can directly patch the slot number
1231 + #define IA64_CAN_PATCH_IP_SLOT 1
1232 + // Helper macros to access the machine context
1233 + #define IA64_CONTEXT_TYPE               struct sigcontext *
1234 + #define IA64_CONTEXT                    scp
1235 + #define IA64_GET_IP()                   (IA64_CONTEXT->sc_ip)
1236 + #define IA64_SET_IP(V)                  (IA64_CONTEXT->sc_ip = (V))
1237 + #define IA64_GET_PR(P)                  ((IA64_CONTEXT->sc_pr >> (P)) & 1)
1238 + #define IA64_GET_NAT(I)                 ((IA64_CONTEXT->sc_nat >> (I)) & 1)
1239 + #define IA64_SET_NAT(I,V)               (IA64_CONTEXT->sc_nat= (IA64_CONTEXT->sc_nat & ~(1ul << (I))) | (((unsigned long)!!(V)) << (I)))
1240 + #define IA64_GET_GR(R)                  (IA64_CONTEXT->sc_gr[(R)])
1241 + #define IA64_SET_GR(R,V)                (IA64_CONTEXT->sc_gr[(R)] = (V))
1242 + #endif
1243 +
1244 + // Instruction operations
1245 + enum {
1246 +        IA64_INST_UNKNOWN = 0,
1247 +        IA64_INST_LD1,                          // ld1 op0=[op1]
1248 +        IA64_INST_LD1_UPDATE,           // ld1 op0=[op1],op2
1249 +        IA64_INST_LD2,                          // ld2 op0=[op1]
1250 +        IA64_INST_LD2_UPDATE,           // ld2 op0=[op1],op2
1251 +        IA64_INST_LD4,                          // ld4 op0=[op1]
1252 +        IA64_INST_LD4_UPDATE,           // ld4 op0=[op1],op2
1253 +        IA64_INST_LD8,                          // ld8 op0=[op1]
1254 +        IA64_INST_LD8_UPDATE,           // ld8 op0=[op1],op2
1255 +        IA64_INST_ST1,                          // st1 [op0]=op1
1256 +        IA64_INST_ST1_UPDATE,           // st1 [op0]=op1,op2
1257 +        IA64_INST_ST2,                          // st2 [op0]=op1
1258 +        IA64_INST_ST2_UPDATE,           // st2 [op0]=op1,op2
1259 +        IA64_INST_ST4,                          // st4 [op0]=op1
1260 +        IA64_INST_ST4_UPDATE,           // st4 [op0]=op1,op2
1261 +        IA64_INST_ST8,                          // st8 [op0]=op1
1262 +        IA64_INST_ST8_UPDATE,           // st8 [op0]=op1,op2
1263 +        IA64_INST_ADD,                          // add op0=op1,op2,op3
1264 +        IA64_INST_SUB,                          // sub op0=op1,op2,op3
1265 +        IA64_INST_SHLADD,                       // shladd op0=op1,op3,op2
1266 +        IA64_INST_AND,                          // and op0=op1,op2
1267 +        IA64_INST_ANDCM,                        // andcm op0=op1,op2
1268 +        IA64_INST_OR,                           // or op0=op1,op2
1269 +        IA64_INST_XOR,                          // xor op0=op1,op2
1270 +        IA64_INST_SXT1,                         // sxt1 op0=op1
1271 +        IA64_INST_SXT2,                         // sxt2 op0=op1
1272 +        IA64_INST_SXT4,                         // sxt4 op0=op1
1273 +        IA64_INST_ZXT1,                         // zxt1 op0=op1
1274 +        IA64_INST_ZXT2,                         // zxt2 op0=op1
1275 +        IA64_INST_ZXT4,                         // zxt4 op0=op1
1276 +        IA64_INST_NOP                           // nop op0
1277 + };
1278 +
1279 + const int IA64_N_OPERANDS = 4;
1280 +
1281 + // Decoded operand type
1282 + struct ia64_operand_t {
1283 +        unsigned char commit;           // commit result of operation to register file?
1284 +        unsigned char valid;            // XXX: not really used, can be removed (debug)
1285 +        signed char index;                      // index of GPR, or -1 if immediate value
1286 +        unsigned char nat;                      // NaT state before operation
1287 +        unsigned long value;            // register contents or immediate value
1288 + };
1289 +
1290 + // Decoded instruction type
1291 + struct ia64_instruction_t {
1292 +        unsigned char mnemo;            // operation to perform
1293 +        unsigned char pred;                     // predicate register to check
1294 +        unsigned char no_memory;        // used to emulated main fault instruction
1295 +        unsigned long inst;                     // the raw instruction bits (41-bit wide)
1296 +        ia64_operand_t operands[IA64_N_OPERANDS];
1297 + };
1298 +
1299 + // Get immediate sign-bit
1300 + static inline int ia64_inst_get_sbit(unsigned long inst)
1301 + {
1302 +        return (inst >> 36) & 1;
1303 + }
1304 +
1305 + // Get 8-bit immediate value (A3, A8, I27, M30)
1306 + static inline unsigned long ia64_inst_get_imm8(unsigned long inst)
1307 + {
1308 +        unsigned long value = (inst >> 13) & 0x7ful;
1309 +        if (ia64_inst_get_sbit(inst))
1310 +                value |= ~0x7ful;
1311 +        return value;
1312 + }
1313 +
1314 + // Get 9-bit immediate value (M3)
1315 + static inline unsigned long ia64_inst_get_imm9b(unsigned long inst)
1316 + {
1317 +        unsigned long value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1318 +        if (ia64_inst_get_sbit(inst))
1319 +                value |= ~0xfful;
1320 +        return value;
1321 + }
1322 +
1323 + // Get 9-bit immediate value (M5)
1324 + static inline unsigned long ia64_inst_get_imm9a(unsigned long inst)
1325 + {
1326 +        unsigned long value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1327 +        if (ia64_inst_get_sbit(inst))
1328 +                value |= ~0xfful;
1329 +        return value;
1330 + }
1331 +
1332 + // Get 14-bit immediate value (A4)
1333 + static inline unsigned long ia64_inst_get_imm14(unsigned long inst)
1334 + {
1335 +        unsigned long value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1336 +        if (ia64_inst_get_sbit(inst))
1337 +                value |= ~0x1fful;
1338 +        return value;
1339 + }
1340 +
1341 + // Get 22-bit immediate value (A5)
1342 + static inline unsigned long ia64_inst_get_imm22(unsigned long inst)
1343 + {
1344 +        unsigned long value = ((((inst >> 22) & 0x1f) << 16) |
1345 +                                                   (((inst >> 27) & 0x1ff) << 7) |
1346 +                                                   (inst & 0x7f));
1347 +        if (ia64_inst_get_sbit(inst))
1348 +                value |= ~0x1ffffful;
1349 +        return value;
1350 + }
1351 +
1352 + // Get 21-bit immediate value (I19)
1353 + static inline unsigned long ia64_inst_get_imm21(unsigned long inst)
1354 + {
1355 +        return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1356 + }
1357 +
1358 + // Get 2-bit count value (A2)
1359 + static inline int ia64_inst_get_count2(unsigned long inst)
1360 + {
1361 +        return (inst >> 27) & 0x3;
1362 + }
1363 +
1364 + // Get bundle template
1365 + static inline unsigned int ia64_get_template(unsigned long raw_ip)
1366 + {
1367 +        unsigned long *ip = (unsigned long *)(raw_ip & ~3ul);
1368 +        return ip[0] & 0x1f;
1369 + }
1370 +
1371 + // Get specified instruction in bundle
1372 + static unsigned long ia64_get_instruction(unsigned long raw_ip, int slot)
1373 + {
1374 +        unsigned long inst;
1375 +        unsigned long *ip = (unsigned long *)(raw_ip & ~3ul);
1376 + #if DEBUG
1377 +        printf("Bundle: %016lx%016lx\n", ip[1], ip[0]);
1378 + #endif
1379 +
1380 +        switch (slot) {
1381 +        case 0:
1382 +                inst = (ip[0] >> 5) & 0x1fffffffffful;
1383 +                break;
1384 +        case 1:
1385 +                inst = ((ip[1] & 0x7ffffful) << 18) | ((ip[0] >> 46) & 0x3fffful);
1386 +                break;
1387 +        case 2:
1388 +                inst = (ip[1] >> 23) & 0x1fffffffffful;
1389 +                break;
1390 +        case 3:
1391 +                fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1392 +                abort();
1393 +                break;
1394 +        }
1395 +
1396 + #if DEBUG
1397 +        printf(" Instruction %d: 0x%016lx\n", slot, inst);
1398 + #endif
1399 +        return inst;
1400 + }
1401 +
1402 + // Decode group 0 instructions
1403 + static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1404 + {
1405 +        const int r1 = (inst->inst >>  6) & 0x7f;
1406 +        const int r3 = (inst->inst >> 20) & 0x7f;
1407 +
1408 +        const int x3 = (inst->inst >> 33) & 0x07;
1409 +        const int x6 = (inst->inst >> 27) & 0x3f;
1410 +        const int x2 = (inst->inst >> 31) & 0x03;
1411 +        const int x4 = (inst->inst >> 27) & 0x0f;
1412 +
1413 +        if (x3 == 0) {
1414 +                switch (x6) {
1415 +                case 0x01:                                              // nop.i (I19)
1416 +                        inst->mnemo = IA64_INST_NOP;
1417 +                        inst->operands[0].valid = true;
1418 +                        inst->operands[0].index = -1;
1419 +                        inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1420 +                        return true;
1421 +                case 0x14:                                              // sxt1 (I29)
1422 +                case 0x15:                                              // sxt2 (I29)
1423 +                case 0x16:                                              // sxt4 (I29)
1424 +                case 0x10:                                              // zxt1 (I29)
1425 +                case 0x11:                                              // zxt2 (I29)
1426 +                case 0x12:                                              // zxt4 (I29)
1427 +                        switch (x6) {
1428 +                        case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1429 +                        case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1430 +                        case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1431 +                        case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1432 +                        case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1433 +                        case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1434 +                        default: abort();
1435 +                        }
1436 +                        inst->operands[0].valid = true;
1437 +                        inst->operands[0].index = r1;
1438 +                        inst->operands[1].valid = true;
1439 +                        inst->operands[1].index = r3;
1440 +                        inst->operands[1].value = IA64_GET_GR(r3);
1441 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1442 +                        return true;
1443 +                }
1444 +        }
1445 +        return false;
1446 + }
1447 +
1448 + // Decode group 4 instructions (load/store instructions)
1449 + static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1450 + {
1451 +        const int r1 = (inst->inst >> 6) & 0x7f;
1452 +        const int r2 = (inst->inst >> 13) & 0x7f;
1453 +        const int r3 = (inst->inst >> 20) & 0x7f;
1454 +
1455 +        const int m  = (inst->inst >> 36) & 1;
1456 +        const int x  = (inst->inst >> 27) & 1;
1457 +        const int x6 = (inst->inst >> 30) & 0x3f;
1458 +
1459 +        switch (x6) {
1460 +        case 0x00:
1461 +        case 0x01:
1462 +        case 0x02:
1463 +        case 0x03:
1464 +                if (x == 0) {
1465 +                        inst->operands[0].valid = true;
1466 +                        inst->operands[0].index = r1;
1467 +                        inst->operands[1].valid = true;
1468 +                        inst->operands[1].index = r3;
1469 +                        inst->operands[1].value = IA64_GET_GR(r3);
1470 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1471 +                        if (m == 0) {
1472 +                                switch (x6) {
1473 +                                case 0x00: inst->mnemo = IA64_INST_LD1; break;
1474 +                                case 0x01: inst->mnemo = IA64_INST_LD2; break;
1475 +                                case 0x02: inst->mnemo = IA64_INST_LD4; break;
1476 +                                case 0x03: inst->mnemo = IA64_INST_LD8; break;
1477 +                                }
1478 +                        }
1479 +                        else {
1480 +                                inst->operands[2].valid = true;
1481 +                                inst->operands[2].index = r2;
1482 +                                inst->operands[2].value = IA64_GET_GR(r2);
1483 +                                inst->operands[2].nat   = IA64_GET_NAT(r2);
1484 +                                switch (x6) {
1485 +                                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1486 +                                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1487 +                                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1488 +                                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1489 +                                }
1490 +                        }
1491 +                        return true;
1492 +                }
1493 +                break;
1494 +        case 0x30:
1495 +        case 0x31:
1496 +        case 0x32:
1497 +        case 0x33:
1498 +                if (m == 0 && x == 0) {
1499 +                        inst->operands[0].valid = true;
1500 +                        inst->operands[0].index = r3;
1501 +                        inst->operands[0].value = IA64_GET_GR(r3);
1502 +                        inst->operands[0].nat   = IA64_GET_NAT(r3);
1503 +                        inst->operands[1].valid = true;
1504 +                        inst->operands[1].index = r2;
1505 +                        inst->operands[1].value = IA64_GET_GR(r2);
1506 +                        inst->operands[1].nat   = IA64_GET_NAT(r2);
1507 +                        switch (x6) {
1508 +                        case 0x30: inst->mnemo = IA64_INST_ST1; break;
1509 +                        case 0x31: inst->mnemo = IA64_INST_ST2; break;
1510 +                        case 0x32: inst->mnemo = IA64_INST_ST4; break;
1511 +                        case 0x33: inst->mnemo = IA64_INST_ST8; break;
1512 +                        }
1513 +                        return true;
1514 +                }
1515 +                break;
1516 +        }
1517 +        return false;
1518 + }
1519 +
1520 + // Decode group 5 instructions (load/store instructions)
1521 + static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1522 + {
1523 +        const int r1 = (inst->inst >> 6) & 0x7f;
1524 +        const int r2 = (inst->inst >> 13) & 0x7f;
1525 +        const int r3 = (inst->inst >> 20) & 0x7f;
1526 +
1527 +        const int x6 = (inst->inst >> 30) & 0x3f;
1528 +
1529 +        switch (x6) {
1530 +        case 0x00:
1531 +        case 0x01:
1532 +        case 0x02:
1533 +        case 0x03:
1534 +                inst->operands[0].valid = true;
1535 +                inst->operands[0].index = r1;
1536 +                inst->operands[1].valid = true;
1537 +                inst->operands[1].index = r3;
1538 +                inst->operands[1].value = IA64_GET_GR(r3);
1539 +                inst->operands[1].nat   = IA64_GET_NAT(r3);
1540 +                inst->operands[2].valid = true;
1541 +                inst->operands[2].index = -1;
1542 +                inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1543 +                inst->operands[2].nat   = 0;
1544 +                switch (x6) {
1545 +                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1546 +                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1547 +                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1548 +                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1549 +                }
1550 +                return true;
1551 +        case 0x30:
1552 +        case 0x31:
1553 +        case 0x32:
1554 +        case 0x33:
1555 +                inst->operands[0].valid = true;
1556 +                inst->operands[0].index = r3;
1557 +                inst->operands[0].value = IA64_GET_GR(r3);
1558 +                inst->operands[0].nat   = IA64_GET_NAT(r3);
1559 +                inst->operands[1].valid = true;
1560 +                inst->operands[1].index = r2;
1561 +                inst->operands[1].value = IA64_GET_GR(r2);
1562 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1563 +                inst->operands[2].valid = true;
1564 +                inst->operands[2].index = -1;
1565 +                inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1566 +                inst->operands[2].nat   = 0;
1567 +                switch (x6) {
1568 +                case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1569 +                case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1570 +                case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1571 +                case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1572 +                }
1573 +                return true;
1574 +        }
1575 +        return false;
1576 + }
1577 +
1578 + // Decode group 8 instructions (ALU integer)
1579 + static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1580 + {
1581 +        const int r1  = (inst->inst >> 6) & 0x7f;
1582 +        const int r2  = (inst->inst >> 13) & 0x7f;
1583 +        const int r3  = (inst->inst >> 20) & 0x7f;
1584 +
1585 +        const int x2a = (inst->inst >> 34) & 0x3;
1586 +        const int x2b = (inst->inst >> 27) & 0x3;
1587 +        const int x4  = (inst->inst >> 29) & 0xf;
1588 +        const int ve  = (inst->inst >> 33) & 0x1;
1589 +
1590 +        // destination register (r1) is always valid in this group
1591 +        inst->operands[0].valid = true;
1592 +        inst->operands[0].index = r1;
1593 +
1594 +        // source register (r3) is always valid in this group
1595 +        inst->operands[2].valid = true;
1596 +        inst->operands[2].index = r3;
1597 +        inst->operands[2].value = IA64_GET_GR(r3);
1598 +        inst->operands[2].nat   = IA64_GET_NAT(r3);
1599 +
1600 +        if (x2a == 0 && ve == 0) {
1601 +                inst->operands[1].valid = true;
1602 +                inst->operands[1].index = r2;
1603 +                inst->operands[1].value = IA64_GET_GR(r2);
1604 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1605 +                switch (x4) {
1606 +                case 0x0:                               // add (A1)
1607 +                        inst->mnemo = IA64_INST_ADD;
1608 +                        inst->operands[3].valid = true;
1609 +                        inst->operands[3].index = -1;
1610 +                        inst->operands[3].value = x2b == 1;
1611 +                        return true;
1612 +                case 0x1:                               // add (A1)
1613 +                        inst->mnemo = IA64_INST_SUB;
1614 +                        inst->operands[3].valid = true;
1615 +                        inst->operands[3].index = -1;
1616 +                        inst->operands[3].value = x2b == 0;
1617 +                        return true;
1618 +                case 0x4:                               // shladd (A2)
1619 +                        inst->mnemo = IA64_INST_SHLADD;
1620 +                        inst->operands[3].valid = true;
1621 +                        inst->operands[3].index = -1;
1622 +                        inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1623 +                        return true;
1624 +                case 0x9:
1625 +                        if (x2b == 1) {
1626 +                                inst->mnemo = IA64_INST_SUB;
1627 +                                inst->operands[1].index = -1;
1628 +                                inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1629 +                                inst->operands[1].nat   = 0;
1630 +                                return true;
1631 +                        }
1632 +                        break;
1633 +                case 0xb:
1634 +                        inst->operands[1].index = -1;
1635 +                        inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1636 +                        inst->operands[1].nat   = 0;
1637 +                        // fall-through
1638 +                case 0x3:
1639 +                        switch (x2b) {
1640 +                        case 0: inst->mnemo = IA64_INST_AND;   break;
1641 +                        case 1: inst->mnemo = IA64_INST_ANDCM; break;
1642 +                        case 2: inst->mnemo = IA64_INST_OR;    break;
1643 +                        case 3: inst->mnemo = IA64_INST_XOR;   break;
1644 +                        }
1645 +                        return true;
1646 +                }
1647 +        }
1648 +        return false;
1649 + }
1650 +
1651 + // Decode instruction
1652 + static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1653 + {
1654 +        const int major = (inst->inst >> 37) & 0xf;
1655 +
1656 +        inst->mnemo = IA64_INST_UNKNOWN;
1657 +        inst->pred  = inst->inst & 0x3f;
1658 +        memset(&inst->operands[0], 0, sizeof(inst->operands));
1659 +
1660 +        switch (major) {
1661 +        case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT);
1662 +        case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT);
1663 +        case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT);
1664 +        case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT);
1665 +        }
1666 +        return false;
1667 + }
1668 +
1669 + static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1670 + {
1671 +        // XXX: handle Register NaT Consumption fault?
1672 +        // XXX: this simple emulator assumes instructions in a bundle
1673 +        // don't depend on effects of other instructions in the same
1674 +        // bundle. It probably would be simpler to JIT-generate code to be
1675 +        // executed natively but probably more costly (inject/extract CPU state)
1676 +        if (inst->mnemo == IA64_INST_UNKNOWN)
1677 +                return false;
1678 +        if (inst->pred && !IA64_GET_PR(inst->pred))
1679 +                return true;
1680 +
1681 +        unsigned char nat, nat2;
1682 +        unsigned long dst, dst2, src1, src2, src3;
1683 +
1684 +        switch (inst->mnemo) {
1685 +        case IA64_INST_NOP:
1686 +                break;
1687 +        case IA64_INST_ADD:
1688 +        case IA64_INST_SUB:
1689 +        case IA64_INST_SHLADD:
1690 +                src3 = inst->operands[3].value;
1691 +                // fall-through
1692 +        case IA64_INST_AND:
1693 +        case IA64_INST_ANDCM:
1694 +        case IA64_INST_OR:
1695 +        case IA64_INST_XOR:
1696 +                src1 = inst->operands[1].value;
1697 +                src2 = inst->operands[2].value;
1698 +                switch (inst->mnemo) {
1699 +                case IA64_INST_ADD:   dst = src1 + src2 + src3; break;
1700 +                case IA64_INST_SUB:   dst = src1 - src2 - src3; break;
1701 +                case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1702 +                case IA64_INST_AND:   dst = src1 & src2;                break;
1703 +                case IA64_INST_ANDCM: dst = src1 &~ src2;               break;
1704 +                case IA64_INST_OR:    dst = src1 | src2;                break;
1705 +                case IA64_INST_XOR:   dst = src1 ^ src2;                break;
1706 +                }
1707 +                inst->operands[0].commit = true;
1708 +                inst->operands[0].value  = dst;
1709 +                inst->operands[0].nat    = inst->operands[1].nat | inst->operands[2].nat;
1710 +                break;
1711 +        case IA64_INST_SXT1:
1712 +        case IA64_INST_SXT2:
1713 +        case IA64_INST_SXT4:
1714 +        case IA64_INST_ZXT1:
1715 +        case IA64_INST_ZXT2:
1716 +        case IA64_INST_ZXT4:
1717 +                src1 = inst->operands[1].value;
1718 +                switch (inst->mnemo) {
1719 +                case IA64_INST_SXT1: dst = (signed long)(signed char)src1;              break;
1720 +                case IA64_INST_SXT2: dst = (signed long)(signed short)src1;             break;
1721 +                case IA64_INST_SXT4: dst = (signed long)(signed int)src1;               break;
1722 +                case IA64_INST_ZXT1: dst = (unsigned char)src1;                                 break;
1723 +                case IA64_INST_ZXT2: dst = (unsigned short)src1;                                break;
1724 +                case IA64_INST_ZXT4: dst = (unsigned int)src1;                                  break;
1725 +                }
1726 +                inst->operands[0].commit = true;
1727 +                inst->operands[0].value  = dst;
1728 +                inst->operands[0].nat    = inst->operands[1].nat;
1729 +                break;
1730 +        case IA64_INST_LD1_UPDATE:
1731 +        case IA64_INST_LD2_UPDATE:
1732 +        case IA64_INST_LD4_UPDATE:
1733 +        case IA64_INST_LD8_UPDATE:
1734 +                inst->operands[1].commit = true;
1735 +                dst2 = inst->operands[1].value + inst->operands[2].value;
1736 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1737 +                // fall-through
1738 +        case IA64_INST_LD1:
1739 +        case IA64_INST_LD2:
1740 +        case IA64_INST_LD4:
1741 +        case IA64_INST_LD8:
1742 +                src1 = inst->operands[1].value;
1743 +                if (inst->no_memory)
1744 +                        dst = 0;
1745 +                else {
1746 +                        switch (inst->mnemo) {
1747 +                        case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((unsigned char *)src1);  break;
1748 +                        case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((unsigned short *)src1); break;
1749 +                        case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((unsigned int *)src1);   break;
1750 +                        case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((unsigned long *)src1);  break;
1751 +                        }
1752 +                }
1753 +                inst->operands[0].commit = true;
1754 +                inst->operands[0].value  = dst;
1755 +                inst->operands[0].nat    = 0;
1756 +                inst->operands[1].value  = dst2;
1757 +                inst->operands[1].nat    = nat2;
1758 +                break;
1759 +        case IA64_INST_ST1_UPDATE:
1760 +        case IA64_INST_ST2_UPDATE:
1761 +        case IA64_INST_ST4_UPDATE:
1762 +        case IA64_INST_ST8_UPDATE:
1763 +                inst->operands[0].commit = 0;
1764 +                dst2 = inst->operands[0].value + inst->operands[2].value;
1765 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1766 +                // fall-through
1767 +        case IA64_INST_ST1:
1768 +        case IA64_INST_ST2:
1769 +        case IA64_INST_ST4:
1770 +        case IA64_INST_ST8:
1771 +                dst  = inst->operands[0].value;
1772 +                src1 = inst->operands[1].value;
1773 +                if (!inst->no_memory) {
1774 +                        switch (inst->mnemo) {
1775 +                        case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((unsigned char *)dst) = src1;  break;
1776 +                        case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((unsigned short *)dst) = src1; break;
1777 +                        case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((unsigned int *)dst) = src1;   break;
1778 +                        case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((unsigned long *)dst) = src1;  break;
1779 +                        }
1780 +                }
1781 +                inst->operands[0].value  = dst2;
1782 +                inst->operands[0].nat    = nat2;
1783 +                break;
1784 +        default:
1785 +                return false;
1786 +        }
1787 +
1788 +        for (int i = 0; i < IA64_N_OPERANDS; i++) {
1789 +                ia64_operand_t const & op = inst->operands[i];
1790 +                if (!op.commit)
1791 +                        continue;
1792 +                if (op.index == -1)
1793 +                        return false; // XXX: internal error
1794 +                IA64_SET_GR(op.index, op.value);
1795 +                IA64_SET_NAT(op.index, op.nat);
1796 +        }
1797 +        return true;
1798 + }
1799 +
1800 + static bool ia64_emulate_instruction(unsigned long raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT)
1801 + {
1802 +        ia64_instruction_t inst;
1803 +        memset(&inst, 0, sizeof(inst));
1804 +        inst.inst = raw_inst;
1805 +        if (!ia64_decode_instruction(&inst, IA64_CONTEXT))
1806 +                return false;
1807 +        return ia64_emulate_instruction(&inst, IA64_CONTEXT);
1808 + }
1809 +
1810 + static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT)
1811 + {
1812 +        unsigned long ip = IA64_GET_IP();
1813 + #if DEBUG
1814 +        printf("IP: 0x%016lx\n", ip);
1815 + #if 0
1816 +        printf(" Template 0x%02x\n", ia64_get_template(ip));
1817 +        ia64_get_instruction(ip, 0);
1818 +        ia64_get_instruction(ip, 1);
1819 +        ia64_get_instruction(ip, 2);
1820 + #endif
1821 + #endif
1822 +
1823 +        // Select which decode switch to use
1824 +        ia64_instruction_t inst;
1825 +        inst.inst = ia64_get_instruction(ip, ip & 3);
1826 +        if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) {
1827 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1828 +                return false;
1829 +        }
1830 +
1831 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1832 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
1833 +
1834 +        switch (inst.mnemo) {
1835 +        case IA64_INST_LD1:
1836 +        case IA64_INST_LD2:
1837 +        case IA64_INST_LD4:
1838 +        case IA64_INST_LD8:
1839 +        case IA64_INST_LD1_UPDATE:
1840 +        case IA64_INST_LD2_UPDATE:
1841 +        case IA64_INST_LD4_UPDATE:
1842 +        case IA64_INST_LD8_UPDATE:
1843 +                transfer_type = SIGSEGV_TRANSFER_LOAD;
1844 +                break;
1845 +        case IA64_INST_ST1:
1846 +        case IA64_INST_ST2:
1847 +        case IA64_INST_ST4:
1848 +        case IA64_INST_ST8:
1849 +        case IA64_INST_ST1_UPDATE:
1850 +        case IA64_INST_ST2_UPDATE:
1851 +        case IA64_INST_ST4_UPDATE:
1852 +        case IA64_INST_ST8_UPDATE:
1853 +                transfer_type = SIGSEGV_TRANSFER_STORE;
1854 +                break;
1855 +        }
1856 +
1857 +        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1858 +                // Unknown machine code, let it crash. Then patch the decoder
1859 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1860 +                return false;
1861 +        }
1862 +
1863 +        switch (inst.mnemo) {
1864 +        case IA64_INST_LD1:
1865 +        case IA64_INST_LD1_UPDATE:
1866 +        case IA64_INST_ST1:
1867 +        case IA64_INST_ST1_UPDATE:
1868 +                transfer_size = SIZE_BYTE;
1869 +                break;
1870 +        case IA64_INST_LD2:
1871 +        case IA64_INST_LD2_UPDATE:
1872 +        case IA64_INST_ST2:
1873 +        case IA64_INST_ST2_UPDATE:
1874 +                transfer_size = SIZE_WORD;
1875 +                break;
1876 +        case IA64_INST_LD4:
1877 +        case IA64_INST_LD4_UPDATE:
1878 +        case IA64_INST_ST4:
1879 +        case IA64_INST_ST4_UPDATE:
1880 +                transfer_size = SIZE_LONG;
1881 +                break;
1882 +        case IA64_INST_LD8:
1883 +        case IA64_INST_LD8_UPDATE:
1884 +        case IA64_INST_ST8:
1885 +        case IA64_INST_ST8_UPDATE:
1886 +                transfer_size = SIZE_QUAD;
1887 +                break;
1888 +        }
1889 +
1890 +        if (transfer_size == SIZE_UNKNOWN) {
1891 +                // Unknown machine code, let it crash. Then patch the decoder
1892 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
1893 +                return false;
1894 +        }
1895 +
1896 +        inst.no_memory = true;
1897 +        if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) {
1898 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
1899 +                return false;
1900 +        }
1901 +
1902 +        int slot = ip & 3;
1903 +        bool emulate_next = false;
1904 +        switch (slot) {
1905 +        case 0:
1906 +                switch (ia64_get_template(ip)) {
1907 +                case 0x2: // MI;I
1908 +                case 0x3: // MI;I;
1909 +                        emulate_next = true;
1910 +                        slot = 2;
1911 +                        break;
1912 +                case 0xa: // M;MI
1913 +                case 0xb: // M;MI;
1914 +                        emulate_next = true;
1915 +                        slot = 1;
1916 +                        break;
1917 +                }
1918 +                break;
1919 +        }
1920 +        if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) {
1921 +                while (slot < 3) {
1922 +                        if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) {
1923 +                                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
1924 +                                return false;
1925 +                        }
1926 +                        ++slot;
1927 +                }
1928 +        }
1929 +
1930 + #if IA64_CAN_PATCH_IP_SLOT
1931 +        if ((slot = ip & 3) < 2)
1932 +                IA64_SET_IP((ip & ~3ul) + (slot + 1));
1933 +        else
1934 + #endif
1935 +                IA64_SET_IP((ip & ~3ul) + 16);
1936 + #if DEBUG
1937 +        printf("IP: 0x%016lx\n", IA64_GET_IP());
1938 + #endif
1939 +        return true;
1940 + }
1941 + #endif
1942 +
1943   // Decode and skip PPC instruction
1944 < #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1944 > #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1945   static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1946   {
1947          instruction_t instr;
# Line 1097 | Line 1977 | static bool powerpc_skip_instruction(uns
1977  
1978   // Decode and skip MIPS instruction
1979   #if (defined(mips) || defined(__mips))
1980 < enum {
1101 < #if (defined(sgi) || defined(__sgi))
1102 <  MIPS_REG_EPC = 35,
1103 < #endif
1104 < };
1105 < static bool mips_skip_instruction(greg_t * regs)
1980 > static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1981   {
1982 <  unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1982 >  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1983  
1984    if (epc == 0)
1985          return false;
# Line 1253 | Line 2128 | static bool mips_skip_instruction(greg_t
2128                   mips_gpr_names[reg]);
2129   #endif
2130  
2131 <  regs[MIPS_REG_EPC] += 4;
2131 >  *pc_p += 4;
2132    return true;
2133   }
2134   #endif
# Line 1265 | Line 2140 | enum {
2140    SPARC_REG_G1 = REG_G1,
2141    SPARC_REG_O0 = REG_O0,
2142    SPARC_REG_PC = REG_PC,
2143 +  SPARC_REG_nPC = REG_nPC
2144   #endif
2145   };
2146   static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
# Line 1328 | Line 2204 | static bool sparc_skip_instruction(unsig
2204          break;
2205    case 7: // Store Doubleword
2206          transfer_type = SIGSEGV_TRANSFER_STORE;
2207 <        transfer_size = SIZE_WORD;
2207 >        transfer_size = SIZE_LONG;
2208          register_pair = true;
2209          break;
2210    }
# Line 1338 | Line 2214 | static bool sparc_skip_instruction(unsig
2214          return false;
2215    }
2216  
1341  // Zero target register in case of a load operation
2217    const int reg = (opcode >> 25) & 0x1f;
2218 +
2219 + #if DEBUG
2220 +  static const char * reg_names[] = {
2221 +        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2222 +        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2223 +        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2224 +        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2225 +  };
2226 +  printf("%s %s register %s\n",
2227 +                 transfer_size == SIZE_BYTE ? "byte" :
2228 +                 transfer_size == SIZE_WORD ? "word" :
2229 +                 transfer_size == SIZE_LONG ? "long" :
2230 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2231 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2232 +                 reg_names[reg]);
2233 + #endif
2234 +
2235 +  // Zero target register in case of a load operation
2236    if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2237          // FIXME: code to handle local & input registers is not tested
2238 <        if (reg >= 1 && reg <= 7) {
2238 >        if (reg >= 1 && reg < 8) {
2239            // global registers
2240            regs[reg - 1 + SPARC_REG_G1] = 0;
2241          }
2242 <        else if (reg >= 8 && reg <= 15) {
2242 >        else if (reg >= 8 && reg < 16) {
2243            // output registers
2244            regs[reg - 8 + SPARC_REG_O0] = 0;
2245          }
2246 <        else if (reg >= 16 && reg <= 23) {
2246 >        else if (reg >= 16 && reg < 24) {
2247            // local registers (in register windows)
2248            if (gwins)
2249                  gwins->wbuf->rw_local[reg - 16] = 0;
# Line 1366 | Line 2259 | static bool sparc_skip_instruction(unsig
2259          }
2260    }
2261  
1369 #if DEBUG
1370  static const char * reg_names[] = {
1371        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1372        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1373        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1374        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1375  };
1376  printf("%s %s register %s\n",
1377                 transfer_size == SIZE_BYTE ? "byte" :
1378                 transfer_size == SIZE_WORD ? "word" :
1379                 transfer_size == SIZE_LONG ? "long" :
1380                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1381                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1382                 reg_names[reg]);
1383 #endif
1384
2262    regs[SPARC_REG_PC] += 4;
2263 +  regs[SPARC_REG_nPC] += 4;
2264    return true;
2265   }
2266   #endif
# Line 1538 | Line 2416 | static bool arm_skip_instruction(unsigne
2416  
2417  
2418   // Fallbacks
2419 + #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2420 + #define SIGSEGV_FAULT_ADDRESS_FAST              SIGSEGV_FAULT_ADDRESS
2421 + #endif
2422 + #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2423 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_FAULT_INSTRUCTION
2424 + #endif
2425   #ifndef SIGSEGV_FAULT_INSTRUCTION
2426 < #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
2426 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_ADDRESS
2427   #endif
2428   #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2429   #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2430   #endif
2431   #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2432 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  sigsegv_fault_handler(ADDR, IP)
2432 > #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2433   #endif
2434  
2435   // SIGSEGV recovery supported ?
# Line 1558 | Line 2442 | static bool arm_skip_instruction(unsigne
2442   *  SIGSEGV global handler
2443   */
2444  
2445 + struct sigsegv_info_t {
2446 +        sigsegv_address_t addr;
2447 +        sigsegv_address_t pc;
2448 + #ifdef HAVE_MACH_EXCEPTIONS
2449 +        mach_port_t thread;
2450 +        bool has_exc_state;
2451 +        SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2452 +        mach_msg_type_number_t exc_state_count;
2453 +        bool has_thr_state;
2454 +        SIGSEGV_THREAD_STATE_TYPE thr_state;
2455 +        mach_msg_type_number_t thr_state_count;
2456 + #endif
2457 + };
2458 +
2459 + #ifdef HAVE_MACH_EXCEPTIONS
2460 + static void mach_get_exception_state(sigsegv_info_t *SIP)
2461 + {
2462 +        SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2463 +        kern_return_t krc = thread_get_state(SIP->thread,
2464 +                                                                                 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2465 +                                                                                 (natural_t *)&SIP->exc_state,
2466 +                                                                                 &SIP->exc_state_count);
2467 +        MACH_CHECK_ERROR(thread_get_state, krc);
2468 +        SIP->has_exc_state = true;
2469 + }
2470 +
2471 + static void mach_get_thread_state(sigsegv_info_t *SIP)
2472 + {
2473 +        SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2474 +        kern_return_t krc = thread_get_state(SIP->thread,
2475 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2476 +                                                                                 (natural_t *)&SIP->thr_state,
2477 +                                                                                 &SIP->thr_state_count);
2478 +        MACH_CHECK_ERROR(thread_get_state, krc);
2479 +        SIP->has_thr_state = true;
2480 + }
2481 +
2482 + static void mach_set_thread_state(sigsegv_info_t *SIP)
2483 + {
2484 +        kern_return_t krc = thread_set_state(SIP->thread,
2485 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2486 +                                                                                 (natural_t *)&SIP->thr_state,
2487 +                                                                                 SIP->thr_state_count);
2488 +        MACH_CHECK_ERROR(thread_set_state, krc);
2489 + }
2490 + #endif
2491 +
2492 + // Return the address of the invalid memory reference
2493 + sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2494 + {
2495 + #ifdef HAVE_MACH_EXCEPTIONS
2496 +        static int use_fast_path = -1;
2497 +        if (use_fast_path != 1 && !SIP->has_exc_state) {
2498 +                mach_get_exception_state(SIP);
2499 +
2500 +                sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2501 +                if (use_fast_path < 0) {
2502 +                        const char *machfault = getenv("SIGSEGV_MACH_FAULT");
2503 +                        if (machfault) {
2504 +                                if (strcmp(machfault, "fast") == 0)
2505 +                                        use_fast_path = 1;
2506 +                                else if (strcmp(machfault, "slow") == 0)
2507 +                                        use_fast_path = 0;
2508 +                        }
2509 +                        if (use_fast_path < 0)
2510 +                                use_fast_path = addr == SIP->addr;
2511 +                }
2512 +                SIP->addr = addr;
2513 +        }
2514 + #endif
2515 +        return SIP->addr;
2516 + }
2517 +
2518 + // Return the address of the instruction that caused the fault, or
2519 + // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2520 + sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2521 + {
2522 + #ifdef HAVE_MACH_EXCEPTIONS
2523 +        if (!SIP->has_thr_state) {
2524 +                mach_get_thread_state(SIP);
2525 +
2526 +                SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2527 +        }
2528 + #endif
2529 +        return SIP->pc;
2530 + }
2531 +
2532   // This function handles the badaccess to memory.
2533   // It is called from the signal handler or the exception handler.
2534   static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2535   {
2536 <        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2537 <        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2538 <        
2536 >        sigsegv_info_t SI;
2537 >        SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2538 >        SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2539 > #ifdef HAVE_MACH_EXCEPTIONS
2540 >        SI.thread = thread;
2541 >        SI.has_exc_state = false;
2542 >        SI.has_thr_state = false;
2543 > #endif
2544 >        sigsegv_info_t * const SIP = &SI;
2545 >
2546          // Call user's handler and reinstall the global handler, if required
2547 <        switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
2547 >        switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2548          case SIGSEGV_RETURN_SUCCESS:
2549                  return true;
2550  
# Line 1574 | Line 2552 | static bool handle_badaccess(SIGSEGV_FAU
2552          case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2553                  // Call the instruction skipper with the register file
2554                  // available
2555 + #ifdef HAVE_MACH_EXCEPTIONS
2556 +                if (!SIP->has_thr_state)
2557 +                        mach_get_thread_state(SIP);
2558 + #endif
2559                  if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2560   #ifdef HAVE_MACH_EXCEPTIONS
2561                          // Unlike UNIX signals where the thread state
2562                          // is modified off of the stack, in Mach we
2563                          // need to actually call thread_set_state to
2564                          // have the register values updated.
2565 <                        kern_return_t krc;
1584 <
1585 <                        krc = thread_set_state(thread,
1586 <                                                                   MACHINE_THREAD_STATE, (thread_state_t)state,
1587 <                                                                   MACHINE_THREAD_STATE_COUNT);
1588 <                        MACH_CHECK_ERROR (thread_get_state, krc);
2565 >                        mach_set_thread_state(SIP);
2566   #endif
2567                          return true;
2568                  }
# Line 1594 | Line 2571 | static bool handle_badaccess(SIGSEGV_FAU
2571          case SIGSEGV_RETURN_FAILURE:
2572                  // We can't do anything with the fault_address, dump state?
2573                  if (sigsegv_state_dumper != 0)
2574 <                        sigsegv_state_dumper(fault_address, fault_instruction);
2574 >                        sigsegv_state_dumper(SIP);
2575                  break;
2576          }
2577  
# Line 1636 | Line 2613 | forward_exception(mach_port_t thread_por
2613          mach_port_t port;
2614          exception_behavior_t behavior;
2615          thread_state_flavor_t flavor;
2616 <        thread_state_t thread_state;
2616 >        thread_state_data_t thread_state;
2617          mach_msg_type_number_t thread_state_count;
2618  
2619          for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
# Line 1655 | Line 2632 | forward_exception(mach_port_t thread_por
2632          behavior = oldExceptionPorts->behaviors[portIndex];
2633          flavor = oldExceptionPorts->flavors[portIndex];
2634  
2635 +        if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2636 +                fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2637 +                return KERN_FAILURE;
2638 +        }
2639 +
2640          /*
2641           fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2642           */
2643  
2644          if (behavior != EXCEPTION_DEFAULT) {
2645                  thread_state_count = THREAD_STATE_MAX;
2646 <                kret = thread_get_state (thread_port, flavor, thread_state,
2646 >                kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2647                                                                   &thread_state_count);
2648                  MACH_CHECK_ERROR (thread_get_state, kret);
2649          }
# Line 1677 | Line 2659 | forward_exception(mach_port_t thread_por
2659            // fprintf(stderr, "forwarding to exception_raise_state\n");
2660            kret = exception_raise_state(port, exception_type, exception_data,
2661                                                                     data_count, &flavor,
2662 <                                                                   thread_state, thread_state_count,
2663 <                                                                   thread_state, &thread_state_count);
2662 >                                                                   (natural_t *)&thread_state, thread_state_count,
2663 >                                                                   (natural_t *)&thread_state, &thread_state_count);
2664            MACH_CHECK_ERROR (exception_raise_state, kret);
2665            break;
2666          case EXCEPTION_STATE_IDENTITY:
# Line 1686 | Line 2668 | forward_exception(mach_port_t thread_por
2668            kret = exception_raise_state_identity(port, thread_port, task_port,
2669                                                                                          exception_type, exception_data,
2670                                                                                          data_count, &flavor,
2671 <                                                                                        thread_state, thread_state_count,
2672 <                                                                                        thread_state, &thread_state_count);
2671 >                                                                                        (natural_t *)&thread_state, thread_state_count,
2672 >                                                                                        (natural_t *)&thread_state, &thread_state_count);
2673            MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2674            break;
2675          default:
2676            fprintf(stderr, "forward_exception got unknown behavior\n");
2677 +          kret = KERN_FAILURE;
2678            break;
2679          }
2680  
2681          if (behavior != EXCEPTION_DEFAULT) {
2682 <                kret = thread_set_state (thread_port, flavor, thread_state,
2682 >                kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2683                                                                   thread_state_count);
2684                  MACH_CHECK_ERROR (thread_set_state, kret);
2685          }
2686  
2687 <        return KERN_SUCCESS;
2687 >        return kret;
2688   }
2689  
2690   /*
# Line 1729 | Line 2712 | catch_exception_raise(mach_port_t except
2712                                            mach_port_t task,
2713                                            exception_type_t exception,
2714                                            exception_data_t code,
2715 <                                          mach_msg_type_number_t codeCount)
2715 >                                          mach_msg_type_number_t code_count)
2716   {
1734        ppc_thread_state_t state;
2717          kern_return_t krc;
2718  
2719 <        if ((exception == EXC_BAD_ACCESS)  && (codeCount >= 2)) {
2720 <                if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2721 <                        return KERN_SUCCESS;
2719 >        if (exception == EXC_BAD_ACCESS) {
2720 >                switch (code[0]) {
2721 >                case KERN_PROTECTION_FAILURE:
2722 >                case KERN_INVALID_ADDRESS:
2723 >                        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2724 >                                return KERN_SUCCESS;
2725 >                        break;
2726 >                }
2727          }
2728  
2729          // In Mach we do not need to remove the exception handler.
2730          // If we forward the exception, eventually some exception handler
2731          // will take care of this exception.
2732 <        krc = forward_exception(thread, task, exception, code, codeCount, &ports);
2732 >        krc = forward_exception(thread, task, exception, code, code_count, &ports);
2733  
2734          return krc;
2735   }
# Line 1870 | Line 2857 | static bool sigsegv_do_install_handler(s
2857          // addressing modes) used in PPC instructions, you will need the
2858          // GPR state anyway.
2859          krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2860 <                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
2860 >                                EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2861          if (krc != KERN_SUCCESS) {
2862                  mach_error("thread_set_exception_ports", krc);
2863                  return false;
# Line 2050 | Line 3037 | void sigsegv_set_dump_state(sigsegv_stat
3037   const int REF_INDEX = 123;
3038   const int REF_VALUE = 45;
3039  
3040 < static int page_size;
3040 > static sigsegv_uintptr_t page_size;
3041   static volatile char * page = 0;
3042   static volatile int handler_called = 0;
3043  
3044 + /* Barriers */
3045 + #ifdef __GNUC__
3046 + #define BARRIER() asm volatile ("" : : : "memory")
3047 + #else
3048 + #define BARRIER() /* nothing */
3049 + #endif
3050 +
3051   #ifdef __GNUC__
3052   // Code range where we expect the fault to come from
3053   static void *b_region, *e_region;
3054   #endif
3055  
3056 < static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
3056 > static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
3057   {
3058 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3059 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3060   #if DEBUG
3061          printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
3062          printf("expected fault at %p\n", page + REF_INDEX);
# Line 2074 | Line 3070 | static sigsegv_return_t sigsegv_test_han
3070   #ifdef __GNUC__
3071          // Make sure reported fault instruction address falls into
3072          // expected code range
3073 <        if (instruction_address != SIGSEGV_INVALID_PC
3073 >        if (instruction_address != SIGSEGV_INVALID_ADDRESS
3074                  && ((instruction_address <  (sigsegv_address_t)b_region) ||
3075                          (instruction_address >= (sigsegv_address_t)e_region)))
3076                  exit(11);
3077   #endif
3078 <        if (vm_protect((char *)((unsigned long)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3078 >        if (vm_protect((char *)((sigsegv_uintptr_t)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0)
3079                  exit(12);
3080          return SIGSEGV_RETURN_SUCCESS;
3081   }
3082  
3083   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3084 < static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
3084 > static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3085   {
3086 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3087 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3088   #if DEBUG
3089          printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3090   #endif
3091 <        if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
3091 >        if (((sigsegv_uintptr_t)fault_address - (sigsegv_uintptr_t)page) < page_size) {
3092   #ifdef __GNUC__
3093                  // Make sure reported fault instruction address falls into
3094                  // expected code range
3095 <                if (instruction_address != SIGSEGV_INVALID_PC
3095 >                if (instruction_address != SIGSEGV_INVALID_ADDRESS
3096                          && ((instruction_address <  (sigsegv_address_t)b_region) ||
3097                                  (instruction_address >= (sigsegv_address_t)e_region)))
3098                          return SIGSEGV_RETURN_FAILURE;
# Line 2108 | Line 3106 | static sigsegv_return_t sigsegv_insn_han
3106   // More sophisticated tests for instruction skipper
3107   static bool arch_insn_skipper_tests()
3108   {
3109 < #if (defined(i386) || defined(__i386__)) || defined(__x86_64__)
3109 > #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64))
3110          static const unsigned char code[] = {
3111                  0x8a, 0x00,                    // mov    (%eax),%al
3112                  0x8a, 0x2c, 0x18,              // mov    (%eax,%ebx,1),%ch
# Line 2122 | Line 3120 | static bool arch_insn_skipper_tests()
3120                  0x8b, 0x0c, 0x18,              // mov    (%eax,%ebx,1),%ecx
3121                  0x89, 0x00,                    // mov    %eax,(%eax)
3122                  0x89, 0x0c, 0x18,              // mov    %ecx,(%eax,%ebx,1)
3123 < #if defined(__x86_64__)
3123 > #if defined(__x86_64__) || defined(_M_X64)
3124                  0x44, 0x8a, 0x00,              // mov    (%rax),%r8b
3125                  0x44, 0x8a, 0x20,              // mov    (%rax),%r12b
3126                  0x42, 0x8a, 0x3c, 0x10,        // mov    (%rax,%r10,1),%dil
# Line 2145 | Line 3143 | static bool arch_insn_skipper_tests()
3143                  0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
3144                  0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
3145                  0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
3146 +                0x63, 0x47, 0x04,              // movslq 4(%rdi),%eax
3147 +                0x48, 0x63, 0x47, 0x04,        // movslq 4(%rdi),%rax
3148   #endif
3149                  0                              // end
3150          };
3151          const int N_REGS = 20;
3152 <        unsigned long regs[N_REGS];
3152 >        SIGSEGV_REGISTER_TYPE regs[N_REGS];
3153          for (int i = 0; i < N_REGS; i++)
3154                  regs[i] = i;
3155 <        const unsigned long start_code = (unsigned long)&code;
3155 >        const sigsegv_uintptr_t start_code = (sigsegv_uintptr_t)&code;
3156          regs[X86_REG_EIP] = start_code;
3157          while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1)
3158                     && ix86_skip_instruction(regs))
# Line 2178 | Line 3178 | int main(void)
3178          
3179          if (!sigsegv_install_handler(sigsegv_test_handler))
3180                  return 4;
3181 <        
3181 >
3182   #ifdef __GNUC__
3183          b_region = &&L_b_region1;
3184          e_region = &&L_e_region1;
3185   #endif
3186 < L_b_region1:
3187 <        page[REF_INDEX] = REF_VALUE;
3188 <        if (page[REF_INDEX] != REF_VALUE)
3189 <          exit(20);
3190 <        page[REF_INDEX] = REF_VALUE;
3191 < L_e_region1:
3186 >        /* This is a really awful hack but otherwise gcc is smart enough
3187 >         * (or bug'ous enough?) to optimize the labels and place them
3188 >         * e.g. at the "main" entry point, which is wrong.
3189 >         */
3190 >        volatile int label_hack = 1;
3191 >        switch (label_hack) {
3192 >        case 1:
3193 >        L_b_region1:
3194 >                page[REF_INDEX] = REF_VALUE;
3195 >                if (page[REF_INDEX] != REF_VALUE)
3196 >                        exit(20);
3197 >                page[REF_INDEX] = REF_VALUE;
3198 >                BARRIER();
3199 >                // fall-through
3200 >        case 2:
3201 >        L_e_region1:
3202 >                BARRIER();
3203 >                break;
3204 >        }
3205  
3206          if (handler_called != 1)
3207                  return 5;
# Line 2219 | Line 3232 | int main(void)
3232          b_region = &&L_b_region2;
3233          e_region = &&L_e_region2;
3234   #endif
3235 < L_b_region2:
3236 <        TEST_SKIP_INSTRUCTION(unsigned char);
3237 <        TEST_SKIP_INSTRUCTION(unsigned short);
3238 <        TEST_SKIP_INSTRUCTION(unsigned int);
3239 <        TEST_SKIP_INSTRUCTION(unsigned long);
3240 <        TEST_SKIP_INSTRUCTION(signed char);
3241 <        TEST_SKIP_INSTRUCTION(signed short);
3242 <        TEST_SKIP_INSTRUCTION(signed int);
3243 <        TEST_SKIP_INSTRUCTION(signed long);
3244 < L_e_region2:
3245 <
3235 >        switch (label_hack) {
3236 >        case 1:
3237 >        L_b_region2:
3238 >                TEST_SKIP_INSTRUCTION(unsigned char);
3239 >                TEST_SKIP_INSTRUCTION(unsigned short);
3240 >                TEST_SKIP_INSTRUCTION(unsigned int);
3241 >                TEST_SKIP_INSTRUCTION(unsigned long);
3242 >                TEST_SKIP_INSTRUCTION(signed char);
3243 >                TEST_SKIP_INSTRUCTION(signed short);
3244 >                TEST_SKIP_INSTRUCTION(signed int);
3245 >                TEST_SKIP_INSTRUCTION(signed long);
3246 >                BARRIER();
3247 >                // fall-through
3248 >        case 2:
3249 >        L_e_region2:
3250 >                BARRIER();
3251 >                break;
3252 >        }
3253          if (!arch_insn_skipper_tests())
3254                  return 20;
3255   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines