diff --git a/src/arch/i386.h b/src/arch/i386.h index df386c5..ab963d2 100644 --- a/src/arch/i386.h +++ b/src/arch/i386.h @@ -38,6 +38,8 @@ static int _decode_immediate(ArchPlugin * plugin, ArchInstructionCall * call, size_t i); static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call, size_t * i); +static int _decode_modrm_do(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i, uint8_t u8); static int _decode_operand(ArchPlugin * plugin, ArchInstructionCall * call, size_t * i); static int _decode_register(ArchPlugin * plugin, ArchInstructionCall * call, @@ -176,29 +178,84 @@ static int _decode_immediate(ArchPlugin * plugin, ArchInstructionCall * call, static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call, size_t * i) { + int ret = -1; ArchPluginHelper * helper = plugin->helper; - ArchOperand * ao = &call->operands[*i]; + ArchOperand * ao1 = &call->operands[*i]; + ArchOperand * ao2 = NULL; uint8_t u8; - uint32_t uW; /* XXX should be uintW_t */ - ArchRegister * ar; + uint8_t mod; + uint8_t reg; + uint8_t rm; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(\"%s\", &%lu)\n", __func__, call->name, *i); #endif + if(*i + 1 < 3 && (AO_GET_TYPE(call->operands[*i + 1].type) + == AOT_REGISTER + || AO_GET_TYPE(call->operands[*i + 1].type) + == AOT_DREGISTER)) + ao2 = &call->operands[*i + 1]; if(helper->read(helper->arch, &u8, sizeof(u8)) != sizeof(u8)) return -1; - if((u8 & 0xc0) == 0xc0) + mod = (u8 >> 6) & 0x3; + reg = (u8 >> 3) & 0x7; + rm = u8 & 0x7; +#ifdef DEBUG + fprintf(stderr, "DEBUG: u8=0x%02x (%u %u %u)\n", u8, mod, reg, rm); +#endif + if(AO_GET_TYPE(ao1->type) == AOT_DREGISTER && ao2 != NULL + && AO_GET_TYPE(ao2->type) & AOT_REGISTER + && AO_GET_FLAGS(ao2->type) & AOF_I386_MODRM) { - if((ar = helper->get_register_by_id_size(helper->arch, - (u8 & 0x38) >> 3, W)) == NULL) + ret = _decode_modrm_do(plugin, call, (*i)++, + (mod << 6) | (rm << 3)); + ret |= _decode_modrm_do(plugin, call, *i, + (0x3 << 6) | (reg << 3)); + } + else if(AO_GET_TYPE(ao1->type) == AOT_REGISTER && ao2 != NULL + && AO_GET_FLAGS(ao2->type) & AOF_I386_MODRM) + { + ret = _decode_modrm_do(plugin, call, (*i)++, + (0x3 << 6) | (reg << 3)); + ret |= _decode_modrm_do(plugin, call, *i, + (mod << 6) | (rm << 3)); + } + else + /* FIXME really implement */ + ret = _decode_modrm_do(plugin, call, *i, u8); + return ret; +} + +static int _decode_modrm_do(ArchPlugin * plugin, ArchInstructionCall * call, + size_t i, uint8_t u8) +{ + ArchPluginHelper * helper = plugin->helper; + ArchOperand * ao = &call->operands[i]; + uint8_t mod; + uint8_t reg; + uint8_t rm; + ArchRegister * ar; + uintW_t uW; + + mod = (u8 >> 6) & 0x3; + reg = (u8 >> 3) & 0x7; + rm = u8 & 0x7; +#ifdef DEBUG + fprintf(stderr, "DEBUG: u8=0x%02x (%u %u %u) size=%u\n", + u8, mod, reg, rm, AO_GET_SIZE(ao->type)); +#endif + if(mod == 3) + { + if((ar = helper->get_register_by_id_size(helper->arch, reg, + AO_GET_SIZE(ao->type))) == NULL) return -1; ao->type = AO_REGISTER(0, 32, 0); ao->value._register.name = ar->name; } - else if((u8 & 0xc0) == 0x80) + else if(mod == 2) { - if((ar = helper->get_register_by_id_size(helper->arch, - (u8 & 0x38) >> 3, W)) == NULL) + if((ar = helper->get_register_by_id_size(helper->arch, reg, W)) + == NULL) return -1; if(helper->read(helper->arch, &uW, sizeof(uW)) != sizeof(uW)) return -1; @@ -206,28 +263,34 @@ static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call, ao->value.dregister.name = ar->name; ao->value.dregister.offset = _htol32(uW); /* XXX _htolW() */ } - else if((u8 & 0xc0) == 0x40) + else if(mod == 1) { - if((ar = helper->get_register_by_id_size(helper->arch, - (u8 & 0x38) >> 3, W)) == NULL) + if((ar = helper->get_register_by_id_size(helper->arch, reg, W)) + == NULL) return -1; ao->type = AO_DREGISTER(0, 8, W, 0); ao->value.dregister.name = ar->name; } - else if((u8 & 0xc0) == 0x00) + else /* mod == 0 */ { - if((ar = helper->get_register_by_id_size(helper->arch, - (u8 & 0x38) >> 3, W)) == NULL) + if(rm == 5) /* dispW */ + { + /* FIXME SIB byte? */ + if(helper->read(helper->arch, &uW, sizeof(uW)) + != sizeof(uW)) + return -1; + /* FIXME endian */ + ao->type = AO_IMMEDIATE(0, 0, W); + ao->value.immediate.value = uW; + } + else if((ar = helper->get_register_by_id_size(helper->arch, reg, + W)) != NULL) + { + ao->type = AO_DREGISTER(0, 0, W, 0); + ao->value.dregister.name = ar->name; + } + else return -1; - ao->type = AO_DREGISTER(0, 0, W, 0); - ao->value.dregister.name = ar->name; - } - if(AO_GET_TYPE(call->operands[*i + 1].type) != AOT_NONE - && AO_GET_FLAGS(call->operands[*i + 1].type) - & AOF_I386_MODRM) - { - /* FIXME really implement */ - (*i)++; } return 0; } @@ -235,17 +298,21 @@ static int _decode_modrm(ArchPlugin * plugin, ArchInstructionCall * call, static int _decode_operand(ArchPlugin * plugin, ArchInstructionCall * call, size_t * i) { - if(AO_GET_FLAGS(call->operands[*i].type) & AOF_I386_MODRM) - return _decode_modrm(plugin, call, i); - switch(AO_GET_TYPE(call->operands[*i].type)) + ArchOperand * ao = &call->operands[*i]; + + switch(AO_GET_TYPE(ao->type)) { case AOT_CONSTANT: return _decode_constant(plugin, call, *i); case AOT_DREGISTER: + if(AO_GET_FLAGS(ao->type) & AOF_I386_MODRM) + return _decode_modrm(plugin, call, i); return _decode_dregister(plugin, call, *i); case AOT_IMMEDIATE: return _decode_immediate(plugin, call, *i); case AOT_REGISTER: + if(AO_GET_FLAGS(ao->type) & AOF_I386_MODRM) + return _decode_modrm(plugin, call, i); return _decode_register(plugin, call, *i); } return -error_set_code(1, "%s", strerror(ENOSYS)); diff --git a/src/arch/i386.ins b/src/arch/i386.ins index ed72abc..c47cfa2 100644 --- a/src/arch/i386.ins +++ b/src/arch/i386.ins @@ -18,6 +18,7 @@ /* platform-specific */ #if defined(ARCH_i386_real) /* i386 in real mode */ # define W 16 +# define uintW_t uint16_t # define REG_AX_id REG_ax_id # define REG_CX_id REG_cx_id # define REG_DX_id REG_dx_id @@ -28,6 +29,7 @@ # define REG_DI_id REG_di_id #else /* i386 and compatible in 32-bit protected mode */ # define W 32 +# define uintW_t uint32_t # define REG_AX_id REG_eax_id # define REG_CX_id REG_ecx_id # define REG_DX_id REG_edx_id @@ -674,6 +676,8 @@ { "iret", 0xcf, OP1F, AOT_NONE, AOT_NONE, AOT_NONE }, /* IRETD 0xcf 1 */ { "iretd", 0xcf, OP1F, AOT_NONE, AOT_NONE, AOT_NONE }, +/* JAE 0x73 1 rel8 */ +{ "jae", 0x73, OP1F, OP_S8, AOT_NONE, AOT_NONE }, /* JMP 0xeb 1 imm8 */ { "jmp", 0xeb, OP1F, OP_S8, AOT_NONE, AOT_NONE }, /* JMP 0xe9 1 immW */ @@ -683,6 +687,10 @@ { "jmp", 0xff, OP1F, OP_RMW_D8+4,AOT_NONE, AOT_NONE }, { "jmp", 0xff, OP1F, OP_RMW_DW+4,AOT_NONE, AOT_NONE }, { "jmp", 0xff, OP1F, OP_RMW_RW+4,AOT_NONE, AOT_NONE }, +/* JNE 0x75 1 rel8 */ +{ "jne", 0x75, OP1F, OP_S8, AOT_NONE, AOT_NONE }, +/* JO 0x70 1 rel8 */ +{ "jo", 0x70, OP1F, OP_S8, AOT_NONE, AOT_NONE }, /* LAHF 0x9f 1 */ { "lahf", 0x9f, OP1F, AOT_NONE, AOT_NONE, AOT_NONE }, /* LEAVE 0xc9 1 */ @@ -728,6 +736,8 @@ { "mov", 0x8b, OP1F, OP_RW_R, OP_RMW_D8, AOT_NONE }, { "mov", 0x8b, OP1F, OP_RW_R, OP_RMW_DW, AOT_NONE }, { "mov", 0x8b, OP1F, OP_RW_R, OP_RMW_RW, AOT_NONE }, +/* MOV 0xa3 1 AX moffsW */ +{ "mov", 0xa3, OP1F, OP_AX, OP_SW, AOT_NONE }, /* MOV 0xb0 +rb 1 r8 imm8 */ { "mov", 0xb0, OP1F, OP_al, OP_S8, AOT_NONE }, { "mov", 0xb1, OP1F, OP_cl, OP_S8, AOT_NONE }, diff --git a/src/arch/i386.reg b/src/arch/i386.reg index 1ebc068..8cdf9df 100644 --- a/src/arch/i386.reg +++ b/src/arch/i386.reg @@ -26,10 +26,10 @@ REG(eax,32, 0x00) REG(ecx,32, 0x01) REG(edx,32, 0x02) REG(ebx,32, 0x03) -REG(esi,32, 0x04) -REG(edi,32, 0x05) -REG(esp,32, 0x06) -REG(ebp,32, 0x07) +REG(esp,32, 0x04) +REG(ebp,32, 0x05) +REG(esi,32, 0x06) +REG(edi,32, 0x07) #endif /* !ARCH_i386_real */ REG(cr0,32, 0x00) REG(cr1,32, 0x01)