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.76 by gbeauche, 2008-01-06T16:36:00Z

# 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 66 | Line 66 | static bool sigsegv_do_install_handler(i
66   *  Instruction decoding aids
67   */
68  
69 + // Transfer type
70 + enum transfer_type_t {
71 +        SIGSEGV_TRANSFER_UNKNOWN        = 0,
72 +        SIGSEGV_TRANSFER_LOAD           = 1,
73 +        SIGSEGV_TRANSFER_STORE          = 2
74 + };
75 +
76   // Transfer size
77   enum transfer_size_t {
78          SIZE_UNKNOWN,
79          SIZE_BYTE,
80          SIZE_WORD, // 2 bytes
81          SIZE_LONG, // 4 bytes
82 <        SIZE_QUAD, // 8 bytes
82 >        SIZE_QUAD  // 8 bytes
83   };
84  
85 < // Transfer type
79 < typedef sigsegv_transfer_type_t transfer_type_t;
80 <
81 < #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
85 > #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
86   // Addressing mode
87   enum addressing_mode_t {
88          MODE_UNKNOWN,
# Line 240 | Line 244 | static void powerpc_decode_instruction(i
244   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
245   #define SIGSEGV_FAULT_INSTRUCTION               (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC]
246   #if (defined(mips) || defined(__mips))
247 < #define SIGSEGV_REGISTER_FILE                   SIGSEGV_CONTEXT_REGS
247 > #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0]
248   #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
249   #endif
250   #endif
# Line 256 | Line 260 | static void powerpc_decode_instruction(i
260   #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW
261   #define SIGSEGV_SKIP_INSTRUCTION                sparc_skip_instruction
262   #endif
263 + #if defined(__i386__)
264 + #include <sys/regset.h>
265 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.gregs)
266 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[EIP]
267 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
268 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
269 + #endif
270   #endif
271 < #if defined(__FreeBSD__)
271 > #if defined(__FreeBSD__) || defined(__OpenBSD__)
272   #if (defined(i386) || defined(__i386__))
273   #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_eip)
274   #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */
# Line 272 | Line 283 | static void powerpc_decode_instruction(i
283   #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
284   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
285   #endif
286 + #if (defined(powerpc) || defined(__powerpc__))
287 + #include <sys/ucontext.h>
288 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.__gregs)
289 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[_REG_PC]
290 + #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0]
291 + #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
292 + #endif
293   #endif
294   #if defined(__linux__)
295   #if (defined(i386) || defined(__i386__))
# Line 289 | Line 307 | static void powerpc_decode_instruction(i
307   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
308   #endif
309   #if (defined(ia64) || defined(__ia64__))
310 < #define SIGSEGV_FAULT_INSTRUCTION               (((struct sigcontext *)scp)->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
310 > #define SIGSEGV_CONTEXT_REGS                    ((struct sigcontext *)scp)
311 > #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */
312 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)SIGSEGV_CONTEXT_REGS
313 > #define SIGSEGV_SKIP_INSTRUCTION                ia64_skip_instruction
314   #endif
315   #if (defined(powerpc) || defined(__powerpc__))
316   #include <sys/ucontext.h>
# Line 309 | Line 330 | static void powerpc_decode_instruction(i
330   #define SIGSEGV_REGISTER_FILE                   (&SIGSEGV_CONTEXT_REGS.arm_r0)
331   #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
332   #endif
333 + #if (defined(mips) || defined(__mips__))
334 + #include <sys/ucontext.h>
335 + #define SIGSEGV_CONTEXT_REGS                    (((struct ucontext *)scp)->uc_mcontext)
336 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS.pc)
337 + #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
338 + #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
339 + #endif
340   #endif
341   #endif
342  
# Line 576 | Line 604 | if (ret != KERN_SUCCESS) { \
604          exit (1); \
605   }
606  
607 < #define SIGSEGV_FAULT_ADDRESS                   code[1]
608 < #define SIGSEGV_FAULT_INSTRUCTION               get_fault_instruction(thread, state)
609 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
610 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
611 < #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
607 > #ifdef __ppc__
608 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state_t
609 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE
610 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE_COUNT
611 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.dar
612 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state_t
613 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE
614 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE_COUNT
615 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.srr0
616   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
617 < #define SIGSEGV_REGISTER_FILE                   &state->srr0, &state->r0
618 <
619 < // Given a suspended thread, stuff the current instruction and
620 < // registers into state.
621 < //
622 < // It would have been nice to have this be ppc/x86 independant which
623 < // could have been done easily with a thread_state_t instead of
624 < // ppc_thread_state_t, but because of the way this is called it is
625 < // easier to do it this way.
626 < #if (defined(ppc) || defined(__ppc__))
627 < static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
628 < {
629 <        kern_return_t krc;
598 <        mach_msg_type_number_t count;
599 <
600 <        count = MACHINE_THREAD_STATE_COUNT;
601 <        krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
602 <        MACH_CHECK_ERROR (thread_get_state, krc);
603 <
604 <        return (sigsegv_address_t)state->srr0;
605 < }
617 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.srr0, (unsigned long *)&SIP->thr_state.r0
618 > #endif
619 > #ifdef __ppc64__
620 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state64_t
621 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE64
622 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE64_COUNT
623 > #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.dar
624 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state64_t
625 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE64
626 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE64_COUNT
627 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.srr0
628 > #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
629 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIP->thr_state.srr0, (unsigned long *)&SIP->thr_state.r0
630   #endif
631 + #ifdef __i386__
632 + #define SIGSEGV_EXCEPTION_STATE_TYPE    struct i386_exception_state
633 + #define SIGSEGV_EXCEPTION_STATE_FLAVOR  i386_EXCEPTION_STATE
634 + #define SIGSEGV_EXCEPTION_STATE_COUNT   i386_EXCEPTION_STATE_COUNT
635 + #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.faultvaddr
636 + #define SIGSEGV_THREAD_STATE_TYPE               struct i386_thread_state
637 + #define SIGSEGV_THREAD_STATE_FLAVOR             i386_THREAD_STATE
638 + #define SIGSEGV_THREAD_STATE_COUNT              i386_THREAD_STATE_COUNT
639 + #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.eip
640 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
641 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&SIP->thr_state.eax) /* EAX is the first GPR we consider */
642 + #endif
643 + #ifdef __x86_64__
644 + #define SIGSEGV_EXCEPTION_STATE_TYPE    struct x86_exception_state64
645 + #define SIGSEGV_EXCEPTION_STATE_FLAVOR  x86_EXCEPTION_STATE64
646 + #define SIGSEGV_EXCEPTION_STATE_COUNT   x86_EXCEPTION_STATE64_COUNT
647 + #define SIGSEGV_FAULT_ADDRESS                   SIP->exc_state.faultvaddr
648 + #define SIGSEGV_THREAD_STATE_TYPE               struct x86_thread_state64
649 + #define SIGSEGV_THREAD_STATE_FLAVOR             x86_THREAD_STATE64
650 + #define SIGSEGV_THREAD_STATE_COUNT              x86_THREAD_STATE64_COUNT
651 + #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.rip
652 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
653 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&SIP->thr_state.rax) /* RAX is the first GPR we consider */
654 + #endif
655 + #define SIGSEGV_FAULT_ADDRESS_FAST              code[1]
656 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_INVALID_ADDRESS
657 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code
658 + #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code
659  
660   // Since there can only be one exception thread running at any time
661   // this is not a problem.
# Line 723 | Line 775 | enum {
775   #endif
776   };
777   #endif
778 + #if defined(__OpenBSD__)
779 + enum {
780 + #if defined(__i386__)
781 +        // EDI is the first register we consider
782 + #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
783 + #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
784 +        X86_REG_EIP = DREG(eip), // 7
785 +        X86_REG_EAX = DREG(eax), // 6
786 +        X86_REG_ECX = DREG(ecx), // 5
787 +        X86_REG_EDX = DREG(edx), // 4
788 +        X86_REG_EBX = DREG(ebx), // 3
789 +        X86_REG_ESP = DREG(esp), // 10
790 +        X86_REG_EBP = DREG(ebp), // 2
791 +        X86_REG_ESI = DREG(esi), // 1
792 +        X86_REG_EDI = DREG(edi)  // 0
793 + #undef DREG
794 + #undef OREG
795 + #endif
796 + };
797 + #endif
798 + #if defined(__sun__)
799 + // Same as for Linux, need to check for x86-64
800 + enum {
801 + #if defined(__i386__)
802 +        X86_REG_EIP = EIP,
803 +        X86_REG_EAX = EAX,
804 +        X86_REG_ECX = ECX,
805 +        X86_REG_EDX = EDX,
806 +        X86_REG_EBX = EBX,
807 +        X86_REG_ESP = ESP,
808 +        X86_REG_EBP = EBP,
809 +        X86_REG_ESI = ESI,
810 +        X86_REG_EDI = EDI
811 + #endif
812 + };
813 + #endif
814 + #if defined(__APPLE__) && defined(__MACH__)
815 + enum {
816 + #if (defined(i386) || defined(__i386__))
817 + #ifdef i386_SAVED_STATE
818 +        // same as FreeBSD (in Open Darwin 8.0.1)
819 +        X86_REG_EIP = 10,
820 +        X86_REG_EAX = 7,
821 +        X86_REG_ECX = 6,
822 +        X86_REG_EDX = 5,
823 +        X86_REG_EBX = 4,
824 +        X86_REG_ESP = 13,
825 +        X86_REG_EBP = 2,
826 +        X86_REG_ESI = 1,
827 +        X86_REG_EDI = 0
828 + #else
829 +        // new layout (MacOS X 10.4.4 for x86)
830 +        X86_REG_EIP = 10,
831 +        X86_REG_EAX = 0,
832 +        X86_REG_ECX = 2,
833 +        X86_REG_EDX = 3,
834 +        X86_REG_EBX = 1,
835 +        X86_REG_ESP = 7,
836 +        X86_REG_EBP = 6,
837 +        X86_REG_ESI = 5,
838 +        X86_REG_EDI = 4
839 + #endif
840 + #endif
841 + #if defined(__x86_64__)
842 +        X86_REG_R8  = 8,
843 +        X86_REG_R9  = 9,
844 +        X86_REG_R10 = 10,
845 +        X86_REG_R11 = 11,
846 +        X86_REG_R12 = 12,
847 +        X86_REG_R13 = 13,
848 +        X86_REG_R14 = 14,
849 +        X86_REG_R15 = 15,
850 +        X86_REG_EDI = 4,
851 +        X86_REG_ESI = 5,
852 +        X86_REG_EBP = 6,
853 +        X86_REG_EBX = 1,
854 +        X86_REG_EDX = 3,
855 +        X86_REG_EAX = 0,
856 +        X86_REG_ECX = 2,
857 +        X86_REG_ESP = 7,
858 +        X86_REG_EIP = 16
859 + #endif
860 + };
861 + #endif
862   #if defined(_WIN32)
863   enum {
864   #if (defined(i386) || defined(__i386__))
# Line 783 | Line 919 | static bool ix86_skip_instruction(unsign
919                  return false;
920   #endif
921          
922 +        enum instruction_type_t {
923 +                i_MOV,
924 +                i_ADD
925 +        };
926 +
927          transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
928          transfer_size_t transfer_size = SIZE_LONG;
929 +        instruction_type_t instruction_type = i_MOV;
930          
931          int reg = -1;
932          int len = 0;
# Line 835 | Line 977 | static bool ix86_skip_instruction(unsign
977   #endif
978  
979          // Decode instruction
980 +        int op_len = 1;
981          int target_size = SIZE_UNKNOWN;
982          switch (eip[0]) {
983          case 0x0f:
# Line 849 | Line 992 | static bool ix86_skip_instruction(unsign
992                          transfer_size = SIZE_WORD;
993                          goto do_mov_extend;
994                    do_mov_extend:
995 <                        switch (eip[2] & 0xc0) {
996 <                        case 0x80:
997 <                                reg = (eip[2] >> 3) & 7;
998 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
999 <                                break;
1000 <                        case 0x40:
1001 <                                reg = (eip[2] >> 3) & 7;
1002 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1003 <                                break;
1004 <                        case 0x00:
1005 <                                reg = (eip[2] >> 3) & 7;
1006 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1007 <                                break;
1008 <                        }
1009 <                        len += 3 + ix86_step_over_modrm(eip + 2);
1010 <                        break;
1011 <            }
1012 <          break;
995 >                        op_len = 2;
996 >                        goto do_transfer_load;
997 >                }
998 >                break;
999 > #if defined(__x86_64__)
1000 >        case 0x63: // MOVSXD r64, r/m32
1001 >                if (has_rex && rex.W) {
1002 >                        transfer_size = SIZE_LONG;
1003 >                        target_size = SIZE_QUAD;
1004 >                }
1005 >                else if (transfer_size != SIZE_WORD) {
1006 >                        transfer_size = SIZE_LONG;
1007 >                        target_size = SIZE_QUAD;
1008 >                }
1009 >                goto do_transfer_load;
1010 > #endif
1011 >        case 0x02: // ADD r8, r/m8
1012 >                transfer_size = SIZE_BYTE;
1013 >        case 0x03: // ADD r32, r/m32
1014 >                instruction_type = i_ADD;
1015 >                goto do_transfer_load;
1016          case 0x8a: // MOV r8, r/m8
1017                  transfer_size = SIZE_BYTE;
1018          case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1019 <                switch (eip[1] & 0xc0) {
1019 >          do_transfer_load:
1020 >                switch (eip[op_len] & 0xc0) {
1021                  case 0x80:
1022 <                        reg = (eip[1] >> 3) & 7;
1022 >                        reg = (eip[op_len] >> 3) & 7;
1023                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1024                          break;
1025                  case 0x40:
1026 <                        reg = (eip[1] >> 3) & 7;
1026 >                        reg = (eip[op_len] >> 3) & 7;
1027                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1028                          break;
1029                  case 0x00:
1030 <                        reg = (eip[1] >> 3) & 7;
1030 >                        reg = (eip[op_len] >> 3) & 7;
1031                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1032                          break;
1033                  }
1034 <                len += 2 + ix86_step_over_modrm(eip + 1);
1034 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1035                  break;
1036 +        case 0x00: // ADD r/m8, r8
1037 +                transfer_size = SIZE_BYTE;
1038 +        case 0x01: // ADD r/m32, r32
1039 +                instruction_type = i_ADD;
1040 +                goto do_transfer_store;
1041          case 0x88: // MOV r/m8, r8
1042                  transfer_size = SIZE_BYTE;
1043          case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1044 <                switch (eip[1] & 0xc0) {
1044 >          do_transfer_store:
1045 >                switch (eip[op_len] & 0xc0) {
1046                  case 0x80:
1047 <                        reg = (eip[1] >> 3) & 7;
1047 >                        reg = (eip[op_len] >> 3) & 7;
1048                          transfer_type = SIGSEGV_TRANSFER_STORE;
1049                          break;
1050                  case 0x40:
1051 <                        reg = (eip[1] >> 3) & 7;
1051 >                        reg = (eip[op_len] >> 3) & 7;
1052                          transfer_type = SIGSEGV_TRANSFER_STORE;
1053                          break;
1054                  case 0x00:
1055 <                        reg = (eip[1] >> 3) & 7;
1055 >                        reg = (eip[op_len] >> 3) & 7;
1056                          transfer_type = SIGSEGV_TRANSFER_STORE;
1057                          break;
1058                  }
1059 <                len += 2 + ix86_step_over_modrm(eip + 1);
1059 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1060                  break;
1061          }
1062          if (target_size == SIZE_UNKNOWN)
# Line 919 | Line 1072 | static bool ix86_skip_instruction(unsign
1072                  reg += 8;
1073   #endif
1074  
1075 <        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1075 >        if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1076                  static const int x86_reg_map[] = {
1077                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1078                          X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
# Line 955 | Line 1108 | static bool ix86_skip_instruction(unsign
1108          }
1109  
1110   #if DEBUG
1111 <        printf("%08x: %s %s access", regs[X86_REG_EIP],
1111 >        printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1112                     transfer_size == SIZE_BYTE ? "byte" :
1113                     transfer_size == SIZE_WORD ? "word" :
1114                     transfer_size == SIZE_LONG ? "long" :
# Line 1010 | Line 1163 | static bool ix86_skip_instruction(unsign
1163   }
1164   #endif
1165  
1166 + // Decode and skip IA-64 instruction
1167 + #if defined(__ia64__)
1168 + #if defined(__linux__)
1169 + // XXX: we assume everything is 8-byte aligned
1170 + #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
1171 + #define IREG(REG) ((OREG(REG) - OREG(flags)) / 8)
1172 + enum {
1173 +        IA64_REG_IP  = IREG(ip),
1174 +        IA64_REG_NAT = IREG(nat),
1175 +        IA64_REG_PR  = IREG(pr),
1176 +        IA64_REG_GR  = IREG(gr)
1177 + };
1178 + #undef IREG
1179 + #undef OREG
1180 + #endif
1181 +
1182 + // Helper macros to access the machine context
1183 + #define IA64_CONTEXT                    (ctx)
1184 + #define IA64_GET_PR(P)                  ((IA64_CONTEXT[IA64_REG_PR] >> (P)) & 1)
1185 + #define IA64_GET_NAT(I)                 ((IA64_CONTEXT[IA64_REG_NAT] >> (I)) & 1)
1186 + #define IA64_SET_NAT(I,V)               (IA64_CONTEXT[IA64_REG_NAT] = (IA64_CONTEXT[IA64_REG_NAT] & ~(1ul << (I))) | (((unsigned long)!!(V)) << (I)))
1187 + #define IA64_GET_GR(R)                  (IA64_CONTEXT[IA64_REG_GR + (R)])
1188 + #define IA64_SET_GR(R,V)                (IA64_CONTEXT[IA64_REG_GR + (R)] = (V))
1189 +
1190 + // Instruction operations
1191 + enum {
1192 +        IA64_INST_UNKNOWN = 0,
1193 +        IA64_INST_LD1,                          // ld1 op0=[op1]
1194 +        IA64_INST_LD1_UPDATE,           // ld1 op0=[op1],op2
1195 +        IA64_INST_LD2,                          // ld2 op0=[op1]
1196 +        IA64_INST_LD2_UPDATE,           // ld2 op0=[op1],op2
1197 +        IA64_INST_LD4,                          // ld4 op0=[op1]
1198 +        IA64_INST_LD4_UPDATE,           // ld4 op0=[op1],op2
1199 +        IA64_INST_LD8,                          // ld8 op0=[op1]
1200 +        IA64_INST_LD8_UPDATE,           // ld8 op0=[op1],op2
1201 +        IA64_INST_ST1,                          // st1 [op0]=op1
1202 +        IA64_INST_ST1_UPDATE,           // st1 [op0]=op1,op2
1203 +        IA64_INST_ST2,                          // st2 [op0]=op1
1204 +        IA64_INST_ST2_UPDATE,           // st2 [op0]=op1,op2
1205 +        IA64_INST_ST4,                          // st4 [op0]=op1
1206 +        IA64_INST_ST4_UPDATE,           // st4 [op0]=op1,op2
1207 +        IA64_INST_ST8,                          // st8 [op0]=op1
1208 +        IA64_INST_ST8_UPDATE,           // st8 [op0]=op1,op2
1209 +        IA64_INST_ADD,                          // add op0=op1,op2,op3
1210 +        IA64_INST_SUB,                          // sub op0=op1,op2,op3
1211 +        IA64_INST_SHLADD,                       // shladd op0=op1,op3,op2
1212 +        IA64_INST_AND,                          // and op0=op1,op2
1213 +        IA64_INST_ANDCM,                        // andcm op0=op1,op2
1214 +        IA64_INST_OR,                           // or op0=op1,op2
1215 +        IA64_INST_XOR,                          // xor op0=op1,op2
1216 +        IA64_INST_SXT1,                         // sxt1 op0=op1
1217 +        IA64_INST_SXT2,                         // sxt2 op0=op1
1218 +        IA64_INST_SXT4,                         // sxt4 op0=op1
1219 +        IA64_INST_ZXT1,                         // zxt1 op0=op1
1220 +        IA64_INST_ZXT2,                         // zxt2 op0=op1
1221 +        IA64_INST_ZXT4,                         // zxt4 op0=op1
1222 +        IA64_INST_NOP                           // nop op0
1223 + };
1224 +
1225 + const int IA64_N_OPERANDS = 4;
1226 +
1227 + // Decoded operand type
1228 + struct ia64_operand_t {
1229 +        unsigned char commit;           // commit result of operation to register file?
1230 +        unsigned char valid;            // XXX: not really used, can be removed (debug)
1231 +        signed char index;                      // index of GPR, or -1 if immediate value
1232 +        unsigned char nat;                      // NaT state before operation
1233 +        unsigned long value;            // register contents or immediate value
1234 + };
1235 +
1236 + // Decoded instruction type
1237 + struct ia64_instruction_t {
1238 +        unsigned char mnemo;            // operation to perform
1239 +        unsigned char pred;                     // predicate register to check
1240 +        unsigned char no_memory;        // used to emulated main fault instruction
1241 +        unsigned long inst;                     // the raw instruction bits (41-bit wide)
1242 +        ia64_operand_t operands[IA64_N_OPERANDS];
1243 + };
1244 +
1245 + // Get immediate sign-bit
1246 + static inline int ia64_inst_get_sbit(unsigned long inst)
1247 + {
1248 +        return (inst >> 36) & 1;
1249 + }
1250 +
1251 + // Get 8-bit immediate value (A3, A8, I27, M30)
1252 + static inline unsigned long ia64_inst_get_imm8(unsigned long inst)
1253 + {
1254 +        unsigned long value = (inst >> 13) & 0x7ful;
1255 +        if (ia64_inst_get_sbit(inst))
1256 +                value |= ~0x7ful;
1257 +        return value;
1258 + }
1259 +
1260 + // Get 9-bit immediate value (M3)
1261 + static inline unsigned long ia64_inst_get_imm9b(unsigned long inst)
1262 + {
1263 +        unsigned long value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f);
1264 +        if (ia64_inst_get_sbit(inst))
1265 +                value |= ~0xfful;
1266 +        return value;
1267 + }
1268 +
1269 + // Get 9-bit immediate value (M5)
1270 + static inline unsigned long ia64_inst_get_imm9a(unsigned long inst)
1271 + {
1272 +        unsigned long value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f);
1273 +        if (ia64_inst_get_sbit(inst))
1274 +                value |= ~0xfful;
1275 +        return value;
1276 + }
1277 +
1278 + // Get 14-bit immediate value (A4)
1279 + static inline unsigned long ia64_inst_get_imm14(unsigned long inst)
1280 + {
1281 +        unsigned long value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f);
1282 +        if (ia64_inst_get_sbit(inst))
1283 +                value |= ~0x1fful;
1284 +        return value;
1285 + }
1286 +
1287 + // Get 22-bit immediate value (A5)
1288 + static inline unsigned long ia64_inst_get_imm22(unsigned long inst)
1289 + {
1290 +        unsigned long value = ((((inst >> 22) & 0x1f) << 16) |
1291 +                                                   (((inst >> 27) & 0x1ff) << 7) |
1292 +                                                   (inst & 0x7f));
1293 +        if (ia64_inst_get_sbit(inst))
1294 +                value |= ~0x1ffffful;
1295 +        return value;
1296 + }
1297 +
1298 + // Get 21-bit immediate value (I19)
1299 + static inline unsigned long ia64_inst_get_imm21(unsigned long inst)
1300 + {
1301 +        return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff);
1302 + }
1303 +
1304 + // Get 2-bit count value (A2)
1305 + static inline int ia64_inst_get_count2(unsigned long inst)
1306 + {
1307 +        return (inst >> 27) & 0x3;
1308 + }
1309 +
1310 + // Get bundle template
1311 + static inline unsigned int ia64_get_template(unsigned long raw_ip)
1312 + {
1313 +        unsigned long *ip = (unsigned long *)(raw_ip & ~3ul);
1314 +        return ip[0] & 0x1f;
1315 + }
1316 +
1317 + // Get specified instruction in bundle
1318 + static unsigned long ia64_get_instruction(unsigned long raw_ip, int slot)
1319 + {
1320 +        unsigned long inst;
1321 +        unsigned long *ip = (unsigned long *)(raw_ip & ~3ul);
1322 + #if DEBUG
1323 +        printf("Bundle: %016lx%016lx\n", ip[1], ip[0]);
1324 + #endif
1325 +
1326 +        switch (slot) {
1327 +        case 0:
1328 +                inst = (ip[0] >> 5) & 0x1fffffffffful;
1329 +                break;
1330 +        case 1:
1331 +                inst = ((ip[1] & 0x7ffffful) << 18) | ((ip[0] >> 46) & 0x3fffful);
1332 +                break;
1333 +        case 2:
1334 +                inst = (ip[1] >> 23) & 0x1fffffffffful;
1335 +                break;
1336 +        case 3:
1337 +                fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot);
1338 +                abort();
1339 +                break;
1340 +        }
1341 +
1342 + #if DEBUG
1343 +        printf(" Instruction %d: 0x%016lx\n", slot, inst);
1344 + #endif
1345 +        return inst;
1346 + }
1347 +
1348 + // Decode group 0 instructions
1349 + static bool ia64_decode_instruction_0(ia64_instruction_t *inst, unsigned long *ctx)
1350 + {
1351 +        const int r1 = (inst->inst >>  6) & 0x7f;
1352 +        const int r3 = (inst->inst >> 20) & 0x7f;
1353 +
1354 +        const int x3 = (inst->inst >> 33) & 0x07;
1355 +        const int x6 = (inst->inst >> 27) & 0x3f;
1356 +        const int x2 = (inst->inst >> 31) & 0x03;
1357 +        const int x4 = (inst->inst >> 27) & 0x0f;
1358 +
1359 +        if (x3 == 0) {
1360 +                switch (x6) {
1361 +                case 0x01:                                              // nop.i (I19)
1362 +                        inst->mnemo = IA64_INST_NOP;
1363 +                        inst->operands[0].valid = true;
1364 +                        inst->operands[0].index = -1;
1365 +                        inst->operands[0].value = ia64_inst_get_imm21(inst->inst);
1366 +                        return true;
1367 +                case 0x14:                                              // sxt1 (I29)
1368 +                case 0x15:                                              // sxt2 (I29)
1369 +                case 0x16:                                              // sxt4 (I29)
1370 +                case 0x10:                                              // zxt1 (I29)
1371 +                case 0x11:                                              // zxt2 (I29)
1372 +                case 0x12:                                              // zxt4 (I29)
1373 +                        switch (x6) {
1374 +                        case 0x14: inst->mnemo = IA64_INST_SXT1; break;
1375 +                        case 0x15: inst->mnemo = IA64_INST_SXT2; break;
1376 +                        case 0x16: inst->mnemo = IA64_INST_SXT4; break;
1377 +                        case 0x10: inst->mnemo = IA64_INST_ZXT1; break;
1378 +                        case 0x11: inst->mnemo = IA64_INST_ZXT2; break;
1379 +                        case 0x12: inst->mnemo = IA64_INST_ZXT4; break;
1380 +                        default: abort();
1381 +                        }
1382 +                        inst->operands[0].valid = true;
1383 +                        inst->operands[0].index = r1;
1384 +                        inst->operands[1].valid = true;
1385 +                        inst->operands[1].index = r3;
1386 +                        inst->operands[1].value = IA64_GET_GR(r3);
1387 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1388 +                        return true;
1389 +                }
1390 +        }
1391 +        return false;
1392 + }
1393 +
1394 + // Decode group 4 instructions (load/store instructions)
1395 + static bool ia64_decode_instruction_4(ia64_instruction_t *inst, unsigned long *ctx)
1396 + {
1397 +        const int r1 = (inst->inst >> 6) & 0x7f;
1398 +        const int r2 = (inst->inst >> 13) & 0x7f;
1399 +        const int r3 = (inst->inst >> 20) & 0x7f;
1400 +
1401 +        const int m  = (inst->inst >> 36) & 1;
1402 +        const int x  = (inst->inst >> 27) & 1;
1403 +        const int x6 = (inst->inst >> 30) & 0x3f;
1404 +
1405 +        switch (x6) {
1406 +        case 0x00:
1407 +        case 0x01:
1408 +        case 0x02:
1409 +        case 0x03:
1410 +                if (x == 0) {
1411 +                        inst->operands[0].valid = true;
1412 +                        inst->operands[0].index = r1;
1413 +                        inst->operands[1].valid = true;
1414 +                        inst->operands[1].index = r3;
1415 +                        inst->operands[1].value = IA64_GET_GR(r3);
1416 +                        inst->operands[1].nat   = IA64_GET_NAT(r3);
1417 +                        if (m == 0) {
1418 +                                switch (x6) {
1419 +                                case 0x00: inst->mnemo = IA64_INST_LD1; break;
1420 +                                case 0x01: inst->mnemo = IA64_INST_LD2; break;
1421 +                                case 0x02: inst->mnemo = IA64_INST_LD4; break;
1422 +                                case 0x03: inst->mnemo = IA64_INST_LD8; break;
1423 +                                }
1424 +                        }
1425 +                        else {
1426 +                                inst->operands[2].valid = true;
1427 +                                inst->operands[2].index = r2;
1428 +                                inst->operands[2].value = IA64_GET_GR(r2);
1429 +                                inst->operands[2].nat   = IA64_GET_NAT(r2);
1430 +                                switch (x6) {
1431 +                                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1432 +                                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1433 +                                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1434 +                                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1435 +                                }
1436 +                        }
1437 +                        return true;
1438 +                }
1439 +                break;
1440 +        case 0x30:
1441 +        case 0x31:
1442 +        case 0x32:
1443 +        case 0x33:
1444 +                if (m == 0 && x == 0) {
1445 +                        inst->operands[0].valid = true;
1446 +                        inst->operands[0].index = r3;
1447 +                        inst->operands[0].value = IA64_GET_GR(r3);
1448 +                        inst->operands[0].nat   = IA64_GET_NAT(r3);
1449 +                        inst->operands[1].valid = true;
1450 +                        inst->operands[1].index = r2;
1451 +                        inst->operands[1].value = IA64_GET_GR(r2);
1452 +                        inst->operands[1].nat   = IA64_GET_NAT(r2);
1453 +                        switch (x6) {
1454 +                        case 0x30: inst->mnemo = IA64_INST_ST1; break;
1455 +                        case 0x31: inst->mnemo = IA64_INST_ST2; break;
1456 +                        case 0x32: inst->mnemo = IA64_INST_ST4; break;
1457 +                        case 0x33: inst->mnemo = IA64_INST_ST8; break;
1458 +                        }
1459 +                        return true;
1460 +                }
1461 +                break;
1462 +        }
1463 +        return false;
1464 + }
1465 +
1466 + // Decode group 5 instructions (load/store instructions)
1467 + static bool ia64_decode_instruction_5(ia64_instruction_t *inst, unsigned long *ctx)
1468 + {
1469 +        const int r1 = (inst->inst >> 6) & 0x7f;
1470 +        const int r2 = (inst->inst >> 13) & 0x7f;
1471 +        const int r3 = (inst->inst >> 20) & 0x7f;
1472 +
1473 +        const int x6 = (inst->inst >> 30) & 0x3f;
1474 +
1475 +        switch (x6) {
1476 +        case 0x00:
1477 +        case 0x01:
1478 +        case 0x02:
1479 +        case 0x03:
1480 +                inst->operands[0].valid = true;
1481 +                inst->operands[0].index = r1;
1482 +                inst->operands[1].valid = true;
1483 +                inst->operands[1].index = r3;
1484 +                inst->operands[1].value = IA64_GET_GR(r3);
1485 +                inst->operands[1].nat   = IA64_GET_NAT(r3);
1486 +                inst->operands[2].valid = true;
1487 +                inst->operands[2].index = -1;
1488 +                inst->operands[2].value = ia64_inst_get_imm9b(inst->inst);
1489 +                inst->operands[2].nat   = 0;
1490 +                switch (x6) {
1491 +                case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break;
1492 +                case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break;
1493 +                case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break;
1494 +                case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break;
1495 +                }
1496 +                return true;
1497 +        case 0x30:
1498 +        case 0x31:
1499 +        case 0x32:
1500 +        case 0x33:
1501 +                inst->operands[0].valid = true;
1502 +                inst->operands[0].index = r3;
1503 +                inst->operands[0].value = IA64_GET_GR(r3);
1504 +                inst->operands[0].nat   = IA64_GET_NAT(r3);
1505 +                inst->operands[1].valid = true;
1506 +                inst->operands[1].index = r2;
1507 +                inst->operands[1].value = IA64_GET_GR(r2);
1508 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1509 +                inst->operands[2].valid = true;
1510 +                inst->operands[2].index = -1;
1511 +                inst->operands[2].value = ia64_inst_get_imm9a(inst->inst);
1512 +                inst->operands[2].nat   = 0;
1513 +                switch (x6) {
1514 +                case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break;
1515 +                case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break;
1516 +                case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break;
1517 +                case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break;
1518 +                }
1519 +                return true;
1520 +        }
1521 +        return false;
1522 + }
1523 +
1524 + // Decode group 8 instructions (ALU integer)
1525 + static bool ia64_decode_instruction_8(ia64_instruction_t *inst, unsigned long *ctx)
1526 + {
1527 +        const int r1  = (inst->inst >> 6) & 0x7f;
1528 +        const int r2  = (inst->inst >> 13) & 0x7f;
1529 +        const int r3  = (inst->inst >> 20) & 0x7f;
1530 +
1531 +        const int x2a = (inst->inst >> 34) & 0x3;
1532 +        const int x2b = (inst->inst >> 27) & 0x3;
1533 +        const int x4  = (inst->inst >> 29) & 0xf;
1534 +        const int ve  = (inst->inst >> 33) & 0x1;
1535 +
1536 +        // destination register (r1) is always valid in this group
1537 +        inst->operands[0].valid = true;
1538 +        inst->operands[0].index = r1;
1539 +
1540 +        // source register (r3) is always valid in this group
1541 +        inst->operands[2].valid = true;
1542 +        inst->operands[2].index = r3;
1543 +        inst->operands[2].value = IA64_GET_GR(r3);
1544 +        inst->operands[2].nat   = IA64_GET_NAT(r3);
1545 +
1546 +        if (x2a == 0 && ve == 0) {
1547 +                inst->operands[1].valid = true;
1548 +                inst->operands[1].index = r2;
1549 +                inst->operands[1].value = IA64_GET_GR(r2);
1550 +                inst->operands[1].nat   = IA64_GET_NAT(r2);
1551 +                switch (x4) {
1552 +                case 0x0:                               // add (A1)
1553 +                        inst->mnemo = IA64_INST_ADD;
1554 +                        inst->operands[3].valid = true;
1555 +                        inst->operands[3].index = -1;
1556 +                        inst->operands[3].value = x2b == 1;
1557 +                        return true;
1558 +                case 0x1:                               // add (A1)
1559 +                        inst->mnemo = IA64_INST_SUB;
1560 +                        inst->operands[3].valid = true;
1561 +                        inst->operands[3].index = -1;
1562 +                        inst->operands[3].value = x2b == 0;
1563 +                        return true;
1564 +                case 0x4:                               // shladd (A2)
1565 +                        inst->mnemo = IA64_INST_SHLADD;
1566 +                        inst->operands[3].valid = true;
1567 +                        inst->operands[3].index = -1;
1568 +                        inst->operands[3].value = ia64_inst_get_count2(inst->inst);
1569 +                        return true;
1570 +                case 0x9:
1571 +                        if (x2b == 1) {
1572 +                                inst->mnemo = IA64_INST_SUB;
1573 +                                inst->operands[1].index = -1;
1574 +                                inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1575 +                                inst->operands[1].nat   = 0;
1576 +                                return true;
1577 +                        }
1578 +                        break;
1579 +                case 0xb:
1580 +                        inst->operands[1].index = -1;
1581 +                        inst->operands[1].value = ia64_inst_get_imm8(inst->inst);
1582 +                        inst->operands[1].nat   = 0;
1583 +                        // fall-through
1584 +                case 0x3:
1585 +                        switch (x2b) {
1586 +                        case 0: inst->mnemo = IA64_INST_AND;   break;
1587 +                        case 1: inst->mnemo = IA64_INST_ANDCM; break;
1588 +                        case 2: inst->mnemo = IA64_INST_OR;    break;
1589 +                        case 3: inst->mnemo = IA64_INST_XOR;   break;
1590 +                        }
1591 +                        return true;
1592 +                }
1593 +        }
1594 +        return false;
1595 + }
1596 +
1597 + // Decode instruction
1598 + static bool ia64_decode_instruction(ia64_instruction_t *inst, unsigned long *ctx)
1599 + {
1600 +        const int major = (inst->inst >> 37) & 0xf;
1601 +
1602 +        inst->mnemo = IA64_INST_UNKNOWN;
1603 +        inst->pred  = inst->inst & 0x3f;
1604 +        memset(&inst->operands[0], 0, sizeof(inst->operands));
1605 +
1606 +        switch (major) {
1607 +        case 0x0: return ia64_decode_instruction_0(inst, ctx);
1608 +        case 0x4: return ia64_decode_instruction_4(inst, ctx);
1609 +        case 0x5: return ia64_decode_instruction_5(inst, ctx);
1610 +        case 0x8: return ia64_decode_instruction_8(inst, ctx);
1611 +        }
1612 +        return false;
1613 + }
1614 +
1615 + static bool ia64_emulate_instruction(ia64_instruction_t *inst, unsigned long *ctx)
1616 + {
1617 +        // XXX: handle Register NaT Consumption fault?
1618 +        // XXX: this simple emulator assumes instructions in a bundle
1619 +        // don't depend on effects of other instructions in the same
1620 +        // bundle. It probably would be simpler to JIT-generate code to be
1621 +        // executed natively but probably more costly (inject/extract CPU state)
1622 +        if (inst->mnemo == IA64_INST_UNKNOWN)
1623 +                return false;
1624 +        if (inst->pred && !IA64_GET_PR(inst->pred))
1625 +                return true;
1626 +
1627 +        unsigned char nat, nat2;
1628 +        unsigned long dst, dst2, src1, src2, src3;
1629 +
1630 +        switch (inst->mnemo) {
1631 +        case IA64_INST_NOP:
1632 +                break;
1633 +        case IA64_INST_ADD:
1634 +        case IA64_INST_SUB:
1635 +        case IA64_INST_SHLADD:
1636 +                src3 = inst->operands[3].value;
1637 +                // fall-through
1638 +        case IA64_INST_AND:
1639 +        case IA64_INST_ANDCM:
1640 +        case IA64_INST_OR:
1641 +        case IA64_INST_XOR:
1642 +                src1 = inst->operands[1].value;
1643 +                src2 = inst->operands[2].value;
1644 +                switch (inst->mnemo) {
1645 +                case IA64_INST_ADD:   dst = src1 + src2 + src3; break;
1646 +                case IA64_INST_SUB:   dst = src1 - src2 - src3; break;
1647 +                case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break;
1648 +                case IA64_INST_AND:   dst = src1 & src2;                break;
1649 +                case IA64_INST_ANDCM: dst = src1 &~ src2;               break;
1650 +                case IA64_INST_OR:    dst = src1 | src2;                break;
1651 +                case IA64_INST_XOR:   dst = src1 ^ src2;                break;
1652 +                }
1653 +                inst->operands[0].commit = true;
1654 +                inst->operands[0].value  = dst;
1655 +                inst->operands[0].nat    = inst->operands[1].nat | inst->operands[2].nat;
1656 +                break;
1657 +        case IA64_INST_SXT1:
1658 +        case IA64_INST_SXT2:
1659 +        case IA64_INST_SXT4:
1660 +        case IA64_INST_ZXT1:
1661 +        case IA64_INST_ZXT2:
1662 +        case IA64_INST_ZXT4:
1663 +                src1 = inst->operands[1].value;
1664 +                switch (inst->mnemo) {
1665 +                case IA64_INST_SXT1: dst = (signed long)(signed char)src1;              break;
1666 +                case IA64_INST_SXT2: dst = (signed long)(signed short)src1;             break;
1667 +                case IA64_INST_SXT4: dst = (signed long)(signed int)src1;               break;
1668 +                case IA64_INST_ZXT1: dst = (unsigned char)src1;                                 break;
1669 +                case IA64_INST_ZXT2: dst = (unsigned short)src1;                                break;
1670 +                case IA64_INST_ZXT4: dst = (unsigned int)src1;                                  break;
1671 +                }
1672 +                inst->operands[0].commit = true;
1673 +                inst->operands[0].value  = dst;
1674 +                inst->operands[0].nat    = inst->operands[1].nat;
1675 +                break;
1676 +        case IA64_INST_LD1_UPDATE:
1677 +        case IA64_INST_LD2_UPDATE:
1678 +        case IA64_INST_LD4_UPDATE:
1679 +        case IA64_INST_LD8_UPDATE:
1680 +                inst->operands[1].commit = true;
1681 +                dst2 = inst->operands[1].value + inst->operands[2].value;
1682 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1683 +                // fall-through
1684 +        case IA64_INST_LD1:
1685 +        case IA64_INST_LD2:
1686 +        case IA64_INST_LD4:
1687 +        case IA64_INST_LD8:
1688 +                src1 = inst->operands[1].value;
1689 +                if (inst->no_memory)
1690 +                        dst = 0;
1691 +                else {
1692 +                        switch (inst->mnemo) {
1693 +                        case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((unsigned char *)src1);  break;
1694 +                        case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((unsigned short *)src1); break;
1695 +                        case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((unsigned int *)src1);   break;
1696 +                        case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((unsigned long *)src1);  break;
1697 +                        }
1698 +                }
1699 +                inst->operands[0].commit = true;
1700 +                inst->operands[0].value  = dst;
1701 +                inst->operands[0].nat    = 0;
1702 +                inst->operands[1].value  = dst2;
1703 +                inst->operands[1].nat    = nat2;
1704 +                break;
1705 +        case IA64_INST_ST1_UPDATE:
1706 +        case IA64_INST_ST2_UPDATE:
1707 +        case IA64_INST_ST4_UPDATE:
1708 +        case IA64_INST_ST8_UPDATE:
1709 +                inst->operands[0].commit = 0;
1710 +                dst2 = inst->operands[0].value + inst->operands[2].value;
1711 +                nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0;
1712 +                // fall-through
1713 +        case IA64_INST_ST1:
1714 +        case IA64_INST_ST2:
1715 +        case IA64_INST_ST4:
1716 +        case IA64_INST_ST8:
1717 +                dst  = inst->operands[0].value;
1718 +                src1 = inst->operands[1].value;
1719 +                if (!inst->no_memory) {
1720 +                        switch (inst->mnemo) {
1721 +                        case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((unsigned char *)dst) = src1;  break;
1722 +                        case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((unsigned short *)dst) = src1; break;
1723 +                        case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((unsigned int *)dst) = src1;   break;
1724 +                        case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((unsigned long *)dst) = src1;  break;
1725 +                        }
1726 +                }
1727 +                inst->operands[0].value  = dst2;
1728 +                inst->operands[0].nat    = nat2;
1729 +                break;
1730 +        default:
1731 +                return false;
1732 +        }
1733 +
1734 +        for (int i = 0; i < IA64_N_OPERANDS; i++) {
1735 +                ia64_operand_t const & op = inst->operands[i];
1736 +                if (!op.commit)
1737 +                        continue;
1738 +                if (op.index == -1)
1739 +                        return false; // XXX: internal error
1740 +                IA64_SET_GR(op.index, op.value);
1741 +                IA64_SET_NAT(op.index, op.nat);
1742 +        }
1743 +        return true;
1744 + }
1745 +
1746 + static bool ia64_emulate_instruction(unsigned long raw_inst, unsigned long *ctx)
1747 + {
1748 +        ia64_instruction_t inst;
1749 +        memset(&inst, 0, sizeof(inst));
1750 +        inst.inst = raw_inst;
1751 +        if (!ia64_decode_instruction(&inst, ctx))
1752 +                return false;
1753 +        return ia64_emulate_instruction(&inst, ctx);
1754 + }
1755 +
1756 + static bool ia64_skip_instruction(unsigned long *ctx)
1757 + {
1758 +        unsigned long ip = ctx[IA64_REG_IP];
1759 + #if DEBUG
1760 +        printf("IP: 0x%016lx\n", ip);
1761 + #if 0
1762 +        printf(" Template 0x%02x\n", ia64_get_template(ip));
1763 +        ia64_get_instruction(ip, 0);
1764 +        ia64_get_instruction(ip, 1);
1765 +        ia64_get_instruction(ip, 2);
1766 + #endif
1767 + #endif
1768 +
1769 +        // Select which decode switch to use
1770 +        ia64_instruction_t inst;
1771 +        inst.inst = ia64_get_instruction(ip, ip & 3);
1772 +        if (!ia64_decode_instruction(&inst, ctx)) {
1773 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n");
1774 +                return false;
1775 +        }
1776 +
1777 +        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1778 +        transfer_size_t transfer_size = SIZE_UNKNOWN;
1779 +
1780 +        switch (inst.mnemo) {
1781 +        case IA64_INST_LD1:
1782 +        case IA64_INST_LD2:
1783 +        case IA64_INST_LD4:
1784 +        case IA64_INST_LD8:
1785 +        case IA64_INST_LD1_UPDATE:
1786 +        case IA64_INST_LD2_UPDATE:
1787 +        case IA64_INST_LD4_UPDATE:
1788 +        case IA64_INST_LD8_UPDATE:
1789 +                transfer_type = SIGSEGV_TRANSFER_LOAD;
1790 +                break;
1791 +        case IA64_INST_ST1:
1792 +        case IA64_INST_ST2:
1793 +        case IA64_INST_ST4:
1794 +        case IA64_INST_ST8:
1795 +        case IA64_INST_ST1_UPDATE:
1796 +        case IA64_INST_ST2_UPDATE:
1797 +        case IA64_INST_ST4_UPDATE:
1798 +        case IA64_INST_ST8_UPDATE:
1799 +                transfer_type = SIGSEGV_TRANSFER_STORE;
1800 +                break;
1801 +        }
1802 +
1803 +        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
1804 +                // Unknown machine code, let it crash. Then patch the decoder
1805 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n");
1806 +                return false;
1807 +        }
1808 +
1809 +        switch (inst.mnemo) {
1810 +        case IA64_INST_LD1:
1811 +        case IA64_INST_LD1_UPDATE:
1812 +        case IA64_INST_ST1:
1813 +        case IA64_INST_ST1_UPDATE:
1814 +                transfer_size = SIZE_BYTE;
1815 +                break;
1816 +        case IA64_INST_LD2:
1817 +        case IA64_INST_LD2_UPDATE:
1818 +        case IA64_INST_ST2:
1819 +        case IA64_INST_ST2_UPDATE:
1820 +                transfer_size = SIZE_WORD;
1821 +                break;
1822 +        case IA64_INST_LD4:
1823 +        case IA64_INST_LD4_UPDATE:
1824 +        case IA64_INST_ST4:
1825 +        case IA64_INST_ST4_UPDATE:
1826 +                transfer_size = SIZE_LONG;
1827 +                break;
1828 +        case IA64_INST_LD8:
1829 +        case IA64_INST_LD8_UPDATE:
1830 +        case IA64_INST_ST8:
1831 +        case IA64_INST_ST8_UPDATE:
1832 +                transfer_size = SIZE_QUAD;
1833 +                break;
1834 +        }
1835 +
1836 +        if (transfer_size == SIZE_UNKNOWN) {
1837 +                // Unknown machine code, let it crash. Then patch the decoder
1838 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n");
1839 +                return false;
1840 +        }
1841 +
1842 +        inst.no_memory = true;
1843 +        if (!ia64_emulate_instruction(&inst, ctx)) {
1844 +                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n");
1845 +                return false;
1846 +        }
1847 +
1848 +        int slot = ip & 3;
1849 +        bool emulate_next = false;
1850 +        switch (slot) {
1851 +        case 0:
1852 +                switch (ia64_get_template(ip)) {
1853 +                case 0x2: // MI;I
1854 +                case 0x3: // MI;I;
1855 +                        emulate_next = true;
1856 +                        slot = 2;
1857 +                        break;
1858 +                case 0xa: // M;MI
1859 +                case 0xb: // M;MI;
1860 +                        emulate_next = true;
1861 +                        slot = 1;
1862 +                        break;
1863 +                }
1864 +                break;
1865 +        }
1866 +        if (emulate_next) {
1867 +                while (slot < 3) {
1868 +                        if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), ctx)) {
1869 +                                fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n");
1870 +                                return false;
1871 +                        }
1872 +                        ++slot;
1873 +                }
1874 +        }
1875 +
1876 +        ctx[IA64_REG_IP] = (ip & ~3ul) + 16;
1877 + #if DEBUG
1878 +        printf("IP: 0x%016lx\n", ctx[IA64_REG_IP]);
1879 + #endif
1880 +        return true;
1881 + }
1882 + #endif
1883 +
1884   // Decode and skip PPC instruction
1885 < #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1885 > #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1886   static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1887   {
1888          instruction_t instr;
# Line 1047 | Line 1918 | static bool powerpc_skip_instruction(uns
1918  
1919   // Decode and skip MIPS instruction
1920   #if (defined(mips) || defined(__mips))
1921 < enum {
1051 < #if (defined(sgi) || defined(__sgi))
1052 <  MIPS_REG_EPC = 35,
1053 < #endif
1054 < };
1055 < static bool mips_skip_instruction(greg_t * regs)
1921 > static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1922   {
1923 <  unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1923 >  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1924  
1925    if (epc == 0)
1926          return false;
# Line 1203 | Line 2069 | static bool mips_skip_instruction(greg_t
2069                   mips_gpr_names[reg]);
2070   #endif
2071  
2072 <  regs[MIPS_REG_EPC] += 4;
2072 >  *pc_p += 4;
2073    return true;
2074   }
2075   #endif
# Line 1215 | Line 2081 | enum {
2081    SPARC_REG_G1 = REG_G1,
2082    SPARC_REG_O0 = REG_O0,
2083    SPARC_REG_PC = REG_PC,
2084 +  SPARC_REG_nPC = REG_nPC
2085   #endif
2086   };
2087   static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
# Line 1278 | Line 2145 | static bool sparc_skip_instruction(unsig
2145          break;
2146    case 7: // Store Doubleword
2147          transfer_type = SIGSEGV_TRANSFER_STORE;
2148 <        transfer_size = SIZE_WORD;
2148 >        transfer_size = SIZE_LONG;
2149          register_pair = true;
2150          break;
2151    }
# Line 1288 | Line 2155 | static bool sparc_skip_instruction(unsig
2155          return false;
2156    }
2157  
1291  // Zero target register in case of a load operation
2158    const int reg = (opcode >> 25) & 0x1f;
2159 +
2160 + #if DEBUG
2161 +  static const char * reg_names[] = {
2162 +        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
2163 +        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
2164 +        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
2165 +        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
2166 +  };
2167 +  printf("%s %s register %s\n",
2168 +                 transfer_size == SIZE_BYTE ? "byte" :
2169 +                 transfer_size == SIZE_WORD ? "word" :
2170 +                 transfer_size == SIZE_LONG ? "long" :
2171 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
2172 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
2173 +                 reg_names[reg]);
2174 + #endif
2175 +
2176 +  // Zero target register in case of a load operation
2177    if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
2178          // FIXME: code to handle local & input registers is not tested
2179 <        if (reg >= 1 && reg <= 7) {
2179 >        if (reg >= 1 && reg < 8) {
2180            // global registers
2181            regs[reg - 1 + SPARC_REG_G1] = 0;
2182          }
2183 <        else if (reg >= 8 && reg <= 15) {
2183 >        else if (reg >= 8 && reg < 16) {
2184            // output registers
2185            regs[reg - 8 + SPARC_REG_O0] = 0;
2186          }
2187 <        else if (reg >= 16 && reg <= 23) {
2187 >        else if (reg >= 16 && reg < 24) {
2188            // local registers (in register windows)
2189            if (gwins)
2190                  gwins->wbuf->rw_local[reg - 16] = 0;
# Line 1316 | Line 2200 | static bool sparc_skip_instruction(unsig
2200          }
2201    }
2202  
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
2203    regs[SPARC_REG_PC] += 4;
2204 +  regs[SPARC_REG_nPC] += 4;
2205    return true;
2206   }
2207   #endif
# Line 1488 | Line 2357 | static bool arm_skip_instruction(unsigne
2357  
2358  
2359   // Fallbacks
2360 + #ifndef SIGSEGV_FAULT_ADDRESS_FAST
2361 + #define SIGSEGV_FAULT_ADDRESS_FAST              SIGSEGV_FAULT_ADDRESS
2362 + #endif
2363 + #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
2364 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_FAULT_INSTRUCTION
2365 + #endif
2366   #ifndef SIGSEGV_FAULT_INSTRUCTION
2367 < #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
2367 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_ADDRESS
2368   #endif
2369   #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
2370   #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
2371   #endif
2372   #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
2373 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  sigsegv_fault_handler(ADDR, IP)
2373 > #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
2374   #endif
2375  
2376   // SIGSEGV recovery supported ?
# Line 1508 | Line 2383 | static bool arm_skip_instruction(unsigne
2383   *  SIGSEGV global handler
2384   */
2385  
2386 + struct sigsegv_info_t {
2387 +        sigsegv_address_t addr;
2388 +        sigsegv_address_t pc;
2389 + #ifdef HAVE_MACH_EXCEPTIONS
2390 +        mach_port_t thread;
2391 +        bool has_exc_state;
2392 +        SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
2393 +        mach_msg_type_number_t exc_state_count;
2394 +        bool has_thr_state;
2395 +        SIGSEGV_THREAD_STATE_TYPE thr_state;
2396 +        mach_msg_type_number_t thr_state_count;
2397 + #endif
2398 + };
2399 +
2400 + #ifdef HAVE_MACH_EXCEPTIONS
2401 + static void mach_get_exception_state(sigsegv_info_t *SIP)
2402 + {
2403 +        SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
2404 +        kern_return_t krc = thread_get_state(SIP->thread,
2405 +                                                                                 SIGSEGV_EXCEPTION_STATE_FLAVOR,
2406 +                                                                                 (natural_t *)&SIP->exc_state,
2407 +                                                                                 &SIP->exc_state_count);
2408 +        MACH_CHECK_ERROR(thread_get_state, krc);
2409 +        SIP->has_exc_state = true;
2410 + }
2411 +
2412 + static void mach_get_thread_state(sigsegv_info_t *SIP)
2413 + {
2414 +        SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
2415 +        kern_return_t krc = thread_get_state(SIP->thread,
2416 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2417 +                                                                                 (natural_t *)&SIP->thr_state,
2418 +                                                                                 &SIP->thr_state_count);
2419 +        MACH_CHECK_ERROR(thread_get_state, krc);
2420 +        SIP->has_thr_state = true;
2421 + }
2422 +
2423 + static void mach_set_thread_state(sigsegv_info_t *SIP)
2424 + {
2425 +        kern_return_t krc = thread_set_state(SIP->thread,
2426 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
2427 +                                                                                 (natural_t *)&SIP->thr_state,
2428 +                                                                                 SIP->thr_state_count);
2429 +        MACH_CHECK_ERROR(thread_set_state, krc);
2430 + }
2431 + #endif
2432 +
2433 + // Return the address of the invalid memory reference
2434 + sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP)
2435 + {
2436 + #ifdef HAVE_MACH_EXCEPTIONS
2437 +        static int use_fast_path = -1;
2438 +        if (use_fast_path != 1 && !SIP->has_exc_state) {
2439 +                mach_get_exception_state(SIP);
2440 +
2441 +                sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2442 +                if (use_fast_path < 0)
2443 +                        use_fast_path = addr == SIP->addr;
2444 +                SIP->addr = addr;
2445 +        }
2446 + #endif
2447 +        return SIP->addr;
2448 + }
2449 +
2450 + // Return the address of the instruction that caused the fault, or
2451 + // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
2452 + sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP)
2453 + {
2454 + #ifdef HAVE_MACH_EXCEPTIONS
2455 +        if (!SIP->has_thr_state) {
2456 +                mach_get_thread_state(SIP);
2457 +
2458 +                SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2459 +        }
2460 + #endif
2461 +        return SIP->pc;
2462 + }
2463 +
2464   // This function handles the badaccess to memory.
2465   // It is called from the signal handler or the exception handler.
2466   static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
2467   {
2468 <        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
2469 <        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
2470 <        
2468 >        sigsegv_info_t SI;
2469 >        SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
2470 >        SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
2471 > #ifdef HAVE_MACH_EXCEPTIONS
2472 >        SI.thread = thread;
2473 >        SI.has_exc_state = false;
2474 >        SI.has_thr_state = false;
2475 > #endif
2476 >        sigsegv_info_t * const SIP = &SI;
2477 >
2478          // Call user's handler and reinstall the global handler, if required
2479 <        switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
2479 >        switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) {
2480          case SIGSEGV_RETURN_SUCCESS:
2481                  return true;
2482  
# Line 1524 | Line 2484 | static bool handle_badaccess(SIGSEGV_FAU
2484          case SIGSEGV_RETURN_SKIP_INSTRUCTION:
2485                  // Call the instruction skipper with the register file
2486                  // available
2487 + #ifdef HAVE_MACH_EXCEPTIONS
2488 +                if (!SIP->has_thr_state)
2489 +                        mach_get_thread_state(SIP);
2490 + #endif
2491                  if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
2492   #ifdef HAVE_MACH_EXCEPTIONS
2493                          // Unlike UNIX signals where the thread state
2494                          // is modified off of the stack, in Mach we
2495                          // need to actually call thread_set_state to
2496                          // have the register values updated.
2497 <                        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);
2497 >                        mach_set_thread_state(SIP);
2498   #endif
2499                          return true;
2500                  }
# Line 1544 | Line 2503 | static bool handle_badaccess(SIGSEGV_FAU
2503          case SIGSEGV_RETURN_FAILURE:
2504                  // We can't do anything with the fault_address, dump state?
2505                  if (sigsegv_state_dumper != 0)
2506 <                        sigsegv_state_dumper(fault_address, fault_instruction);
2506 >                        sigsegv_state_dumper(SIP);
2507                  break;
2508          }
2509  
# Line 1586 | Line 2545 | forward_exception(mach_port_t thread_por
2545          mach_port_t port;
2546          exception_behavior_t behavior;
2547          thread_state_flavor_t flavor;
2548 <        thread_state_t thread_state;
2548 >        thread_state_data_t thread_state;
2549          mach_msg_type_number_t thread_state_count;
2550  
2551          for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
# Line 1605 | Line 2564 | forward_exception(mach_port_t thread_por
2564          behavior = oldExceptionPorts->behaviors[portIndex];
2565          flavor = oldExceptionPorts->flavors[portIndex];
2566  
2567 +        if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
2568 +                fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
2569 +                return KERN_FAILURE;
2570 +        }
2571 +
2572          /*
2573           fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
2574           */
2575  
2576          if (behavior != EXCEPTION_DEFAULT) {
2577                  thread_state_count = THREAD_STATE_MAX;
2578 <                kret = thread_get_state (thread_port, flavor, thread_state,
2578 >                kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
2579                                                                   &thread_state_count);
2580                  MACH_CHECK_ERROR (thread_get_state, kret);
2581          }
# Line 1627 | Line 2591 | forward_exception(mach_port_t thread_por
2591            // fprintf(stderr, "forwarding to exception_raise_state\n");
2592            kret = exception_raise_state(port, exception_type, exception_data,
2593                                                                     data_count, &flavor,
2594 <                                                                   thread_state, thread_state_count,
2595 <                                                                   thread_state, &thread_state_count);
2594 >                                                                   (natural_t *)&thread_state, thread_state_count,
2595 >                                                                   (natural_t *)&thread_state, &thread_state_count);
2596            MACH_CHECK_ERROR (exception_raise_state, kret);
2597            break;
2598          case EXCEPTION_STATE_IDENTITY:
# Line 1636 | Line 2600 | forward_exception(mach_port_t thread_por
2600            kret = exception_raise_state_identity(port, thread_port, task_port,
2601                                                                                          exception_type, exception_data,
2602                                                                                          data_count, &flavor,
2603 <                                                                                        thread_state, thread_state_count,
2604 <                                                                                        thread_state, &thread_state_count);
2603 >                                                                                        (natural_t *)&thread_state, thread_state_count,
2604 >                                                                                        (natural_t *)&thread_state, &thread_state_count);
2605            MACH_CHECK_ERROR (exception_raise_state_identity, kret);
2606            break;
2607          default:
2608            fprintf(stderr, "forward_exception got unknown behavior\n");
2609 +          kret = KERN_FAILURE;
2610            break;
2611          }
2612  
2613          if (behavior != EXCEPTION_DEFAULT) {
2614 <                kret = thread_set_state (thread_port, flavor, thread_state,
2614 >                kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
2615                                                                   thread_state_count);
2616                  MACH_CHECK_ERROR (thread_set_state, kret);
2617          }
2618  
2619 <        return KERN_SUCCESS;
2619 >        return kret;
2620   }
2621  
2622   /*
# Line 1679 | Line 2644 | catch_exception_raise(mach_port_t except
2644                                            mach_port_t task,
2645                                            exception_type_t exception,
2646                                            exception_data_t code,
2647 <                                          mach_msg_type_number_t codeCount)
2647 >                                          mach_msg_type_number_t code_count)
2648   {
1684        ppc_thread_state_t state;
2649          kern_return_t krc;
2650  
2651 <        if ((exception == EXC_BAD_ACCESS)  && (codeCount >= 2)) {
2652 <                if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2653 <                        return KERN_SUCCESS;
2651 >        if (exception == EXC_BAD_ACCESS) {
2652 >                switch (code[0]) {
2653 >                case KERN_PROTECTION_FAILURE:
2654 >                case KERN_INVALID_ADDRESS:
2655 >                        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
2656 >                                return KERN_SUCCESS;
2657 >                        break;
2658 >                }
2659          }
2660  
2661          // In Mach we do not need to remove the exception handler.
2662          // If we forward the exception, eventually some exception handler
2663          // will take care of this exception.
2664 <        krc = forward_exception(thread, task, exception, code, codeCount, &ports);
2664 >        krc = forward_exception(thread, task, exception, code, code_count, &ports);
2665  
2666          return krc;
2667   }
# Line 1820 | Line 2789 | static bool sigsegv_do_install_handler(s
2789          // addressing modes) used in PPC instructions, you will need the
2790          // GPR state anyway.
2791          krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2792 <                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
2792 >                                EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2793          if (krc != KERN_SUCCESS) {
2794                  mach_error("thread_set_exception_ports", krc);
2795                  return false;
# Line 2004 | Line 2973 | static int page_size;
2973   static volatile char * page = 0;
2974   static volatile int handler_called = 0;
2975  
2976 + /* Barriers */
2977 + #ifdef __GNUC__
2978 + #define BARRIER() asm volatile ("" : : : "memory")
2979 + #else
2980 + #define BARRIER() /* nothing */
2981 + #endif
2982 +
2983   #ifdef __GNUC__
2984   // Code range where we expect the fault to come from
2985   static void *b_region, *e_region;
2986   #endif
2987  
2988 < static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2988 > static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2989   {
2990 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2991 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2992   #if DEBUG
2993          printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2994          printf("expected fault at %p\n", page + REF_INDEX);
# Line 2024 | Line 3002 | static sigsegv_return_t sigsegv_test_han
3002   #ifdef __GNUC__
3003          // Make sure reported fault instruction address falls into
3004          // expected code range
3005 <        if (instruction_address != SIGSEGV_INVALID_PC
3005 >        if (instruction_address != SIGSEGV_INVALID_ADDRESS
3006                  && ((instruction_address <  (sigsegv_address_t)b_region) ||
3007                          (instruction_address >= (sigsegv_address_t)e_region)))
3008                  exit(11);
# Line 2035 | Line 3013 | static sigsegv_return_t sigsegv_test_han
3013   }
3014  
3015   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
3016 < static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
3016 > static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
3017   {
3018 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
3019 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
3020   #if DEBUG
3021          printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
3022   #endif
# Line 2044 | Line 3024 | static sigsegv_return_t sigsegv_insn_han
3024   #ifdef __GNUC__
3025                  // Make sure reported fault instruction address falls into
3026                  // expected code range
3027 <                if (instruction_address != SIGSEGV_INVALID_PC
3027 >                if (instruction_address != SIGSEGV_INVALID_ADDRESS
3028                          && ((instruction_address <  (sigsegv_address_t)b_region) ||
3029                                  (instruction_address >= (sigsegv_address_t)e_region)))
3030                          return SIGSEGV_RETURN_FAILURE;
# Line 2095 | Line 3075 | static bool arch_insn_skipper_tests()
3075                  0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
3076                  0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
3077                  0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
3078 +                0x63, 0x47, 0x04,              // movslq 4(%rdi),%eax
3079 +                0x48, 0x63, 0x47, 0x04,        // movslq 4(%rdi),%rax
3080   #endif
3081                  0                              // end
3082          };
# Line 2118 | Line 3100 | int main(void)
3100          if (vm_init() < 0)
3101                  return 1;
3102  
3103 < #ifdef _WIN32
2122 <        page_size = 4096;
2123 < #else
2124 <        page_size = getpagesize();
2125 < #endif
3103 >        page_size = vm_get_page_size();
3104          if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
3105                  return 2;
3106          
# Line 2132 | Line 3110 | int main(void)
3110          
3111          if (!sigsegv_install_handler(sigsegv_test_handler))
3112                  return 4;
3113 <        
3113 >
3114   #ifdef __GNUC__
3115          b_region = &&L_b_region1;
3116          e_region = &&L_e_region1;
3117   #endif
3118 < L_b_region1:
3119 <        page[REF_INDEX] = REF_VALUE;
3120 <        if (page[REF_INDEX] != REF_VALUE)
3121 <          exit(20);
3122 <        page[REF_INDEX] = REF_VALUE;
3123 < L_e_region1:
3118 >        /* This is a really awful hack but otherwise gcc is smart enough
3119 >         * (or bug'ous enough?) to optimize the labels and place them
3120 >         * e.g. at the "main" entry point, which is wrong.
3121 >         */
3122 >        volatile int label_hack = 1;
3123 >        switch (label_hack) {
3124 >        case 1:
3125 >        L_b_region1:
3126 >                page[REF_INDEX] = REF_VALUE;
3127 >                if (page[REF_INDEX] != REF_VALUE)
3128 >                        exit(20);
3129 >                page[REF_INDEX] = REF_VALUE;
3130 >                BARRIER();
3131 >                // fall-through
3132 >        case 2:
3133 >        L_e_region1:
3134 >                BARRIER();
3135 >                break;
3136 >        }
3137  
3138          if (handler_called != 1)
3139                  return 5;
# Line 2173 | Line 3164 | int main(void)
3164          b_region = &&L_b_region2;
3165          e_region = &&L_e_region2;
3166   #endif
3167 < L_b_region2:
3168 <        TEST_SKIP_INSTRUCTION(unsigned char);
3169 <        TEST_SKIP_INSTRUCTION(unsigned short);
3170 <        TEST_SKIP_INSTRUCTION(unsigned int);
3171 <        TEST_SKIP_INSTRUCTION(unsigned long);
3172 <        TEST_SKIP_INSTRUCTION(signed char);
3173 <        TEST_SKIP_INSTRUCTION(signed short);
3174 <        TEST_SKIP_INSTRUCTION(signed int);
3175 <        TEST_SKIP_INSTRUCTION(signed long);
3176 < L_e_region2:
3177 <
3167 >        switch (label_hack) {
3168 >        case 1:
3169 >        L_b_region2:
3170 >                TEST_SKIP_INSTRUCTION(unsigned char);
3171 >                TEST_SKIP_INSTRUCTION(unsigned short);
3172 >                TEST_SKIP_INSTRUCTION(unsigned int);
3173 >                TEST_SKIP_INSTRUCTION(unsigned long);
3174 >                TEST_SKIP_INSTRUCTION(signed char);
3175 >                TEST_SKIP_INSTRUCTION(signed short);
3176 >                TEST_SKIP_INSTRUCTION(signed int);
3177 >                TEST_SKIP_INSTRUCTION(signed long);
3178 >                BARRIER();
3179 >                // fall-through
3180 >        case 2:
3181 >        L_e_region2:
3182 >                BARRIER();
3183 >                break;
3184 >        }
3185          if (!arch_insn_skipper_tests())
3186                  return 20;
3187   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines