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.57 by gbeauche, 2006-01-22T00:05:05Z vs.
Revision 1.74 by gbeauche, 2008-01-06T16:19:27Z

# 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 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 591 | Line 602 | if (ret != KERN_SUCCESS) { \
602   }
603  
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               state->srr0
612 > #define SIGSEGV_FAULT_INSTRUCTION               SIP->thr_state.srr0
613   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
614 < #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&state->srr0, (unsigned long *)&state->r0
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 < #ifdef i386_SAVED_STATE
630 < #define SIGSEGV_THREAD_STATE_TYPE               struct i386_saved_state
631 < #define SIGSEGV_THREAD_STATE_FLAVOR             i386_SAVED_STATE
632 < #define SIGSEGV_THREAD_STATE_COUNT              i386_SAVED_STATE_COUNT
606 < #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&state->edi) /* EDI is the first GPR we consider */
607 < #else
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_REGISTER_FILE                   ((unsigned long *)&state->eax) /* EAX is the first GPR we consider */
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 < #define SIGSEGV_FAULT_INSTRUCTION               state->eip
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                   code[1]
653 < #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
654 < #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, SIGSEGV_THREAD_STATE_TYPE *state
655 < #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
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 774 | Line 810 | enum {
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,
# Line 790 | Line 827 | enum {
827          X86_REG_EIP = 10,
828          X86_REG_EAX = 0,
829          X86_REG_ECX = 2,
830 <        X86_REG_EDX = 4,
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)
# Line 859 | 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 911 | 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 925 | 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 995 | 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 1031 | 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 1087 | 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 1123 | Line 1197 | static bool powerpc_skip_instruction(uns
1197  
1198   // Decode and skip MIPS instruction
1199   #if (defined(mips) || defined(__mips))
1200 < enum {
1127 < #if (defined(sgi) || defined(__sgi))
1128 <  MIPS_REG_EPC = 35,
1129 < #endif
1130 < };
1131 < 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 1279 | 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 1291 | 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 1354 | 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 1364 | Line 1434 | static bool sparc_skip_instruction(unsig
1434          return false;
1435    }
1436  
1367  // 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 1392 | Line 1479 | static bool sparc_skip_instruction(unsig
1479          }
1480    }
1481  
1395 #if DEBUG
1396  static const char * reg_names[] = {
1397        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1398        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1399        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1400        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1401  };
1402  printf("%s %s register %s\n",
1403                 transfer_size == SIZE_BYTE ? "byte" :
1404                 transfer_size == SIZE_WORD ? "word" :
1405                 transfer_size == SIZE_LONG ? "long" :
1406                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1407                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1408                 reg_names[reg]);
1409 #endif
1410
1482    regs[SPARC_REG_PC] += 4;
1483 +  regs[SPARC_REG_nPC] += 4;
1484    return true;
1485   }
1486   #endif
# Line 1564 | 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 1584 | 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_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 <        // We must match the initial count when writing back the CPU state registers
1752 <        kern_return_t krc;
1753 <        mach_msg_type_number_t count;
1595 <
1596 <        count = SIGSEGV_THREAD_STATE_COUNT;
1597 <        krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
1598 <        MACH_CHECK_ERROR (thread_get_state, krc);
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  
1601        sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1602        sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1603        
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 1610 | 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 <                        krc = thread_set_state(thread,
1620 <                                                                   SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
1621 <                                                                   count);
1622 <                        MACH_CHECK_ERROR (thread_set_state, krc);
1776 >                        mach_set_thread_state(SIP);
1777   #endif
1778                          return true;
1779                  }
# Line 1628 | 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 1689 | 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 1711 | 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 1720 | 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 1763 | 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   {
1768        SIGSEGV_THREAD_STATE_TYPE 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 2088 | 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 2108 | 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 2119 | 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 2128 | 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 2179 | 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 2212 | Line 2389 | int main(void)
2389          
2390          if (!sigsegv_install_handler(sigsegv_test_handler))
2391                  return 4;
2392 <        
2392 >
2393   #ifdef __GNUC__
2394          b_region = &&L_b_region1;
2395          e_region = &&L_e_region1;
2396   #endif
2397 < L_b_region1:
2398 <        page[REF_INDEX] = REF_VALUE;
2399 <        if (page[REF_INDEX] != REF_VALUE)
2400 <          exit(20);
2401 <        page[REF_INDEX] = REF_VALUE;
2402 < L_e_region1:
2397 >        /* This is a really awful hack but otherwise gcc is smart enough
2398 >         * (or bug'ous enough?) to optimize the labels and place them
2399 >         * e.g. at the "main" entry point, which is wrong.
2400 >         */
2401 >        volatile int label_hack = 1;
2402 >        switch (label_hack) {
2403 >        case 1:
2404 >        L_b_region1:
2405 >                page[REF_INDEX] = REF_VALUE;
2406 >                if (page[REF_INDEX] != REF_VALUE)
2407 >                        exit(20);
2408 >                page[REF_INDEX] = REF_VALUE;
2409 >                BARRIER();
2410 >                // fall-through
2411 >        case 2:
2412 >        L_e_region1:
2413 >                BARRIER();
2414 >                break;
2415 >        }
2416  
2417          if (handler_called != 1)
2418                  return 5;
# Line 2253 | Line 2443 | int main(void)
2443          b_region = &&L_b_region2;
2444          e_region = &&L_e_region2;
2445   #endif
2446 < L_b_region2:
2447 <        TEST_SKIP_INSTRUCTION(unsigned char);
2448 <        TEST_SKIP_INSTRUCTION(unsigned short);
2449 <        TEST_SKIP_INSTRUCTION(unsigned int);
2450 <        TEST_SKIP_INSTRUCTION(unsigned long);
2451 <        TEST_SKIP_INSTRUCTION(signed char);
2452 <        TEST_SKIP_INSTRUCTION(signed short);
2453 <        TEST_SKIP_INSTRUCTION(signed int);
2454 <        TEST_SKIP_INSTRUCTION(signed long);
2455 < L_e_region2:
2456 <
2446 >        switch (label_hack) {
2447 >        case 1:
2448 >        L_b_region2:
2449 >                TEST_SKIP_INSTRUCTION(unsigned char);
2450 >                TEST_SKIP_INSTRUCTION(unsigned short);
2451 >                TEST_SKIP_INSTRUCTION(unsigned int);
2452 >                TEST_SKIP_INSTRUCTION(unsigned long);
2453 >                TEST_SKIP_INSTRUCTION(signed char);
2454 >                TEST_SKIP_INSTRUCTION(signed short);
2455 >                TEST_SKIP_INSTRUCTION(signed int);
2456 >                TEST_SKIP_INSTRUCTION(signed long);
2457 >                BARRIER();
2458 >                // fall-through
2459 >        case 2:
2460 >        L_e_region2:
2461 >                BARRIER();
2462 >                break;
2463 >        }
2464          if (!arch_insn_skipper_tests())
2465                  return 20;
2466   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines