Skip to content

Commit

Permalink
Inital support for x86 implicit operands
Browse files Browse the repository at this point in the history
  • Loading branch information
John Detter committed Aug 17, 2016
1 parent 7bcafa0 commit 8074859
Show file tree
Hide file tree
Showing 5 changed files with 544 additions and 500 deletions.
57 changes: 31 additions & 26 deletions common/src/arch-x86.C
Expand Up @@ -709,7 +709,11 @@ static int vex3_simdop_convert[3][4] = {
#define ST5 { am_reg, x86::ist5 }
#define ST6 { am_reg, x86::ist6 }
#define ST7 { am_reg, x86::ist7 }
#define FPOS 17

/**
* NOTE: if more than 256 hacks are needed here, then the bit fields in arch-x86.h need
* to be adjusted.
*/

enum {
fNT=1, // non-temporal
Expand All @@ -722,7 +726,7 @@ enum {
fCALL,
fNEARRET,
fFARRET,
fIRET,
fIRET, /* 10 */
fENTER,
fLEAVE,
fXLAT,
Expand All @@ -732,7 +736,7 @@ enum {
fCMPXCH,
fCMPXCH8,
fINDIRCALL,
fINDIRJUMP,
fINDIRJUMP, /* 20*/
fFXSAVE,
fFXRSTOR,
fCLFLUSH,
Expand All @@ -741,6 +745,7 @@ enum {
fCMPS
};


COMMON_EXPORT dyn_hash_map<entryID, std::string> entryNames_IAPI = map_list_of
(e_aaa, "aaa")
(e_aad, "aad")
Expand Down Expand Up @@ -2105,7 +2110,7 @@ static ia32_entry oneByteMap[256] = {
{ e_add, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
{ e_add, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
{ e_add, t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
{ e_push, t_done, 0, false, { ES, eSP, Zz }, 0, s1R2RW }, // Semantics rewritten to ignore stack "operand"
{ e_push, t_done, 0, false, { ES, eSP, Zz }, 0, s1R2RW | s2I }, // Semantics rewritten to ignore stack "operand"
{ e_pop, t_done, 0, false, { ES, eSP, Zz }, 0, s1W2RW },
/* 08 */
{ e_or, t_done, 0,
Expand All @@ -2115,7 +2120,7 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_or, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
{ e_or, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
{ e_or, t_done, 0, false, { rAX, Iz, Zz }, 0, s1RW2R },
{ e_push, t_done, 0, false, { CS, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { CS, eSP, Zz }, 0, s1R2RW | s2I },
{ e_No_Entry, t_twoB, 0, false, { Zz, Zz, Zz }, 0, 0 },
/* 10 */
{ e_adc, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
Expand All @@ -2124,7 +2129,7 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_adc, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
{ e_adc, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
{ e_adc, t_done, 0, false, { rAX, Iz, Zz }, 0, s1RW2R },
{ e_push, t_done, 0, false, { SS, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { SS, eSP, Zz }, 0, s1R2RW | s2I },
{ e_pop, t_done, 0, false, { SS, eSP, Zz }, 0, s1W2RW },
/* 18 */
{ e_sbb, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
Expand All @@ -2133,7 +2138,7 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_sbb, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
{ e_sbb, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
{ e_sbb, t_done, 0, false, { rAX, Iz, Zz }, 0, s1RW2R },
{ e_push, t_done, 0, false, { DS, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { DS, eSP, Zz }, 0, s1R2RW | s2I },
{ e_pop , t_done, 0, false, { DS, eSP, Zz }, 0, s1W2RW },
/* 20 */
{ e_and, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
Expand Down Expand Up @@ -2190,14 +2195,14 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_dec, t_done, 0, false, { eSI, Zz, Zz }, 0, s1RW },
{ e_dec, t_done, 0, false, { eDI, Zz, Zz }, 0, s1RW },
/* 50 */
{ e_push, t_done, 0, false, { rAX, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rCX, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rDX, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rBX, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rSP, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rBP, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rSI, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rDI, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { rAX, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rCX, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rDX, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rBX, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rSP, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rBP, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rSI, eSP, Zz }, 0, s1R2RW | s2I },
{ e_push, t_done, 0, false, { rDI, eSP, Zz }, 0, s1R2RW | s2I },
/* 58 */
{ e_pop, t_done, 0, false, { rAX, eSP, Zz }, 0, s1W2RW },
{ e_pop, t_done, 0, false, { rCX, eSP, Zz }, 0, s1W2RW },
Expand All @@ -2208,7 +2213,7 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_pop, t_done, 0, false, { rSI, eSP, Zz }, 0, s1W2RW },
{ e_pop, t_done, 0, false, { rDI, eSP, Zz }, 0, s1W2RW },
/* 60 */
{ e_pushad, t_done, 0, false, { GPRS, eSP, Zz }, 0, s1R2RW },
{ e_pushad, t_done, 0, false, { GPRS, eSP, Zz }, 0, s1R2RW | s2I },
{ e_popad, t_done, 0, false, { GPRS, eSP, Zz }, 0, s1W2RW },
{ e_bound, t_done, 0, true, { Gv, Ma, Zz }, 0, s1R2R }, // or VEX
{ e_arpl, t_done, 0, true, { Ew, Gw, Zz }, 0, s1R2R }, /* No REX */
Expand All @@ -2217,9 +2222,9 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_No_Entry, t_ill, 2, false, { Zz, Zz, Zz }, 0, 0 }, /* operand size prefix (PREFIX_OPR_SZ) (depricated: prefixedSSE)*/
{ e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 }, /* address size prefix (PREFIX_ADDR_SZ)*/
/* 68 */
{ e_push, t_done, 0, false, { Iz, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { Iz, eSP, Zz }, 0, s1R2RW | s2I },
{ e_imul, t_done, 0, true, { Gv, Ev, Iz }, 0, s1W2R3R },
{ e_push, t_done, 0, false, { Ib, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { Ib, eSP, Zz }, 0, s1R2RW | s2I },
{ e_imul, t_done, 0, true, { Gv, Ev, Ib }, 0, s1W2R3R },
{ e_insb, t_done, 0, false, { Yb, DX, Zz }, 0, s1W2R | (fREP << FPOS) }, // (e)SI/DI changed
{ e_insd, t_done, 0, false, { Yv, DX, Zz }, 0, s1W2R | (fREP << FPOS) },
Expand Down Expand Up @@ -2276,7 +2281,7 @@ true, { Eb, Gb, Zz }, 0, s1RW2R },
{ e_cdq, t_done, 0, false, { eDX, eAX, Zz }, 0, s1W2R },
{ e_call, t_done, 0, false, { Ap, Zz, Zz }, IS_CALL | PTR_WX, s1R },
{ e_wait, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
{ e_pushfd, t_done, 0, false, { Fv, rSP, Zz }, 0, s1R2RW },
{ e_pushfd, t_done, 0, false, { Fv, rSP, Zz }, 0, s1R2RW | s2I },
{ e_popfd, t_done, 0, false, { Fv, rSP, Zz }, 0, s1W2RW },
{ e_sahf, t_done, 0, false, { Zz, Zz, Zz }, 0, 0 }, // FIXME Intel
{ e_lahf, t_done, 0, false, { Zz, Zz, Zz }, 0, 0 }, // FIXME Intel
Expand Down Expand Up @@ -2580,7 +2585,7 @@ static ia32_entry twoByteMap[256] = {
{ e_setle, t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
{ e_setnle, t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
/* A0 */
{ e_push, t_done, 0, false, { FS, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { FS, eSP, Zz }, 0, s1R2RW | s2I },
{ e_pop, t_done, 0, false, { FS, eSP, Zz }, 0, s1W2RW },
{ e_cpuid, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
{ e_bt, t_done, 0, true, { Ev, Gv, Zz }, 0, s1R2R },
Expand All @@ -2589,7 +2594,7 @@ static ia32_entry twoByteMap[256] = {
{ e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 },
{ e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 },
/* A8 */
{ e_push, t_done, 0, false, { GS, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, false, { GS, eSP, Zz }, 0, s1R2RW | s2I },
{ e_pop, t_done, 0, false, { GS, eSP, Zz }, 0, s1W2RW },
{ e_rsm, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
{ e_bts, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
Expand Down Expand Up @@ -3555,7 +3560,7 @@ static ia32_entry groupMap[][8] = {
{ e_call, t_done, 0, true, { Ep, Zz, Zz }, (IS_CALL | INDIR), s1R | (fINDIRCALL << FPOS) },
{ e_jmp, t_done, 0, true, { Ev, Zz, Zz }, (IS_JUMP | INDIR), s1R | (fINDIRJUMP << FPOS) },
{ e_jmp, t_done, 0, true, { Ep, Zz, Zz }, (IS_JUMP | INDIR), s1R | (fINDIRJUMP << FPOS) },
{ e_push, t_done, 0, true, { Ev, eSP, Zz }, 0, s1R2RW },
{ e_push, t_done, 0, true, { Ev, eSP, Zz }, 0, s1R2RW | s2I },
{ e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
},

Expand Down Expand Up @@ -8344,8 +8349,8 @@ ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32
/* Decode the memory accesses if requested */
if(capa & IA32_DECODE_MEMACCESS)
{
int sema = gotit->opsema & ((1<<FPOS)-1);
int hack = gotit->opsema >> FPOS;
int sema = sGETSEM(gotit->opsema);
int hack = sGETHACK(gotit->opsema);

switch(sema)
{
Expand Down Expand Up @@ -9034,7 +9039,7 @@ int ia32_decode_opcode(unsigned int capa, const unsigned char* addr,
/* Set the condition bits if we need to */
if(capa & IA32_DECODE_CONDITION)
{
int hack = gotit->opsema >> FPOS;
int hack = sGETHACK(gotit->opsema);
if(hack == fCOND)
instruct.cond->set(condbits);
}
Expand Down Expand Up @@ -9789,7 +9794,7 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref,
}

/* Are there 4 operands? */
if((gotit.opsema & 0xffff) >= s4OP)
if((sGETSEM(gotit.opsema)) >= s4OP)
{
/* This last one is always Ib */
int imm_size = type2size(op_b, operSzAttr);
Expand Down
13 changes: 13 additions & 0 deletions common/src/arch-x86.h
Expand Up @@ -640,6 +640,18 @@ enum { sNONE=0, // the instruction does something that cannot be classified as r
/* This should equal the first operand semantic where 4 operands are used. */
#define s4OP s1W2R3R4R

/* Implicit operand specifier */
#define s1I (1 << 18)
#define s2I (1 << 19)
#define s3I (1 << 20)
#define s4I (1 << 21)

/* Masks */
#define FPOS 17
#define sGETHACK(i) (((i) >> FPOS) & 0xFF)
#define sGETIMPL(i) (((i) >> 29) & 0x7)
#define sGETSEM(i) ((i) & ((1 << FPOS) - 1))


struct modRMByte {
unsigned mod : 2;
Expand Down Expand Up @@ -817,6 +829,7 @@ struct ia32_entry {
// code to decode memory access - this field should be seen as two 16 bit fields
// the lower half gives operand semantics, e.g. s1RW2R, the upper half is a fXXX hack if needed
// before hating me for this: it takes a LOT less time to add ONE field to ~2000 table lines!
// The upper 3 bits of this field (bits 29, 30, 31) are specifiers for implicit operands.
unsigned int opsema;
};

Expand Down
8 changes: 6 additions & 2 deletions instructionAPI/h/Operand.h
Expand Up @@ -59,13 +59,13 @@ namespace Dyninst
{
public:
typedef boost::shared_ptr<Operand> Ptr;
Operand() : m_isRead(false), m_isWritten(false) {}
Operand() : m_isRead(false), m_isWritten(false), m_isImplicit(false) {}
/// \brief Create an operand from a %Expression and flags describing whether the %ValueComputation
/// is read, written or both.
/// \param val Reference-counted pointer to the %Expression that will be contained in the %Operand being constructed
/// \param read True if this operand is read
/// \param written True if this operand is written
Operand(Expression::Ptr val, bool read, bool written) : op_value(val), m_isRead(read), m_isWritten(written)
Operand(Expression::Ptr val, bool read, bool written) : op_value(val), m_isRead(read), m_isWritten(written), m_isImplicit(false)
{
}
virtual ~Operand()
Expand Down Expand Up @@ -101,6 +101,9 @@ namespace Dyninst
return m_isRead; }
INSTRUCTION_EXPORT bool isWritten() const {
return m_isWritten; }

INSTRUCTION_EXPORT bool isImplicit() const { return m_isImplicit; }
INSTRUCTION_EXPORT void setImplicit(bool i) { m_isImplicit = i; }

/// Returns true if this operand reads memory
INSTRUCTION_EXPORT bool readsMemory() const;
Expand All @@ -124,6 +127,7 @@ namespace Dyninst
Expression::Ptr op_value;
bool m_isRead;
bool m_isWritten;
bool m_isImplicit;
};
};
};
Expand Down

0 comments on commit 8074859

Please sign in to comment.