Files
sigmaker-ida/idasdk76/include/intel.hpp
2021-10-31 21:20:46 +02:00

1233 lines
37 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _INTEL_HPP
#define _INTEL_HPP
#include <ua.hpp>
#include <typeinf.hpp>
#include <allins.hpp>
#define PROC_MAXOP 5 // max number of operands
CASSERT(PROC_MAXOP <= UA_MAXOP);
//---------------------------------
// Intel 80x86 insn_t.auxpref bits
#define aux_lock 0x00000001
#define aux_rep 0x00000002
#define aux_repne 0x00000004
#define aux_use32 0x00000008 // segment type is 32-bits
#define aux_use64 0x00000010 // segment type is 64-bits
#define aux_large 0x00000020 // offset field is 32-bit (16-bit is not enough)
#define aux_short 0x00000040 // short (byte) displacement used
#define aux_sgpref 0x00000080 // a segment prefix byte is not used
#define aux_oppref 0x00000100 // operand size prefix byte is not used
#define aux_adpref 0x00000200 // address size prefix byte is not used
#define aux_basess 0x00000400 // SS based instruction
#define aux_natop 0x00000800 // operand size is not overridden by prefix
#define aux_natad 0x00001000 // addressing mode is not overridden by prefix
#define aux_fpemu 0x00002000 // FP emulator instruction
#define aux_vexpr 0x00004000 // VEX-encoded instruction
#define aux_bnd 0x00008000 // MPX-encoded instruction
#define aux_evex 0x00010000 // EVEX-encoded instruction
#define aux_xop 0x00020000 // XOP-encoded instruction
#define aux_xacquire 0x00040000 // HLE prefix hints
#define aux_xrelease 0x00080000 // HLE prefix hints
//---------------------------------
// operand types and other customization:
#define o_trreg o_idpspec0 // IDP specific type
#define o_dbreg o_idpspec1 // IDP specific type
#define o_crreg o_idpspec2 // IDP specific type
#define o_fpreg o_idpspec3 // IDP specific type
#define o_mmxreg o_idpspec4 // IDP specific type
#define o_xmmreg o_idpspec5 // xmm register
#define o_ymmreg o_idpspec5+1 // ymm register
#define o_zmmreg o_idpspec5+2 // zmm register
#define o_kreg o_idpspec5+3 // opmask register
// 04.10.97: For o_mem,o_near,o_far we keep segment information as
// segrg - number of segment register to use
// if it is == SEGREG_IMM, then the segment was specified as an immediate
// value, look at segsel.
#define segrg specval_shorts.high
#define SEGREG_IMM 0xFFFF // this value of segrg means that
// segment selector value is in
// "segsel":
#define segsel specval_shorts.low
#define hasSIB specflag1
#define sib specflag2
#define rex insnpref // REX byte for 64-bit mode, or bits from the VEX byte if vexpr()
// Op6 is used for opmask registers in EVEX.
// specflags from Op6 are used to extend insn_t.
#define evex_flags Op6.specflag2 // bits from the EVEX byte if evexpr()
#define cr_suff specflag1 // o_crreg: D suffix for cr registers (used for CR8D)
// bits in insn_t.evex_flags:
const int EVEX_R = 0x01; // High-16 register specifier modifier
const int EVEX_L = 0x02; // Vector length/RC
const int EVEX_z = 0x04; // Zeroing/Merging
const int EVEX_b = 0x08; // Broadcast/RC/SAE Context
const int EVEX_V = 0x10; // High-16 NDS/VIDX register specifier
// bits in insn_t.rex:
const int REX_W = 8; // 64-bit operand size
const int REX_R = 4; // modrm reg field extension
const int REX_X = 2; // sib index field extension
const int REX_B = 1; // modrm r/m, sib base, or opcode reg fields extension
const int VEX_L = 0x80; // 256-bit operation (YMM register)
typedef short regnum_t;
enum RegNo
{
R_none = -1,
R_ax = 0,
R_cx, // 1
R_dx, // 2
R_bx, // 3
R_sp, // 4
R_bp, // 5
R_si, // 6
R_di, // 7
R_r8, // 8
R_r9, // 9
R_r10, // 10
R_r11, // 11
R_r12, // 12
R_r13, // 13
R_r14, // 14
R_r15, // 15
R_al,
R_cl,
R_dl,
R_bl,
R_ah,
R_ch,
R_dh,
R_bh,
R_spl,
R_bpl,
R_sil,
R_dil,
R_ip,
R_es, // 0
R_cs, // 1
R_ss, // 2
R_ds, // 3
R_fs,
R_gs,
R_cf, // main cc's
R_zf,
R_sf,
R_of,
R_pf, // additional cc's
R_af,
R_tf,
R_if,
R_df,
R_efl, // eflags
// the following registers will be used in the disassembly
// starting from ida v5.7
R_st0, // floating point registers (not used in disassembly)
R_st1,
R_st2,
R_st3,
R_st4,
R_st5,
R_st6,
R_st7,
R_fpctrl,// fpu control register
R_fpstat,// fpu status register
R_fptags,// fpu tags register
R_mm0, // mmx registers
R_mm1,
R_mm2,
R_mm3,
R_mm4,
R_mm5,
R_mm6,
R_mm7,
R_xmm0, // xmm registers
R_xmm1,
R_xmm2,
R_xmm3,
R_xmm4,
R_xmm5,
R_xmm6,
R_xmm7,
R_xmm8,
R_xmm9,
R_xmm10,
R_xmm11,
R_xmm12,
R_xmm13,
R_xmm14,
R_xmm15,
R_mxcsr,
R_ymm0, // AVX 256-bit registers
R_ymm1,
R_ymm2,
R_ymm3,
R_ymm4,
R_ymm5,
R_ymm6,
R_ymm7,
R_ymm8,
R_ymm9,
R_ymm10,
R_ymm11,
R_ymm12,
R_ymm13,
R_ymm14,
R_ymm15,
R_bnd0, // MPX registers
R_bnd1,
R_bnd2,
R_bnd3,
R_xmm16, // AVX-512 extended XMM registers
R_xmm17,
R_xmm18,
R_xmm19,
R_xmm20,
R_xmm21,
R_xmm22,
R_xmm23,
R_xmm24,
R_xmm25,
R_xmm26,
R_xmm27,
R_xmm28,
R_xmm29,
R_xmm30,
R_xmm31,
R_ymm16, // AVX-512 extended YMM registers
R_ymm17,
R_ymm18,
R_ymm19,
R_ymm20,
R_ymm21,
R_ymm22,
R_ymm23,
R_ymm24,
R_ymm25,
R_ymm26,
R_ymm27,
R_ymm28,
R_ymm29,
R_ymm30,
R_ymm31,
R_zmm0, // AVX-512 ZMM registers
R_zmm1,
R_zmm2,
R_zmm3,
R_zmm4,
R_zmm5,
R_zmm6,
R_zmm7,
R_zmm8,
R_zmm9,
R_zmm10,
R_zmm11,
R_zmm12,
R_zmm13,
R_zmm14,
R_zmm15,
R_zmm16,
R_zmm17,
R_zmm18,
R_zmm19,
R_zmm20,
R_zmm21,
R_zmm22,
R_zmm23,
R_zmm24,
R_zmm25,
R_zmm26,
R_zmm27,
R_zmm28,
R_zmm29,
R_zmm30,
R_zmm31,
R_k0, // AVX-512 opmask registers
R_k1,
R_k2,
R_k3,
R_k4,
R_k5,
R_k6,
R_k7,
R_last,
};
CASSERT(R_last == 173);
inline bool is_segreg(int r) { return r >= R_es && r <= R_gs; }
inline bool is_fpureg(int r) { return r >= R_st0 && r <= R_st7; }
inline bool is_mmxreg(int r) { return r >= R_mm0 && r <= R_mm7; }
inline bool is_xmmreg(int r) { return r >= R_xmm0 && r <= R_xmm15; }
inline bool is_ymmreg(int r) { return r >= R_ymm0 && r <= R_ymm15; }
int cvt_to_wholereg(int _reg, bool allow_high_byte_regs); // byte reg -> whole reg
int calc_dbg_reg_index(const char *name);
//-------------------------------------------------------------------------
// is conditional branch?
inline bool insn_jcc(const insn_t &insn)
{
switch ( insn.itype )
{
case NN_ja:
case NN_jae:
case NN_jb:
case NN_jbe:
case NN_jc:
case NN_je:
case NN_jg:
case NN_jge:
case NN_jl:
case NN_jle:
case NN_jna:
case NN_jnae:
case NN_jnb:
case NN_jnbe:
case NN_jnc:
case NN_jne:
case NN_jng:
case NN_jnge:
case NN_jnl:
case NN_jnle:
case NN_jno:
case NN_jnp:
case NN_jns:
case NN_jnz:
case NN_jo:
case NN_jp:
case NN_jpe:
case NN_jpo:
case NN_js:
case NN_jz:
return true;
}
return false;
}
//-------------------------------------------------------------------------
inline bool insn_default_opsize_64(const insn_t &insn)
{
if ( insn_jcc(insn) )
return true;
switch ( insn.itype )
{
// use ss
case NN_pop:
case NN_popf:
case NN_popfq:
case NN_push:
case NN_pushf:
case NN_pushfq:
case NN_retn:
case NN_retf:
case NN_retnq:
case NN_retfq:
case NN_call:
case NN_callfi:
case NN_callni:
case NN_enter:
case NN_enterq:
case NN_leave:
case NN_leaveq:
// near branches
case NN_jcxz:
case NN_jecxz:
case NN_jrcxz:
case NN_jmp:
case NN_jmpni:
case NN_jmpshort:
case NN_loop:
case NN_loopq:
case NN_loope:
case NN_loopqe:
case NN_loopne:
case NN_loopqne:
return true;
}
return false;
}
inline bool mode16(const insn_t &insn) { return (insn.auxpref & (aux_use32|aux_use64)) == 0; } // 16-bit mode?
inline bool mode32(const insn_t &insn) { return (insn.auxpref & aux_use32) != 0; } // 32-bit mode?
inline bool mode64(const insn_t &insn) { return (insn.auxpref & aux_use64) != 0; } // 64-bit mode?
inline bool natad(const insn_t &insn) { return (insn.auxpref & aux_natad) != 0; } // natural address size (no prefixes)?
inline bool natop(const insn_t &insn) { return (insn.auxpref & aux_natop) != 0; } // natural operand size (no prefixes)?
inline bool vexpr(const insn_t &insn) { return (insn.auxpref & aux_vexpr) != 0; } // VEX encoding used
inline bool evexpr(const insn_t &insn) { return (insn.auxpref & aux_evex) != 0; } // EVEX encoding used
inline bool xopexpr(const insn_t &insn) { return (insn.auxpref & aux_xop) != 0; } // XOP encoding used
inline bool ad16(const insn_t &insn) // is current addressing 16-bit?
{
int p = insn.auxpref & (aux_use32|aux_use64|aux_natad);
return p == aux_natad || p == aux_use32;
}
inline bool ad32(const insn_t &insn) // is current addressing 32-bit?
{
int p = insn.auxpref & (aux_use32|aux_use64|aux_natad);
return p == (aux_natad|aux_use32)
|| p == 0
|| p == aux_use64;
}
inline bool ad64(const insn_t &insn) // is current addressing 64-bit?
{
#ifdef __EA64__
int p = insn.auxpref & (aux_use32|aux_use64|aux_natad);
return p == (aux_natad|aux_use64);
#else
qnotused(insn);
return false;
#endif
}
inline bool op16(const insn_t &insn) // is current operand size 16-bit?
{
int p = insn.auxpref & (aux_use32|aux_use64|aux_natop);
return p == aux_natop // 16-bit segment, no prefixes
|| p == aux_use32 // 32-bit segment, 66h
|| p == aux_use64 && (insn.rex & REX_W) == 0; // 64-bit segment, 66h, no rex.w
}
inline bool op32(const insn_t &insn) // is current operand size 32-bit?
{
int p = insn.auxpref & (aux_use32|aux_use64|aux_natop);
return p == 0 // 16-bit segment, 66h
|| p == (aux_use32|aux_natop) // 32-bit segment, no prefixes
|| p == (aux_use64|aux_natop) && (insn.rex & REX_W) == 0; // 64-bit segment, 66h, no rex.w
}
inline bool op64(const insn_t &insn) // is current operand size 64-bit?
{
#ifdef __EA64__
return mode64(insn)
&& ((insn.rex & REX_W) != 0
|| natop(insn) && insn_default_opsize_64(insn)); // 64-bit segment, rex.w or insns-64
#else
qnotused(insn);
return false;
#endif
}
inline bool op256(const insn_t &insn) // is VEX.L == 1 or EVEX.L'L == 01?
{
return (insn.rex & VEX_L) != 0
&& (vexpr(insn)
|| xopexpr(insn)
|| evexpr(insn) && (insn.evex_flags & EVEX_L) == 0);
}
inline bool op512(const insn_t &insn) // is EVEX.L'L == 10?
{
return evexpr(insn) && (insn.rex & VEX_L) == 0 && (insn.evex_flags & EVEX_L) != 0;
}
inline bool is_vsib(const insn_t &insn) // does instruction use VSIB variant of the sib byte?
{
switch ( insn.itype )
{
case NN_vgatherdps:
case NN_vgatherdpd:
case NN_vgatherqps:
case NN_vgatherqpd:
case NN_vpgatherdd:
case NN_vpgatherdq:
case NN_vpgatherqd:
case NN_vpgatherqq:
case NN_vscatterdps:
case NN_vscatterdpd:
case NN_vscatterqps:
case NN_vscatterqpd:
case NN_vpscatterdd:
case NN_vpscatterdq:
case NN_vpscatterqd:
case NN_vpscatterqq:
case NN_vgatherpf0dps:
case NN_vgatherpf0qps:
case NN_vgatherpf0dpd:
case NN_vgatherpf0qpd:
case NN_vgatherpf1dps:
case NN_vgatherpf1qps:
case NN_vgatherpf1dpd:
case NN_vgatherpf1qpd:
case NN_vscatterpf0dps:
case NN_vscatterpf0qps:
case NN_vscatterpf0dpd:
case NN_vscatterpf0qpd:
case NN_vscatterpf1dps:
case NN_vscatterpf1qps:
case NN_vscatterpf1dpd:
case NN_vscatterpf1qpd:
return true;
}
return false;
}
inline regnum_t vsib_index_fixreg(const insn_t &insn, regnum_t index)
{
switch ( insn.itype )
{
case NN_vscatterdps:
case NN_vscatterqps:
case NN_vscatterqpd:
case NN_vpscatterdd:
case NN_vpscatterqd:
case NN_vpscatterqq:
case NN_vpgatherdd:
case NN_vpgatherqd:
case NN_vpgatherqq:
case NN_vgatherdps:
case NN_vgatherqps:
case NN_vgatherqpd:
if ( index > 15 )
index += op512(insn) ? R_zmm0 : op256(insn) ? (R_ymm16 - 16) : (R_xmm16 - 16);
else
index += op512(insn) ? R_zmm0 : op256(insn) ? R_ymm0 : R_xmm0;
break;
case NN_vscatterdpd:
case NN_vpscatterdq:
case NN_vgatherdpd:
case NN_vpgatherdq:
if ( index > 15 )
index += op512(insn) ? (R_ymm16 - 16) : (R_xmm16 - 16);
else
index += op512(insn) ? R_ymm0 : R_xmm0;
break;
case NN_vgatherpf0dps:
case NN_vgatherpf0qps:
case NN_vgatherpf0qpd:
case NN_vgatherpf1dps:
case NN_vgatherpf1qps:
case NN_vgatherpf1qpd:
case NN_vscatterpf0dps:
case NN_vscatterpf0qps:
case NN_vscatterpf0qpd:
case NN_vscatterpf1dps:
case NN_vscatterpf1qps:
case NN_vscatterpf1qpd:
index += R_zmm0;
break;
case NN_vgatherpf0dpd:
case NN_vgatherpf1dpd:
case NN_vscatterpf0dpd:
case NN_vscatterpf1dpd:
if ( index > 15 )
index += R_ymm16 - 16;
else
index += R_ymm0;
break;
}
return index;
}
inline int sib_base(const insn_t &insn, const op_t &x) // get extended sib base
{
int base = x.sib & 7;
#ifdef __EA64__
if ( insn.rex & REX_B )
base |= 8;
#else
qnotused(insn);
#endif
return base;
}
inline regnum_t sib_index(const insn_t &insn, const op_t &x) // get extended sib index
{
regnum_t index = regnum_t((x.sib >> 3) & 7);
#ifdef __EA64__
if ( (insn.rex & REX_X) != 0 )
index |= 8;
#endif
if ( is_vsib(insn) )
{
if ( (insn.evex_flags & EVEX_V) != 0 )
index |= 16;
index = vsib_index_fixreg(insn, index);
}
return index;
}
inline int sib_scale(const op_t &x)
{
int scale = (x.sib >> 6) & 3;
return scale;
}
// get the base register of the operand with a displacement
// NB: for 16-bit code, returns a phrase number
// use x86_base_reg() if you need to handle 16-bit instructions
inline int x86_base(const insn_t &insn, const op_t &x)
{
return x.hasSIB ? sib_base(insn, x) : x.phrase;
}
// get the base register of the operand with a displacement
// returns correct register for 16-bit code too
inline int x86_base_reg(const insn_t &insn, const op_t &x)
{
if ( x.hasSIB )
{
if ( x.type == o_mem )
return R_none;
return sib_base(insn, x); // base register is encoded in the SIB
}
else if ( !ad16(insn) )
{
return x.phrase; // 'phrase' contains the base register number
}
else if ( x.phrase == ushort(R_none) )
{
return R_sp;
}
switch ( x.phrase )
{
case 0: // [BX+SI]
case 1: // [BX+DI]
case 7: // [BX]
return R_bx;
case 2: // [BP+SI]
case 3: // [BP+DI]
case 6: // [BP]
return R_bp;
case 4: // [SI]
return R_si;
case 5: // [DI]
return R_di;
default:
INTERR(10259);
}
}
const int INDEX_NONE = 4; // no index register is present
// get the index register of the operand with a displacement
inline int x86_index(const insn_t &insn, const op_t &x)
{
return x.hasSIB ? sib_index(insn, x) : INDEX_NONE;
}
inline int x86_index_reg(const insn_t &insn, const op_t &x)
{
if ( x.hasSIB )
{
int idx = sib_index(insn, x);
if ( idx != INDEX_NONE )
return idx;
return R_none;
}
if ( !ad16(insn) )
return R_none;
switch ( x.phrase )
{
case 0: // [BX+SI]
case 2: // [BP+SI]
return R_si;
case 1: // [BX+DI]
case 3: // [BP+DI]
return R_di;
case 4: // [SI]
case 5: // [DI]
case 7: // [BX]
case 6: // [BP]
return R_none;
default:
INTERR(10260);
}
}
// get the scale factor of the operand with a displacement
inline int x86_scale(const op_t &x)
{
return x.hasSIB ? sib_scale(x) : 0;
}
// does the operand have a displacement?
inline int has_displ(const op_t &x)
{
return x.type == o_displ || x.type == o_mem && x.hasSIB;
}
// does the insn refer to the TLS variable?
inline bool has_tls_segpref(const insn_t &insn)
{
if ( insn.segpref == 0 )
return false;
return mode64(insn) && insn.segpref == R_fs
|| mode32(insn) && insn.segpref == R_gs;
}
// should we treat the memory operand as a displacement?
inline bool mem_as_displ(const insn_t &insn, const op_t &x)
{
// the operand should be an offset and it should be the TLS variable
// or the second operand of "lea" instruction
// .text:08000000 mov eax, gs:(ti1 - static_TP)
// .text:08000E8F lea ecx, (_ZN4dmngL4sessE - _GLOBAL_OFFSET_TABLE_)
return (has_tls_segpref(insn) || insn.itype == NN_lea)
&& is_off(get_flags(insn.ea), x.n);
}
// does the operand refer to stack? (sp or bp based)
bool is_stack_ref(const insn_t &insn, const op_t &x, int breg);
// return addressing width in form of dt_... constant
inline op_dtype_t address_dtype(const insn_t &insn)
{
return char(ad64(insn) ? dt_qword : ad32(insn) ? dt_dword : dt_word);
}
// return operand width in form of dt_... constant
inline op_dtype_t operand_dtype(const insn_t &insn)
{
return char(op64(insn) ? dt_qword : op32(insn) ? dt_dword : op16(insn) ? dt_word : dt_byte);
}
inline bool is_io_insn(const insn_t &insn)
{
return insn.itype == NN_ins
|| insn.itype == NN_outs
|| insn.itype == NN_out
|| insn.itype == NN_in;
}
//---------------------------------
#define PROCMOD_NODE_NAME "$ vmm functions"
#define PROCMOD_NAME pc
const char callee_tag = 'A';
const char fbase_tag = 'b';
const char frame_tag = 'f';
const char purge_tag = 'p';
const char ret_tag = 'r';
const char pushinfo_tag = 's';
const char is_ptr_tag = 'P';
const char finally_tag = 'F';
const char handler_tag = 'h';
const char vxd_tag1 = 'V';
const char vxd_tag2 = 'W';
// fbase reg is a register used to access data for the current function
// it is usually initialized by __i686_get_pc_thunk() function
struct fbase_reg_t
{
ea_t value;
ea_t minea; // address where the fbase reg is defined
int16 reg;
};
// the second operand of lea instruction should not be treated as memory reference
// unless there is cs: prefix or the user has specified 'offset' flag
// in other cases lea is used for arbirary calculations
inline bool is_arith_lea(const insn_t &insn, const op_t &x)
{
return insn.itype == NN_lea
&& x.segrg != R_cs
&& !is_off(get_flags(insn.ea), x.n);
}
// the following operand types are ignored for imul's third operand
inline bool is_forbidden_imul_flag(const insn_t &insn, const op_t &x, flags_t F)
{
if ( x.n == 2 && insn.Op2.shown() )
return is_off1(F) || is_stroff1(F) || is_stkvar1(F);
return false;
}
inline bool is_push_ecx(uchar b)
{
return b == 0x51; // push ecx
}
inline bool is_push_eax(uchar b)
{
return b == 0x50; // push eax
}
inline bool is_push_edx(uchar b)
{
return b == 0x52; // push edx
}
inline bool is_push_ebx(uchar b)
{
return b == 0x53; // push ebx
}
inline bool is_volatile_reg(int r)
{
return r != R_bx
&& r != R_bp
&& r != R_si
&& r != R_di
&& r != R_r12
&& r != R_r13
&& r != R_r14
&& r != R_r15;
}
//------------------------------------------------------------------
struct pushreg_t
{
ea_t ea; // instruction ea
sval_t off; // offset from the frame top (sp delta)
sval_t width; // register width (or number of allocated bytes)
regnum_t reg; // register number (R_none means stack space allocation)
uint16 flags; // additional flags
#define PRF_NONE 0x0000 // Entry describes a push or an allocation
#define PRF_MOVE 0x0001 // Entrz describes a register save by a move instruction
#define PRF_SPILL 0x0002 // Indicates that entry is located before local stack region
#define PRF_MASK (PRF_MOVE | PRF_SPILL)
};
struct pushinfo_t
{
enum { PUSHINFO_VERSION = 4 };
int flags;
#define PINF_SEHCALL 0x0001 // call to SEH_prolog is present
#define PINF_SEHMAN 0x0002 // Manual SEH setup
#define PINF_COOKIE 0x0004 // Has security cookie
#define PINF_ALIGNED 0x0008 // Lvars are align stred (visual studio)
#define PINF_VARARG 0x0010 // Vararg prolog (currently used for gcc64)
#define PINF_BPOFF 0x0020 // xmm_stkoff/reg_stkoff are from rbp (otherwise from rsp)
#define PINF_HAVE_SSIZE 0x0040 // pushinfo_t structure contains its own size (field 'cb')
#define PINF_PSI_FLAGS 0x0080 // pushreg_t structure contains flags field
qvector<pushreg_t> psi; // stack allocation instructions
ssize_t bpidx = -1; // index into psi
uint32 spoiled = 0; // bitmask of spoiled registers at the end of prolog
eavec_t prolog_insns; // additional prolog instruction addresses
// (in addition to instructions from psi)
typedef qvector<eavec_t> pop_info_t;
pop_info_t pops; // pop insns for pushs (indexes shifted by one)
// in other words, this is epilog instructions
// index 0: epilog insns not linked to a push insn
// 1..psi.size(): epilog insns for each push insn
// usually there will be only one pop for each push.
// but there might be several pops for each push.
// (because the function has several returns)
int eh_type; // function has exception handling
// low 16 bits: type, high 16 bits: version
#define EH_NONE 0 // no EH found
#define EH_VCSEH 1 // SEH (__except_handlerN, __SEH_prologN)
#define EH_VCCPPEH 2 // MSVC C++ EH (_EH_prolog[N])
int seh_ver()
{
if ( (eh_type & 0xFFFF) == EH_VCSEH )
return (eh_type >> 16) & 0xFFFF;
return 0;
}
int eh_ver()
{
if ( (eh_type & 0xFFFF) == EH_VCCPPEH )
return (eh_type >> 16) & 0xFFFF;
return 0;
}
ea_t eh_info = BADADDR; // for SEH: scopetable address, for C++ EH: __ehhandler address
// for gcc64 vararg (see PINF_VARARG):
sval_t xmm_stkoff = 0; // offset from ebp to xmm savearea
sval_t reg_stkoff = 0; // offset from ebp to gpreg savearea
// these 2 offsets are either from rsp or rbp
// see PINF_BPOFF for that
int xmm_nsaved = 0; // number of saved xmm regs
int reg_nsaved = 0; // number of saved general purpose regs
int cb = sizeof(pushinfo_t); // size of this structure
pushinfo_t(void) : flags(PINF_HAVE_SSIZE|PINF_PSI_FLAGS), eh_type(EH_NONE) {}
};
enum spec_func_type_t
{
SF_NONE,
SF_EH_PROLOG,
SF_SEH_PROLOG,
SF_SEH_EPILOG,
SF_ALLOCA,
SF_CHK,
SF_SYSINIT,
SF_EH_EPILOG,
SF_LSTRCATN,
};
inline bool is_mingw_abi(void)
{
if ( default_compiler() != COMP_MS )
return false; // "mingw" abi can be defined only for MSVC
qstring abiname;
get_abi_name(&abiname);
return abiname == "mingw";
}
inline bool is_msabi(void)
{
comp_t cc = default_compiler();
return cc == COMP_MS || cc == COMP_UNK && inf_get_filetype() == f_PE;
}
inline int pc_shadow_area_size()
{
return inf_is_64bit() && is_msabi() ? 4 * 8 : 0;
}
struct regval_t;
typedef const regval_t &idaapi getreg_t(const char *name, const regval_t *regvalues);
// Structure where information about a mmx/xmm/ymm type is returned
struct mmtype_t
{
const char *name;
const type_t *type;
const type_t *fields;
tinfo_t tif;
};
//----------------------------------------------------------------------
// The following events are supported by the PC module in the processor_t::notify() function
namespace pc_module_t
{
enum event_codes_t
{
ev_set_difbase = processor_t::ev_loader,
// set AFIDP_DIFBASE flag
// in: int onoff
// Returns: nothing
ev_restore_pushinfo,// Restore function prolog info from the database
// in: pushinfo_t *pi
// ea_t func_start
// Returns: 1-ok, otherwise-failed
ev_save_pushinfo, // Save function prolog info to the database
// in: ea_t func_start
// pushinfo_t *pi
// Returns: 1-ok, otherwise-failed
ev_prolog_analyzed, // This event is generated by the PC module
// at the end of prolog analysis. Plugins may
// hook to it and improve the analysis.
// in: ea_t first_past_prolog_insn
// pushinfo_t *pi
// Returns: 1-ok, 2-ok but do not automatically verify epilog
ev_verify_epilog, // Verify function epilog
// in: int *answer
// pushinfo_t *pi
// const insn_t *insn
// 'insn' structure must be filled with the first epilog instruction
// number of verified epilog instructions will be in the 'answer'
// returns: 1-ok, otherwise-failed
obsolete_ev_find_reg_value, // not used anymore, use ev_find_reg_value
ev_dbgtools_path, // Returns the configuration value of the debugging tools path (from IDA.CFG)
// in: char *path
// size_t path_size
// returns: 1-if value is set, 0-if value not set in IDA.CFG
ev_is_get_pc_thunk, // Detect get_pc_thunk calls
// in: RegNo *p_reg,
// ea_t *p_end
// const insn_t *ins
// returns: 1-found, -1-not found, 0-not implemented
ev_vxd_loaded, // notification: a virtual device driver (Vxd) is loaded
ev_get_borland_template_node,
// out: netnode *node
// returns: 1-found, -1-not found
ev_clear_borland_template_node,
// returns: nothing
ev_borland_template,// Applies Borland RTTI template for the given address
// in: ea_t ea,
// bool bp_mode if false - bc
// bool recursive
// returns: 1-created, -1-not created
ev_get_segval, // Get segment for the specified instruction operand
// in: ea_t *out,
// const insn_t *insn,
// const op_t *x
// returns: 1-success
ev_get_idpflags, // Get idpflags
// in: uint32 *idpflags
// returns: 1 success, fill IDPFLAGS
ev_get_ret_target, // Some 'ret' insns do not return from the function but are used for short jumps
// (for example: push off; ret). The following functions mark such 'ret' instructions.
// in: ea_t ea
// ea_t *target
// returns: 1 success, fill TARGET
ev_set_ret_target, // in: ea_t ea
// ea_t target
ev_del_ret_target, // in: ea_t ea
};
inline processor_t::event_t idp_ev(event_codes_t ev)
{
return processor_t::event_t(ev);
}
inline void set_difbase(int onoff)
{
processor_t::notify(idp_ev(ev_set_difbase), onoff);
}
inline bool restore_pushinfo(pushinfo_t *pi, ea_t func_start)
{
return processor_t::notify(idp_ev(ev_restore_pushinfo), pi, func_start) == 1;
}
inline bool save_pushinfo(ea_t func_start, pushinfo_t *pi)
{
return processor_t::notify(idp_ev(ev_restore_pushinfo), func_start, pi) == 1;
}
inline int prolog_analyzed(ea_t first_past_prolog_insn, pushinfo_t *pi)
{
return processor_t::notify(idp_ev(ev_prolog_analyzed), first_past_prolog_insn, pi);
}
inline bool verify_epilog(int *answer, pushinfo_t *pi, const insn_t &insn)
{
return processor_t::notify(idp_ev(ev_verify_epilog), answer, pi, &insn) == 1;
}
inline bool dbgtools_path(char *path, size_t path_size)
{
return processor_t::notify(idp_ev(ev_dbgtools_path), path, path_size) == 1;
}
inline int is_get_pc_thunk(RegNo *p_reg, ea_t *p_end, const insn_t &insn)
{
return processor_t::notify(idp_ev(ev_is_get_pc_thunk), p_reg, p_end, &insn);
}
inline int vxd_loaded()
{
return processor_t::notify(idp_ev(ev_vxd_loaded));
}
inline bool get_borland_template_node(netnode *node)
{
return processor_t::notify(idp_ev(ev_get_borland_template_node), node) > 0;
}
inline void clear_borland_template_node(void)
{
processor_t::notify(idp_ev(ev_clear_borland_template_node));
}
inline bool borland_template(ea_t ea, bool bp_mode, bool recursive)
{
return processor_t::notify(idp_ev(ev_borland_template),
ea,
bp_mode,
recursive) > 0;
}
inline ea_t get_segval(const insn_t &insn, const op_t &x)
{
ea_t ea = BADADDR;
processor_t::notify(idp_ev(ev_get_segval), &ea, &insn, &x);
return ea;
}
inline uint32 get_idpflags()
{
uint32 idpflags;
processor_t::notify(idp_ev(ev_get_idpflags), &idpflags);
return idpflags;
}
inline bool get_ret_target(ea_t ea, ea_t *target)
{
return processor_t::notify(idp_ev(ev_get_ret_target), ea, target) == 1;
}
inline void set_ret_target(ea_t ea, ea_t target)
{
processor_t::notify(idp_ev(ev_set_ret_target), ea, target);
}
inline void del_ret_target(ea_t ea)
{
processor_t::notify(idp_ev(ev_del_ret_target), ea);
}
}
//-------------------------------------------------------------------------
#define AFIDP_PUSH 0x0001 // push seg; push num; is converted to offset
#define AFIDP_NOP 0x0002 // db 90h after jmp is converted to nop
#define AFIDP_MOVOFF 0x0004 // mov reg, numoff <- convert to offset
// mov segreg, immseg
#define AFIDP_MOVOFF2 0x0008 // mov z, numoff <- convert to offset
// mov z, immseg
// where z - o_mem, o_displ
#define AFIDP_ZEROINS 0x0010 // allow zero opcode instructions:
// add [bx+si], al (16bit)
// add [eax], al (32bit)
// add [rax], al (64bit)
#define AFIDP_BRTTI 0x0020 // Advanced analysis of Borlands RTTI
#define AFIDP_UNKRTTI 0x0040 // -"- with 'unknown_libname'
#define AFIDP_EXPFUNC 0x0080 // for PE? bc(ms?) - expanding
// function (exception subblock)
#define AFIDP_DIFBASE 0x0100 // Allow references with different segment bases
#define AFIDP_NOPREF 0x0200 // Don't display superfluous prefixes
#define AFIDP_NOVXD 0x0400 // Don't interpret int 20 as VxDcall
#define AFIDP_NOFPEMU 0x0800 // Disable FPU emulation instructions
#define AFIDP_SHOWRIP 0x1000 // Explicit RIP-addressing
#define AFIDP_NOSEH 0x2000 // Disable SEH/EH analysis
#define AFIDP_INT3STOP 0x4000 // int 3 may stop code flow
// call <func>
// int 3 <- this is likely a no-return guard
#define AFIDP_NOAGGRJMPS 0x8000 // Don't aggressively convert jumps to thunk functions
// 'NO' is used to simplify upgrading existing idbs
inline bool should_af_push(void) { return (pc_module_t::get_idpflags() & AFIDP_PUSH) != 0; }
inline bool should_af_nop(void) { return (pc_module_t::get_idpflags() & AFIDP_NOP) != 0; }
inline bool should_af_movoff(void) { return (pc_module_t::get_idpflags() & AFIDP_MOVOFF) != 0; }
inline bool should_af_movoff2(void) { return (pc_module_t::get_idpflags() & AFIDP_MOVOFF2) != 0; }
inline bool should_af_zeroins(void) { return (pc_module_t::get_idpflags() & AFIDP_ZEROINS) != 0; }
inline bool should_af_brtti(void) { return (pc_module_t::get_idpflags() & AFIDP_BRTTI) != 0; }
inline bool should_af_urtti(void) { return (pc_module_t::get_idpflags() & AFIDP_UNKRTTI) != 0; }
inline bool should_af_fexp(void) { return (pc_module_t::get_idpflags() & AFIDP_EXPFUNC) != 0; }
inline bool should_af_difbase(void) { return (pc_module_t::get_idpflags() & AFIDP_DIFBASE) != 0; }
inline bool should_af_nopref(void) { return (pc_module_t::get_idpflags() & AFIDP_NOPREF) != 0; }
inline bool should_af_vxd(void) { return (pc_module_t::get_idpflags() & AFIDP_NOVXD) == 0; }
inline bool should_af_fpemu(void) { return (pc_module_t::get_idpflags() & AFIDP_NOFPEMU) == 0; }
inline bool should_af_showrip(void) { return (pc_module_t::get_idpflags() & AFIDP_SHOWRIP) != 0; }
inline bool should_af_seh(void) { return (pc_module_t::get_idpflags() & AFIDP_NOSEH) == 0; }
inline bool should_af_int3stop(void) { return (pc_module_t::get_idpflags() & AFIDP_INT3STOP) != 0; }
inline bool should_af_aggrjmps(void) { return (pc_module_t::get_idpflags() & AFIDP_NOAGGRJMPS) == 0; }
//-------------------------------------------------------------------------
inline bool get_ret_target(ea_t ea, ea_t *target) { return pc_module_t::get_ret_target(ea, target); }
inline void set_ret_target(ea_t ea, ea_t target) { return pc_module_t::set_ret_target(ea, target); }
inline void del_ret_target(ea_t ea) { return pc_module_t::del_ret_target(ea); }
//-------------------------------------------------------------------------
// Don't use the following define's with underscores at the start!
#define _PT_486p 0x00000001
#define _PT_486r 0x00000002
#define _PT_386p 0x00000004
#define _PT_386r 0x00000008
#define _PT_286p 0x00000010
#define _PT_286r 0x00000020
#define _PT_086 0x00000040
#define _PT_586p 0x00000080 // Pentium real mode
#define _PT_586r 0x00000100 // Pentium protected mode
#define _PT_686r 0x00000200 // Pentium Pro real
#define _PT_686p 0x00000400 // Pentium Pro protected
#define _PT_mmx 0x00000800 // MMX extensions
#define _PT_pii 0x00001000 // Pentium II
#define _PT_3d 0x00002000 // 3DNow! extensions
#define _PT_piii 0x00004000 // Pentium III
#define _PT_k7 0x00008000 // AMD K7
#define _PT_p4 0x00010000 // Pentium 4
#define _PT_sse3 0x00020000 // SSE3 + SSSE3
#define _PT_sse4 0x00040000 // SSE4.1 + SSE4.2
//
// The following values mean 'is XXX processor or better?'
//
#define PT_sse4 _PT_sse4
#define PT_sse3 (_PT_sse3 | _PT_sse4 )
#define PT_p4 ( PT_sse3 | _PT_p4 )
#define PT_k7 ( PT_p4 | _PT_k7 )
#define PT_piii ( PT_k7 | _PT_piii )
#define PT_k62 ( PT_piii | _PT_3d )
#define PT_3d _PT_3d
#define PT_pii ( PT_piii | _PT_pii )
#define PT_mmx (_PT_mmx | _PT_3d )
#define PT_686p ( PT_pii | _PT_686p )
#define PT_686r ( PT_686p | _PT_686r )
#define PT_586p ( PT_686r | _PT_586p )
#define PT_586r ( PT_586p | _PT_586r )
#define PT_486p ( PT_586r | _PT_486p )
#define PT_486r ( PT_486p | _PT_486r )
#define PT_386p ( PT_486r | _PT_386p )
#define PT_386r ( PT_386p | _PT_386r )
#define PT_286p ( PT_386r | _PT_286p )
#define PT_286r ( PT_286p | _PT_286r )
#define PT_086 ( PT_286r | _PT_086 )
//
// The following values mean 'is exactly XXX processor?'
//
#define PT_ismmx (_PT_mmx )
#define PT_is686 (_PT_686r | _PT_686p)
#define PT_is586 (_PT_586r | _PT_586p)
#define PT_is486 (_PT_486r | _PT_486p)
#define PT_is386 (_PT_386r | _PT_386p)
#define PT_is286 (_PT_286r | _PT_286p)
#define PT_is086 (_PT_086)
//---------------------------------------------------------------------
inline bool isProtected(uint32 type)
{
return (type
& (_PT_286p
| _PT_386p
| _PT_486p
| _PT_586p
| _PT_686p
| _PT_pii)) != 0;
}
inline bool isAMD(uint32 type) { return (type & PT_k7 ) != 0; }
inline bool isp4(uint32 type) { return (type & PT_p4 ) != 0; }
inline bool isp3(uint32 type) { return (type & PT_piii) != 0; }
inline bool is3dnow(uint32 type) { return (type & PT_3d ) != 0; }
inline bool ismmx(uint32 type) { return (type & PT_mmx ) != 0; }
inline bool isp2(uint32 type) { return (type & PT_pii ) != 0; }
inline bool is686(uint32 type) { return (type & PT_686r) != 0; }
inline bool is586(uint32 type) { return (type & PT_586r) != 0; }
inline bool is486(uint32 type) { return (type & PT_486r) != 0; }
inline bool is386(uint32 type) { return (type & PT_386r) != 0; } // is 386 or better ?
inline bool is286(uint32 type) { return (type & PT_286r) != 0; } // is 286 or better ?
#endif // _INTEL_HPP