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); } }
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])); }
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])); }