/* ============================================================================= * ud_decode() - Instruction decoder. Returns the number of bytes decoded. * ============================================================================= */ public int ud_decode(ref ud u) { inp_start(ref u); clear_insn(ref u); u.le = InstructionTables.ud_lookup_table_list[0]; u.error = (byte)((decode_prefixes(ref u) == -1 || decode_opcode(ref u) == -1 || u.error == 1) ? 1 : 0); /* Handle decode error. */ if (u.error == 1) { /* clear out the decode data. */ clear_insn(ref u); /* mark the sequence of bytes as invalid. */ u.itab_entry = InstructionTables.ud_itab[0]; /* entry 0 is invalid */ u.mnemonic = u.itab_entry.Mnemonic; } /* maybe this stray segment override byte * should be spewed out? */ if (BitOps.P_SEG(u.itab_entry.Prefix) == 0 && u.operand[0].type != ud_type.UD_OP_MEM && u.operand[1].type != ud_type.UD_OP_MEM) { u.pfx_seg = 0; } u.insn_offset = u.pc; /* set offset of instruction */ u.asm_buf_fill = 0; /* set translation buffer index to 0 */ u.pc += (uint)u.inp_ctr; /* move program counter by bytes decoded */ /* return number of bytes disassembled. */ return(u.inp_ctr); }
/* * decode_modrm_reg * * Decodes reg field of mod/rm byte * */ void decode_modrm_reg(ref ud u, ref ud_operand operand, reg_class type, ud_operand_size size) { byte reg = (byte)((BitOps.REX_R(u._rex) << 3) | BitOps.MODRM_REG(modrm(ref u))); decode_reg(ref u, ref operand, type, reg, size); }
decode_vex(ref ud u) { byte index; if (u.dis_mode != 64 && BitOps.MODRM_MOD((byte)inp_peek(ref u)) != 0x3) { index = 0; } else { u.vex_op = (byte)inp_curr(ref u); u.vex_b1 = (byte)inp_next(ref u); if (u.vex_op == 0xc4) { byte pp, m; /* 3-byte vex */ u.vex_b2 = inp_next(ref u); if (u.error != 0) { return(u.error); } m = (byte)(u.vex_b1 & 0x1f); if (m == 0 || m > 3) { u.error = 1; u.errorMessage = "decode-error: reserved vex.m-mmmm value"; } pp = (byte)(u.vex_b2 & 0x3); index = (byte)((pp << 2) | m); } else { /* 2-byte vex */ Debug.Assert(u.vex_op == 0xc5); index = (byte)(0x1 | ((u.vex_b1 & 0x3) << 2)); } } if (u.le.Table.Length > index) { return(decode_ext(ref u, u.le.Table[index])); } else { u.error = 1; u.errorMessage = string.Format("decoding vex error: index value {0} of 'u.le.Table' is out of range {1}", index, u.le.Table.Length); return(-1); } }
resolve_pfx_str(ref ud u) { if (u.pfx_str == 0xf3) { if (BitOps.P_STR(u.itab_entry.Prefix) > 0) { u.pfx_rep = 0xf3; } else { u.pfx_repe = 0xf3; } } else if (u.pfx_str == 0xf2) { u.pfx_repne = 0xf3; } return(0); }
decode_vex(ref ud u) { byte index; if (u.dis_mode != 64 && BitOps.MODRM_MOD((byte)inp_peek(ref u)) != 0x3) { index = 0; } else { u.vex_op = (byte)inp_curr(ref u); u.vex_b1 = (byte)inp_next(ref u); if (u.vex_op == 0xc4) { byte pp, m; /* 3-byte vex */ u.vex_b2 = inp_next(ref u); if (u.error != 0) { return(u.error); } m = (byte)(u.vex_b1 & 0x1f); if (m == 0 || m > 3) { u.error = 1; u.errorMessage = "decode-error: reserved vex.m-mmmm value"; return(u.error); } pp = (byte)(u.vex_b2 & 0x3); index = (byte)((pp << 2) | m); } else { /* 2-byte vex */ Debug.Assert(u.vex_op == 0xc5); index = (byte)(0x1 | ((u.vex_b1 & 0x3) << 2)); } } return(decode_ext(ref u, u.le.Table[index])); }
ud_operand_size resolve_operand_size(ref ud u, ud_operand_size oSize) { switch (oSize) { case ud_operand_size.SZ_V: return((ud_operand_size)u.opr_mode); case ud_operand_size.SZ_Z: return((ud_operand_size)((u.opr_mode == 16) ? 16 : 32)); case ud_operand_size.SZ_Y: return((ud_operand_size)((u.opr_mode == 16) ? 32 : u.opr_mode)); case ud_operand_size.SZ_RDQ: return((ud_operand_size)((u.dis_mode == 64) ? 64 : 32)); case ud_operand_size.SZ_X: Debug.Assert(u.vex_op != 0); return((BitOps.P_VEXL(u.itab_entry.Prefix) > 0 && vex_l(ref u) > 0) ? ud_operand_size.SZ_QQ : ud_operand_size.SZ_DQ); default: return(oSize); } }
decode_operand(ref ud u, ref ud_operand operand, ud_operand_code type, ud_operand_size size) { operand.type = ud_type.UD_NONE; operand._oprcode = type; switch (type) { case ud_operand_code.OP_A: decode_a(ref u, ref operand); break; case ud_operand_code.OP_MR: decode_modrm_rm(ref u, ref operand, (byte)reg_class.REGCLASS_GPR, BitOps.MODRM_MOD(modrm(ref u)) == 3 ? size.Mx_reg_size() : size.Mx_mem_size()); break; case ud_operand_code.OP_F: u.br_far = 1; if (BitOps.MODRM_MOD(modrm(ref u)) == 3) { u.error = 1; u.errorMessage = "expected modrm.mod != 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_M: if (BitOps.MODRM_MOD(modrm(ref u)) == 3) { u.error = 1; u.errorMessage = "expected modrm.mod != 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_E: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_G: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_sI: case ud_operand_code.OP_I: decode_imm(ref u, size, ref operand); break; case ud_operand_code.OP_I1: operand.type = ud_type.UD_OP_CONST; operand.lval.udword = 1; break; case ud_operand_code.OP_N: if (BitOps.MODRM_MOD(modrm(ref u)) != 3) { u.error = 1; u.errorMessage = "expected modrm.mod == 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_MMX, size); break; case ud_operand_code.OP_Q: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_MMX, size); break; case ud_operand_code.OP_P: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_MMX, size); break; case ud_operand_code.OP_U: if (BitOps.MODRM_MOD(modrm(ref u)) != 3) { u.error = 1; u.errorMessage = "expected modrm.mod == 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_XMM, size); break; case ud_operand_code.OP_W: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_XMM, size); break; case ud_operand_code.OP_V: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_XMM, size); break; case ud_operand_code.OP_H: decode_vex_vvvv(ref u, ref operand, size); break; case ud_operand_code.OP_MU: decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_XMM, BitOps.MODRM_MOD(modrm(ref u)) == 3 ? size.Mx_reg_size() : size.Mx_mem_size()); break; case ud_operand_code.OP_S: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_SEG, size); break; case ud_operand_code.OP_O: decode_moffset(ref u, size, ref operand); break; case ud_operand_code.OP_R0: case ud_operand_code.OP_R1: case ud_operand_code.OP_R2: case ud_operand_code.OP_R3: case ud_operand_code.OP_R4: case ud_operand_code.OP_R5: case ud_operand_code.OP_R6: case ud_operand_code.OP_R7: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, (byte)((BitOps.REX_B(u._rex) << 3) | (type - ud_operand_code.OP_R0)), size); break; case ud_operand_code.OP_AL: case ud_operand_code.OP_AX: case ud_operand_code.OP_eAX: case ud_operand_code.OP_rAX: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, 0, size); break; case ud_operand_code.OP_CL: case ud_operand_code.OP_CX: case ud_operand_code.OP_eCX: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, 1, size); break; case ud_operand_code.OP_DL: case ud_operand_code.OP_DX: case ud_operand_code.OP_eDX: decode_reg(ref u, ref operand, reg_class.REGCLASS_GPR, 2, size); break; case ud_operand_code.OP_ES: case ud_operand_code.OP_CS: case ud_operand_code.OP_DS: case ud_operand_code.OP_SS: case ud_operand_code.OP_FS: case ud_operand_code.OP_GS: /* in 64bits mode, only fs and gs are allowed */ if (u.dis_mode == 64) { if (type != ud_operand_code.OP_FS && type != ud_operand_code.OP_GS) { u.error = 1; u.errorMessage = "invalid segment register in 64bits\n"; } } operand.type = ud_type.UD_OP_REG; operand.@base = (type - ud_operand_code.OP_ES) + ud_type.UD_R_ES; operand.size = 16; break; case ud_operand_code.OP_J: decode_imm(ref u, size, ref operand); operand.type = ud_type.UD_OP_JIMM; break; case ud_operand_code.OP_R: if (BitOps.MODRM_MOD(modrm(ref u)) != 3) { u.error = 1; u.errorMessage = "expected modrm.mod == 3\n"; } decode_modrm_rm(ref u, ref operand, reg_class.REGCLASS_GPR, size); break; case ud_operand_code.OP_C: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_CR, size); break; case ud_operand_code.OP_D: decode_modrm_reg(ref u, ref operand, reg_class.REGCLASS_DB, size); break; case ud_operand_code.OP_I3: operand.type = ud_type.UD_OP_CONST; operand.lval.@sbyte = 3; break; case ud_operand_code.OP_ST0: case ud_operand_code.OP_ST1: case ud_operand_code.OP_ST2: case ud_operand_code.OP_ST3: case ud_operand_code.OP_ST4: case ud_operand_code.OP_ST5: case ud_operand_code.OP_ST6: case ud_operand_code.OP_ST7: operand.type = ud_type.UD_OP_REG; operand.@base = (type - ud_operand_code.OP_ST0) + ud_type.UD_R_ST0; operand.size = 80; break; case ud_operand_code.OP_L: decode_vex_immreg(ref u, ref operand, size); break; default: operand.type = ud_type.UD_NONE; break; } return(operand.type); }
decode_modrm_rm(ref ud u, ref ud_operand op, reg_class type, /* register type */ ud_operand_size size) /* operand size */ { int offset = 0; byte mod, rm; /* get mod, r/m and reg fields */ mod = BitOps.MODRM_MOD(modrm(ref u)); rm = (byte)((BitOps.REX_B(u._rex) << 3) | BitOps.MODRM_RM(modrm(ref u))); /* * If mod is 11b, then the modrm.rm specifies a register. * */ if (mod == 3) { decode_reg(ref u, ref op, type, rm, size); return; } /* * !11b => Memory Address */ op.type = ud_type.UD_OP_MEM; op.size = (byte)resolve_operand_size(ref u, size); if (u.adr_mode == 64) { op.@base = ud_type.UD_R_RAX + rm; if (mod == 1) { offset = 8; } else if (mod == 2) { offset = 32; } else if (mod == 0 && (rm & 7) == 5) { op.@base = ud_type.UD_R_RIP; offset = 32; } else { offset = 0; } /* * Scale-Index-Base (SIB) */ if ((rm & 7) == 4) { inp_next(ref u); op.@base = ud_type.UD_R_RAX + (BitOps.SIB_B(inp_curr(ref u)) | (BitOps.REX_B(u._rex) << 3)); op.index = ud_type.UD_R_RAX + (BitOps.SIB_I(inp_curr(ref u)) | (BitOps.REX_X(u._rex) << 3)); /* special conditions for base reference */ if (op.index == ud_type.UD_R_RSP) { op.index = ud_type.UD_NONE; op.scale = (byte)ud_type.UD_NONE; } else { op.scale = (byte)((1 << BitOps.SIB_S(inp_curr(ref u))) & ~1); } if (op.@base == ud_type.UD_R_RBP || op.@base == ud_type.UD_R_R13) { if (mod == 0) { op.@base = ud_type.UD_NONE; } if (mod == 1) { offset = 8; } else { offset = 32; } } } else { op.scale = 0; op.index = ud_type.UD_NONE; } } else if (u.adr_mode == 32) { op.@base = ud_type.UD_R_EAX + rm; if (mod == 1) { offset = 8; } else if (mod == 2) { offset = 32; } else if (mod == 0 && rm == 5) { op.@base = ud_type.UD_NONE; offset = 32; } else { offset = 0; } /* Scale-Index-Base (SIB) */ if ((rm & 7) == 4) { inp_next(ref u); op.scale = (byte)((1 << BitOps.SIB_S(inp_curr(ref u))) & ~1); op.index = ud_type.UD_R_EAX + (BitOps.SIB_I(inp_curr(ref u)) | (BitOps.REX_X(u.pfx_rex) << 3)); op.@base = ud_type.UD_R_EAX + (BitOps.SIB_B(inp_curr(ref u)) | (BitOps.REX_B(u.pfx_rex) << 3)); if (op.index == ud_type.UD_R_ESP) { op.index = ud_type.UD_NONE; op.scale = (byte)ud_type.UD_NONE; } /* special condition for base reference */ if (op.@base == ud_type.UD_R_EBP) { if (mod == 0) { op.@base = ud_type.UD_NONE; } if (mod == 1) { offset = 8; } else { offset = 32; } } } else { op.scale = 0; op.index = ud_type.UD_NONE; } } else { ud_type[] bases = { ud_type.UD_R_BX, ud_type.UD_R_BX, ud_type.UD_R_BP, ud_type.UD_R_BP, ud_type.UD_R_SI, ud_type.UD_R_DI, ud_type.UD_R_BP, ud_type.UD_R_BX }; ud_type[] indices = { ud_type.UD_R_SI, ud_type.UD_R_DI, ud_type.UD_R_SI, ud_type.UD_R_DI, ud_type.UD_NONE, ud_type.UD_NONE, ud_type.UD_NONE, ud_type.UD_NONE }; op.@base = bases[rm & 7]; op.index = indices[rm & 7]; op.scale = 0; if (mod == 0 && rm == 6) { offset = 16; op.@base = ud_type.UD_NONE; } else if (mod == 1) { offset = 8; } else if (mod == 2) { offset = 16; } } if (offset > 0) { decode_mem_disp(ref u, offset, ref op); } else { op.offset = 0; } }
/* * decode_ext() * * Decode opcode extensions (if any) */ int decode_ext(ref ud u, ushort ptr) { byte idx = 0; if ((ptr & 0x8000) == 0) { return(decode_insn(ref u, ptr)); } u.le = InstructionTables.ud_lookup_table_list[(~0x8000 & ptr)]; if (u.le.Type == ud_table_type.UD_TAB__OPC_3DNOW) { return(decode_3dnow(ref u)); } switch (u.le.Type) { case ud_table_type.UD_TAB__OPC_MOD: /* !11 = 0, 11 = 1 */ idx = (byte)((BitOps.MODRM_MOD(modrm(ref u)) + 1) / 4); break; /* disassembly mode/operand size/address size based tables. * 16 = 0,, 32 = 1, 64 = 2 */ case ud_table_type.UD_TAB__OPC_MODE: idx = (byte)(u.dis_mode != 64 ? 0 : 1); break; case ud_table_type.UD_TAB__OPC_OSIZE: idx = (byte)(eff_opr_mode(u.dis_mode, BitOps.REX_W(u.pfx_rex), u.pfx_opr) / 32); break; case ud_table_type.UD_TAB__OPC_ASIZE: idx = (byte)(eff_adr_mode(u.dis_mode, u.pfx_adr) / 32); break; case ud_table_type.UD_TAB__OPC_X87: idx = (byte)(modrm(ref u) - 0xC0); break; case ud_table_type.UD_TAB__OPC_VENDOR: if (u.vendor == UD_VENDOR_ANY) { /* choose a valid entry */ idx = (byte)((u.le.Table[idx] != 0) ? 0 : 1); } else if (u.vendor == UD_VENDOR_AMD) { idx = 0; } else { idx = 1; } break; case ud_table_type.UD_TAB__OPC_RM: idx = BitOps.MODRM_RM(modrm(ref u)); break; case ud_table_type.UD_TAB__OPC_REG: idx = BitOps.MODRM_REG(modrm(ref u)); break; case ud_table_type.UD_TAB__OPC_SSE: return(decode_ssepfx(ref u)); case ud_table_type.UD_TAB__OPC_VEX: return(decode_vex(ref u)); case ud_table_type.UD_TAB__OPC_VEX_W: idx = vex_w(ref u); break; case ud_table_type.UD_TAB__OPC_VEX_L: idx = vex_l(ref u); break; case ud_table_type.UD_TAB__OPC_TABLE: inp_next(ref u); return(decode_opcode(ref u)); default: Debug.Assert(false, "not reached"); break; } return(decode_ext(ref u, u.le.Table[idx])); }
resolve_mode(ref ud u) { int default64; /* if in error state, bail out */ if (u.error == 1) { return(-1); } /* propagate prefix effects */ if (u.dis_mode == 64) { /* set 64bit-mode flags */ /* Check validity of instruction m64 */ if (BitOps.P_INV64(u.itab_entry.Prefix) > 0) { u.error = 1; u.errorMessage = "instruction invalid in 64bits\n"; return(-1); } /* compute effective rex based on, * - vex prefix (if any) * - rex prefix (if any, and not vex) * - allowed prefixes specified by the opcode map */ if (u.vex_op == 0xc4) { /* vex has rex.rxb in 1's complement */ u._rex = (byte)((~(u.vex_b1 >> 5) & 0x7) /* rex.0rxb */ | ((u.vex_b2 >> 4) & 0x8) /* rex.w000 */); } else if (u.vex_op == 0xc5) { /* vex has rex.r in 1's complement */ u._rex = (byte)((~(u.vex_b1 >> 5)) & 4); } else { Debug.Assert(u.vex_op == 0); u._rex = u.pfx_rex; } u._rex &= (byte)BitOps.REX_PFX_MASK(u.itab_entry.Prefix); /* whether this instruction has a default operand size of * 64bit, also hardcoded into the opcode map. */ default64 = (int)BitOps.P_DEF64(u.itab_entry.Prefix); /* calculate effective operand size */ if (BitOps.REX_W(u._rex) > 0) { u.opr_mode = 64; } else if (u.pfx_opr > 0) { 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 = (byte)(default64 > 0 ? 64 : 32); } /* calculate effective address size */ u.adr_mode = (byte)((u.pfx_adr > 0) ? 32 : 64); } else if (u.dis_mode == 32) { /* set 32bit-mode flags */ u.opr_mode = (byte)((u.pfx_opr > 0) ? 16 : 32); u.adr_mode = (byte)((u.pfx_adr > 0) ? 16 : 32); } else if (u.dis_mode == 16) { /* set 16bit-mode flags */ u.opr_mode = (byte)((u.pfx_opr > 0) ? 32 : 16); u.adr_mode = (byte)((u.pfx_adr > 0) ? 32 : 16); } return(0); }
/* ============================================================================= * translates to intel syntax * ============================================================================= */ public void ud_translate_intel(ref ud u) { /* check if P_OSO prefix is used */ if (BitOps.P_OSO(u.itab_entry.Prefix) == 0 && u.pfx_opr > 0) { switch (u.dis_mode) { case 16: ud_asmprintf(ref u, "o32 "); break; case 32: case 64: ud_asmprintf(ref u, "o16 "); break; } } /* check if P_ASO prefix was used */ if (BitOps.P_ASO(u.itab_entry.Prefix) == 0 && u.pfx_adr > 0) { switch (u.dis_mode) { case 16: ud_asmprintf(ref u, "a32 "); break; case 32: ud_asmprintf(ref u, "a16 "); break; case 64: ud_asmprintf(ref u, "a32 "); break; } } if (u.pfx_seg > 0 && u.operand[0].type != ud_type.UD_OP_MEM && u.operand[1].type != ud_type.UD_OP_MEM) { ud_asmprintf(ref u, "{0} ", ud_reg_tab[u.pfx_seg - (byte)ud_type.UD_R_AL]); } if (u.pfx_lock > 0) { ud_asmprintf(ref u, "lock "); } if (u.pfx_rep > 0) { ud_asmprintf(ref u, "rep "); } else if (u.pfx_repe > 0) { ud_asmprintf(ref u, "repe "); } else if (u.pfx_repne > 0) { ud_asmprintf(ref u, "repne "); } /* print the instruction mnemonic */ ud_asmprintf(ref u, "{0}", udis86.ud_lookup_mnemonic(u.mnemonic)); if (u.operand[0].type != ud_type.UD_NONE) { int cast = 0; ud_asmprintf(ref u, " "); if (u.operand[0].type == ud_type.UD_OP_MEM) { if (u.operand[1].type == ud_type.UD_OP_IMM || u.operand[1].type == ud_type.UD_OP_CONST || u.operand[1].type == ud_type.UD_NONE || (u.operand[0].size != u.operand[1].size && u.operand[1].type != ud_type.UD_OP_REG)) { cast = 1; } else if (u.operand[1].type == ud_type.UD_OP_REG && u.operand[1].@base == ud_type.UD_R_CL) { switch (u.mnemonic) { case ud_mnemonic_code.UD_Ircl: case ud_mnemonic_code.UD_Irol: case ud_mnemonic_code.UD_Iror: case ud_mnemonic_code.UD_Ircr: case ud_mnemonic_code.UD_Ishl: case ud_mnemonic_code.UD_Ishr: case ud_mnemonic_code.UD_Isar: cast = 1; break; default: break; } } } gen_operand(ref u, ref u.operand[0], cast); } if (u.operand[1].type != ud_type.UD_NONE) { int cast = 0; ud_asmprintf(ref u, ", "); if (u.operand[1].type == ud_type.UD_OP_MEM && u.operand[0].size != u.operand[1].size && !udis86.ud_opr_is_sreg(ref u.operand[0])) { cast = 1; } gen_operand(ref u, ref u.operand[1], cast); } if (u.operand[2].type != ud_type.UD_NONE) { int cast = 0; ud_asmprintf(ref u, ", "); if (u.operand[2].type == ud_type.UD_OP_MEM && u.operand[2].size != u.operand[1].size) { cast = 1; } gen_operand(ref u, ref u.operand[2], cast); } if (u.operand[3].type != ud_type.UD_NONE) { ud_asmprintf(ref u, ", "); gen_operand(ref u, ref u.operand[3], 0); } }