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.45 by gbeauche, 2004-01-21T23:50:06Z vs.
Revision 1.65 by gbeauche, 2007-06-05T13:15:57Z

# 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-2004 Christian Bauer
13 > *  Basilisk II (C) 1997-2005 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  
78 // Transfer type
79 typedef sigsegv_transfer_type_t transfer_type_t;
80
85   #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
86   // Addressing mode
87   enum addressing_mode_t {
# Line 97 | Line 101 | struct instruction_t {
101          char                            ra, rd;
102   };
103  
104 < static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned int * gpr)
104 > static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr)
105   {
106          // Get opcode and divide into fields
107 <        unsigned int opcode = *((unsigned int *)nip);
107 >        unsigned int opcode = *((unsigned int *)(unsigned long)nip);
108          unsigned int primop = opcode >> 26;
109          unsigned int exop = (opcode >> 1) & 0x3ff;
110          unsigned int ra = (opcode >> 16) & 0x1f;
# Line 174 | Line 178 | static void powerpc_decode_instruction(i
178                  transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
179          case 45:        // sthu
180                  transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
181 +        case 58:        // ld, ldu, lwa
182 +                transfer_type = SIGSEGV_TRANSFER_LOAD;
183 +                transfer_size = SIZE_QUAD;
184 +                addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
185 +                imm &= ~3;
186 +                break;
187 +        case 62:        // std, stdu, stq
188 +                transfer_type = SIGSEGV_TRANSFER_STORE;
189 +                transfer_size = SIZE_QUAD;
190 +                addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM;
191 +                imm &= ~3;
192 +                break;
193          }
194          
195          // Calculate effective address
# Line 214 | Line 230 | static void powerpc_decode_instruction(i
230  
231   #if HAVE_SIGINFO_T
232   // Generic extended signal handler
233 < #if defined(__NetBSD__) || defined(__FreeBSD__)
233 > #if defined(__FreeBSD__)
234   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGBUS)
235   #else
236   #define SIGSEGV_ALL_SIGNALS                             FAULT_HANDLER(SIGSEGV)
# Line 228 | 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 244 | 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 < #if defined(__FreeBSD__)
270 > #endif
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 */
275   #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
276   #endif
277   #endif
278 + #if defined(__NetBSD__)
279 + #if (defined(i386) || defined(__i386__))
280 + #include <sys/ucontext.h>
281 + #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.__gregs)
282 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS[_REG_EIP]
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__))
296   #include <sys/ucontext.h>
# Line 274 | Line 313 | static void powerpc_decode_instruction(i
313   #include <sys/ucontext.h>
314   #define SIGSEGV_CONTEXT_REGS                    (((ucontext_t *)scp)->uc_mcontext.regs)
315   #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS->nip)
316 < #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned int *)(SIGSEGV_CONTEXT_REGS->gpr)
316 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr)
317   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
318   #endif
319   #if (defined(hppa) || defined(__hppa__))
# Line 288 | 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 317 | Line 363 | static void powerpc_decode_instruction(i
363   #define SIGSEGV_FAULT_HANDLER_ARGS              sig, scp
364   #define SIGSEGV_FAULT_ADDRESS                   scp->regs->dar
365   #define SIGSEGV_FAULT_INSTRUCTION               scp->regs->nip
366 < #define SIGSEGV_REGISTER_FILE                   (unsigned int *)&scp->regs->nip, (unsigned int *)(scp->regs->gpr)
366 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr)
367   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
368   #endif
369   #if (defined(alpha) || defined(__alpha__))
# Line 481 | Line 527 | static sigsegv_address_t get_fault_addre
527   #endif
528   #endif
529  
530 + #if HAVE_WIN32_EXCEPTIONS
531 + #define WIN32_LEAN_AND_MEAN /* avoid including junk */
532 + #include <windows.h>
533 + #include <winerror.h>
534 +
535 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   EXCEPTION_POINTERS *ExceptionInfo
536 + #define SIGSEGV_FAULT_HANDLER_ARGS              ExceptionInfo
537 + #define SIGSEGV_FAULT_ADDRESS                   ExceptionInfo->ExceptionRecord->ExceptionInformation[1]
538 + #define SIGSEGV_CONTEXT_REGS                    ExceptionInfo->ContextRecord
539 + #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_CONTEXT_REGS->Eip
540 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&SIGSEGV_CONTEXT_REGS->Edi)
541 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
542 + #endif
543 +
544   #if HAVE_MACH_EXCEPTIONS
545  
546   // This can easily be extended to other Mach systems, but really who
# Line 541 | 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_THREAD_STATE_TYPE               ppc_thread_state_t
606 > #define SIGSEGV_THREAD_STATE_FLAVOR             PPC_THREAD_STATE
607 > #define SIGSEGV_THREAD_STATE_COUNT              PPC_THREAD_STATE_COUNT
608 > #define SIGSEGV_FAULT_INSTRUCTION               state->srr0
609   #define SIGSEGV_SKIP_INSTRUCTION                powerpc_skip_instruction
610 < #define SIGSEGV_REGISTER_FILE                   &state->srr0, &state->r0
551 <
552 < // Given a suspended thread, stuff the current instruction and
553 < // registers into state.
554 < //
555 < // It would have been nice to have this be ppc/x86 independant which
556 < // could have been done easily with a thread_state_t instead of
557 < // ppc_thread_state_t, but because of the way this is called it is
558 < // easier to do it this way.
559 < #if (defined(ppc) || defined(__ppc__))
560 < static inline sigsegv_address_t get_fault_instruction(mach_port_t thread, ppc_thread_state_t *state)
561 < {
562 <        kern_return_t krc;
563 <        mach_msg_type_number_t count;
564 <
565 <        count = MACHINE_THREAD_STATE_COUNT;
566 <        krc = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)state, &count);
567 <        MACH_CHECK_ERROR (thread_get_state, krc);
568 <
569 <        return (sigsegv_address_t)state->srr0;
570 < }
610 > #define SIGSEGV_REGISTER_FILE                   (unsigned long *)&state->srr0, (unsigned long *)&state->r0
611   #endif
612 + #ifdef __i386__
613 + #ifdef i386_SAVED_STATE
614 + #define SIGSEGV_THREAD_STATE_TYPE               struct i386_saved_state
615 + #define SIGSEGV_THREAD_STATE_FLAVOR             i386_SAVED_STATE
616 + #define SIGSEGV_THREAD_STATE_COUNT              i386_SAVED_STATE_COUNT
617 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&state->edi) /* EDI is the first GPR we consider */
618 + #else
619 + #define SIGSEGV_THREAD_STATE_TYPE               struct i386_thread_state
620 + #define SIGSEGV_THREAD_STATE_FLAVOR             i386_THREAD_STATE
621 + #define SIGSEGV_THREAD_STATE_COUNT              i386_THREAD_STATE_COUNT
622 + #define SIGSEGV_REGISTER_FILE                   ((unsigned long *)&state->eax) /* EAX is the first GPR we consider */
623 + #endif
624 + #define SIGSEGV_FAULT_INSTRUCTION               state->eip
625 + #define SIGSEGV_SKIP_INSTRUCTION                ix86_skip_instruction
626 + #endif
627 + #define SIGSEGV_FAULT_ADDRESS                   code[1]
628 + #define SIGSEGV_FAULT_HANDLER_INVOKE(ADDR, IP)  ((code[0] == KERN_PROTECTION_FAILURE || code[0] == KERN_INVALID_ADDRESS) ? sigsegv_fault_handler(ADDR, IP) : SIGSEGV_RETURN_FAILURE)
629 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   mach_port_t thread, exception_data_t code, SIGSEGV_THREAD_STATE_TYPE *state
630 + #define SIGSEGV_FAULT_HANDLER_ARGS              thread, code, &state
631  
632   // Since there can only be one exception thread running at any time
633   // this is not a problem.
# Line 658 | Line 717 | enum {
717   #endif
718   };
719   #endif
720 < #if defined(__NetBSD__) || defined(__FreeBSD__)
720 > #if defined(__NetBSD__)
721 > enum {
722 > #if (defined(i386) || defined(__i386__))
723 >        X86_REG_EIP = _REG_EIP,
724 >        X86_REG_EAX = _REG_EAX,
725 >        X86_REG_ECX = _REG_ECX,
726 >        X86_REG_EDX = _REG_EDX,
727 >        X86_REG_EBX = _REG_EBX,
728 >        X86_REG_ESP = _REG_ESP,
729 >        X86_REG_EBP = _REG_EBP,
730 >        X86_REG_ESI = _REG_ESI,
731 >        X86_REG_EDI = _REG_EDI
732 > #endif
733 > };
734 > #endif
735 > #if defined(__FreeBSD__)
736   enum {
737   #if (defined(i386) || defined(__i386__))
738          X86_REG_EIP = 10,
# Line 673 | Line 747 | enum {
747   #endif
748   };
749   #endif
750 + #if defined(__OpenBSD__)
751 + enum {
752 + #if defined(__i386__)
753 +        // EDI is the first register we consider
754 + #define OREG(REG) offsetof(struct sigcontext, sc_##REG)
755 + #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4)
756 +        X86_REG_EIP = DREG(eip), // 7
757 +        X86_REG_EAX = DREG(eax), // 6
758 +        X86_REG_ECX = DREG(ecx), // 5
759 +        X86_REG_EDX = DREG(edx), // 4
760 +        X86_REG_EBX = DREG(ebx), // 3
761 +        X86_REG_ESP = DREG(esp), // 10
762 +        X86_REG_EBP = DREG(ebp), // 2
763 +        X86_REG_ESI = DREG(esi), // 1
764 +        X86_REG_EDI = DREG(edi)  // 0
765 + #undef DREG
766 + #undef OREG
767 + #endif
768 + };
769 + #endif
770 + #if defined(__sun__)
771 + // Same as for Linux, need to check for x86-64
772 + enum {
773 + #if defined(__i386__)
774 +        X86_REG_EIP = EIP,
775 +        X86_REG_EAX = EAX,
776 +        X86_REG_ECX = ECX,
777 +        X86_REG_EDX = EDX,
778 +        X86_REG_EBX = EBX,
779 +        X86_REG_ESP = ESP,
780 +        X86_REG_EBP = EBP,
781 +        X86_REG_ESI = ESI,
782 +        X86_REG_EDI = EDI
783 + #endif
784 + };
785 + #endif
786 + #if defined(__APPLE__) && defined(__MACH__)
787 + enum {
788 + #ifdef i386_SAVED_STATE
789 +        // same as FreeBSD (in Open Darwin 8.0.1)
790 +        X86_REG_EIP = 10,
791 +        X86_REG_EAX = 7,
792 +        X86_REG_ECX = 6,
793 +        X86_REG_EDX = 5,
794 +        X86_REG_EBX = 4,
795 +        X86_REG_ESP = 13,
796 +        X86_REG_EBP = 2,
797 +        X86_REG_ESI = 1,
798 +        X86_REG_EDI = 0
799 + #else
800 +        // new layout (MacOS X 10.4.4 for x86)
801 +        X86_REG_EIP = 10,
802 +        X86_REG_EAX = 0,
803 +        X86_REG_ECX = 2,
804 +        X86_REG_EDX = 4,
805 +        X86_REG_EBX = 1,
806 +        X86_REG_ESP = 7,
807 +        X86_REG_EBP = 6,
808 +        X86_REG_ESI = 5,
809 +        X86_REG_EDI = 4
810 + #endif
811 + };
812 + #endif
813 + #if defined(_WIN32)
814 + enum {
815 + #if (defined(i386) || defined(__i386__))
816 +        X86_REG_EIP = 7,
817 +        X86_REG_EAX = 5,
818 +        X86_REG_ECX = 4,
819 +        X86_REG_EDX = 3,
820 +        X86_REG_EBX = 2,
821 +        X86_REG_ESP = 10,
822 +        X86_REG_EBP = 6,
823 +        X86_REG_ESI = 1,
824 +        X86_REG_EDI = 0
825 + #endif
826 + };
827 + #endif
828   // FIXME: this is partly redundant with the instruction decoding phase
829   // to discover transfer type and register number
830   static inline int ix86_step_over_modrm(unsigned char * p)
# Line 713 | Line 865 | static bool ix86_skip_instruction(unsign
865  
866          if (eip == 0)
867                  return false;
868 + #ifdef _WIN32
869 +        if (IsBadCodePtr((FARPROC)eip))
870 +                return false;
871 + #endif
872          
873 +        enum instruction_type_t {
874 +                i_MOV,
875 +                i_ADD
876 +        };
877 +
878          transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
879          transfer_size_t transfer_size = SIZE_LONG;
880 +        instruction_type_t instruction_type = i_MOV;
881          
882          int reg = -1;
883          int len = 0;
# Line 766 | Line 928 | static bool ix86_skip_instruction(unsign
928   #endif
929  
930          // Decode instruction
931 +        int op_len = 1;
932          int target_size = SIZE_UNKNOWN;
933          switch (eip[0]) {
934          case 0x0f:
# Line 775 | Line 938 | static bool ix86_skip_instruction(unsign
938              case 0xb6: // MOVZX r32, r/m8
939                          transfer_size = SIZE_BYTE;
940                          goto do_mov_extend;
941 +                case 0xbf: // MOVSX r32, r/m16
942              case 0xb7: // MOVZX r32, r/m16
943                          transfer_size = SIZE_WORD;
944                          goto do_mov_extend;
945                    do_mov_extend:
946 <                        switch (eip[2] & 0xc0) {
947 <                        case 0x80:
948 <                                reg = (eip[2] >> 3) & 7;
949 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
950 <                                break;
951 <                        case 0x40:
952 <                                reg = (eip[2] >> 3) & 7;
953 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
954 <                                break;
955 <                        case 0x00:
956 <                                reg = (eip[2] >> 3) & 7;
957 <                                transfer_type = SIGSEGV_TRANSFER_LOAD;
958 <                                break;
959 <                        }
960 <                        len += 3 + ix86_step_over_modrm(eip + 2);
961 <                        break;
962 <            }
963 <          break;
946 >                        op_len = 2;
947 >                        goto do_transfer_load;
948 >                }
949 >                break;
950 > #if defined(__x86_64__)
951 >        case 0x63: // MOVSXD r64, r/m32
952 >                if (has_rex && rex.W) {
953 >                        transfer_size = SIZE_LONG;
954 >                        target_size = SIZE_QUAD;
955 >                }
956 >                else if (transfer_size != SIZE_WORD) {
957 >                        transfer_size = SIZE_LONG;
958 >                        target_size = SIZE_QUAD;
959 >                }
960 >                goto do_transfer_load;
961 > #endif
962 >        case 0x02: // ADD r8, r/m8
963 >                transfer_size = SIZE_BYTE;
964 >        case 0x03: // ADD r32, r/m32
965 >                instruction_type = i_ADD;
966 >                goto do_transfer_load;
967          case 0x8a: // MOV r8, r/m8
968                  transfer_size = SIZE_BYTE;
969          case 0x8b: // MOV r32, r/m32 (or 16-bit operation)
970 <                switch (eip[1] & 0xc0) {
970 >          do_transfer_load:
971 >                switch (eip[op_len] & 0xc0) {
972                  case 0x80:
973 <                        reg = (eip[1] >> 3) & 7;
973 >                        reg = (eip[op_len] >> 3) & 7;
974                          transfer_type = SIGSEGV_TRANSFER_LOAD;
975                          break;
976                  case 0x40:
977 <                        reg = (eip[1] >> 3) & 7;
977 >                        reg = (eip[op_len] >> 3) & 7;
978                          transfer_type = SIGSEGV_TRANSFER_LOAD;
979                          break;
980                  case 0x00:
981 <                        reg = (eip[1] >> 3) & 7;
981 >                        reg = (eip[op_len] >> 3) & 7;
982                          transfer_type = SIGSEGV_TRANSFER_LOAD;
983                          break;
984                  }
985 <                len += 2 + ix86_step_over_modrm(eip + 1);
985 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
986                  break;
987 +        case 0x00: // ADD r/m8, r8
988 +                transfer_size = SIZE_BYTE;
989 +        case 0x01: // ADD r/m32, r32
990 +                instruction_type = i_ADD;
991 +                goto do_transfer_store;
992          case 0x88: // MOV r/m8, r8
993                  transfer_size = SIZE_BYTE;
994          case 0x89: // MOV r/m32, r32 (or 16-bit operation)
995 <                switch (eip[1] & 0xc0) {
995 >          do_transfer_store:
996 >                switch (eip[op_len] & 0xc0) {
997                  case 0x80:
998 <                        reg = (eip[1] >> 3) & 7;
998 >                        reg = (eip[op_len] >> 3) & 7;
999                          transfer_type = SIGSEGV_TRANSFER_STORE;
1000                          break;
1001                  case 0x40:
1002 <                        reg = (eip[1] >> 3) & 7;
1002 >                        reg = (eip[op_len] >> 3) & 7;
1003                          transfer_type = SIGSEGV_TRANSFER_STORE;
1004                          break;
1005                  case 0x00:
1006 <                        reg = (eip[1] >> 3) & 7;
1006 >                        reg = (eip[op_len] >> 3) & 7;
1007                          transfer_type = SIGSEGV_TRANSFER_STORE;
1008                          break;
1009                  }
1010 <                len += 2 + ix86_step_over_modrm(eip + 1);
1010 >                len += 1 + op_len + ix86_step_over_modrm(eip + op_len);
1011                  break;
1012          }
1013          if (target_size == SIZE_UNKNOWN)
# Line 849 | Line 1023 | static bool ix86_skip_instruction(unsign
1023                  reg += 8;
1024   #endif
1025  
1026 <        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1026 >        if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
1027                  static const int x86_reg_map[] = {
1028                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
1029                          X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI,
# Line 885 | Line 1059 | static bool ix86_skip_instruction(unsign
1059          }
1060  
1061   #if DEBUG
1062 <        printf("%08x: %s %s access", regs[X86_REG_EIP],
1062 >        printf("%p: %s %s access", (void *)regs[X86_REG_EIP],
1063                     transfer_size == SIZE_BYTE ? "byte" :
1064                     transfer_size == SIZE_WORD ? "word" :
1065                     transfer_size == SIZE_LONG ? "long" :
# Line 919 | Line 1093 | static bool ix86_skip_instruction(unsign
1093                          "r12", "r13", "r14", "r15",
1094                  };
1095                  const char * reg_str = NULL;
1096 <                switch (transfer_size) {
1096 >                switch (target_size) {
1097                  case SIZE_BYTE:
1098                          reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg];
1099                          break;
# Line 942 | Line 1116 | static bool ix86_skip_instruction(unsign
1116  
1117   // Decode and skip PPC instruction
1118   #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__))
1119 < static bool powerpc_skip_instruction(unsigned int * nip_p, unsigned int * regs)
1119 > static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs)
1120   {
1121          instruction_t instr;
1122          powerpc_decode_instruction(&instr, *nip_p, regs);
# Line 954 | Line 1128 | static bool powerpc_skip_instruction(uns
1128  
1129   #if DEBUG
1130          printf("%08x: %s %s access", *nip_p,
1131 <                   instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
1131 >                   instr.transfer_size == SIZE_BYTE ? "byte" :
1132 >                   instr.transfer_size == SIZE_WORD ? "word" :
1133 >                   instr.transfer_size == SIZE_LONG ? "long" : "quad",
1134                     instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
1135          
1136          if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
# Line 975 | Line 1151 | static bool powerpc_skip_instruction(uns
1151  
1152   // Decode and skip MIPS instruction
1153   #if (defined(mips) || defined(__mips))
1154 < enum {
979 < #if (defined(sgi) || defined(__sgi))
980 <  MIPS_REG_EPC = 35,
981 < #endif
982 < };
983 < static bool mips_skip_instruction(greg_t * regs)
1154 > static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs)
1155   {
1156 <  unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC];
1156 >  unsigned int * epc = (unsigned int *)(unsigned long)*pc_p;
1157  
1158    if (epc == 0)
1159          return false;
# Line 1131 | Line 1302 | static bool mips_skip_instruction(greg_t
1302                   mips_gpr_names[reg]);
1303   #endif
1304  
1305 <  regs[MIPS_REG_EPC] += 4;
1305 >  *pc_p += 4;
1306    return true;
1307   }
1308   #endif
# Line 1143 | Line 1314 | enum {
1314    SPARC_REG_G1 = REG_G1,
1315    SPARC_REG_O0 = REG_O0,
1316    SPARC_REG_PC = REG_PC,
1317 +  SPARC_REG_nPC = REG_nPC
1318   #endif
1319   };
1320   static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin)
# Line 1206 | Line 1378 | static bool sparc_skip_instruction(unsig
1378          break;
1379    case 7: // Store Doubleword
1380          transfer_type = SIGSEGV_TRANSFER_STORE;
1381 <        transfer_size = SIZE_WORD;
1381 >        transfer_size = SIZE_LONG;
1382          register_pair = true;
1383          break;
1384    }
# Line 1216 | Line 1388 | static bool sparc_skip_instruction(unsig
1388          return false;
1389    }
1390  
1219  // Zero target register in case of a load operation
1391    const int reg = (opcode >> 25) & 0x1f;
1392 +
1393 + #if DEBUG
1394 +  static const char * reg_names[] = {
1395 +        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1396 +        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1397 +        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1398 +        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1399 +  };
1400 +  printf("%s %s register %s\n",
1401 +                 transfer_size == SIZE_BYTE ? "byte" :
1402 +                 transfer_size == SIZE_WORD ? "word" :
1403 +                 transfer_size == SIZE_LONG ? "long" :
1404 +                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1405 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1406 +                 reg_names[reg]);
1407 + #endif
1408 +
1409 +  // Zero target register in case of a load operation
1410    if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) {
1411          // FIXME: code to handle local & input registers is not tested
1412 <        if (reg >= 1 && reg <= 7) {
1412 >        if (reg >= 1 && reg < 8) {
1413            // global registers
1414            regs[reg - 1 + SPARC_REG_G1] = 0;
1415          }
1416 <        else if (reg >= 8 && reg <= 15) {
1416 >        else if (reg >= 8 && reg < 16) {
1417            // output registers
1418            regs[reg - 8 + SPARC_REG_O0] = 0;
1419          }
1420 <        else if (reg >= 16 && reg <= 23) {
1420 >        else if (reg >= 16 && reg < 24) {
1421            // local registers (in register windows)
1422            if (gwins)
1423                  gwins->wbuf->rw_local[reg - 16] = 0;
# Line 1244 | Line 1433 | static bool sparc_skip_instruction(unsig
1433          }
1434    }
1435  
1247 #if DEBUG
1248  static const char * reg_names[] = {
1249        "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
1250        "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
1251        "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
1252        "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
1253  };
1254  printf("%s %s register %s\n",
1255                 transfer_size == SIZE_BYTE ? "byte" :
1256                 transfer_size == SIZE_WORD ? "word" :
1257                 transfer_size == SIZE_LONG ? "long" :
1258                 transfer_size == SIZE_QUAD ? "quad" : "unknown",
1259                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1260                 reg_names[reg]);
1261 #endif
1262
1436    regs[SPARC_REG_PC] += 4;
1437 +  regs[SPARC_REG_nPC] += 4;
1438    return true;
1439   }
1440   #endif
# Line 1436 | Line 1610 | static bool arm_skip_instruction(unsigne
1610   *  SIGSEGV global handler
1611   */
1612  
1439 #if defined(HAVE_SIGSEGV_RECOVERY) || defined(HAVE_MACH_EXCEPTIONS)
1613   // This function handles the badaccess to memory.
1614   // It is called from the signal handler or the exception handler.
1615   static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1)
1616   {
1617 + #ifdef HAVE_MACH_EXCEPTIONS
1618 +        // We must match the initial count when writing back the CPU state registers
1619 +        kern_return_t krc;
1620 +        mach_msg_type_number_t count;
1621 +
1622 +        count = SIGSEGV_THREAD_STATE_COUNT;
1623 +        krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
1624 +        MACH_CHECK_ERROR (thread_get_state, krc);
1625 + #endif
1626 +
1627          sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
1628          sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
1629          
# Line 1459 | Line 1642 | static bool handle_badaccess(SIGSEGV_FAU
1642                          // is modified off of the stack, in Mach we
1643                          // need to actually call thread_set_state to
1644                          // have the register values updated.
1462                        kern_return_t krc;
1463
1645                          krc = thread_set_state(thread,
1646 <                                                                   MACHINE_THREAD_STATE, (thread_state_t)state,
1647 <                                                                   MACHINE_THREAD_STATE_COUNT);
1648 <                        MACH_CHECK_ERROR (thread_get_state, krc);
1646 >                                                                   SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
1647 >                                                                   count);
1648 >                        MACH_CHECK_ERROR (thread_set_state, krc);
1649   #endif
1650                          return true;
1651                  }
1652                  break;
1653   #endif
1654          case SIGSEGV_RETURN_FAILURE:
1655 <                return false;
1655 >                // We can't do anything with the fault_address, dump state?
1656 >                if (sigsegv_state_dumper != 0)
1657 >                        sigsegv_state_dumper(fault_address, fault_instruction);
1658 >                break;
1659          }
1476        
1477        // We can't do anything with the fault_address, dump state?
1478        if (sigsegv_state_dumper != 0)
1479                sigsegv_state_dumper(fault_address, fault_instruction);
1660  
1661          return false;
1662   }
1483 #endif
1663  
1664  
1665   /*
# Line 1517 | Line 1696 | forward_exception(mach_port_t thread_por
1696          mach_port_t port;
1697          exception_behavior_t behavior;
1698          thread_state_flavor_t flavor;
1699 <        thread_state_t thread_state;
1699 >        thread_state_data_t thread_state;
1700          mach_msg_type_number_t thread_state_count;
1701  
1702          for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
# Line 1536 | Line 1715 | forward_exception(mach_port_t thread_por
1715          behavior = oldExceptionPorts->behaviors[portIndex];
1716          flavor = oldExceptionPorts->flavors[portIndex];
1717  
1718 +        if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
1719 +                fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
1720 +                return KERN_FAILURE;
1721 +        }
1722 +
1723          /*
1724           fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
1725           */
1726  
1727          if (behavior != EXCEPTION_DEFAULT) {
1728                  thread_state_count = THREAD_STATE_MAX;
1729 <                kret = thread_get_state (thread_port, flavor, thread_state,
1729 >                kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
1730                                                                   &thread_state_count);
1731                  MACH_CHECK_ERROR (thread_get_state, kret);
1732          }
# Line 1558 | Line 1742 | forward_exception(mach_port_t thread_por
1742            // fprintf(stderr, "forwarding to exception_raise_state\n");
1743            kret = exception_raise_state(port, exception_type, exception_data,
1744                                                                     data_count, &flavor,
1745 <                                                                   thread_state, thread_state_count,
1746 <                                                                   thread_state, &thread_state_count);
1745 >                                                                   (natural_t *)&thread_state, thread_state_count,
1746 >                                                                   (natural_t *)&thread_state, &thread_state_count);
1747            MACH_CHECK_ERROR (exception_raise_state, kret);
1748            break;
1749          case EXCEPTION_STATE_IDENTITY:
# Line 1567 | Line 1751 | forward_exception(mach_port_t thread_por
1751            kret = exception_raise_state_identity(port, thread_port, task_port,
1752                                                                                          exception_type, exception_data,
1753                                                                                          data_count, &flavor,
1754 <                                                                                        thread_state, thread_state_count,
1755 <                                                                                        thread_state, &thread_state_count);
1754 >                                                                                        (natural_t *)&thread_state, thread_state_count,
1755 >                                                                                        (natural_t *)&thread_state, &thread_state_count);
1756            MACH_CHECK_ERROR (exception_raise_state_identity, kret);
1757            break;
1758          default:
1759            fprintf(stderr, "forward_exception got unknown behavior\n");
1760 +          kret = KERN_FAILURE;
1761            break;
1762          }
1763  
1764          if (behavior != EXCEPTION_DEFAULT) {
1765 <                kret = thread_set_state (thread_port, flavor, thread_state,
1765 >                kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
1766                                                                   thread_state_count);
1767                  MACH_CHECK_ERROR (thread_set_state, kret);
1768          }
1769  
1770 <        return KERN_SUCCESS;
1770 >        return kret;
1771   }
1772  
1773   /*
# Line 1612 | Line 1797 | catch_exception_raise(mach_port_t except
1797                                            exception_data_t code,
1798                                            mach_msg_type_number_t codeCount)
1799   {
1800 <        ppc_thread_state_t state;
1800 >        SIGSEGV_THREAD_STATE_TYPE state;
1801          kern_return_t krc;
1802  
1803          if ((exception == EXC_BAD_ACCESS)  && (codeCount >= 2)) {
# Line 1751 | Line 1936 | static bool sigsegv_do_install_handler(s
1936          // addressing modes) used in PPC instructions, you will need the
1937          // GPR state anyway.
1938          krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
1939 <                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
1939 >                                EXCEPTION_DEFAULT, SIGSEGV_THREAD_STATE_FLAVOR);
1940          if (krc != KERN_SUCCESS) {
1941                  mach_error("thread_set_exception_ports", krc);
1942                  return false;
# Line 1774 | Line 1959 | static bool sigsegv_do_install_handler(s
1959   }
1960   #endif
1961  
1962 + #ifdef HAVE_WIN32_EXCEPTIONS
1963 + static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo)
1964 + {
1965 +        if (sigsegv_fault_handler != NULL
1966 +                && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
1967 +                && ExceptionInfo->ExceptionRecord->NumberParameters == 2
1968 +                && handle_badaccess(ExceptionInfo))
1969 +                return EXCEPTION_CONTINUE_EXECUTION;
1970 +
1971 +        return EXCEPTION_CONTINUE_SEARCH;
1972 + }
1973 +
1974 + #if defined __CYGWIN__ && defined __i386__
1975 + /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin
1976 +   installs a global exception handler.  We have to dig deep in order to install
1977 +   our main_exception_filter.  */
1978 +
1979 + /* Data structures for the current thread's exception handler chain.
1980 +   On the x86 Windows uses register fs, offset 0 to point to the current
1981 +   exception handler; Cygwin mucks with it, so we must do the same... :-/ */
1982 +
1983 + /* Magic taken from winsup/cygwin/include/exceptions.h.  */
1984 +
1985 + struct exception_list {
1986 +    struct exception_list *prev;
1987 +    int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
1988 + };
1989 + typedef struct exception_list exception_list;
1990 +
1991 + /* Magic taken from winsup/cygwin/exceptions.cc.  */
1992 +
1993 + __asm__ (".equ __except_list,0");
1994 +
1995 + extern exception_list *_except_list __asm__ ("%fs:__except_list");
1996 +
1997 + /* For debugging.  _except_list is not otherwise accessible from gdb.  */
1998 + static exception_list *
1999 + debug_get_except_list ()
2000 + {
2001 +  return _except_list;
2002 + }
2003 +
2004 + /* Cygwin's original exception handler.  */
2005 + static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
2006 +
2007 + /* Our exception handler.  */
2008 + static int
2009 + libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch)
2010 + {
2011 +  EXCEPTION_POINTERS ExceptionInfo;
2012 +  ExceptionInfo.ExceptionRecord = exception;
2013 +  ExceptionInfo.ContextRecord = context;
2014 +  if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH)
2015 +    return cygwin_exception_handler (exception, frame, context, dispatch);
2016 +  else
2017 +    return 0;
2018 + }
2019 +
2020 + static void
2021 + do_install_main_exception_filter ()
2022 + {
2023 +  /* We cannot insert any handler into the chain, because such handlers
2024 +     must lie on the stack (?).  Instead, we have to replace(!) Cygwin's
2025 +     global exception handler.  */
2026 +  cygwin_exception_handler = _except_list->handler;
2027 +  _except_list->handler = libsigsegv_exception_handler;
2028 + }
2029 +
2030 + #else
2031 +
2032 + static void
2033 + do_install_main_exception_filter ()
2034 + {
2035 +  SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter);
2036 + }
2037 + #endif
2038 +
2039 + static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
2040 + {
2041 +        static bool main_exception_filter_installed = false;
2042 +        if (!main_exception_filter_installed) {
2043 +                do_install_main_exception_filter();
2044 +                main_exception_filter_installed = true;
2045 +        }
2046 +        sigsegv_fault_handler = handler;
2047 +        return true;
2048 + }
2049 + #endif
2050 +
2051   bool sigsegv_install_handler(sigsegv_fault_handler_t handler)
2052   {
2053   #if defined(HAVE_SIGSEGV_RECOVERY)
# Line 1784 | Line 2058 | bool sigsegv_install_handler(sigsegv_fau
2058          if (success)
2059              sigsegv_fault_handler = handler;
2060          return success;
2061 < #elif defined(HAVE_MACH_EXCEPTIONS)
2061 > #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS)
2062          return sigsegv_do_install_handler(handler);
2063   #else
2064          // FAIL: no siginfo_t nor sigcontext subterfuge is available
# Line 1810 | Line 2084 | void sigsegv_deinstall_handler(void)
2084          SIGSEGV_ALL_SIGNALS
2085   #undef FAULT_HANDLER
2086   #endif
2087 + #ifdef HAVE_WIN32_EXCEPTIONS
2088 +        sigsegv_fault_handler = NULL;
2089 + #endif
2090   }
2091  
2092  
# Line 1831 | Line 2108 | void sigsegv_set_dump_state(sigsegv_stat
2108   #include <stdio.h>
2109   #include <stdlib.h>
2110   #include <fcntl.h>
2111 + #ifdef HAVE_SYS_MMAN_H
2112   #include <sys/mman.h>
2113 + #endif
2114   #include "vm_alloc.h"
2115  
2116   const int REF_INDEX = 123;
# Line 1841 | Line 2120 | static int page_size;
2120   static volatile char * page = 0;
2121   static volatile int handler_called = 0;
2122  
2123 + /* Barriers */
2124 + #ifdef __GNUC__
2125 + #define BARRIER() asm volatile ("" : : : "memory")
2126 + #else
2127 + #define BARRIER() /* nothing */
2128 + #endif
2129 +
2130   #ifdef __GNUC__
2131   // Code range where we expect the fault to come from
2132   static void *b_region, *e_region;
# Line 1932 | Line 2218 | static bool arch_insn_skipper_tests()
2218                  0x4c, 0x89, 0x18,              // mov    %r11,(%rax)
2219                  0x4a, 0x89, 0x0c, 0x10,        // mov    %rcx,(%rax,%r10,1)
2220                  0x4e, 0x89, 0x1c, 0x10,        // mov    %r11,(%rax,%r10,1)
2221 +                0x63, 0x47, 0x04,              // movslq 4(%rdi),%eax
2222 +                0x48, 0x63, 0x47, 0x04,        // movslq 4(%rdi),%rax
2223   #endif
2224                  0                              // end
2225          };
# Line 1955 | Line 2243 | int main(void)
2243          if (vm_init() < 0)
2244                  return 1;
2245  
2246 <        page_size = getpagesize();
2246 >        page_size = vm_get_page_size();
2247          if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED)
2248                  return 2;
2249          
# Line 1975 | Line 2263 | int main(void)
2263          if (page[REF_INDEX] != REF_VALUE)
2264            exit(20);
2265          page[REF_INDEX] = REF_VALUE;
2266 +        BARRIER();
2267   L_e_region1:
2268  
2269          if (handler_called != 1)
# Line 2015 | Line 2304 | int main(void)
2304          TEST_SKIP_INSTRUCTION(signed short);
2305          TEST_SKIP_INSTRUCTION(signed int);
2306          TEST_SKIP_INSTRUCTION(signed long);
2307 +        BARRIER();
2308   L_e_region2:
2309  
2310          if (!arch_insn_skipper_tests())

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines