Index: third_party/mach_override/libudis86/decode.c |
diff --git a/third_party/mach_override/libudis86/decode.c b/third_party/mach_override/libudis86/decode.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2b352dc879951260c171573777aa738a8426caf9 |
--- /dev/null |
+++ b/third_party/mach_override/libudis86/decode.c |
@@ -0,0 +1,1094 @@ |
+/* udis86 - libudis86/decode.c |
+ * |
+ * Copyright (c) 2002-2009 Vivek Thampi |
+ * All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without modification, |
+ * are permitted provided that the following conditions are met: |
+ * |
+ * * Redistributions of source code must retain the above copyright notice, |
+ * this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above copyright notice, |
+ * this list of conditions and the following disclaimer in the documentation |
+ * and/or other materials provided with the distribution. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+#include "udint.h" |
+#include "types.h" |
+#include "input.h" |
+#include "decode.h" |
+ |
+#ifndef __UD_STANDALONE__ |
+# include <string.h> |
+#endif /* __UD_STANDALONE__ */ |
+ |
+/* The max number of prefixes to an instruction */ |
+#define MAX_PREFIXES 15 |
+ |
+/* rex prefix bits */ |
+#define REX_W(r) ( ( 0xF & ( r ) ) >> 3 ) |
+#define REX_R(r) ( ( 0x7 & ( r ) ) >> 2 ) |
+#define REX_X(r) ( ( 0x3 & ( r ) ) >> 1 ) |
+#define REX_B(r) ( ( 0x1 & ( r ) ) >> 0 ) |
+#define REX_PFX_MASK(n) ( ( P_REXW(n) << 3 ) | \ |
+ ( P_REXR(n) << 2 ) | \ |
+ ( P_REXX(n) << 1 ) | \ |
+ ( P_REXB(n) << 0 ) ) |
+ |
+/* scable-index-base bits */ |
+#define SIB_S(b) ( ( b ) >> 6 ) |
+#define SIB_I(b) ( ( ( b ) >> 3 ) & 7 ) |
+#define SIB_B(b) ( ( b ) & 7 ) |
+ |
+/* modrm bits */ |
+#define MODRM_REG(b) ( ( ( b ) >> 3 ) & 7 ) |
+#define MODRM_NNN(b) ( ( ( b ) >> 3 ) & 7 ) |
+#define MODRM_MOD(b) ( ( ( b ) >> 6 ) & 3 ) |
+#define MODRM_RM(b) ( ( b ) & 7 ) |
+ |
+static int decode_ext(struct ud *u, uint16_t ptr); |
+ |
+enum reg_class { /* register classes */ |
+ REGCLASS_NONE, |
+ REGCLASS_GPR, |
+ REGCLASS_MMX, |
+ REGCLASS_CR, |
+ REGCLASS_DB, |
+ REGCLASS_SEG, |
+ REGCLASS_XMM |
+}; |
+ |
+ |
+/* |
+ * inp_uint8 |
+ * int_uint16 |
+ * int_uint32 |
+ * int_uint64 |
+ * Load little-endian values from input |
+ */ |
+static uint8_t |
+inp_uint8(struct ud* u) |
+{ |
+ return ud_inp_next(u); |
+} |
+ |
+static uint16_t |
+inp_uint16(struct ud* u) |
+{ |
+ uint16_t r, ret; |
+ |
+ ret = ud_inp_next(u); |
+ r = ud_inp_next(u); |
+ return ret | (r << 8); |
+} |
+ |
+static uint32_t |
+inp_uint32(struct ud* u) |
+{ |
+ uint32_t r, ret; |
+ |
+ ret = ud_inp_next(u); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 8); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 16); |
+ r = ud_inp_next(u); |
+ return ret | (r << 24); |
+} |
+ |
+static uint64_t |
+inp_uint64(struct ud* u) |
+{ |
+ uint64_t r, ret; |
+ |
+ ret = ud_inp_next(u); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 8); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 16); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 24); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 32); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 40); |
+ r = ud_inp_next(u); |
+ ret = ret | (r << 48); |
+ r = ud_inp_next(u); |
+ return ret | (r << 56); |
+} |
+ |
+ |
+static inline int |
+eff_opr_mode(int dis_mode, int rex_w, int pfx_opr) |
+{ |
+ if (dis_mode == 64) { |
+ return rex_w ? 64 : (pfx_opr ? 16 : 32); |
+ } else if (dis_mode == 32) { |
+ return pfx_opr ? 16 : 32; |
+ } else { |
+ UD_ASSERT(dis_mode == 16); |
+ return pfx_opr ? 32 : 16; |
+ } |
+} |
+ |
+ |
+static inline int |
+eff_adr_mode(int dis_mode, int pfx_adr) |
+{ |
+ if (dis_mode == 64) { |
+ return pfx_adr ? 32 : 64; |
+ } else if (dis_mode == 32) { |
+ return pfx_adr ? 16 : 32; |
+ } else { |
+ UD_ASSERT(dis_mode == 16); |
+ return pfx_adr ? 32 : 16; |
+ } |
+} |
+ |
+ |
+/* Looks up mnemonic code in the mnemonic string table |
+ * Returns NULL if the mnemonic code is invalid |
+ */ |
+const char* |
+ud_lookup_mnemonic(enum ud_mnemonic_code c) |
+{ |
+ if (c < UD_MAX_MNEMONIC_CODE) { |
+ return ud_mnemonics_str[c]; |
+ } else { |
+ return NULL; |
+ } |
+} |
+ |
+ |
+/* |
+ * decode_prefixes |
+ * |
+ * Extracts instruction prefixes. |
+ */ |
+static int |
+decode_prefixes(struct ud *u) |
+{ |
+ int done = 0; |
+ uint8_t curr; |
+ UD_RETURN_ON_ERROR(u); |
+ |
+ do { |
+ ud_inp_next(u); |
+ UD_RETURN_ON_ERROR(u); |
+ if (inp_len(u) == MAX_INSN_LENGTH) { |
+ UD_RETURN_WITH_ERROR(u, "max instruction length"); |
+ } |
+ curr = inp_curr(u); |
+ |
+ switch (curr) |
+ { |
+ case 0x2E : |
+ u->pfx_seg = UD_R_CS; |
+ break; |
+ case 0x36 : |
+ u->pfx_seg = UD_R_SS; |
+ break; |
+ case 0x3E : |
+ u->pfx_seg = UD_R_DS; |
+ break; |
+ case 0x26 : |
+ u->pfx_seg = UD_R_ES; |
+ break; |
+ case 0x64 : |
+ u->pfx_seg = UD_R_FS; |
+ break; |
+ case 0x65 : |
+ u->pfx_seg = UD_R_GS; |
+ break; |
+ case 0x67 : /* adress-size override prefix */ |
+ u->pfx_adr = 0x67; |
+ break; |
+ case 0xF0 : |
+ u->pfx_lock = 0xF0; |
+ break; |
+ case 0x66: |
+ u->pfx_opr = 0x66; |
+ break; |
+ case 0xF2: |
+ u->pfx_str = 0xf2; |
+ break; |
+ case 0xF3: |
+ u->pfx_str = 0xf3; |
+ break; |
+ default: |
+ done = 1; |
+ break; |
+ } |
+ } while (!done); |
+ |
+ if (u->dis_mode == 64 && (curr & 0xF0) == 0x40) { |
+ /* rex prefixes in 64bit mode, must be the last prefix |
+ */ |
+ u->pfx_rex = curr; |
+ } else { |
+ /* rewind back one byte in stream, since the above loop |
+ * stops with a non-prefix byte. |
+ */ |
+ inp_back(u); |
+ } |
+ return 0; |
+} |
+ |
+ |
+static inline unsigned int modrm( struct ud * u ) |
+{ |
+ if ( !u->have_modrm ) { |
+ u->modrm = ud_inp_next( u ); |
+ u->have_modrm = 1; |
+ } |
+ return u->modrm; |
+} |
+ |
+ |
+static unsigned int |
+resolve_operand_size( const struct ud * u, unsigned int s ) |
+{ |
+ switch ( s ) |
+ { |
+ case SZ_V: |
+ return ( u->opr_mode ); |
+ case SZ_Z: |
+ return ( u->opr_mode == 16 ) ? 16 : 32; |
+ case SZ_Y: |
+ return ( u->opr_mode == 16 ) ? 32 : u->opr_mode; |
+ case SZ_RDQ: |
+ return ( u->dis_mode == 64 ) ? 64 : 32; |
+ default: |
+ return s; |
+ } |
+} |
+ |
+ |
+static int resolve_mnemonic( struct ud* u ) |
+{ |
+ /* resolve 3dnow weirdness. */ |
+ if ( u->mnemonic == UD_I3dnow ) { |
+ u->mnemonic = ud_itab[ u->le->table[ inp_curr( u ) ] ].mnemonic; |
+ } |
+ /* SWAPGS is only valid in 64bits mode */ |
+ if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) { |
+ UDERR(u, "swapgs invalid in 64bits mode"); |
+ return -1; |
+ } |
+ |
+ if (u->mnemonic == UD_Ixchg) { |
+ if ((u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_AX && |
+ u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_AX) || |
+ (u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_EAX && |
+ u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_EAX)) { |
+ u->operand[0].type = UD_NONE; |
+ u->operand[1].type = UD_NONE; |
+ u->mnemonic = UD_Inop; |
+ } |
+ } |
+ |
+ if (u->mnemonic == UD_Inop && u->pfx_repe) { |
+ u->pfx_repe = 0; |
+ u->mnemonic = UD_Ipause; |
+ } |
+ return 0; |
+} |
+ |
+ |
+/* ----------------------------------------------------------------------------- |
+ * decode_a()- Decodes operands of the type seg:offset |
+ * ----------------------------------------------------------------------------- |
+ */ |
+static void |
+decode_a(struct ud* u, struct ud_operand *op) |
+{ |
+ if (u->opr_mode == 16) { |
+ /* seg16:off16 */ |
+ op->type = UD_OP_PTR; |
+ op->size = 32; |
+ op->lval.ptr.off = inp_uint16(u); |
+ op->lval.ptr.seg = inp_uint16(u); |
+ } else { |
+ /* seg16:off32 */ |
+ op->type = UD_OP_PTR; |
+ op->size = 48; |
+ op->lval.ptr.off = inp_uint32(u); |
+ op->lval.ptr.seg = inp_uint16(u); |
+ } |
+} |
+ |
+/* ----------------------------------------------------------------------------- |
+ * decode_gpr() - Returns decoded General Purpose Register |
+ * ----------------------------------------------------------------------------- |
+ */ |
+static enum ud_type |
+decode_gpr(register struct ud* u, unsigned int s, unsigned char rm) |
+{ |
+ switch (s) { |
+ case 64: |
+ return UD_R_RAX + rm; |
+ case 32: |
+ return UD_R_EAX + rm; |
+ case 16: |
+ return UD_R_AX + rm; |
+ case 8: |
+ if (u->dis_mode == 64 && u->pfx_rex) { |
+ if (rm >= 4) |
+ return UD_R_SPL + (rm-4); |
+ return UD_R_AL + rm; |
+ } else return UD_R_AL + rm; |
+ default: |
+ UD_ASSERT(!"invalid operand size"); |
+ return 0; |
+ } |
+} |
+ |
+static void |
+decode_reg(struct ud *u, |
+ struct ud_operand *opr, |
+ int type, |
+ int num, |
+ int size) |
+{ |
+ int reg; |
+ size = resolve_operand_size(u, size); |
+ switch (type) { |
+ case REGCLASS_GPR : reg = decode_gpr(u, size, num); break; |
+ case REGCLASS_MMX : reg = UD_R_MM0 + (num & 7); break; |
+ case REGCLASS_XMM : reg = UD_R_XMM0 + num; break; |
+ case REGCLASS_CR : reg = UD_R_CR0 + num; break; |
+ case REGCLASS_DB : reg = UD_R_DR0 + num; break; |
+ case REGCLASS_SEG : { |
+ /* |
+ * Only 6 segment registers, anything else is an error. |
+ */ |
+ if ((num & 7) > 5) { |
+ UDERR(u, "invalid segment register value"); |
+ return; |
+ } else { |
+ reg = UD_R_ES + (num & 7); |
+ } |
+ break; |
+ } |
+ default: |
+ UD_ASSERT(!"invalid register type"); |
+ break; |
+ } |
+ opr->type = UD_OP_REG; |
+ opr->base = reg; |
+ opr->size = size; |
+} |
+ |
+ |
+/* |
+ * decode_imm |
+ * |
+ * Decode Immediate values. |
+ */ |
+static void |
+decode_imm(struct ud* u, unsigned int size, struct ud_operand *op) |
+{ |
+ op->size = resolve_operand_size(u, size); |
+ op->type = UD_OP_IMM; |
+ |
+ switch (op->size) { |
+ case 8: op->lval.sbyte = inp_uint8(u); break; |
+ case 16: op->lval.uword = inp_uint16(u); break; |
+ case 32: op->lval.udword = inp_uint32(u); break; |
+ case 64: op->lval.uqword = inp_uint64(u); break; |
+ default: return; |
+ } |
+} |
+ |
+ |
+/* |
+ * decode_mem_disp |
+ * |
+ * Decode mem address displacement. |
+ */ |
+static void |
+decode_mem_disp(struct ud* u, unsigned int size, struct ud_operand *op) |
+{ |
+ switch (size) { |
+ case 8: |
+ op->offset = 8; |
+ op->lval.ubyte = inp_uint8(u); |
+ break; |
+ case 16: |
+ op->offset = 16; |
+ op->lval.uword = inp_uint16(u); |
+ break; |
+ case 32: |
+ op->offset = 32; |
+ op->lval.udword = inp_uint32(u); |
+ break; |
+ case 64: |
+ op->offset = 64; |
+ op->lval.uqword = inp_uint64(u); |
+ break; |
+ default: |
+ return; |
+ } |
+} |
+ |
+ |
+/* |
+ * decode_modrm_reg |
+ * |
+ * Decodes reg field of mod/rm byte |
+ * |
+ */ |
+static inline void |
+decode_modrm_reg(struct ud *u, |
+ struct ud_operand *operand, |
+ unsigned int type, |
+ unsigned int size) |
+{ |
+ uint8_t reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(modrm(u)); |
+ decode_reg(u, operand, type, reg, size); |
+} |
+ |
+ |
+/* |
+ * decode_modrm_rm |
+ * |
+ * Decodes rm field of mod/rm byte |
+ * |
+ */ |
+static void |
+decode_modrm_rm(struct ud *u, |
+ struct ud_operand *op, |
+ unsigned char type, /* register type */ |
+ unsigned int size) /* operand size */ |
+ |
+{ |
+ size_t offset = 0; |
+ unsigned char mod, rm; |
+ |
+ /* get mod, r/m and reg fields */ |
+ mod = MODRM_MOD(modrm(u)); |
+ rm = (REX_B(u->pfx_rex) << 3) | MODRM_RM(modrm(u)); |
+ |
+ /* |
+ * If mod is 11b, then the modrm.rm specifies a register. |
+ * |
+ */ |
+ if (mod == 3) { |
+ decode_reg(u, op, type, rm, size); |
+ return; |
+ } |
+ |
+ /* |
+ * !11b => Memory Address |
+ */ |
+ op->type = UD_OP_MEM; |
+ op->size = resolve_operand_size(u, size); |
+ |
+ if (u->adr_mode == 64) { |
+ op->base = 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_R_RIP; |
+ offset = 32; |
+ } else { |
+ offset = 0; |
+ } |
+ /* |
+ * Scale-Index-Base (SIB) |
+ */ |
+ if ((rm & 7) == 4) { |
+ ud_inp_next(u); |
+ |
+ op->scale = (1 << SIB_S(inp_curr(u))) & ~1; |
+ op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); |
+ op->base = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3)); |
+ |
+ /* special conditions for base reference */ |
+ if (op->index == UD_R_RSP) { |
+ op->index = UD_NONE; |
+ op->scale = UD_NONE; |
+ } |
+ |
+ if (op->base == UD_R_RBP || op->base == UD_R_R13) { |
+ if (mod == 0) { |
+ op->base = UD_NONE; |
+ } |
+ if (mod == 1) { |
+ offset = 8; |
+ } else { |
+ offset = 32; |
+ } |
+ } |
+ } |
+ } else if (u->adr_mode == 32) { |
+ op->base = UD_R_EAX + rm; |
+ if (mod == 1) { |
+ offset = 8; |
+ } else if (mod == 2) { |
+ offset = 32; |
+ } else if (mod == 0 && rm == 5) { |
+ op->base = UD_NONE; |
+ offset = 32; |
+ } else { |
+ offset = 0; |
+ } |
+ |
+ /* Scale-Index-Base (SIB) */ |
+ if ((rm & 7) == 4) { |
+ ud_inp_next(u); |
+ |
+ op->scale = (1 << SIB_S(inp_curr(u))) & ~1; |
+ op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); |
+ op->base = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3)); |
+ |
+ if (op->index == UD_R_ESP) { |
+ op->index = UD_NONE; |
+ op->scale = UD_NONE; |
+ } |
+ |
+ /* special condition for base reference */ |
+ if (op->base == UD_R_EBP) { |
+ if (mod == 0) { |
+ op->base = UD_NONE; |
+ } |
+ if (mod == 1) { |
+ offset = 8; |
+ } else { |
+ offset = 32; |
+ } |
+ } |
+ } |
+ } else { |
+ const unsigned int bases[] = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP, |
+ UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX }; |
+ const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI, |
+ UD_NONE, UD_NONE, UD_NONE, UD_NONE }; |
+ op->base = bases[rm & 7]; |
+ op->index = indices[rm & 7]; |
+ if (mod == 0 && rm == 6) { |
+ offset = 16; |
+ op->base = UD_NONE; |
+ } else if (mod == 1) { |
+ offset = 8; |
+ } else if (mod == 2) { |
+ offset = 16; |
+ } |
+ } |
+ |
+ if (offset) { |
+ decode_mem_disp(u, offset, op); |
+ } |
+} |
+ |
+ |
+/* |
+ * decode_moffset |
+ * Decode offset-only memory operand |
+ */ |
+static void |
+decode_moffset(struct ud *u, unsigned int size, struct ud_operand *opr) |
+{ |
+ opr->type = UD_OP_MEM; |
+ opr->size = resolve_operand_size(u, size); |
+ decode_mem_disp(u, u->adr_mode, opr); |
+} |
+ |
+ |
+/* ----------------------------------------------------------------------------- |
+ * decode_operands() - Disassembles Operands. |
+ * ----------------------------------------------------------------------------- |
+ */ |
+static int |
+decode_operand(struct ud *u, |
+ struct ud_operand *operand, |
+ enum ud_operand_code type, |
+ unsigned int size) |
+{ |
+ operand->_oprcode = type; |
+ |
+ switch (type) { |
+ case OP_A : |
+ decode_a(u, operand); |
+ break; |
+ case OP_MR: |
+ decode_modrm_rm(u, operand, REGCLASS_GPR, |
+ MODRM_MOD(modrm(u)) == 3 ? |
+ Mx_reg_size(size) : Mx_mem_size(size)); |
+ break; |
+ case OP_F: |
+ u->br_far = 1; |
+ /* intended fall through */ |
+ case OP_M: |
+ if (MODRM_MOD(modrm(u)) == 3) { |
+ UDERR(u, "expected modrm.mod != 3"); |
+ } |
+ /* intended fall through */ |
+ case OP_E: |
+ decode_modrm_rm(u, operand, REGCLASS_GPR, size); |
+ break; |
+ case OP_G: |
+ decode_modrm_reg(u, operand, REGCLASS_GPR, size); |
+ break; |
+ case OP_sI: |
+ case OP_I: |
+ decode_imm(u, size, operand); |
+ break; |
+ case OP_I1: |
+ operand->type = UD_OP_CONST; |
+ operand->lval.udword = 1; |
+ break; |
+ case OP_N: |
+ if (MODRM_MOD(modrm(u)) != 3) { |
+ UDERR(u, "expected modrm.mod == 3"); |
+ } |
+ /* intended fall through */ |
+ case OP_Q: |
+ decode_modrm_rm(u, operand, REGCLASS_MMX, size); |
+ break; |
+ case OP_P: |
+ decode_modrm_reg(u, operand, REGCLASS_MMX, size); |
+ break; |
+ case OP_U: |
+ if (MODRM_MOD(modrm(u)) != 3) { |
+ UDERR(u, "expected modrm.mod == 3"); |
+ } |
+ /* intended fall through */ |
+ case OP_W: |
+ decode_modrm_rm(u, operand, REGCLASS_XMM, size); |
+ break; |
+ case OP_V: |
+ decode_modrm_reg(u, operand, REGCLASS_XMM, size); |
+ break; |
+ case OP_MU: |
+ decode_modrm_rm(u, operand, REGCLASS_XMM, |
+ MODRM_MOD(modrm(u)) == 3 ? |
+ Mx_reg_size(size) : Mx_mem_size(size)); |
+ break; |
+ case OP_S: |
+ decode_modrm_reg(u, operand, REGCLASS_SEG, size); |
+ break; |
+ case OP_O: |
+ decode_moffset(u, size, operand); |
+ break; |
+ case OP_R0: |
+ case OP_R1: |
+ case OP_R2: |
+ case OP_R3: |
+ case OP_R4: |
+ case OP_R5: |
+ case OP_R6: |
+ case OP_R7: |
+ decode_reg(u, operand, REGCLASS_GPR, |
+ (REX_B(u->pfx_rex) << 3) | (type - OP_R0), size); |
+ break; |
+ case OP_AL: |
+ case OP_AX: |
+ case OP_eAX: |
+ case OP_rAX: |
+ decode_reg(u, operand, REGCLASS_GPR, 0, size); |
+ break; |
+ case OP_CL: |
+ case OP_CX: |
+ case OP_eCX: |
+ decode_reg(u, operand, REGCLASS_GPR, 1, size); |
+ break; |
+ case OP_DL: |
+ case OP_DX: |
+ case OP_eDX: |
+ decode_reg(u, operand, REGCLASS_GPR, 2, size); |
+ break; |
+ case OP_ES: |
+ case OP_CS: |
+ case OP_DS: |
+ case OP_SS: |
+ case OP_FS: |
+ case OP_GS: |
+ /* in 64bits mode, only fs and gs are allowed */ |
+ if (u->dis_mode == 64) { |
+ if (type != OP_FS && type != OP_GS) { |
+ UDERR(u, "invalid segment register in 64bits"); |
+ } |
+ } |
+ operand->type = UD_OP_REG; |
+ operand->base = (type - OP_ES) + UD_R_ES; |
+ operand->size = 16; |
+ break; |
+ case OP_J : |
+ decode_imm(u, size, operand); |
+ operand->type = UD_OP_JIMM; |
+ break ; |
+ case OP_R : |
+ if (MODRM_MOD(modrm(u)) != 3) { |
+ UDERR(u, "expected modrm.mod == 3"); |
+ } |
+ decode_modrm_rm(u, operand, REGCLASS_GPR, size); |
+ break; |
+ case OP_C: |
+ decode_modrm_reg(u, operand, REGCLASS_CR, size); |
+ break; |
+ case OP_D: |
+ decode_modrm_reg(u, operand, REGCLASS_DB, size); |
+ break; |
+ case OP_I3 : |
+ operand->type = UD_OP_CONST; |
+ operand->lval.sbyte = 3; |
+ break; |
+ case OP_ST0: |
+ case OP_ST1: |
+ case OP_ST2: |
+ case OP_ST3: |
+ case OP_ST4: |
+ case OP_ST5: |
+ case OP_ST6: |
+ case OP_ST7: |
+ operand->type = UD_OP_REG; |
+ operand->base = (type - OP_ST0) + UD_R_ST0; |
+ operand->size = 80; |
+ break; |
+ default : |
+ break; |
+ } |
+ return 0; |
+} |
+ |
+ |
+/* |
+ * decode_operands |
+ * |
+ * Disassemble upto 3 operands of the current instruction being |
+ * disassembled. By the end of the function, the operand fields |
+ * of the ud structure will have been filled. |
+ */ |
+static int |
+decode_operands(struct ud* u) |
+{ |
+ decode_operand(u, &u->operand[0], |
+ u->itab_entry->operand1.type, |
+ u->itab_entry->operand1.size); |
+ decode_operand(u, &u->operand[1], |
+ u->itab_entry->operand2.type, |
+ u->itab_entry->operand2.size); |
+ decode_operand(u, &u->operand[2], |
+ u->itab_entry->operand3.type, |
+ u->itab_entry->operand3.size); |
+ return 0; |
+} |
+ |
+/* ----------------------------------------------------------------------------- |
+ * clear_insn() - clear instruction structure |
+ * ----------------------------------------------------------------------------- |
+ */ |
+static void |
+clear_insn(register struct ud* u) |
+{ |
+ u->error = 0; |
+ u->pfx_seg = 0; |
+ u->pfx_opr = 0; |
+ u->pfx_adr = 0; |
+ u->pfx_lock = 0; |
+ u->pfx_repne = 0; |
+ u->pfx_rep = 0; |
+ u->pfx_repe = 0; |
+ u->pfx_rex = 0; |
+ u->pfx_str = 0; |
+ u->mnemonic = UD_Inone; |
+ u->itab_entry = NULL; |
+ u->have_modrm = 0; |
+ u->br_far = 0; |
+ |
+ memset( &u->operand[ 0 ], 0, sizeof( struct ud_operand ) ); |
+ memset( &u->operand[ 1 ], 0, sizeof( struct ud_operand ) ); |
+ memset( &u->operand[ 2 ], 0, sizeof( struct ud_operand ) ); |
+} |
+ |
+ |
+static inline int |
+resolve_pfx_str(struct ud* u) |
+{ |
+ if (u->pfx_str == 0xf3) { |
+ if (P_STR(u->itab_entry->prefix)) { |
+ u->pfx_rep = 0xf3; |
+ } else { |
+ u->pfx_repe = 0xf3; |
+ } |
+ } else if (u->pfx_str == 0xf2) { |
+ u->pfx_repne = 0xf3; |
+ } |
+ return 0; |
+} |
+ |
+ |
+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 ) ) { |
+ UDERR(u, "instruction invalid in 64bits"); |
+ 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; |
+ } |
+ |
+ /* set flags for implicit addressing */ |
+ u->implicit_addr = P_IMPADDR( u->itab_entry->prefix ); |
+ |
+ return 0; |
+} |
+ |
+ |
+static inline int |
+decode_insn(struct ud *u, uint16_t ptr) |
+{ |
+ UD_ASSERT((ptr & 0x8000) == 0); |
+ u->itab_entry = &ud_itab[ ptr ]; |
+ u->mnemonic = u->itab_entry->mnemonic; |
+ return (resolve_pfx_str(u) == 0 && |
+ resolve_mode(u) == 0 && |
+ decode_operands(u) == 0 && |
+ resolve_mnemonic(u) == 0) ? 0 : -1; |
+} |
+ |
+ |
+/* |
+ * decode_3dnow() |
+ * |
+ * Decoding 3dnow is a little tricky because of its strange opcode |
+ * structure. The final opcode disambiguation depends on the last |
+ * byte that comes after the operands have been decoded. Fortunately, |
+ * all 3dnow instructions have the same set of operand types. So we |
+ * go ahead and decode the instruction by picking an arbitrarily chosen |
+ * valid entry in the table, decode the operands, and read the final |
+ * byte to resolve the menmonic. |
+ */ |
+static inline int |
+decode_3dnow(struct ud* u) |
+{ |
+ uint16_t ptr; |
+ UD_ASSERT(u->le->type == UD_TAB__OPC_3DNOW); |
+ UD_ASSERT(u->le->table[0xc] != 0); |
+ decode_insn(u, u->le->table[0xc]); |
+ ud_inp_next(u); |
+ if (u->error) { |
+ return -1; |
+ } |
+ ptr = u->le->table[inp_curr(u)]; |
+ UD_ASSERT((ptr & 0x8000) == 0); |
+ u->mnemonic = ud_itab[ptr].mnemonic; |
+ return 0; |
+} |
+ |
+ |
+static int |
+decode_ssepfx(struct ud *u) |
+{ |
+ uint8_t idx; |
+ uint8_t pfx; |
+ |
+ /* |
+ * String prefixes (f2, f3) take precedence over operand |
+ * size prefix (66). |
+ */ |
+ pfx = u->pfx_str; |
+ if (pfx == 0) { |
+ pfx = u->pfx_opr; |
+ } |
+ idx = ((pfx & 0xf) + 1) / 2; |
+ if (u->le->table[idx] == 0) { |
+ idx = 0; |
+ } |
+ if (idx && u->le->table[idx] != 0) { |
+ /* |
+ * "Consume" the prefix as a part of the opcode, so it is no |
+ * longer exported as an instruction prefix. |
+ */ |
+ u->pfx_str = 0; |
+ if (pfx == 0x66) { |
+ /* |
+ * consume "66" only if it was used for decoding, leaving |
+ * it to be used as an operands size override for some |
+ * simd instructions. |
+ */ |
+ u->pfx_opr = 0; |
+ } |
+ } |
+ return decode_ext(u, u->le->table[idx]); |
+} |
+ |
+ |
+/* |
+ * 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 != 64 ? 0 : 1; |
+ 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: |
+ UD_ASSERT(!"not reached"); |
+ break; |
+ } |
+ |
+ return decode_ext(u, u->le->table[idx]); |
+} |
+ |
+ |
+static int |
+decode_opcode(struct ud *u) |
+{ |
+ uint16_t ptr; |
+ UD_ASSERT(u->le->type == UD_TAB__OPC_TABLE); |
+ ud_inp_next(u); |
+ if (u->error) { |
+ return -1; |
+ } |
+ u->primary_opcode = inp_curr(u); |
+ ptr = u->le->table[inp_curr(u)]; |
+ if (ptr & 0x8000) { |
+ u->le = &ud_lookup_table_list[ptr & ~0x8000]; |
+ if (u->le->type == UD_TAB__OPC_TABLE) { |
+ return decode_opcode(u); |
+ } |
+ } |
+ return decode_ext(u, ptr); |
+} |
+ |
+ |
+/* ============================================================================= |
+ * ud_decode() - Instruction decoder. Returns the number of bytes decoded. |
+ * ============================================================================= |
+ */ |
+unsigned int |
+ud_decode(struct ud *u) |
+{ |
+ inp_start(u); |
+ clear_insn(u); |
+ u->le = &ud_lookup_table_list[0]; |
+ u->error = decode_prefixes(u) == -1 || |
+ decode_opcode(u) == -1 || |
+ u->error; |
+ /* Handle decode error. */ |
+ if (u->error) { |
+ /* clear out the decode data. */ |
+ clear_insn(u); |
+ /* mark the sequence of bytes as invalid. */ |
+ u->itab_entry = &ud_itab[0]; /* entry 0 is invalid */ |
+ u->mnemonic = u->itab_entry->mnemonic; |
+ } |
+ |
+ /* maybe this stray segment override byte |
+ * should be spewed out? |
+ */ |
+ if ( !P_SEG( u->itab_entry->prefix ) && |
+ u->operand[0].type != UD_OP_MEM && |
+ u->operand[1].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 += u->inp_ctr; /* move program counter by bytes decoded */ |
+ |
+ /* return number of bytes disassembled. */ |
+ return u->inp_ctr; |
+} |
+ |
+/* |
+vim: set ts=2 sw=2 expandtab |
+*/ |