static int resolve_mode( struct ud* u ) { /* if in error state, bail out */ if ( u->error ) return -1; /* propagate prefix effects */ if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */ /* Check validity of instruction m64 */ if ( P_INV64( u->itab_entry->prefix ) ) { u->error = 1; return -1; } /* effective rex prefix is the effective mask for the * instruction hard-coded in the opcode map. */ u->pfx_rex = ( u->pfx_rex & 0x40 ) | ( u->pfx_rex & REX_PFX_MASK( u->itab_entry->prefix ) ); /* whether this instruction has a default operand size of * 64bit, also hardcoded into the opcode map. */ u->default64 = P_DEF64( u->itab_entry->prefix ); /* calculate effective operand size */ if ( REX_W( u->pfx_rex ) ) { u->opr_mode = 64; } else if ( u->pfx_opr ) { u->opr_mode = 16; } else { /* unless the default opr size of instruction is 64, * the effective operand size in the absence of rex.w * prefix is 32. */ u->opr_mode = ( u->default64 ) ? 64 : 32; } /* calculate effective address size */ u->adr_mode = (u->pfx_adr) ? 32 : 64; } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */ u->opr_mode = ( u->pfx_opr ) ? 16 : 32; u->adr_mode = ( u->pfx_adr ) ? 16 : 32; } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */ u->opr_mode = ( u->pfx_opr ) ? 32 : 16; u->adr_mode = ( u->pfx_adr ) ? 32 : 16; } /* These flags determine which operand to apply the operand size * cast to. */ u->c1 = ( P_C1( u->itab_entry->prefix ) ) ? 1 : 0; u->c2 = ( P_C2( u->itab_entry->prefix ) ) ? 1 : 0; u->c3 = ( P_C3( u->itab_entry->prefix ) ) ? 1 : 0; /* set flags for implicit addressing */ u->implicit_addr = P_IMPADDR( u->itab_entry->prefix ); return 0; }
/* * decode_ext() * * Decode opcode extensions (if any) */ static int decode_ext(struct ud *u, uint16_t ptr) { uint8_t idx = 0; if ((ptr & 0x8000) == 0) { return decode_insn(u, ptr); } u->le = &ud_lookup_table_list[(~0x8000 & ptr)]; if (u->le->type == UD_TAB__OPC_3DNOW) { return decode_3dnow(u); } switch (u->le->type) { case UD_TAB__OPC_MOD: /* !11 = 0, 11 = 1 */ idx = (MODRM_MOD(modrm(u)) + 1) / 4; break; /* disassembly mode/operand size/address size based tables. * 16 = 0,, 32 = 1, 64 = 2 */ case UD_TAB__OPC_MODE: idx = u->dis_mode / 32; break; case UD_TAB__OPC_OSIZE: idx = eff_opr_mode(u->dis_mode, REX_W(u->pfx_rex), u->pfx_opr) / 32; break; case UD_TAB__OPC_ASIZE: idx = eff_adr_mode(u->dis_mode, u->pfx_adr) / 32; break; case UD_TAB__OPC_X87: idx = modrm(u) - 0xC0; break; case UD_TAB__OPC_VENDOR: if (u->vendor == UD_VENDOR_ANY) { /* choose a valid entry */ idx = (u->le->table[idx] != 0) ? 0 : 1; } else if (u->vendor == UD_VENDOR_AMD) { idx = 0; } else { idx = 1; } break; case UD_TAB__OPC_RM: idx = MODRM_RM(modrm(u)); break; case UD_TAB__OPC_REG: idx = MODRM_REG(modrm(u)); break; case UD_TAB__OPC_SSE: return decode_ssepfx(u); default: assert(!"not reached"); break; } return decode_ext(u, u->le->table[idx]); }
static int resolve_mode( struct ud* u ) { int default64; /* if in error state, bail out */ if ( u->error ) return -1; /* propagate prefix effects */ if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */ /* Check validity of instruction m64 */ if ( P_INV64( u->itab_entry->prefix ) ) { UDERR(u, "instruction invalid in 64bits\n"); return -1; } /* effective rex prefix is the effective mask for the * instruction hard-coded in the opcode map. */ u->pfx_rex = ( u->pfx_rex & 0x40 ) | ( u->pfx_rex & REX_PFX_MASK( u->itab_entry->prefix ) ); /* whether this instruction has a default operand size of * 64bit, also hardcoded into the opcode map. */ default64 = P_DEF64( u->itab_entry->prefix ); /* calculate effective operand size */ if ( REX_W( u->pfx_rex ) ) { u->opr_mode = 64; } else if ( u->pfx_opr ) { u->opr_mode = 16; } else { /* unless the default opr size of instruction is 64, * the effective operand size in the absence of rex.w * prefix is 32. */ u->opr_mode = default64 ? 64 : 32; } /* calculate effective address size */ u->adr_mode = (u->pfx_adr) ? 32 : 64; } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */ u->opr_mode = ( u->pfx_opr ) ? 16 : 32; u->adr_mode = ( u->pfx_adr ) ? 16 : 32; } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */ u->opr_mode = ( u->pfx_opr ) ? 32 : 16; u->adr_mode = ( u->pfx_adr ) ? 32 : 16; } return 0; }
/* ----------------------------------------------------------------------------- * resolve_gpr64() - 64bit General Purpose Register-Selection. * ----------------------------------------------------------------------------- */ static enum ud_type resolve_gpr64(struct ud* u, enum ud_operand_code gpr_op) { if (gpr_op >= OP_rAXr8 && gpr_op <= OP_rDIr15) gpr_op = (gpr_op - OP_rAXr8) | (REX_B(u->pfx_rex) << 3); else gpr_op = (gpr_op - OP_rAX); if (u->opr_mode == 16) return gpr_op + UD_R_AX; if (u->dis_mode == 32 || (u->opr_mode == 32 && ! (REX_W(u->pfx_rex) || u->default64))) { return gpr_op + UD_R_EAX; } return gpr_op + UD_R_RAX; }
/* * Disassemble instruction at 'loc'. 'altfmt' specifies an * (optional) alternate format. Return address of start of * next instruction. */ db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt) { int inst; int size; int short_addr; char * seg; struct inst * ip; char * i_name; int i_size; int i_mode; int regmodrm = 0; boolean_t first; int displ; int prefix; long imm; int imm2; int len; int rex = 0; int segovr_grp; int repe, repne; struct i_addr address; db_addr_t loc_orig = loc; char tmpfmt[28]; get_value_inc(inst, loc, 1, FALSE); short_addr = FALSE; size = LONG; seg = 0; segovr_grp = 0; repe = 0; repne = 0; /* * Get prefixes */ prefix = TRUE; do { switch (inst) { case 0x66: /* data16 */ size = WORD; break; case 0x67: short_addr = TRUE; break; case 0x26: segovr_grp++; db_printf(" <segment override prefix ignored>"); break; case 0x36: db_printf(" <segment override prefix ignored>"); segovr_grp++; break; case 0x2e: db_printf(" <segment override prefix ignored>"); segovr_grp++; break; case 0x3e: db_printf(" <segment override prefix ignored>"); segovr_grp++; break; case 0x64: segovr_grp++; seg = "%fs"; break; case 0x65: segovr_grp++; seg = "%gs"; break; case 0xf0: db_printf("lock "); break; case 0xf2: repne++; break; case 0xf3: repe++; break; default: prefix = FALSE; break; } if (prefix) get_value_inc(inst, loc, 1, FALSE); } while (prefix); if (segovr_grp > 1) seg = "<bad segment override prefix combination> "; if (repe > 0 && repne > 0) db_printf("<bad repeat prefex combination> "); else if (repe > 0) db_printf("repe "); /* XXX "rep" if not CMPSx or SCASx */ else if (repne > 0) db_printf("repne "); if (inst >= 0x40 && inst <= 0x4f) { // rex page 14 rex = inst; if (REX_W(rex)) size = QUAD; get_value_inc(inst, loc, 1, FALSE); } if (inst >= 0xd8 && inst <= 0xdf) { loc = db_disasm_esc(loc, inst, short_addr, size, rex, seg); goto done; } if (inst == 0x0f) { get_value_inc(inst, loc, 1, FALSE); if (inst == 0x0f) { loc = db_disasm_3dnow(loc, short_addr, size, rex, seg); goto done; } ip = db_inst_0f[inst>>4]; if (ip == 0) ip = &db_bad_inst; else ip = &ip[inst&0xf]; } else {
/* Extracts instruction prefixes. */ static int get_prefixes( struct ud* u ) { unsigned int have_pfx = 1; unsigned int i; uint8_t curr; /* if in error state, bail out */ if ( u->error ) return -1; /* keep going as long as there are prefixes available */ for ( i = 0; have_pfx ; ++i ) { /* Get next byte. */ inp_next(u); if ( u->error ) return -1; curr = inp_curr( u ); /* rex prefixes in 64bit mode */ if ( u->dis_mode == 64 && ( curr & 0xF0 ) == 0x40 ) { u->pfx_rex = curr; } else { switch ( curr ) { case 0x2E : u->pfx_seg = UD_R_CS; u->pfx_rex = 0; break; case 0x36 : u->pfx_seg = UD_R_SS; u->pfx_rex = 0; break; case 0x3E : u->pfx_seg = UD_R_DS; u->pfx_rex = 0; break; case 0x26 : u->pfx_seg = UD_R_ES; u->pfx_rex = 0; break; case 0x64 : u->pfx_seg = UD_R_FS; u->pfx_rex = 0; break; case 0x65 : u->pfx_seg = UD_R_GS; u->pfx_rex = 0; break; case 0x67 : /* adress-size override prefix */ u->pfx_adr = 0x67; u->pfx_rex = 0; break; case 0xF0 : u->pfx_lock = 0xF0; u->pfx_rex = 0; break; case 0x66: /* the 0x66 sse prefix is only effective if no other sse prefix * has already been specified. */ if ( !u->pfx_insn ) u->pfx_insn = 0x66; u->pfx_opr = 0x66; u->pfx_rex = 0; break; case 0xF2: u->pfx_insn = 0xF2; u->pfx_repne = 0xF2; u->pfx_rex = 0; break; case 0xF3: u->pfx_insn = 0xF3; u->pfx_rep = 0xF3; u->pfx_repe = 0xF3; u->pfx_rex = 0; break; default : /* No more prefixes */ have_pfx = 0; break; } } /* check if we reached max instruction length */ if ( i + 1 == MAX_INSN_LENGTH ) { u->error = 1; break; } } /* return status */ if ( u->error ) return -1; /* rewind back one byte in stream, since the above loop * stops with a non-prefix byte. */ inp_back(u); /* speculatively determine the effective operand mode, * based on the prefixes and the current disassembly * mode. This may be inaccurate, but useful for mode * dependent decoding. */ if ( u->dis_mode == 64 ) { u->opr_mode = REX_W( u->pfx_rex ) ? 64 : ( ( u->pfx_opr ) ? 16 : 32 ) ; u->adr_mode = ( u->pfx_adr ) ? 32 : 64; } else if ( u->dis_mode == 32 ) { u->opr_mode = ( u->pfx_opr ) ? 16 : 32; u->adr_mode = ( u->pfx_adr ) ? 16 : 32; } else if ( u->dis_mode == 16 ) { u->opr_mode = ( u->pfx_opr ) ? 32 : 16; u->adr_mode = ( u->pfx_adr ) ? 32 : 16; } return 0; }