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, |
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 { |
863 |
|
return false; |
864 |
|
#endif |
865 |
|
|
866 |
+ |
enum instruction_type_t { |
867 |
+ |
i_MOV, |
868 |
+ |
i_ADD |
869 |
+ |
}; |
870 |
+ |
|
871 |
|
transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; |
872 |
|
transfer_size_t transfer_size = SIZE_LONG; |
873 |
+ |
instruction_type_t instruction_type = i_MOV; |
874 |
|
|
875 |
|
int reg = -1; |
876 |
|
int len = 0; |
921 |
|
#endif |
922 |
|
|
923 |
|
// Decode instruction |
924 |
+ |
int op_len = 1; |
925 |
|
int target_size = SIZE_UNKNOWN; |
926 |
|
switch (eip[0]) { |
927 |
|
case 0x0f: |
936 |
|
transfer_size = SIZE_WORD; |
937 |
|
goto do_mov_extend; |
938 |
|
do_mov_extend: |
939 |
< |
switch (eip[2] & 0xc0) { |
940 |
< |
case 0x80: |
941 |
< |
reg = (eip[2] >> 3) & 7; |
942 |
< |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
932 |
< |
break; |
933 |
< |
case 0x40: |
934 |
< |
reg = (eip[2] >> 3) & 7; |
935 |
< |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
936 |
< |
break; |
937 |
< |
case 0x00: |
938 |
< |
reg = (eip[2] >> 3) & 7; |
939 |
< |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
940 |
< |
break; |
941 |
< |
} |
942 |
< |
len += 3 + ix86_step_over_modrm(eip + 2); |
943 |
< |
break; |
944 |
< |
} |
945 |
< |
break; |
939 |
> |
op_len = 2; |
940 |
> |
goto do_transfer_load; |
941 |
> |
} |
942 |
> |
break; |
943 |
|
#if defined(__x86_64__) |
944 |
|
case 0x63: // MOVSXD r64, r/m32 |
945 |
|
if (has_rex && rex.W) { |
950 |
|
transfer_size = SIZE_LONG; |
951 |
|
target_size = SIZE_QUAD; |
952 |
|
} |
953 |
< |
switch (eip[1] & 0xc0) { |
957 |
< |
case 0x80: |
958 |
< |
reg = (eip[1] >> 3) & 7; |
959 |
< |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
960 |
< |
break; |
961 |
< |
case 0x40: |
962 |
< |
reg = (eip[1] >> 3) & 7; |
963 |
< |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
964 |
< |
break; |
965 |
< |
case 0x00: |
966 |
< |
reg = (eip[1] >> 3) & 7; |
967 |
< |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
968 |
< |
break; |
969 |
< |
} |
970 |
< |
len += 2 + ix86_step_over_modrm(eip + 1); |
971 |
< |
break; |
953 |
> |
goto do_transfer_load; |
954 |
|
#endif |
955 |
+ |
case 0x02: // ADD r8, r/m8 |
956 |
+ |
transfer_size = SIZE_BYTE; |
957 |
+ |
case 0x03: // ADD r32, r/m32 |
958 |
+ |
instruction_type = i_ADD; |
959 |
+ |
goto do_transfer_load; |
960 |
|
case 0x8a: // MOV r8, r/m8 |
961 |
|
transfer_size = SIZE_BYTE; |
962 |
|
case 0x8b: // MOV r32, r/m32 (or 16-bit operation) |
963 |
< |
switch (eip[1] & 0xc0) { |
963 |
> |
do_transfer_load: |
964 |
> |
switch (eip[op_len] & 0xc0) { |
965 |
|
case 0x80: |
966 |
< |
reg = (eip[1] >> 3) & 7; |
966 |
> |
reg = (eip[op_len] >> 3) & 7; |
967 |
|
transfer_type = SIGSEGV_TRANSFER_LOAD; |
968 |
|
break; |
969 |
|
case 0x40: |
970 |
< |
reg = (eip[1] >> 3) & 7; |
970 |
> |
reg = (eip[op_len] >> 3) & 7; |
971 |
|
transfer_type = SIGSEGV_TRANSFER_LOAD; |
972 |
|
break; |
973 |
|
case 0x00: |
974 |
< |
reg = (eip[1] >> 3) & 7; |
974 |
> |
reg = (eip[op_len] >> 3) & 7; |
975 |
|
transfer_type = SIGSEGV_TRANSFER_LOAD; |
976 |
|
break; |
977 |
|
} |
978 |
< |
len += 2 + ix86_step_over_modrm(eip + 1); |
978 |
> |
len += 1 + op_len + ix86_step_over_modrm(eip + op_len); |
979 |
|
break; |
980 |
+ |
case 0x00: // ADD r/m8, r8 |
981 |
+ |
transfer_size = SIZE_BYTE; |
982 |
+ |
case 0x01: // ADD r/m32, r32 |
983 |
+ |
instruction_type = i_ADD; |
984 |
+ |
goto do_transfer_store; |
985 |
|
case 0x88: // MOV r/m8, r8 |
986 |
|
transfer_size = SIZE_BYTE; |
987 |
|
case 0x89: // MOV r/m32, r32 (or 16-bit operation) |
988 |
< |
switch (eip[1] & 0xc0) { |
988 |
> |
do_transfer_store: |
989 |
> |
switch (eip[op_len] & 0xc0) { |
990 |
|
case 0x80: |
991 |
< |
reg = (eip[1] >> 3) & 7; |
991 |
> |
reg = (eip[op_len] >> 3) & 7; |
992 |
|
transfer_type = SIGSEGV_TRANSFER_STORE; |
993 |
|
break; |
994 |
|
case 0x40: |
995 |
< |
reg = (eip[1] >> 3) & 7; |
995 |
> |
reg = (eip[op_len] >> 3) & 7; |
996 |
|
transfer_type = SIGSEGV_TRANSFER_STORE; |
997 |
|
break; |
998 |
|
case 0x00: |
999 |
< |
reg = (eip[1] >> 3) & 7; |
999 |
> |
reg = (eip[op_len] >> 3) & 7; |
1000 |
|
transfer_type = SIGSEGV_TRANSFER_STORE; |
1001 |
|
break; |
1002 |
|
} |
1003 |
< |
len += 2 + ix86_step_over_modrm(eip + 1); |
1003 |
> |
len += 1 + op_len + ix86_step_over_modrm(eip + op_len); |
1004 |
|
break; |
1005 |
|
} |
1006 |
|
if (target_size == SIZE_UNKNOWN) |
1016 |
|
reg += 8; |
1017 |
|
#endif |
1018 |
|
|
1019 |
< |
if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) { |
1019 |
> |
if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) { |
1020 |
|
static const int x86_reg_map[] = { |
1021 |
|
X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX, |
1022 |
|
X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI, |
1052 |
|
} |
1053 |
|
|
1054 |
|
#if DEBUG |
1055 |
< |
printf("%08x: %s %s access", regs[X86_REG_EIP], |
1055 |
> |
printf("%p: %s %s access", (void *)regs[X86_REG_EIP], |
1056 |
|
transfer_size == SIZE_BYTE ? "byte" : |
1057 |
|
transfer_size == SIZE_WORD ? "word" : |
1058 |
|
transfer_size == SIZE_LONG ? "long" : |