2782 lines
66 KiB
C
2782 lines
66 KiB
C
/* 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 "extern.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);
|
|
static int decode_opcode(struct ud *u);
|
|
|
|
enum reg_class { /* register classes */
|
|
REGCLASS_GPR,
|
|
REGCLASS_MMX,
|
|
REGCLASS_CR,
|
|
REGCLASS_DB,
|
|
REGCLASS_SEG,
|
|
REGCLASS_XMM,
|
|
REGCLASS_BOUNDS,
|
|
REGCLASS_OPMASK
|
|
};
|
|
|
|
/*
|
|
* inp_start
|
|
* Should be called before each de-code operation.
|
|
*/
|
|
static void
|
|
inp_start(struct ud *u)
|
|
{
|
|
u->inp_ctr = 0;
|
|
}
|
|
|
|
static uint8_t
|
|
inp_peek(struct ud *u)
|
|
{
|
|
if (u->inp_end == 0) {
|
|
if (u->inp_buf != NULL) {
|
|
if (u->inp_buf_index < u->inp_buf_size) {
|
|
return u->inp_buf[u->inp_buf_index];
|
|
}
|
|
} else if (u->inp_peek != UD_EOI) {
|
|
return u->inp_peek;
|
|
} else {
|
|
int c;
|
|
if ((c = u->inp_hook(u)) != UD_EOI) {
|
|
u->inp_peek = c;
|
|
return u->inp_peek;
|
|
}
|
|
}
|
|
}
|
|
u->inp_end = 1;
|
|
UDERR(u, "byte expected, eoi received\n");
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t
|
|
inp_next(struct ud *u)
|
|
{
|
|
if (u->inp_end == 0) {
|
|
if (u->inp_buf != NULL) {
|
|
if (u->inp_buf_index < u->inp_buf_size) {
|
|
u->inp_ctr++;
|
|
return (u->inp_curr = u->inp_buf[u->inp_buf_index++]);
|
|
}
|
|
} else {
|
|
int c = u->inp_peek;
|
|
if (c != UD_EOI || (c = u->inp_hook(u)) != UD_EOI) {
|
|
u->inp_peek = UD_EOI;
|
|
u->inp_curr = c;
|
|
u->inp_sess[u->inp_ctr++] = u->inp_curr;
|
|
return u->inp_curr;
|
|
}
|
|
}
|
|
}
|
|
u->inp_end = 1;
|
|
UDERR(u, "byte expected, eoi received\n");
|
|
return 0;
|
|
}
|
|
|
|
static uint8_t
|
|
inp_curr(struct ud *u)
|
|
{
|
|
return u->inp_curr;
|
|
}
|
|
|
|
|
|
/*
|
|
* inp_uint8
|
|
* int_uint16
|
|
* int_uint32
|
|
* int_uint64
|
|
* Load little-endian values from input
|
|
*/
|
|
static uint8_t
|
|
inp_uint8(struct ud* u)
|
|
{
|
|
return inp_next(u);
|
|
}
|
|
|
|
static uint16_t
|
|
inp_uint16(struct ud* u)
|
|
{
|
|
uint16_t r, ret;
|
|
|
|
ret = inp_next(u);
|
|
r = inp_next(u);
|
|
return ret | (r << 8);
|
|
}
|
|
|
|
static uint32_t
|
|
inp_uint32(struct ud* u)
|
|
{
|
|
uint32_t r, ret;
|
|
|
|
ret = inp_next(u);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 8);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 16);
|
|
r = inp_next(u);
|
|
return ret | (r << 24);
|
|
}
|
|
|
|
static uint64_t
|
|
inp_uint64(struct ud* u)
|
|
{
|
|
uint64_t r, ret;
|
|
|
|
ret = inp_next(u);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 8);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 16);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 24);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 32);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 40);
|
|
r = inp_next(u);
|
|
ret = ret | (r << 48);
|
|
r = inp_next(u);
|
|
return ret | (r << 56);
|
|
}
|
|
|
|
|
|
static UD_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 UD_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;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* decode_prefixes
|
|
*
|
|
* Extracts instruction prefixes.
|
|
*/
|
|
int ud_decode_prefixes(struct ud *u)
|
|
{
|
|
int done = 0;
|
|
uint8_t curr = 0, last = 0;
|
|
UD_RETURN_ON_ERROR(u);
|
|
|
|
do {
|
|
last = curr;
|
|
curr = inp_next(u);
|
|
UD_RETURN_ON_ERROR(u);
|
|
if (u->inp_ctr == MAX_INSN_LENGTH) {
|
|
UD_RETURN_WITH_ERROR(u, "max instruction length");
|
|
}
|
|
|
|
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:
|
|
/* consume if rex */
|
|
done = (u->dis_mode == 64 && (curr & 0xF0) == 0x40) ? 0 : 1;
|
|
break;
|
|
}
|
|
} while (!done);
|
|
/* rex prefixes in 64bit mode, must be the last prefix */
|
|
if (u->dis_mode == 64 && (last & 0xF0) == 0x40) {
|
|
u->pfx_rex = last;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* vex_l, vex_w
|
|
* Return the vex.L and vex.W bits
|
|
*/
|
|
static UD_INLINE uint8_t
|
|
vex_l(const struct ud *u)
|
|
{
|
|
UD_ASSERT(u->vex_op != 0);
|
|
return ((u->vex_op != 0xc5 ? u->vex_b2 : u->vex_b1) >> 2) & 1;
|
|
}
|
|
|
|
static UD_INLINE uint8_t
|
|
vex_w(const struct ud *u)
|
|
{
|
|
UD_ASSERT(u->vex_op != 0);
|
|
return u->vex_op != 0xc5 ? ((u->vex_b2 >> 7) & 1) : 0;
|
|
}
|
|
|
|
|
|
static UD_INLINE uint8_t
|
|
modrm(struct ud * u)
|
|
{
|
|
if ( !u->have_modrm ) {
|
|
u->modrm = inp_next( u );
|
|
u->have_modrm = 1;
|
|
}
|
|
return u->modrm;
|
|
}
|
|
|
|
|
|
static unsigned int
|
|
resolve_operand_size(const struct ud* u, ud_operand_size_t osize)
|
|
{
|
|
switch (osize) {
|
|
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;
|
|
case SZ_X:
|
|
UD_ASSERT(u->vex_op != 0);
|
|
return (P_VEXL(u->itab_entry->prefix) && vex_l(u)) ? SZ_QQ : SZ_DQ;
|
|
default:
|
|
return osize;
|
|
}
|
|
}
|
|
|
|
|
|
static int resolve_mnemonic( struct ud* u )
|
|
{
|
|
if( u->mnemonic == UD_I3dnow )
|
|
{
|
|
// resolve 3dnow weirdness.
|
|
uint8_t idx = inp_curr( u );
|
|
|
|
if( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
|
|
u->mnemonic = ud_itab[ u->le->table[idx] ].mnemonic;
|
|
}
|
|
else if( u->mnemonic == UD_Iswapgs )
|
|
{
|
|
if( u->dis_mode != 64 )
|
|
{
|
|
UDERR(u, "swapgs invalid in 64bits mode\n");
|
|
return -1;
|
|
}
|
|
}
|
|
else 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;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Inop )
|
|
{
|
|
if( u->pfx_repe )
|
|
{
|
|
u->pfx_repe = 0;
|
|
u->mnemonic = UD_Ipause;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ixrstor )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ixrstor64;
|
|
}
|
|
else if( u->mnemonic == UD_Ixrstors )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ixrstors64;
|
|
}
|
|
else if( u->mnemonic == UD_Ixsave )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ixsave64;
|
|
}
|
|
else if( u->mnemonic == UD_Ixsavec )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ixsavec64;
|
|
}
|
|
else if( u->mnemonic == UD_Ixsaveopt )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ixsaveopt64;
|
|
}
|
|
else if( u->mnemonic == UD_Ixsaves )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ixsaves64;
|
|
}
|
|
else if( u->mnemonic == UD_Ifxrstor )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ifxrstor64;
|
|
}
|
|
else if( u->mnemonic == UD_Ifxsave )
|
|
{
|
|
if( u->pfx_rex != 0 && u->dis_mode == 64 && u->opr_mode == 64 )
|
|
u->mnemonic = UD_Ifxsave64;
|
|
}
|
|
else
|
|
{
|
|
// test the third/fourth operand for a immediate to see if we need to change the opcode.
|
|
if( u->operand[2].type == UD_OP_IMM )
|
|
{
|
|
if( u->mnemonic == UD_Ipclmulqdq )
|
|
{
|
|
switch( u->operand[2].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ipclmullqlqdq;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ipclmulhqlqdq;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x10:
|
|
u->mnemonic = UD_Ipclmullqhqdq;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x11:
|
|
u->mnemonic = UD_Ipclmulhqhqdq;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Icmppd )
|
|
{
|
|
switch( u->operand[2].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Icmpeqpd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Icmpltpd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Icmplepd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Icmpunordpd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Icmpneqpd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Icmpnltpd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Icmpnlepd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Icmpordpd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Icmpps )
|
|
{
|
|
switch( u->operand[2].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Icmpeqps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Icmpltps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Icmpleps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Icmpunordps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Icmpneqps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Icmpnltps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Icmpnleps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Icmpordps;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Icmpss )
|
|
{
|
|
switch( u->operand[2].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Icmpeqss;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Icmpltss;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Icmpless;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Icmpunordss;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Icmpneqss;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Icmpnltss;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Icmpnless;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Icmpordss;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Icmpsd )
|
|
{
|
|
switch( u->operand[2].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Icmpeqsd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Icmpltsd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Icmplesd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Icmpunordsd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Icmpneqsd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Icmpnltsd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Icmpnlesd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Icmpordsd;
|
|
u->operand[2].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if( u->operand[3].type == UD_OP_IMM )
|
|
{
|
|
if( u->mnemonic == UD_Ivpclmulqdq )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpclmullqlqdq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpclmulhqlqdq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x10:
|
|
u->mnemonic = UD_Ivpclmullqhqdq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x11:
|
|
u->mnemonic = UD_Ivpclmulhqhqdq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivcmppd )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivcmpeqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivcmpltpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivcmplepd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivcmpunordpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivcmpneqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivcmpnltpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivcmpnlepd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivcmpordpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x08:
|
|
u->mnemonic = UD_Ivcmpeq_uqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x09:
|
|
u->mnemonic = UD_Ivcmpngepd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0A:
|
|
u->mnemonic = UD_Ivcmpngtpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0B:
|
|
u->mnemonic = UD_Ivcmpfalsepd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0C:
|
|
u->mnemonic = UD_Ivcmpneq_oqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0D:
|
|
u->mnemonic = UD_Ivcmpgepd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0E:
|
|
u->mnemonic = UD_Ivcmpgtpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0F:
|
|
u->mnemonic = UD_Ivcmptruepd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x10:
|
|
u->mnemonic = UD_Ivcmpeq_ospd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x11:
|
|
u->mnemonic = UD_Ivcmplt_oqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x12:
|
|
u->mnemonic = UD_Ivcmple_oqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x13:
|
|
u->mnemonic = UD_Ivcmpunord_spd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x14:
|
|
u->mnemonic = UD_Ivcmpneq_uspd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x15:
|
|
u->mnemonic = UD_Ivcmpnlt_uqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x16:
|
|
u->mnemonic = UD_Ivcmpnle_uqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x17:
|
|
u->mnemonic = UD_Ivcmpord_spd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x18:
|
|
u->mnemonic = UD_Ivcmpeq_uspd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x19:
|
|
u->mnemonic = UD_Ivcmpnge_uqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1A:
|
|
u->mnemonic = UD_Ivcmpngt_uqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1B:
|
|
u->mnemonic = UD_Ivcmpfalse_ospd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1C:
|
|
u->mnemonic = UD_Ivcmpneq_ospd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1D:
|
|
u->mnemonic = UD_Ivcmpge_oqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1E:
|
|
u->mnemonic = UD_Ivcmpgt_oqpd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1F:
|
|
u->mnemonic = UD_Ivcmptrue_uspd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivcmpps )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivcmpeqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivcmpltps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivcmpleps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivcmpunordps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivcmpneqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivcmpnltps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivcmpnleps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivcmpordps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x08:
|
|
u->mnemonic = UD_Ivcmpeq_uqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x09:
|
|
u->mnemonic = UD_Ivcmpngeps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0A:
|
|
u->mnemonic = UD_Ivcmpngtps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0B:
|
|
u->mnemonic = UD_Ivcmpfalseps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0C:
|
|
u->mnemonic = UD_Ivcmpneq_oqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0D:
|
|
u->mnemonic = UD_Ivcmpgeps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0E:
|
|
u->mnemonic = UD_Ivcmpgtps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0F:
|
|
u->mnemonic = UD_Ivcmptrueps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x10:
|
|
u->mnemonic = UD_Ivcmpeq_osps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x11:
|
|
u->mnemonic = UD_Ivcmplt_oqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x12:
|
|
u->mnemonic = UD_Ivcmple_oqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x13:
|
|
u->mnemonic = UD_Ivcmpunord_sps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x14:
|
|
u->mnemonic = UD_Ivcmpneq_usps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x15:
|
|
u->mnemonic = UD_Ivcmpnlt_uqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x16:
|
|
u->mnemonic = UD_Ivcmpnle_uqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x17:
|
|
u->mnemonic = UD_Ivcmpord_sps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x18:
|
|
u->mnemonic = UD_Ivcmpeq_usps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x19:
|
|
u->mnemonic = UD_Ivcmpnge_uqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1A:
|
|
u->mnemonic = UD_Ivcmpngt_uqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1B:
|
|
u->mnemonic = UD_Ivcmpfalse_osps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1C:
|
|
u->mnemonic = UD_Ivcmpneq_osps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1D:
|
|
u->mnemonic = UD_Ivcmpge_oqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1E:
|
|
u->mnemonic = UD_Ivcmpgt_oqps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1F:
|
|
u->mnemonic = UD_Ivcmptrue_usps;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivcmpss )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivcmpeqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivcmpltss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivcmpless;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivcmpunordss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivcmpneqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivcmpnltss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivcmpnless;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivcmpordss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x08:
|
|
u->mnemonic = UD_Ivcmpeq_uqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x09:
|
|
u->mnemonic = UD_Ivcmpngess;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0A:
|
|
u->mnemonic = UD_Ivcmpngtss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0B:
|
|
u->mnemonic = UD_Ivcmpfalsess;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0C:
|
|
u->mnemonic = UD_Ivcmpneq_oqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0D:
|
|
u->mnemonic = UD_Ivcmpgess;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0E:
|
|
u->mnemonic = UD_Ivcmpgtss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0F:
|
|
u->mnemonic = UD_Ivcmptruess;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x10:
|
|
u->mnemonic = UD_Ivcmpeq_osss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x11:
|
|
u->mnemonic = UD_Ivcmplt_oqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x12:
|
|
u->mnemonic = UD_Ivcmple_oqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x13:
|
|
u->mnemonic = UD_Ivcmpunord_sss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x14:
|
|
u->mnemonic = UD_Ivcmpneq_usss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x15:
|
|
u->mnemonic = UD_Ivcmpnlt_uqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x16:
|
|
u->mnemonic = UD_Ivcmpnle_uqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x17:
|
|
u->mnemonic = UD_Ivcmpord_sss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x18:
|
|
u->mnemonic = UD_Ivcmpeq_usss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x19:
|
|
u->mnemonic = UD_Ivcmpnge_uqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1A:
|
|
u->mnemonic = UD_Ivcmpngt_uqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1B:
|
|
u->mnemonic = UD_Ivcmpfalse_osss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1C:
|
|
u->mnemonic = UD_Ivcmpneq_osss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1D:
|
|
u->mnemonic = UD_Ivcmpge_oqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1E:
|
|
u->mnemonic = UD_Ivcmpgt_oqss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1F:
|
|
u->mnemonic = UD_Ivcmptrue_usss;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivcmpsd )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivcmpeqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivcmpltsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivcmplesd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivcmpunordsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivcmpneqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivcmpnltsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivcmpnlesd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivcmpordsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x08:
|
|
u->mnemonic = UD_Ivcmpeq_uqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x09:
|
|
u->mnemonic = UD_Ivcmpngesd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0A:
|
|
u->mnemonic = UD_Ivcmpngtsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0B:
|
|
u->mnemonic = UD_Ivcmpfalsesd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0C:
|
|
u->mnemonic = UD_Ivcmpneq_oqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0D:
|
|
u->mnemonic = UD_Ivcmpgesd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0E:
|
|
u->mnemonic = UD_Ivcmpgtsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x0F:
|
|
u->mnemonic = UD_Ivcmptruesd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x10:
|
|
u->mnemonic = UD_Ivcmpeq_ossd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x11:
|
|
u->mnemonic = UD_Ivcmplt_oqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x12:
|
|
u->mnemonic = UD_Ivcmple_oqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x13:
|
|
u->mnemonic = UD_Ivcmpunord_ssd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x14:
|
|
u->mnemonic = UD_Ivcmpneq_ussd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x15:
|
|
u->mnemonic = UD_Ivcmpnlt_uqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x16:
|
|
u->mnemonic = UD_Ivcmpnle_uqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x17:
|
|
u->mnemonic = UD_Ivcmpord_ssd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x18:
|
|
u->mnemonic = UD_Ivcmpeq_ussd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x19:
|
|
u->mnemonic = UD_Ivcmpnge_uqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1A:
|
|
u->mnemonic = UD_Ivcmpngt_uqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1B:
|
|
u->mnemonic = UD_Ivcmpfalse_ossd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1C:
|
|
u->mnemonic = UD_Ivcmpneq_ossd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1D:
|
|
u->mnemonic = UD_Ivcmpge_oqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1E:
|
|
u->mnemonic = UD_Ivcmpgt_oqsd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x1F:
|
|
u->mnemonic = UD_Ivcmptrue_ussd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomb )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomleb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgeb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomeqb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomneqb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalseb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrueb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomd )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomled;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomged;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomeqd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomneqd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalsed;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrued;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomq )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomleq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgeq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomeqq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomneqq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalseq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrueq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomub )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltub;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomleub;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtub;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgeub;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomequb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomnequb;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalseub;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrueub;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomud )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltud;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomleud;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtud;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgeud;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomequd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomnequd;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalseud;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrueud;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomuq )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltuq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomleuq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtuq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgeuq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomequq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomnequq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalseuq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrueuq;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomuw )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltuw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomleuw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtuw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgeuw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomequw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomnequw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalseuw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtrueuw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ivpcomw )
|
|
{
|
|
switch( u->operand[3].lval.ubyte )
|
|
{
|
|
case 0x00:
|
|
u->mnemonic = UD_Ivpcomltw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x01:
|
|
u->mnemonic = UD_Ivpcomlew;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x02:
|
|
u->mnemonic = UD_Ivpcomgtw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x03:
|
|
u->mnemonic = UD_Ivpcomgew;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x04:
|
|
u->mnemonic = UD_Ivpcomeqw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x05:
|
|
u->mnemonic = UD_Ivpcomneqw;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x06:
|
|
u->mnemonic = UD_Ivpcomfalsew;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
case 0x07:
|
|
u->mnemonic = UD_Ivpcomtruew;
|
|
u->operand[3].type = UD_NONE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
case 0:
|
|
/* invalid size in case of a decode error */
|
|
UD_ASSERT(u->error);
|
|
return UD_NONE;
|
|
default:
|
|
UD_ASSERT(!"invalid operand size");
|
|
return UD_NONE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_reg(struct ud *u,
|
|
struct ud_operand *opr,
|
|
int type,
|
|
int num,
|
|
int size)
|
|
{
|
|
int reg = -1;
|
|
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 = num + (size == SZ_QQ ? UD_R_YMM0 : UD_R_XMM0);
|
|
break;
|
|
case REGCLASS_CR : reg = UD_R_CR0 + num; break;
|
|
case REGCLASS_DB : reg = UD_R_DR0 + num; break;
|
|
case REGCLASS_BOUNDS : reg = UD_R_BND0 + num; break;
|
|
case REGCLASS_OPMASK : reg = UD_R_K0 + num; break;
|
|
case REGCLASS_SEG : {
|
|
/*
|
|
* Only 6 segment registers, anything else is an error.
|
|
*/
|
|
if ((num & 7) > 5) {
|
|
UDERR(u, "invalid segment register value\n");
|
|
return;
|
|
} else {
|
|
reg = UD_R_ES + (num & 7);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
UD_ASSERT(!"invalid register type");
|
|
return;
|
|
}
|
|
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 UD_INLINE void
|
|
decode_modrm_reg(struct ud *u,
|
|
struct ud_operand *operand,
|
|
unsigned int type,
|
|
unsigned int size)
|
|
{
|
|
uint8_t reg = (REX_R(u->_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->_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) {
|
|
inp_next(u);
|
|
|
|
op->base = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->_rex) << 3));
|
|
op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->_rex) << 3));
|
|
/* special conditions for base reference */
|
|
if (op->index == UD_R_RSP) {
|
|
op->index = UD_NONE;
|
|
op->scale = UD_NONE;
|
|
} else {
|
|
op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
|
|
}
|
|
|
|
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 {
|
|
op->scale = UD_NONE;
|
|
op->index = UD_NONE;
|
|
}
|
|
} 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) {
|
|
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 {
|
|
op->scale = UD_NONE;
|
|
op->index = UD_NONE;
|
|
}
|
|
} 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];
|
|
op->scale = UD_NONE;
|
|
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, (unsigned int) offset, op);
|
|
} else {
|
|
op->offset = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 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->base = UD_NONE;
|
|
opr->index = UD_NONE;
|
|
opr->scale = UD_NONE;
|
|
opr->size = resolve_operand_size(u, size);
|
|
decode_mem_disp(u, u->adr_mode, opr);
|
|
}
|
|
|
|
|
|
static void
|
|
decode_vex_vvvv(struct ud *u, struct ud_operand *opr, unsigned char type, unsigned size)
|
|
{
|
|
uint8_t vvvv;
|
|
UD_ASSERT(u->vex_op != 0);
|
|
vvvv = ((u->vex_op != 0xc5 ? u->vex_b2 : u->vex_b1) >> 3) & 0xf;
|
|
decode_reg(u, opr, type, (0xf & ~vvvv), size);
|
|
}
|
|
|
|
|
|
/*
|
|
* decode_vex_immreg
|
|
* Decode source operand encoded in immediate byte [7:4]
|
|
*/
|
|
static int
|
|
decode_vex_immreg(struct ud *u, struct ud_operand *opr, unsigned size)
|
|
{
|
|
uint8_t imm = inp_next(u);
|
|
uint8_t mask = u->dis_mode == 64 ? 0xf : 0x7;
|
|
UD_RETURN_ON_ERROR(u);
|
|
UD_ASSERT(u->vex_op != 0);
|
|
decode_reg(u, opr, REGCLASS_XMM, mask & (imm >> 4), size);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void decode_vex_vsib( struct ud *u, struct ud_operand *op, unsigned size, enum ud_type index_base )
|
|
{
|
|
size_t offset = 0;
|
|
unsigned char mod, rm;
|
|
|
|
mod = MODRM_MOD(modrm(u));
|
|
|
|
if (mod == 3)
|
|
return;
|
|
|
|
rm = (REX_B(u->_rex) << 3) | MODRM_RM(modrm(u));
|
|
|
|
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) {
|
|
inp_next(u);
|
|
|
|
op->base = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->_rex) << 3));
|
|
op->index = index_base + (SIB_I(inp_curr(u)) | (REX_X(u->_rex) << 3));
|
|
/* special conditions for base reference */
|
|
if (op->index == UD_R_RSP) {
|
|
op->index = UD_NONE;
|
|
op->scale = UD_NONE;
|
|
} else {
|
|
op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
|
|
}
|
|
|
|
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 {
|
|
op->scale = UD_NONE;
|
|
op->index = UD_NONE;
|
|
}
|
|
} 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) {
|
|
inp_next(u);
|
|
|
|
op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
|
|
op->index = index_base + (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 {
|
|
op->scale = UD_NONE;
|
|
op->index = UD_NONE;
|
|
}
|
|
}
|
|
|
|
if (offset) {
|
|
decode_mem_disp(u, offset, op);
|
|
} else {
|
|
op->offset = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
/*
|
|
* decode_operand
|
|
*
|
|
* Decodes a single operand.
|
|
* Returns the type of the operand (UD_NONE if none)
|
|
*/
|
|
static int
|
|
decode_operand(struct ud *u,
|
|
struct ud_operand *operand,
|
|
enum ud_operand_code type,
|
|
unsigned int size)
|
|
{
|
|
operand->type = UD_NONE;
|
|
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\n");
|
|
}
|
|
/* 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_B:
|
|
decode_modrm_reg(u, operand, REGCLASS_BOUNDS, size);
|
|
break;
|
|
case OP_BM:
|
|
decode_modrm_rm(u, operand, REGCLASS_BOUNDS, size);
|
|
break;
|
|
case OP_BMR:
|
|
decode_modrm_rm(u, operand, REGCLASS_BOUNDS,
|
|
MODRM_MOD(modrm(u)) == 3 ?
|
|
Mx_reg_size(size) : Mx_mem_size(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\n");
|
|
}
|
|
/* 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\n");
|
|
}
|
|
/* 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_H:
|
|
decode_vex_vvvv(u, operand, REGCLASS_XMM, size);
|
|
break;
|
|
case OP_HR:
|
|
decode_vex_vvvv(u, operand, REGCLASS_GPR, size);
|
|
break;
|
|
case OP_XS:
|
|
decode_vex_vsib(u, operand, size, ((P_VEXL(u->itab_entry->prefix) && vex_l(u)) ? UD_R_YMM0 : UD_R_XMM0) );
|
|
break;
|
|
case OP_XSX:
|
|
decode_vex_vsib(u, operand, size, UD_R_XMM0 );
|
|
break;
|
|
case OP_XSY:
|
|
decode_vex_vsib(u, operand, size, UD_R_YMM0 );
|
|
break;
|
|
case OP_K:
|
|
decode_modrm_reg(u, operand, REGCLASS_OPMASK, size);
|
|
break;
|
|
case OP_KM:
|
|
decode_modrm_rm(u, operand, REGCLASS_OPMASK, size);
|
|
break;
|
|
case OP_KH:
|
|
decode_vex_vvvv(u, operand, REGCLASS_OPMASK, 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->_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\n");
|
|
}
|
|
}
|
|
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\n");
|
|
}
|
|
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;
|
|
case OP_L:
|
|
decode_vex_immreg(u, operand, size);
|
|
break;
|
|
case OP_IMP_XMM0:
|
|
operand->type = UD_OP_REG;
|
|
operand->base = UD_R_XMM0;
|
|
operand->size = SZ_DQ;
|
|
break;
|
|
default :
|
|
operand->type = UD_NONE;
|
|
break;
|
|
}
|
|
return operand->type;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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
|
|
);
|
|
|
|
u->operand[0].access = u->itab_entry->access1;
|
|
|
|
if( u->operand[0].access == UD_ACCESS_NONE && u->operand[0].type == UD_OP_IMM )
|
|
u->operand[0].access = UD_ACCESS_READ;
|
|
|
|
if( u->operand[0].type != UD_NONE )
|
|
{
|
|
decode_operand(
|
|
u,
|
|
&u->operand[1],
|
|
u->itab_entry->operand2.type,
|
|
u->itab_entry->operand2.size
|
|
);
|
|
|
|
u->operand[1].access = u->itab_entry->access2;
|
|
|
|
if( u->operand[1].access == UD_ACCESS_NONE && u->operand[1].type == UD_OP_IMM )
|
|
u->operand[1].access = UD_ACCESS_READ;
|
|
}
|
|
|
|
if( u->operand[1].type != UD_NONE )
|
|
{
|
|
decode_operand(
|
|
u,
|
|
&u->operand[2],
|
|
u->itab_entry->operand3.type,
|
|
u->itab_entry->operand3.size
|
|
);
|
|
|
|
u->operand[2].access = u->itab_entry->access3;
|
|
|
|
if( u->operand[2].access == UD_ACCESS_NONE && u->operand[2].type == UD_OP_IMM )
|
|
u->operand[2].access = UD_ACCESS_READ;
|
|
}
|
|
|
|
if( u->operand[2].type != UD_NONE )
|
|
{
|
|
decode_operand(
|
|
u,
|
|
&u->operand[3],
|
|
u->itab_entry->operand4.type,
|
|
u->itab_entry->operand4.size
|
|
);
|
|
|
|
u->operand[3].access = u->itab_entry->access4;
|
|
|
|
if( u->operand[3].access == UD_ACCESS_NONE && u->operand[3].type == UD_OP_IMM )
|
|
u->operand[3].access = UD_ACCESS_READ;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* clear_insn() - clear instruction structure
|
|
* -----------------------------------------------------------------------------
|
|
*/
|
|
void ud_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_bnd = 0;
|
|
u->pfx_xacquire = 0;
|
|
u->pfx_xrelease = 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;
|
|
u->vex_op = 0;
|
|
u->_rex = 0;
|
|
u->operand[0].type = UD_NONE;
|
|
u->operand[1].type = UD_NONE;
|
|
u->operand[2].type = UD_NONE;
|
|
u->operand[3].type = UD_NONE;
|
|
}
|
|
|
|
static UD_INLINE int resolve_pfx_str( struct ud * u )
|
|
{
|
|
if( u->pfx_str == 0xf3 )
|
|
{
|
|
if( u->vendor == UD_VENDOR_AMD )
|
|
{
|
|
u->pfx_repe = u->pfx_str;
|
|
}
|
|
else
|
|
{
|
|
if( u->pfx_lock == 0xf0 )
|
|
{
|
|
if( u->operand[0].type == UD_OP_MEM )
|
|
{
|
|
switch( u->mnemonic )
|
|
{
|
|
case UD_Iadd:
|
|
case UD_Iadc:
|
|
case UD_Iand:
|
|
case UD_Ibtc:
|
|
case UD_Ibtr:
|
|
case UD_Ibts:
|
|
case UD_Icmpxchg:
|
|
case UD_Icmpxchg8b:
|
|
case UD_Idec:
|
|
case UD_Iinc:
|
|
case UD_Ineg:
|
|
case UD_Inot:
|
|
case UD_Ior:
|
|
case UD_Isbb:
|
|
case UD_Isub:
|
|
case UD_Ixor:
|
|
case UD_Ixadd:
|
|
case UD_Ixchg:
|
|
u->pfx_xrelease = u->pfx_str;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ixchg )
|
|
{
|
|
u->pfx_xrelease = u->pfx_str;
|
|
}
|
|
else if( u->mnemonic == UD_Imov && u->operand[0].type == UD_OP_MEM && (u->operand[1].type == UD_OP_REG || u->operand[1].type == UD_OP_IMM ) )
|
|
{
|
|
u->pfx_xrelease = u->pfx_str;
|
|
}
|
|
|
|
if( u->pfx_xrelease != u->pfx_str )
|
|
{
|
|
if( P_STR( u->itab_entry->prefix ) )
|
|
{
|
|
u->pfx_rep = u->pfx_str;
|
|
}
|
|
else
|
|
{
|
|
u->pfx_repe = u->pfx_str;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( u->pfx_str == 0xf2 )
|
|
{
|
|
if( u->vendor == UD_VENDOR_AMD )
|
|
{
|
|
u->pfx_repne = u->pfx_str;
|
|
}
|
|
else
|
|
{
|
|
if( u->pfx_lock == 0xf0 )
|
|
{
|
|
if( u->operand[0].type == UD_OP_MEM )
|
|
{
|
|
switch( u->mnemonic )
|
|
{
|
|
case UD_Iadd:
|
|
case UD_Iadc:
|
|
case UD_Iand:
|
|
case UD_Ibtc:
|
|
case UD_Ibtr:
|
|
case UD_Ibts:
|
|
case UD_Icmpxchg:
|
|
case UD_Icmpxchg8b:
|
|
case UD_Idec:
|
|
case UD_Iinc:
|
|
case UD_Ineg:
|
|
case UD_Inot:
|
|
case UD_Ior:
|
|
case UD_Isbb:
|
|
case UD_Isub:
|
|
case UD_Ixor:
|
|
case UD_Ixadd:
|
|
case UD_Ixchg:
|
|
u->pfx_xacquire = u->pfx_str;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if( u->mnemonic == UD_Ixchg )
|
|
{
|
|
u->pfx_xacquire = u->pfx_str;
|
|
}
|
|
|
|
if( u->pfx_xacquire != u->pfx_str )
|
|
{
|
|
switch( u->mnemonic )
|
|
{
|
|
case UD_Icall:
|
|
case UD_Iret:
|
|
case UD_Ija:
|
|
case UD_Ijae:
|
|
case UD_Ijb:
|
|
case UD_Ijbe:
|
|
case UD_Ijcxz:
|
|
case UD_Ijecxz:
|
|
case UD_Ijg:
|
|
case UD_Ijge:
|
|
case UD_Ijl:
|
|
case UD_Ijle:
|
|
case UD_Ijmp:
|
|
case UD_Ijno:
|
|
case UD_Ijnp:
|
|
case UD_Ijns:
|
|
case UD_Ijnz:
|
|
case UD_Ijo:
|
|
case UD_Ijp:
|
|
case UD_Ijrcxz:
|
|
case UD_Ijs:
|
|
case UD_Ijz:
|
|
u->pfx_bnd = u->pfx_str;
|
|
break;
|
|
default:
|
|
u->pfx_repne = u->pfx_str;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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 || u->vex_op == 0x8f ) {
|
|
/* vex has rex.rxb in 1's complement */
|
|
u->_rex = ((~(u->vex_b1 >> 5) & 0x7) /* rex.0rxb */ | ((u->vex_b2 >> 4) & 0x8) /* rex.w000 */);
|
|
// patch back in pfx_rex so decode_mod_rm() works as expected under certain conditions.
|
|
u->pfx_rex = u->_rex;
|
|
} else if (u->vex_op == 0xc5) {
|
|
/* vex has rex.r in 1's complement */
|
|
u->_rex = (~(u->vex_b1 >> 5)) & 4;
|
|
// patch back in pfx_rex...
|
|
u->pfx_rex = u->_rex;
|
|
} else {
|
|
UD_ASSERT(u->vex_op == 0);
|
|
u->_rex = u->pfx_rex;
|
|
}
|
|
u->_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->_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;
|
|
}
|
|
|
|
|
|
static UD_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_mode(u) == 0 &&
|
|
decode_operands(u) == 0 &&
|
|
resolve_pfx_str(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 UD_INLINE int
|
|
decode_3dnow(struct ud* u)
|
|
{
|
|
uint8_t idx;
|
|
uint16_t ptr;
|
|
UD_ASSERT(u->le->type == UD_TAB__OPC_3DNOW);
|
|
UD_ASSERT(u->le->table[0xc] != 0);
|
|
if( 0xc > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
decode_insn(u, u->le->table[0xc]);
|
|
inp_next(u);
|
|
if (u->error) {
|
|
return -1;
|
|
}
|
|
idx = inp_curr(u);
|
|
if( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
ptr = u->le->table[idx];
|
|
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( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
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]);
|
|
}
|
|
|
|
|
|
static int
|
|
decode_vex(struct ud *u)
|
|
{
|
|
uint8_t idx;
|
|
if (u->dis_mode != 64 && MODRM_MOD(inp_peek(u)) != 0x3)
|
|
{
|
|
idx = 0;
|
|
}
|
|
else
|
|
{
|
|
u->vex_op = inp_curr(u);
|
|
u->vex_b1 = inp_next(u);
|
|
if (u->vex_op == 0xc4 || u->vex_op == 0x8f)
|
|
{
|
|
uint8_t pp, m;
|
|
/* 3-byte vex/xop */
|
|
u->vex_b2 = inp_next(u);
|
|
UD_RETURN_ON_ERROR(u);
|
|
m = u->vex_b1 & 0x1f;
|
|
if (u->vex_op == 0x8f)
|
|
{
|
|
if( m != 8 && m != 9 && m != 10 )
|
|
UD_RETURN_WITH_ERROR(u, "reserved vex.m-mmmm value");
|
|
// see ud_opcode.py:93
|
|
pp = u->vex_b2 & 0x3;
|
|
if( m == 8 )
|
|
idx = (pp << 2) | 0x10;
|
|
else if( m == 9 )
|
|
idx = (pp << 2) | 0x14;
|
|
else
|
|
idx = (pp << 2) | 0x18;
|
|
}
|
|
else if (m == 0 || m > 3)
|
|
{
|
|
UD_RETURN_WITH_ERROR(u, "reserved vex.m-mmmm value");
|
|
}
|
|
else
|
|
{
|
|
pp = u->vex_b2 & 0x3;
|
|
idx = (pp << 2) | m;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 2-byte vex */
|
|
UD_ASSERT(u->vex_op == 0xc5);
|
|
idx = 0x1 | ((u->vex_b1 & 0x3) << 2);
|
|
}
|
|
}
|
|
|
|
if( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
|
|
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 */
|
|
if( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
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);
|
|
case UD_TAB__OPC_VEX:
|
|
{
|
|
// if we have an XOP inst, test the map is < 8 then this is a POP not an XOP instruction.
|
|
if( (inp_curr( u ) == 0x8F) && (( inp_peek( u ) & 0x1f ) < 8) )
|
|
{
|
|
// table 0 in the VEX tables is where we encoded the POP with
|
|
// <opc>/vex=10 /reg=0</opc>
|
|
return decode_ext( u, u->le->table[0] );
|
|
}
|
|
return decode_vex(u);
|
|
}
|
|
case UD_TAB__OPC_VEX_W:
|
|
idx = vex_w(u);
|
|
break;
|
|
case UD_TAB__OPC_VEX_L:
|
|
idx = vex_l(u);
|
|
break;
|
|
case UD_TAB__OPC_TABLE:
|
|
inp_next(u);
|
|
return decode_opcode(u);
|
|
default:
|
|
UD_ASSERT(!"not reached");
|
|
break;
|
|
}
|
|
|
|
if( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
|
|
return decode_ext(u, u->le->table[idx]);
|
|
}
|
|
|
|
|
|
static int
|
|
decode_opcode(struct ud *u)
|
|
{
|
|
uint16_t ptr;
|
|
uint8_t idx;
|
|
|
|
UD_ASSERT(u->le->type == UD_TAB__OPC_TABLE);
|
|
UD_RETURN_ON_ERROR(u);
|
|
|
|
idx = inp_curr(u);
|
|
|
|
if( idx > u->le->limit ) {
|
|
UDERR(u, "out of bounds table idx\n");
|
|
return -1;
|
|
}
|
|
|
|
ptr = u->le->table[idx];
|
|
|
|
return decode_ext(u, ptr);
|
|
}
|
|
|
|
|
|
/* =============================================================================
|
|
* ud_decode() - Instruction decoder. Returns the number of bytes decoded.
|
|
* =============================================================================
|
|
*/
|
|
unsigned int
|
|
ud_decode(struct ud *u)
|
|
{
|
|
int i = 0;
|
|
inp_start(u);
|
|
ud_clear_insn(u);
|
|
u->le = &ud_lookup_table_list[0];
|
|
u->error = ud_decode_prefixes(u) == -1 ||
|
|
decode_opcode(u) == -1 ||
|
|
u->error;
|
|
/* Handle decode error. */
|
|
if (u->error) {
|
|
/* clear out the decode data. */
|
|
ud_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;
|
|
|
|
/* Retrieve some information about operands. */
|
|
for (i=0; i<4; i++) {
|
|
struct ud_operand *op = &u->operand[i];
|
|
switch (op->type) {
|
|
case UD_OP_REG: op->signed_lval = 0; break;
|
|
case UD_OP_MEM: op->signed_lval = 0; break;
|
|
case UD_OP_IMM: op->signed_lval = (op->_oprcode == OP_sI ? 1 : 0); break;
|
|
case UD_OP_JIMM: op->signed_lval = 1; break;
|
|
case UD_OP_PTR: op->signed_lval = 0; break;
|
|
case UD_OP_CONST: op->signed_lval = 0; break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
u->operand[0].access = u->itab_entry->operand1_access;
|
|
u->operand[1].access = u->itab_entry->operand2_access;
|
|
u->operand[2].access = UD_OP_ACCESS_READ;
|
|
u->operand[3].access = UD_OP_ACCESS_READ;
|
|
|
|
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 (unsigned int) u->inp_ctr;
|
|
}
|
|
|
|
/*
|
|
vim: set ts=2 sw=2 expandtab
|
|
*/
|