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.54 by gbeauche, 2005-03-23T21:37:24Z vs.
Revision 1.71 by gbeauche, 2008-01-01T09:40:33Z

# 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,
# Line 75 | Line 82 | enum transfer_size_t {
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 264 | Line 268 | static void powerpc_decode_instruction(i
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 323 | Line 327 | static void powerpc_decode_instruction(i
327   #define SIGSEGV_REGISTER_FILE                   (&SIGSEGV_CONTEXT_REGS.arm_r0)
328   #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
329   #endif
330 + #if (defined(mips) || defined(__mips__))
331 + #include <sys/ucontext.h>
332 + #define SIGSEGV_CONTEXT_REGS                    (((struct ucontext *)scp)->uc_mcontext)
333 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS.pc)
334 + #define SIGSEGV_REGISTER_FILE                   &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0]
335 + #define SIGSEGV_SKIP_INSTRUCTION                mips_skip_instruction
336 + #endif
337   #endif
338   #endif
339  
# Line 590 | Line 601 | if (ret != KERN_SUCCESS) { \
601          exit (1); \
602   }
603  
604 < #define SIGSEGV_FAULT_ADDRESS                   code[1]
605 < #define SIGSEGV_FAULT_INSTRUCTION               get_fault_instruction(thread, state)
606 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
607 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, ppc_thread_state_t *state
608 < #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
604 > #ifdef __ppc__
605 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state_t
606 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE
607 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE_COUNT
608 > #define SIGSEGV_FAULT_ADDRESS                   sip->exc_state.dar
609 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state_t
610 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE
611 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE_COUNT
612 > #define SIGSEGV_FAULT_INSTRUCTION               sip->thr_state.srr0
613   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
614 < #define SIGSEGV_REGISTER_FILE                   &state->srr0, &state->r0
615 <
616 < // Given a suspended thread, stuff the current instruction and
617 < // registers into state.
618 < //
619 < // It would have been nice to have this be ppc/x86 independant which
620 < // could have been done easily with a thread_state_t instead of
621 < // ppc_thread_state_t, but because of the way this is called it is
622 < // easier to do it this way.
623 < #if (defined(ppc) || defined(__ppc__))
624 < static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
625 < {
626 <        kern_return_t krc;
627 <        mach_msg_type_number_t count;
628 <
629 <        count = MACHINE_THREAD_STATE_COUNT;
630 <        krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
631 <        MACH_CHECK_ERROR (thread_get_state, krc);
632 <
633 <        return (sigsegv_address_t)state->srr0;
634 < }
614 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&sip->thr_state.srr0, (unsigned long *)&sip->thr_state.r0
615 > #endif
616 > #ifdef __ppc64__
617 > #define SIGSEGV_EXCEPTION_STATE_TYPE    ppc_exception_state64_t
618 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  PPC_EXCEPTION_STATE64
619 > #define SIGSEGV_EXCEPTION_STATE_COUNT   PPC_EXCEPTION_STATE64_COUNT
620 > #define SIGSEGV_FAULT_ADDRESS                   sip->exc_state.dar
621 > #define SIGSEGV_THREAD_STATE_TYPE               ppc_thread_state64_t
622 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE64
623 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE64_COUNT
624 > #define SIGSEGV_FAULT_INSTRUCTION               sip->thr_state.srr0
625 > #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
626 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&sip->thr_state.srr0, (unsigned long *)&sip->thr_state.r0
627 > #endif
628 > #ifdef __i386__
629 > #define SIGSEGV_EXCEPTION_STATE_TYPE    struct i386_exception_state
630 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  i386_EXCEPTION_STATE
631 > #define SIGSEGV_EXCEPTION_STATE_COUNT   i386_EXCEPTION_STATE_COUNT
632 > #define SIGSEGV_FAULT_ADDRESS                   sip->exc_state.faultvaddr
633 > #define SIGSEGV_THREAD_STATE_TYPE               struct i386_thread_state
634 > #define SIGSEGV_THREAD_STATE_FLAVOR             i386_THREAD_STATE
635 > #define SIGSEGV_THREAD_STATE_COUNT              i386_THREAD_STATE_COUNT
636 > #define SIGSEGV_FAULT_INSTRUCTION               sip->thr_state.eip
637 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
638 > #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&sip->thr_state.eax) /* EAX is the first GPR we consider */
639 > #endif
640 > #ifdef __x86_64__
641 > #define SIGSEGV_EXCEPTION_STATE_TYPE    struct x86_exception_state64
642 > #define SIGSEGV_EXCEPTION_STATE_FLAVOR  x86_EXCEPTION_STATE64
643 > #define SIGSEGV_EXCEPTION_STATE_COUNT   x86_EXCEPTION_STATE64_COUNT
644 > #define SIGSEGV_FAULT_ADDRESS                   sip->exc_state.faultvaddr
645 > #define SIGSEGV_THREAD_STATE_TYPE               struct x86_thread_state64
646 > #define SIGSEGV_THREAD_STATE_FLAVOR             x86_THREAD_STATE64
647 > #define SIGSEGV_THREAD_STATE_COUNT              x86_THREAD_STATE64_COUNT
648 > #define SIGSEGV_FAULT_INSTRUCTION               sip->thr_state.rip
649 > #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
650 > #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&sip->thr_state.rax) /* RAX is the first GPR we consider */
651   #endif
652 + #define SIGSEGV_FAULT_ADDRESS_FAST              code[1]
653 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_INVALID_ADDRESS
654 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code
655 + #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code
656  
657   // Since there can only be one exception thread running at any time
658   // this is not a problem.
# Line 737 | Line 772 | enum {
772   #endif
773   };
774   #endif
775 + #if defined(__OpenBSD__)
776 + enum {
777 + #if defined(__i386__)
778 +        // EDI is the first register we consider
779 + #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
780 + #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
781 +        X86_REG_EIP = DREG(eip), // 7
782 +        X86_REG_EAX = DREG(eax), // 6
783 +        X86_REG_ECX = DREG(ecx), // 5
784 +        X86_REG_EDX = DREG(edx), // 4
785 +        X86_REG_EBX = DREG(ebx), // 3
786 +        X86_REG_ESP = DREG(esp), // 10
787 +        X86_REG_EBP = DREG(ebp), // 2
788 +        X86_REG_ESI = DREG(esi), // 1
789 +        X86_REG_EDI = DREG(edi)  // 0
790 + #undef DREG
791 + #undef OREG
792 + #endif
793 + };
794 + #endif
795   #if defined(__sun__)
796   // Same as for Linux, need to check for x86-64
797   enum {
# Line 753 | Line 808 | enum {
808   #endif
809   };
810   #endif
811 + #if defined(__APPLE__) && defined(__MACH__)
812 + enum {
813 + #if (defined(i386) || defined(__i386__))
814 + #ifdef i386_SAVED_STATE
815 +        // same as FreeBSD (in Open Darwin 8.0.1)
816 +        X86_REG_EIP = 10,
817 +        X86_REG_EAX = 7,
818 +        X86_REG_ECX = 6,
819 +        X86_REG_EDX = 5,
820 +        X86_REG_EBX = 4,
821 +        X86_REG_ESP = 13,
822 +        X86_REG_EBP = 2,
823 +        X86_REG_ESI = 1,
824 +        X86_REG_EDI = 0
825 + #else
826 +        // new layout (MacOS X 10.4.4 for x86)
827 +        X86_REG_EIP = 10,
828 +        X86_REG_EAX = 0,
829 +        X86_REG_ECX = 2,
830 +        X86_REG_EDX = 3,
831 +        X86_REG_EBX = 1,
832 +        X86_REG_ESP = 7,
833 +        X86_REG_EBP = 6,
834 +        X86_REG_ESI = 5,
835 +        X86_REG_EDI = 4
836 + #endif
837 + #endif
838 + #if defined(__x86_64__)
839 +        X86_REG_R8  = 8,
840 +        X86_REG_R9  = 9,
841 +        X86_REG_R10 = 10,
842 +        X86_REG_R11 = 11,
843 +        X86_REG_R12 = 12,
844 +        X86_REG_R13 = 13,
845 +        X86_REG_R14 = 14,
846 +        X86_REG_R15 = 15,
847 +        X86_REG_EDI = 4,
848 +        X86_REG_ESI = 5,
849 +        X86_REG_EBP = 6,
850 +        X86_REG_EBX = 1,
851 +        X86_REG_EDX = 3,
852 +        X86_REG_EAX = 0,
853 +        X86_REG_ECX = 2,
854 +        X86_REG_ESP = 7,
855 +        X86_REG_EIP = 16
856 + #endif
857 + };
858 + #endif
859   #if defined(_WIN32)
860   enum {
861   #if (defined(i386) || defined(__i386__))
# Line 813 | Line 916 | static bool ix86_skip_instruction(unsign
916                  return false;
917   #endif
918          
919 +        enum instruction_type_t {
920 +                i_MOV,
921 +                i_ADD
922 +        };
923 +
924          transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
925          transfer_size_t transfer_size = SIZE_LONG;
926 +        instruction_type_t instruction_type = i_MOV;
927          
928          int reg = -1;
929          int len = 0;
# Line 865 | Line 974 | static bool ix86_skip_instruction(unsign
974   #endif
975  
976          // Decode instruction
977 +        int op_len = 1;
978          int target_size = SIZE_UNKNOWN;
979          switch (eip[0]) {
980          case 0x0f:
# Line 879 | Line 989 | static bool ix86_skip_instruction(unsign
989                          transfer_size = SIZE_WORD;
990                          goto do_mov_extend;
991                    do_mov_extend:
992 <                        switch (eip[2] & 0xc0) {
993 <                        case 0x80:
994 <                                reg = (eip[2] >> 3) & 7;
995 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
996 <                                break;
997 <                        case 0x40:
998 <                                reg = (eip[2] >> 3) & 7;
999 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1000 <                                break;
1001 <                        case 0x00:
1002 <                                reg = (eip[2] >> 3) & 7;
1003 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
1004 <                                break;
1005 <                        }
1006 <                        len += 3 + ix86_step_over_modrm(eip + 2);
1007 <                        break;
1008 <            }
1009 <          break;
992 >                        op_len = 2;
993 >                        goto do_transfer_load;
994 >                }
995 >                break;
996 > #if defined(__x86_64__)
997 >        case 0x63: // MOVSXD r64, r/m32
998 >                if (has_rex && rex.W) {
999 >                        transfer_size = SIZE_LONG;
1000 >                        target_size = SIZE_QUAD;
1001 >                }
1002 >                else if (transfer_size != SIZE_WORD) {
1003 >                        transfer_size = SIZE_LONG;
1004 >                        target_size = SIZE_QUAD;
1005 >                }
1006 >                goto do_transfer_load;
1007 > #endif
1008 >        case 0x02: // ADD r8, r/m8
1009 >                transfer_size = SIZE_BYTE;
1010 >        case 0x03: // ADD r32, r/m32
1011 >                instruction_type = i_ADD;
1012 >                goto do_transfer_load;
1013          case 0x8a: // MOV r8, r/m8
1014                  transfer_size = SIZE_BYTE;
1015          case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
1016 <                switch (eip[1] & 0xc0) {
1016 >          do_transfer_load:
1017 >                switch (eip[op_len] & 0xc0) {
1018                  case 0x80:
1019 <                        reg = (eip[1] >> 3) & 7;
1019 >                        reg = (eip[op_len] >> 3) & 7;
1020                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1021                          break;
1022                  case 0x40:
1023 <                        reg = (eip[1] >> 3) & 7;
1023 >                        reg = (eip[op_len] >> 3) & 7;
1024                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1025                          break;
1026                  case 0x00:
1027 <                        reg = (eip[1] >> 3) & 7;
1027 >                        reg = (eip[op_len] >> 3) & 7;
1028                          transfer_type = SIGSEGV_TRANSFER_LOAD;
1029                          break;
1030                  }
1031 <                len += 2 + ix86_step_over_modrm(eip + 1);
1031 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1032                  break;
1033 +        case 0x00: // ADD r/m8, r8
1034 +                transfer_size = SIZE_BYTE;
1035 +        case 0x01: // ADD r/m32, r32
1036 +                instruction_type = i_ADD;
1037 +                goto do_transfer_store;
1038          case 0x88: // MOV r/m8, r8
1039                  transfer_size = SIZE_BYTE;
1040          case 0x89: // MOV r/m32, r32 (or 16-bit operation)
1041 <                switch (eip[1] & 0xc0) {
1041 >          do_transfer_store:
1042 >                switch (eip[op_len] & 0xc0) {
1043                  case 0x80:
1044 <                        reg = (eip[1] >> 3) & 7;
1044 >                        reg = (eip[op_len] >> 3) & 7;
1045                          transfer_type = SIGSEGV_TRANSFER_STORE;
1046                          break;
1047                  case 0x40:
1048 <                        reg = (eip[1] >> 3) & 7;
1048 >                        reg = (eip[op_len] >> 3) & 7;
1049                          transfer_type = SIGSEGV_TRANSFER_STORE;
1050                          break;
1051                  case 0x00:
1052 <                        reg = (eip[1] >> 3) & 7;
1052 >                        reg = (eip[op_len] >> 3) & 7;
1053                          transfer_type = SIGSEGV_TRANSFER_STORE;
1054                          break;
1055                  }
1056 <                len += 2 + ix86_step_over_modrm(eip + 1);
1056 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1057                  break;
1058          }
1059          if (target_size == SIZE_UNKNOWN)
# Line 949 | Line 1069 | static bool ix86_skip_instruction(unsign
1069                  reg += 8;
1070   #endif
1071  
1072 <        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1072 >        if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1073                  static const int x86_reg_map[] = {
1074                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1075                          X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
# Line 985 | Line 1105 | static bool ix86_skip_instruction(unsign
1105          }
1106  
1107   #if DEBUG
1108 <        printf("%08x: %s %s access", regs[X86_REG_EIP],
1108 >        printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1109                     transfer_size == SIZE_BYTE ? "byte" :
1110                     transfer_size == SIZE_WORD ? "word" :
1111                     transfer_size == SIZE_LONG ? "long" :
# Line 1041 | Line 1161 | static bool ix86_skip_instruction(unsign
1161   #endif
1162  
1163   // Decode and skip PPC instruction
1164 < #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1164 > #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__))
1165   static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1166   {
1167          instruction_t instr;
# Line 1077 | Line 1197 | static bool powerpc_skip_instruction(uns
1197  
1198   // Decode and skip MIPS instruction
1199   #if (defined(mips) || defined(__mips))
1200 < enum {
1081 < #if (defined(sgi) || defined(__sgi))
1082 <  MIPS_REG_EPC = 35,
1083 < #endif
1084 < };
1085 < static bool mips_skip_instruction(greg_t * regs)
1200 > static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1201   {
1202 <  unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1202 >  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1203  
1204    if (epc == 0)
1205          return false;
# Line 1233 | Line 1348 | static bool mips_skip_instruction(greg_t
1348                   mips_gpr_names[reg]);
1349   #endif
1350  
1351 <  regs[MIPS_REG_EPC] += 4;
1351 >  *pc_p += 4;
1352    return true;
1353   }
1354   #endif
# Line 1245 | Line 1360 | enum {
1360    SPARC_REG_G1 = REG_G1,
1361    SPARC_REG_O0 = REG_O0,
1362    SPARC_REG_PC = REG_PC,
1363 +  SPARC_REG_nPC = REG_nPC
1364   #endif
1365   };
1366   static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
# Line 1308 | Line 1424 | static bool sparc_skip_instruction(unsig
1424          break;
1425    case 7: // Store Doubleword
1426          transfer_type = SIGSEGV_TRANSFER_STORE;
1427 <        transfer_size = SIZE_WORD;
1427 >        transfer_size = SIZE_LONG;
1428          register_pair = true;
1429          break;
1430    }
# Line 1318 | Line 1434 | static bool sparc_skip_instruction(unsig
1434          return false;
1435    }
1436  
1321  // Zero target register in case of a load operation
1437    const int reg = (opcode >> 25) & 0x1f;
1438 +
1439 + #if DEBUG
1440 +  static const char * reg_names[] = {
1441 +        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1442 +        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1443 +        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1444 +        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1445 +  };
1446 +  printf("%s %s register %s\n",
1447 +                 transfer_size == SIZE_BYTE ? "byte" :
1448 +                 transfer_size == SIZE_WORD ? "word" :
1449 +                 transfer_size == SIZE_LONG ? "long" :
1450 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1451 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1452 +                 reg_names[reg]);
1453 + #endif
1454 +
1455 +  // Zero target register in case of a load operation
1456    if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1457          // FIXME: code to handle local & input registers is not tested
1458 <        if (reg >= 1 && reg <= 7) {
1458 >        if (reg >= 1 && reg < 8) {
1459            // global registers
1460            regs[reg - 1 + SPARC_REG_G1] = 0;
1461          }
1462 <        else if (reg >= 8 && reg <= 15) {
1462 >        else if (reg >= 8 && reg < 16) {
1463            // output registers
1464            regs[reg - 8 + SPARC_REG_O0] = 0;
1465          }
1466 <        else if (reg >= 16 && reg <= 23) {
1466 >        else if (reg >= 16 && reg < 24) {
1467            // local registers (in register windows)
1468            if (gwins)
1469                  gwins->wbuf->rw_local[reg - 16] = 0;
# Line 1346 | Line 1479 | static bool sparc_skip_instruction(unsig
1479          }
1480    }
1481  
1349 #if DEBUG
1350  static const char * reg_names[] = {
1351        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1352        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1353        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1354        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1355  };
1356  printf("%s %s register %s\n",
1357                 transfer_size == SIZE_BYTE ? "byte" :
1358                 transfer_size == SIZE_WORD ? "word" :
1359                 transfer_size == SIZE_LONG ? "long" :
1360                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1361                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1362                 reg_names[reg]);
1363 #endif
1364
1482    regs[SPARC_REG_PC] += 4;
1483 +  regs[SPARC_REG_nPC] += 4;
1484    return true;
1485   }
1486   #endif
# Line 1518 | Line 1636 | static bool arm_skip_instruction(unsigne
1636  
1637  
1638   // Fallbacks
1639 + #ifndef SIGSEGV_FAULT_ADDRESS_FAST
1640 + #define SIGSEGV_FAULT_ADDRESS_FAST              SIGSEGV_FAULT_ADDRESS
1641 + #endif
1642 + #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST
1643 + #define SIGSEGV_FAULT_INSTRUCTION_FAST  SIGSEGV_FAULT_INSTRUCTION
1644 + #endif
1645   #ifndef SIGSEGV_FAULT_INSTRUCTION
1646 < #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
1646 > #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_ADDRESS
1647   #endif
1648   #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1
1649   #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST
1650   #endif
1651   #ifndef SIGSEGV_FAULT_HANDLER_INVOKE
1652 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  sigsegv_fault_handler(ADDR, IP)
1652 > #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P)
1653   #endif
1654  
1655   // SIGSEGV recovery supported ?
# Line 1538 | Line 1662 | static bool arm_skip_instruction(unsigne
1662   *  SIGSEGV global handler
1663   */
1664  
1665 + struct sigsegv_info_t {
1666 +        sigsegv_address_t addr;
1667 +        sigsegv_address_t pc;
1668 + #ifdef HAVE_MACH_EXCEPTIONS
1669 +        mach_port_t thread;
1670 +        bool has_exc_state;
1671 +        SIGSEGV_EXCEPTION_STATE_TYPE exc_state;
1672 +        mach_msg_type_number_t exc_state_count;
1673 +        bool has_thr_state;
1674 +        SIGSEGV_THREAD_STATE_TYPE thr_state;
1675 +        mach_msg_type_number_t thr_state_count;
1676 + #endif
1677 + };
1678 +
1679 + #ifdef HAVE_MACH_EXCEPTIONS
1680 + static void mach_get_exception_state(sigsegv_info_t *sip)
1681 + {
1682 +        sip->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT;
1683 +        kern_return_t krc = thread_get_state(sip->thread,
1684 +                                                                                 SIGSEGV_EXCEPTION_STATE_FLAVOR,
1685 +                                                                                 (natural_t *)&sip->exc_state,
1686 +                                                                                 &sip->exc_state_count);
1687 +        MACH_CHECK_ERROR(thread_get_state, krc);
1688 +        sip->has_exc_state = true;
1689 + }
1690 +
1691 + static void mach_get_thread_state(sigsegv_info_t *sip)
1692 + {
1693 +        sip->thr_state_count = SIGSEGV_THREAD_STATE_COUNT;
1694 +        kern_return_t krc = thread_get_state(sip->thread,
1695 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
1696 +                                                                                 (natural_t *)&sip->thr_state,
1697 +                                                                                 &sip->thr_state_count);
1698 +        MACH_CHECK_ERROR(thread_get_state, krc);
1699 +        sip->has_thr_state = true;
1700 + }
1701 +
1702 + static void mach_set_thread_state(sigsegv_info_t *sip)
1703 + {
1704 +        kern_return_t krc = thread_set_state(sip->thread,
1705 +                                                                                 SIGSEGV_THREAD_STATE_FLAVOR,
1706 +                                                                                 (natural_t *)&sip->thr_state,
1707 +                                                                                 sip->thr_state_count);
1708 +        MACH_CHECK_ERROR(thread_set_state, krc);
1709 + }
1710 + #endif
1711 +
1712 + // Return the address of the invalid memory reference
1713 + sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip)
1714 + {
1715 + #ifdef HAVE_MACH_EXCEPTIONS
1716 +        static int use_fast_path = -1;
1717 +        if (use_fast_path != 1 && !sip->has_exc_state) {
1718 +                mach_get_exception_state(sip);
1719 +
1720 +                sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1721 +                if (use_fast_path < 0)
1722 +                        use_fast_path = addr == sip->addr;
1723 +                sip->addr = addr;
1724 +        }
1725 + #endif
1726 +        return sip->addr;
1727 + }
1728 +
1729 + // Return the address of the instruction that caused the fault, or
1730 + // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information
1731 + sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip)
1732 + {
1733 + #ifdef HAVE_MACH_EXCEPTIONS
1734 +        if (!sip->has_thr_state) {
1735 +                mach_get_thread_state(sip);
1736 +
1737 +                sip->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1738 +        }
1739 + #endif
1740 +        return sip->pc;
1741 + }
1742 +
1743   // This function handles the badaccess to memory.
1744   // It is called from the signal handler or the exception handler.
1745   static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1746   {
1747 <        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1748 <        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1749 <        
1747 >        sigsegv_info_t si;
1748 >        si.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST;
1749 >        si.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST;
1750 > #ifdef HAVE_MACH_EXCEPTIONS
1751 >        si.thread = thread;
1752 >        si.has_exc_state = false;
1753 >        si.has_thr_state = false;
1754 > #endif
1755 >        sigsegv_info_t * const sip = &si;
1756 >
1757          // Call user's handler and reinstall the global handler, if required
1758 <        switch (SIGSEGV_FAULT_HANDLER_INVOKE(fault_address, fault_instruction)) {
1758 >        switch (SIGSEGV_FAULT_HANDLER_INVOKE(sip)) {
1759          case SIGSEGV_RETURN_SUCCESS:
1760                  return true;
1761  
# Line 1554 | Line 1763 | static bool handle_badaccess(SIGSEGV_FAU
1763          case SIGSEGV_RETURN_SKIP_INSTRUCTION:
1764                  // Call the instruction skipper with the register file
1765                  // available
1766 + #ifdef HAVE_MACH_EXCEPTIONS
1767 +                if (!sip->has_thr_state)
1768 +                        mach_get_thread_state(sip);
1769 + #endif
1770                  if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) {
1771   #ifdef HAVE_MACH_EXCEPTIONS
1772                          // Unlike UNIX signals where the thread state
1773                          // is modified off of the stack, in Mach we
1774                          // need to actually call thread_set_state to
1775                          // have the register values updated.
1776 <                        kern_return_t krc;
1564 <
1565 <                        krc = thread_set_state(thread,
1566 <                                                                   MACHINE_THREAD_STATE, (thread_state_t)state,
1567 <                                                                   MACHINE_THREAD_STATE_COUNT);
1568 <                        MACH_CHECK_ERROR (thread_get_state, krc);
1776 >                        mach_set_thread_state(sip);
1777   #endif
1778                          return true;
1779                  }
# Line 1574 | Line 1782 | static bool handle_badaccess(SIGSEGV_FAU
1782          case SIGSEGV_RETURN_FAILURE:
1783                  // We can't do anything with the fault_address, dump state?
1784                  if (sigsegv_state_dumper != 0)
1785 <                        sigsegv_state_dumper(fault_address, fault_instruction);
1785 >                        sigsegv_state_dumper(sip);
1786                  break;
1787          }
1788  
# Line 1616 | Line 1824 | forward_exception(mach_port_t thread_por
1824          mach_port_t port;
1825          exception_behavior_t behavior;
1826          thread_state_flavor_t flavor;
1827 <        thread_state_t thread_state;
1827 >        thread_state_data_t thread_state;
1828          mach_msg_type_number_t thread_state_count;
1829  
1830          for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
# Line 1635 | Line 1843 | forward_exception(mach_port_t thread_por
1843          behavior = oldExceptionPorts->behaviors[portIndex];
1844          flavor = oldExceptionPorts->flavors[portIndex];
1845  
1846 +        if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1847 +                fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1848 +                return KERN_FAILURE;
1849 +        }
1850 +
1851          /*
1852           fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1853           */
1854  
1855          if (behavior != EXCEPTION_DEFAULT) {
1856                  thread_state_count = THREAD_STATE_MAX;
1857 <                kret = thread_get_state (thread_port, flavor, thread_state,
1857 >                kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1858                                                                   &thread_state_count);
1859                  MACH_CHECK_ERROR (thread_get_state, kret);
1860          }
# Line 1657 | Line 1870 | forward_exception(mach_port_t thread_por
1870            // fprintf(stderr, "forwarding to exception_raise_state\n");
1871            kret = exception_raise_state(port, exception_type, exception_data,
1872                                                                     data_count, &flavor,
1873 <                                                                   thread_state, thread_state_count,
1874 <                                                                   thread_state, &thread_state_count);
1873 >                                                                   (natural_t *)&thread_state, thread_state_count,
1874 >                                                                   (natural_t *)&thread_state, &thread_state_count);
1875            MACH_CHECK_ERROR (exception_raise_state, kret);
1876            break;
1877          case EXCEPTION_STATE_IDENTITY:
# Line 1666 | Line 1879 | forward_exception(mach_port_t thread_por
1879            kret = exception_raise_state_identity(port, thread_port, task_port,
1880                                                                                          exception_type, exception_data,
1881                                                                                          data_count, &flavor,
1882 <                                                                                        thread_state, thread_state_count,
1883 <                                                                                        thread_state, &thread_state_count);
1882 >                                                                                        (natural_t *)&thread_state, thread_state_count,
1883 >                                                                                        (natural_t *)&thread_state, &thread_state_count);
1884            MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1885            break;
1886          default:
1887            fprintf(stderr, "forward_exception got unknown behavior\n");
1888 +          kret = KERN_FAILURE;
1889            break;
1890          }
1891  
1892          if (behavior != EXCEPTION_DEFAULT) {
1893 <                kret = thread_set_state (thread_port, flavor, thread_state,
1893 >                kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1894                                                                   thread_state_count);
1895                  MACH_CHECK_ERROR (thread_set_state, kret);
1896          }
1897  
1898 <        return KERN_SUCCESS;
1898 >        return kret;
1899   }
1900  
1901   /*
# Line 1709 | Line 1923 | catch_exception_raise(mach_port_t except
1923                                            mach_port_t task,
1924                                            exception_type_t exception,
1925                                            exception_data_t code,
1926 <                                          mach_msg_type_number_t codeCount)
1926 >                                          mach_msg_type_number_t code_count)
1927   {
1714        ppc_thread_state_t state;
1928          kern_return_t krc;
1929  
1930 <        if ((exception == EXC_BAD_ACCESS)  && (codeCount >= 2)) {
1931 <                if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1932 <                        return KERN_SUCCESS;
1930 >        if (exception == EXC_BAD_ACCESS) {
1931 >                switch (code[0]) {
1932 >                case KERN_PROTECTION_FAILURE:
1933 >                case KERN_INVALID_ADDRESS:
1934 >                        if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS))
1935 >                                return KERN_SUCCESS;
1936 >                        break;
1937 >                }
1938          }
1939  
1940          // In Mach we do not need to remove the exception handler.
1941          // If we forward the exception, eventually some exception handler
1942          // will take care of this exception.
1943 <        krc = forward_exception(thread, task, exception, code, codeCount, &ports);
1943 >        krc = forward_exception(thread, task, exception, code, code_count, &ports);
1944  
1945          return krc;
1946   }
# Line 1850 | Line 2068 | static bool sigsegv_do_install_handler(s
2068          // addressing modes) used in PPC instructions, you will need the
2069          // GPR state anyway.
2070          krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
2071 <                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
2071 >                                EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
2072          if (krc != KERN_SUCCESS) {
2073                  mach_error("thread_set_exception_ports", krc);
2074                  return false;
# Line 2034 | Line 2252 | static int page_size;
2252   static volatile char * page = 0;
2253   static volatile int handler_called = 0;
2254  
2255 + /* Barriers */
2256 + #ifdef __GNUC__
2257 + #define BARRIER() asm volatile ("" : : : "memory")
2258 + #else
2259 + #define BARRIER() /* nothing */
2260 + #endif
2261 +
2262   #ifdef __GNUC__
2263   // Code range where we expect the fault to come from
2264   static void *b_region, *e_region;
2265   #endif
2266  
2267 < static sigsegv_return_t sigsegv_test_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2267 > static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip)
2268   {
2269 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2270 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2271   #if DEBUG
2272          printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address);
2273          printf("expected fault at %p\n", page + REF_INDEX);
# Line 2054 | Line 2281 | static sigsegv_return_t sigsegv_test_han
2281   #ifdef __GNUC__
2282          // Make sure reported fault instruction address falls into
2283          // expected code range
2284 <        if (instruction_address != SIGSEGV_INVALID_PC
2284 >        if (instruction_address != SIGSEGV_INVALID_ADDRESS
2285                  && ((instruction_address <  (sigsegv_address_t)b_region) ||
2286                          (instruction_address >= (sigsegv_address_t)e_region)))
2287                  exit(11);
# Line 2065 | Line 2292 | static sigsegv_return_t sigsegv_test_han
2292   }
2293  
2294   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
2295 < static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
2295 > static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip)
2296   {
2297 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
2298 +        const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip);
2299   #if DEBUG
2300          printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
2301   #endif
# Line 2074 | Line 2303 | static sigsegv_return_t sigsegv_insn_han
2303   #ifdef __GNUC__
2304                  // Make sure reported fault instruction address falls into
2305                  // expected code range
2306 <                if (instruction_address != SIGSEGV_INVALID_PC
2306 >                if (instruction_address != SIGSEGV_INVALID_ADDRESS
2307                          && ((instruction_address <  (sigsegv_address_t)b_region) ||
2308                                  (instruction_address >= (sigsegv_address_t)e_region)))
2309                          return SIGSEGV_RETURN_FAILURE;
# Line 2125 | Line 2354 | static bool arch_insn_skipper_tests()
2354                  0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
2355                  0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
2356                  0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
2357 +                0x63, 0x47, 0x04,              // movslq 4(%rdi),%eax
2358 +                0x48, 0x63, 0x47, 0x04,        // movslq 4(%rdi),%rax
2359   #endif
2360                  0                              // end
2361          };
# Line 2168 | Line 2399 | int main(void)
2399          if (page[REF_INDEX] != REF_VALUE)
2400            exit(20);
2401          page[REF_INDEX] = REF_VALUE;
2402 +        BARRIER();
2403   L_e_region1:
2404  
2405          if (handler_called != 1)
# Line 2208 | Line 2440 | int main(void)
2440          TEST_SKIP_INSTRUCTION(signed short);
2441          TEST_SKIP_INSTRUCTION(signed int);
2442          TEST_SKIP_INSTRUCTION(signed long);
2443 +        BARRIER();
2444   L_e_region2:
2445  
2446          if (!arch_insn_skipper_tests())

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines