123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- #include <stdlib.h>
- #include <string.h>
- #include "ia32_invariant.h"
- #include "ia32_insn.h"
- #include "ia32_settings.h"
- extern ia32_table_desc_t *ia32_tables;
- extern ia32_settings_t ia32_settings;
- extern size_t ia32_table_lookup( unsigned char *buf, size_t buf_len,
- unsigned int table, ia32_insn_t **raw_insn,
- unsigned int *prefixes );
- /* -------------------------------- ModR/M, SIB */
- /* Convenience flags */
- #define MODRM_EA 1 /* ModR/M is an effective addr */
- #define MODRM_reg 2 /* ModR/M is a register */
- /* ModR/M flags */
- #define MODRM_RM_SIB 0x04 /* R/M == 100 */
- #define MODRM_RM_NOREG 0x05 /* R/B == 101 */
- /* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
- #define MODRM_MOD_NODISP 0x00 /* mod == 00 */
- #define MODRM_MOD_DISP8 0x01 /* mod == 01 */
- #define MODRM_MOD_DISP32 0x02 /* mod == 10 */
- #define MODRM_MOD_NOEA 0x03 /* mod == 11 */
- /* 16-bit modrm flags */
- #define MOD16_MOD_NODISP 0
- #define MOD16_MOD_DISP8 1
- #define MOD16_MOD_DISP16 2
- #define MOD16_MOD_REG 3
- #define MOD16_RM_BXSI 0
- #define MOD16_RM_BXDI 1
- #define MOD16_RM_BPSI 2
- #define MOD16_RM_BPDI 3
- #define MOD16_RM_SI 4
- #define MOD16_RM_DI 5
- #define MOD16_RM_BP 6
- #define MOD16_RM_BX 7
- /* SIB flags */
- #define SIB_INDEX_NONE 0x04
- #define SIB_BASE_EBP 0x05
- #define SIB_SCALE_NOBASE 0x00
- /* Convenience struct for modR/M bitfield */
- struct modRM_byte {
- unsigned int mod : 2;
- unsigned int reg : 3;
- unsigned int rm : 3;
- };
- /* Convenience struct for SIB bitfield */
- struct SIB_byte {
- unsigned int scale : 2;
- unsigned int index : 3;
- unsigned int base : 3;
- };
- #ifdef WIN32
- static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
- #else
- static inline void byte_decode(unsigned char b, struct modRM_byte *modrm) {
- #endif
- /* generic bitfield-packing routine */
- modrm->mod = b >> 6; /* top 2 bits */
- modrm->reg = (b & 56) >> 3; /* middle 3 bits */
- modrm->rm = b & 7; /* bottom 3 bits */
- }
- static int ia32_invariant_modrm( unsigned char *in, unsigned char *out,
- unsigned int mode_16, x86_invariant_op_t *op) {
- struct modRM_byte modrm;
- struct SIB_byte sib;
- unsigned char *c, *cin;
- unsigned short *s;
- unsigned int *i;
- int size = 0; /* modrm byte is already counted */
- byte_decode(*in, &modrm); /* get bitfields */
- out[0] = in[0]; /* save modrm byte */
- cin = &in[1];
- c = &out[1];
- s = (unsigned short *)&out[1];
- i = (unsigned int *)&out[1];
- op->type = op_expression;
- op->flags.op_pointer = true; //|= op_pointer;
- if ( ! mode_16 && modrm.rm == MODRM_RM_SIB &&
- modrm.mod != MODRM_MOD_NOEA ) {
- size ++;
- byte_decode(*cin, (struct modRM_byte *)(void*)&sib);
- out[1] = in[1]; /* save sib byte */
- cin = &in[2];
- c = &out[2];
- s = (unsigned short *)&out[2];
- i = (unsigned int *)&out[2];
- if ( sib.base == SIB_BASE_EBP && ! modrm.mod ) {
- /* disp 32 is variant! */
- memset( i, X86_WILDCARD_BYTE, 4 );
- size += 4;
- }
- }
- if (! modrm.mod && modrm.rm == 101) {
- if ( mode_16 ) { /* straight RVA in disp */
- memset( s, X86_WILDCARD_BYTE, 2 );
- size += 2;
- } else {
- memset( i, X86_WILDCARD_BYTE, 2 );
- size += 4;
- }
- } else if (modrm.mod && modrm.mod < 3) {
- if (modrm.mod == MODRM_MOD_DISP8) { /* offset in disp */
- *c = *cin;
- size += 1;
- } else if ( mode_16 ) {
- *s = (* ((unsigned short *) cin));
- size += 2;
- } else {
- *i = (*((unsigned int *) cin));
- size += 4;
- }
- } else if ( modrm.mod == 3 ) {
- op->type = op_register;
- op->flags.op_pointer = false;// &= ~op_pointer;
- }
- return (size);
- }
- static int ia32_decode_invariant( unsigned char *buf, size_t /*buf_len*/,
- ia32_insn_t *t, unsigned char *out,
- unsigned int prefixes, x86_invariant_t *inv) {
- unsigned int addr_size, op_size, mode_16;
- unsigned int op_flags[3] = { t->dest_flag, t->src_flag, t->aux_flag };
- int x, type, bytes = 0, size = 0, modrm = 0;
- /* set addressing mode */
- if (ia32_settings.options & opt_16_bit) {
- op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2;
- addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2;
- mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 0 : 1;
- } else {
- op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4;
- addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4;
- mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 1 : 0;
- }
- for (x = 0; x < 3; x++) {
- inv->operands[x].access = (enum x86_op_access) OP_PERM(op_flags[x]);
- inv->operands[x].flags.whole = (OP_FLAGS(op_flags[x]) >> 12);
- //(enum x86_op_flags) (OP_FLAGS(op_flags[x]) >> 12);
- switch (op_flags[x] & OPTYPE_MASK) {
- case OPTYPE_c:
- size = (op_size == 4) ? 2 : 1;
- break;
- case OPTYPE_a: case OPTYPE_v:
- size = (op_size == 4) ? 4 : 2;
- break;
- case OPTYPE_p:
- size = (op_size == 4) ? 6 : 4;
- break;
- case OPTYPE_b:
- size = 1;
- break;
- case OPTYPE_w:
- size = 2;
- break;
- case OPTYPE_d: case OPTYPE_fs: case OPTYPE_fd:
- case OPTYPE_fe: case OPTYPE_fb: case OPTYPE_fv:
- case OPTYPE_si: case OPTYPE_fx:
- size = 4;
- break;
- case OPTYPE_s:
- size = 6;
- break;
- case OPTYPE_q: case OPTYPE_pi:
- size = 8;
- break;
- case OPTYPE_dq: case OPTYPE_ps: case OPTYPE_ss:
- case OPTYPE_pd: case OPTYPE_sd:
- size = 16;
- break;
- case OPTYPE_m:
- size = (addr_size == 4) ? 4 : 2;
- break;
- default:
- break;
- }
- type = op_flags[x] & ADDRMETH_MASK;
- switch (type) {
- case ADDRMETH_E: case ADDRMETH_M: case ADDRMETH_Q:
- case ADDRMETH_R: case ADDRMETH_W:
- modrm = 1;
- bytes += ia32_invariant_modrm( buf, out,
- mode_16, &inv->operands[x]);
- break;
- case ADDRMETH_C: case ADDRMETH_D: case ADDRMETH_G:
- case ADDRMETH_P: case ADDRMETH_S: case ADDRMETH_T:
- case ADDRMETH_V:
- inv->operands[x].type = op_register;
- modrm = 1;
- break;
- case ADDRMETH_A: case ADDRMETH_O:
- /* pad with xF4's */
- memset( &out[bytes + modrm], X86_WILDCARD_BYTE,
- size );
- bytes += size;
- inv->operands[x].type = op_offset;
- if ( type == ADDRMETH_O ) {
- inv->operands[x].flags.op_signed = true;
- inv->operands[x].flags.op_pointer = true;
- }
- break;
- case ADDRMETH_I: case ADDRMETH_J:
- /* grab imm value */
- if ((op_flags[x] & OPTYPE_MASK) == OPTYPE_v) {
- /* assume this is an address */
- memset( &out[bytes + modrm], X86_WILDCARD_BYTE, size );
- } else {
- memcpy( &out[bytes + modrm], &buf[bytes + modrm], size );
- }
-
- bytes += size;
- if ( type == ADDRMETH_J ) {
- if ( size == 1 ) {
- inv->operands[x].type = op_relative_near;
- } else {
- inv->operands[x].type = op_relative_far;
- }
- inv->operands[x].flags.op_signed=true;
- } else {
- inv->operands[x].type = op_immediate;
- }
- break;
- case ADDRMETH_F:
- inv->operands[x].type = op_register;
- break;
- case ADDRMETH_X:
- inv->operands[x].flags.op_signed=true;
- inv->operands[x].flags.op_pointer=true;
- inv->operands[x].flags.op_seg=(x86_op_flags::op_ds_seg)>>8;
- inv->operands[x].flags.op_string=true;
- break;
- case ADDRMETH_Y:
- inv->operands[x].flags.op_signed=true;
- inv->operands[x].flags.op_pointer=true;
- inv->operands[x].flags.op_seg=x86_op_flags::op_es_seg>>8;
- inv->operands[x].flags.op_string=true;
- break;
- case ADDRMETH_RR:
- inv->operands[x].type = op_register;
- break;
- case ADDRMETH_II:
- inv->operands[x].type = op_immediate;
- break;
- default:
- inv->operands[x].type = op_unused;
- break;
- }
- }
- return (bytes + modrm);
- }
- size_t ia32_disasm_invariant( unsigned char * buf, size_t buf_len,
- x86_invariant_t *inv ) {
- ia32_insn_t *raw_insn = NULL;
- unsigned int prefixes=0;
- unsigned int type;
- size_t size;
-
- /* Perform recursive table lookup starting with main table (0) */
- size = ia32_table_lookup( buf, buf_len, 0, &raw_insn, &prefixes );
- if ( size == INVALID_INSN || size > buf_len ) {
- /* TODO: set errno */
- return 0;
- }
- /* copy opcode bytes to buffer */
- memcpy( inv->bytes, buf, size );
- /* set mnemonic type and group */
- type = raw_insn->mnem_flag & ~INS_FLAG_MASK;
- inv->group = (x86_insn_t::x86_insn_group) ((INS_GROUP(type)) >> 12);
- inv->type = (enum x86_insn_type) INS_TYPE(type);
- /* handle operands */
- size += ia32_decode_invariant( buf + size, buf_len - size, raw_insn,
- &buf[size - 1], prefixes, inv );
- inv->size = size;
- return size; /* return size of instruction in bytes */
- }
- size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ) {
- x86_invariant_t inv;
- memset(&inv,0,sizeof(x86_invariant_t));
- return( ia32_disasm_invariant( buf, buf_len, &inv ) );
- }
|