diff options
Diffstat (limited to 'src/3rdparty/masm/disassembler/udis86/udis86_decode.c')
-rw-r--r-- | src/3rdparty/masm/disassembler/udis86/udis86_decode.c | 1141 |
1 files changed, 1141 insertions, 0 deletions
diff --git a/src/3rdparty/masm/disassembler/udis86/udis86_decode.c b/src/3rdparty/masm/disassembler/udis86/udis86_decode.c new file mode 100644 index 0000000000..3d567b6df2 --- /dev/null +++ b/src/3rdparty/masm/disassembler/udis86/udis86_decode.c @@ -0,0 +1,1141 @@ +/* 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 "config.h" + +#if USE(UDIS86) + +#include "udis86_extern.h" +#include "udis86_types.h" +#include "udis86_input.h" +#include "udis86_decode.h" +#include <wtf/Assertions.h> + +#define dbg(x, n...) +/* #define dbg printf */ + +#ifndef __UD_STANDALONE__ +# include <string.h> +#endif /* __UD_STANDALONE__ */ + +/* The max number of prefixes to an instruction */ +#define MAX_PREFIXES 15 + +/* instruction aliases and special cases */ +static struct ud_itab_entry s_ie__invalid = + { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }; + +static int +decode_ext(struct ud *u, uint16_t ptr); + + +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 { + 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 { + 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 ) +{ + return ud_mnemonics_str[ c ]; +} + + +/* + * decode_prefixes + * + * Extracts instruction prefixes. + */ +static int +decode_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. */ + ud_inp_next(u); + if ( u->error ) + return -1; + curr = ud_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. + */ + ud_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_P: + return ( u->opr_mode == 16 ) ? SZ_WP : SZ_DP; + case SZ_MDQ: + 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 ) +{ + /* far/near flags */ + u->br_far = 0; + u->br_near = 0; + /* readjust operand sizes for call/jmp instrcutions */ + if ( u->mnemonic == UD_Icall || u->mnemonic == UD_Ijmp ) { + /* WP: 16:16 pointer */ + if ( u->operand[ 0 ].size == SZ_WP ) { + u->operand[ 0 ].size = 16; + u->br_far = 1; + u->br_near= 0; + /* DP: 32:32 pointer */ + } else if ( u->operand[ 0 ].size == SZ_DP ) { + u->operand[ 0 ].size = 32; + u->br_far = 1; + u->br_near= 0; + } else { + u->br_far = 0; + u->br_near= 1; + } + /* resolve 3dnow weirdness. */ + } else if ( u->mnemonic == UD_I3dnow ) { + u->mnemonic = ud_itab[ u->le->table[ ud_inp_curr( u ) ] ].mnemonic; + } + /* SWAPGS is only valid in 64bits mode */ + if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) { + u->error = 1; + 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_rep) { + u->pfx_rep = 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 = ud_inp_uint16(u); + op->lval.ptr.seg = ud_inp_uint16(u); + } else { + /* seg16:off32 */ + op->type = UD_OP_PTR; + op->size = 48; + op->lval.ptr.off = ud_inp_uint32(u); + op->lval.ptr.seg = ud_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) +{ + s = resolve_operand_size(u, s); + + switch (s) { + case 64: + return UD_R_RAX + rm; + case SZ_DP: + case 32: + return UD_R_EAX + rm; + case SZ_WP: + 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: + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * resolve_gpr64() - 64bit General Purpose Register-Selection. + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_gpr64(struct ud* u, enum ud_operand_code gpr_op, enum ud_operand_size * size) +{ + 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) { + *size = 16; + return gpr_op + UD_R_AX; + } + if (u->dis_mode == 32 || + (u->opr_mode == 32 && ! (REX_W(u->pfx_rex) || u->default64))) { + *size = 32; + return gpr_op + UD_R_EAX; + } + + *size = 64; + return gpr_op + UD_R_RAX; +} + +/* ----------------------------------------------------------------------------- + * resolve_gpr32 () - 32bit General Purpose Register-Selection. + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_gpr32(struct ud* u, enum ud_operand_code gpr_op) +{ + gpr_op = gpr_op - OP_eAX; + + if (u->opr_mode == 16) + return gpr_op + UD_R_AX; + + return gpr_op + UD_R_EAX; +} + +/* ----------------------------------------------------------------------------- + * resolve_reg() - Resolves the register type + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_reg(struct ud* u, unsigned int type, unsigned char i) +{ + switch (type) { + case T_MMX : return UD_R_MM0 + (i & 7); + case T_XMM : return UD_R_XMM0 + i; + case T_CRG : return UD_R_CR0 + i; + case T_DBG : return UD_R_DR0 + i; + case T_SEG : { + /* + * Only 6 segment registers, anything else is an error. + */ + if ((i & 7) > 5) { + u->error = 1; + } else { + return UD_R_ES + (i & 7); + } + } + case T_NONE: + default: return UD_NONE; + } +} + +/* ----------------------------------------------------------------------------- + * decode_imm() - Decodes Immediate values. + * ----------------------------------------------------------------------------- + */ +static void +decode_imm(struct ud* u, unsigned int s, struct ud_operand *op) +{ + op->size = resolve_operand_size(u, s); + op->type = UD_OP_IMM; + + switch (op->size) { + case 8: op->lval.sbyte = ud_inp_uint8(u); break; + case 16: op->lval.uword = ud_inp_uint16(u); break; + case 32: op->lval.udword = ud_inp_uint32(u); break; + case 64: op->lval.uqword = ud_inp_uint64(u); break; + default: return; + } +} + + +/* + * decode_modrm_reg + * + * Decodes reg field of mod/rm byte + * + */ +static 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)); + operand->type = UD_OP_REG; + operand->size = resolve_operand_size(u, size); + + if (type == T_GPR) { + operand->base = decode_gpr(u, operand->size, reg); + } else { + operand->base = resolve_reg(u, type, reg); + } +} + + +/* + * 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, + unsigned int size) + +{ + unsigned char mod, rm, reg; + + /* get mod, r/m and reg fields */ + mod = MODRM_MOD(modrm(u)); + rm = (REX_B(u->pfx_rex) << 3) | MODRM_RM(modrm(u)); + reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(modrm(u)); + + op->size = resolve_operand_size(u, size); + + /* + * If mod is 11b, then the modrm.rm specifies a register. + * + */ + if (mod == 3) { + op->type = UD_OP_REG; + if (type == T_GPR) { + op->base = decode_gpr(u, op->size, rm); + } else { + op->base = resolve_reg(u, type, (REX_B(u->pfx_rex) << 3) | (rm & 7)); + } + return; + } + + + /* + * !11 => Memory Address + */ + op->type = UD_OP_MEM; + + if (u->adr_mode == 64) { + op->base = UD_R_RAX + rm; + if (mod == 1) { + op->offset = 8; + } else if (mod == 2) { + op->offset = 32; + } else if (mod == 0 && (rm & 7) == 5) { + op->base = UD_R_RIP; + op->offset = 32; + } else { + op->offset = 0; + } + /* + * Scale-Index-Base (SIB) + */ + if ((rm & 7) == 4) { + ud_inp_next(u); + + op->scale = (1 << SIB_S(ud_inp_curr(u))) & ~1; + op->index = UD_R_RAX + (SIB_I(ud_inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); + op->base = UD_R_RAX + (SIB_B(ud_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) { + op->offset = 8; + } else { + op->offset = 32; + } + } + } + } else if (u->adr_mode == 32) { + op->base = UD_R_EAX + rm; + if (mod == 1) { + op->offset = 8; + } else if (mod == 2) { + op->offset = 32; + } else if (mod == 0 && rm == 5) { + op->base = UD_NONE; + op->offset = 32; + } else { + op->offset = 0; + } + + /* Scale-Index-Base (SIB) */ + if ((rm & 7) == 4) { + ud_inp_next(u); + + op->scale = (1 << SIB_S(ud_inp_curr(u))) & ~1; + op->index = UD_R_EAX + (SIB_I(ud_inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); + op->base = UD_R_EAX + (SIB_B(ud_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) { + op->offset = 8; + } else { + op->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) { + op->offset= 16; + op->base = UD_NONE; + } else if (mod == 1) { + op->offset = 8; + } else if (mod == 2) { + op->offset = 16; + } + } + + /* + * extract offset, if any + */ + switch (op->offset) { + case 8 : op->lval.ubyte = ud_inp_uint8(u); break; + case 16: op->lval.uword = ud_inp_uint16(u); break; + case 32: op->lval.udword = ud_inp_uint32(u); break; + case 64: op->lval.uqword = ud_inp_uint64(u); break; + default: break; + } +} + +/* ----------------------------------------------------------------------------- + * decode_o() - Decodes offset + * ----------------------------------------------------------------------------- + */ +static void +decode_o(struct ud* u, unsigned int s, struct ud_operand *op) +{ + switch (u->adr_mode) { + case 64: + op->offset = 64; + op->lval.uqword = ud_inp_uint64(u); + break; + case 32: + op->offset = 32; + op->lval.udword = ud_inp_uint32(u); + break; + case 16: + op->offset = 16; + op->lval.uword = ud_inp_uint16(u); + break; + default: + return; + } + op->type = UD_OP_MEM; + op->size = resolve_operand_size(u, s); +} + +/* ----------------------------------------------------------------------------- + * decode_operands() - Disassembles Operands. + * ----------------------------------------------------------------------------- + */ +static int +decode_operand(struct ud *u, + struct ud_operand *operand, + enum ud_operand_code type, + unsigned int size) +{ + switch (type) { + case OP_A : + decode_a(u, operand); + break; + case OP_MR: + if (MODRM_MOD(modrm(u)) == 3) { + decode_modrm_rm(u, operand, T_GPR, + size == SZ_DY ? SZ_MDQ : SZ_V); + } else if (size == SZ_WV) { + decode_modrm_rm( u, operand, T_GPR, SZ_W); + } else if (size == SZ_BV) { + decode_modrm_rm( u, operand, T_GPR, SZ_B); + } else if (size == SZ_DY) { + decode_modrm_rm( u, operand, T_GPR, SZ_D); + } else { + ASSERT(!"unexpected size"); + } + break; + case OP_M: + if (MODRM_MOD(modrm(u)) == 3) { + u->error = 1; + } + /* intended fall through */ + case OP_E: + decode_modrm_rm(u, operand, T_GPR, size); + break; + break; + case OP_G: + decode_modrm_reg(u, operand, T_GPR, size); + break; + case OP_I: + decode_imm(u, size, operand); + break; + case OP_I1: + operand->type = UD_OP_CONST; + operand->lval.udword = 1; + break; + case OP_PR: + if (MODRM_MOD(modrm(u)) != 3) { + u->error = 1; + } + decode_modrm_rm(u, operand, T_MMX, size); + break; + case OP_P: + decode_modrm_reg(u, operand, T_MMX, size); + break; + case OP_VR: + if (MODRM_MOD(modrm(u)) != 3) { + u->error = 1; + } + /* intended fall through */ + case OP_W: + decode_modrm_rm(u, operand, T_XMM, size); + break; + case OP_V: + decode_modrm_reg(u, operand, T_XMM, size); + break; + case OP_S: + decode_modrm_reg(u, operand, T_SEG, size); + break; + case OP_AL: + case OP_CL: + case OP_DL: + case OP_BL: + case OP_AH: + case OP_CH: + case OP_DH: + case OP_BH: + operand->type = UD_OP_REG; + operand->base = UD_R_AL + (type - OP_AL); + operand->size = 8; + break; + case OP_DX: + operand->type = UD_OP_REG; + operand->base = UD_R_DX; + operand->size = 16; + break; + case OP_O: + decode_o(u, size, operand); + break; + case OP_rAXr8: + case OP_rCXr9: + case OP_rDXr10: + case OP_rBXr11: + case OP_rSPr12: + case OP_rBPr13: + case OP_rSIr14: + case OP_rDIr15: + case OP_rAX: + case OP_rCX: + case OP_rDX: + case OP_rBX: + case OP_rSP: + case OP_rBP: + case OP_rSI: + case OP_rDI: + operand->type = UD_OP_REG; + operand->base = resolve_gpr64(u, type, &operand->size); + break; + case OP_ALr8b: + case OP_CLr9b: + case OP_DLr10b: + case OP_BLr11b: + case OP_AHr12b: + case OP_CHr13b: + case OP_DHr14b: + case OP_BHr15b: { + ud_type_t gpr = (type - OP_ALr8b) + UD_R_AL + + (REX_B(u->pfx_rex) << 3); + if (UD_R_AH <= gpr && u->pfx_rex) { + gpr = gpr + 4; + } + operand->type = UD_OP_REG; + operand->base = gpr; + break; + } + case OP_eAX: + case OP_eCX: + case OP_eDX: + case OP_eBX: + case OP_eSP: + case OP_eBP: + case OP_eSI: + case OP_eDI: + operand->type = UD_OP_REG; + operand->base = resolve_gpr32(u, type); + operand->size = u->opr_mode == 16 ? 16 : 32; + 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) { + u->error= 1; + } + } + 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_Q: + decode_modrm_rm(u, operand, T_MMX, size); + break; + case OP_R : + decode_modrm_rm(u, operand, T_GPR, size); + break; + case OP_C: + decode_modrm_reg(u, operand, T_CRG, size); + break; + case OP_D: + decode_modrm_reg(u, operand, T_DBG, 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 = 0; + break; + case OP_AX: + operand->type = UD_OP_REG; + operand->base = UD_R_AX; + operand->size = 16; + break; + default : + operand->type = UD_NONE; + 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_insn = 0; + u->mnemonic = UD_Inone; + u->itab_entry = NULL; + u->have_modrm = 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 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; +} + +static int gen_hex( struct ud *u ) +{ + unsigned int i; + unsigned char *src_ptr = ud_inp_sess( u ); + char* src_hex; + + /* bail out if in error stat. */ + if ( u->error ) return -1; + /* output buffer pointe */ + src_hex = ( char* ) u->insn_hexcode; + /* for each byte used to decode instruction */ + for ( i = 0; i < u->inp_ctr; ++i, ++src_ptr) { + sprintf( src_hex, "%02x", *src_ptr & 0xFF ); + src_hex += 2; + } + return 0; +} + + +static inline int +decode_insn(struct ud *u, uint16_t ptr) +{ + ASSERT((ptr & 0x8000) == 0); + u->itab_entry = &ud_itab[ ptr ]; + u->mnemonic = u->itab_entry->mnemonic; + return (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; + ASSERT(u->le->type == UD_TAB__OPC_3DNOW); + 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[ud_inp_curr(u)]; + ASSERT((ptr & 0x8000) == 0); + u->mnemonic = ud_itab[ptr].mnemonic; + return 0; +} + + +static int +decode_ssepfx(struct ud *u) +{ + uint8_t idx = ((u->pfx_insn & 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. + */ + switch (u->pfx_insn) { + case 0xf2: + u->pfx_repne = 0; + break; + case 0xf3: + u->pfx_rep = 0; + u->pfx_repe = 0; + break; + case 0x66: + u->pfx_opr = 0; + break; + } + } + 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 / 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 inline int +decode_opcode(struct ud *u) +{ + uint16_t ptr; + ASSERT(u->le->type == UD_TAB__OPC_TABLE); + ud_inp_next(u); + if (u->error) { + return -1; + } + ptr = u->le->table[ud_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) +{ + ud_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 = & s_ie__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->insn_fill = 0; /* set translation buffer index to 0 */ + u->pc += u->inp_ctr; /* move program counter by bytes decoded */ + gen_hex( u ); /* generate hex code */ + + /* return number of bytes disassembled. */ + return u->inp_ctr; +} + +/* +vim: set ts=2 sw=2 expandtab +*/ + +#endif // USE(UDIS86) |