A few changes to libdisasm

This commit is contained in:
Artur K 2012-03-18 11:35:13 +01:00
parent 71fc8bfef7
commit fee4d6fe9a
5 changed files with 598 additions and 584 deletions

View File

@ -31,204 +31,204 @@
* of the MMX registers, so this aliasing is not 100% accurate. * of the MMX registers, so this aliasing is not 100% accurate.
* */ * */
static struct { static struct {
unsigned char alias; /* id of register this is an alias for */ unsigned char alias; /* id of register this is an alias for */
unsigned char shift; /* # of bits register must be shifted */ unsigned char shift; /* # of bits register must be shifted */
} ia32_reg_aliases[] = { } ia32_reg_aliases[] = {
{ 0,0 }, { 0,0 },
{ REG_DWORD_OFFSET, 0 }, /* al : 1 */ { REG_DWORD_OFFSET, 0 }, /* al : 1 */
{ REG_DWORD_OFFSET, 8 }, /* ah : 2 */ { REG_DWORD_OFFSET, 8 }, /* ah : 2 */
{ REG_DWORD_OFFSET, 0 }, /* ax : 3 */ { REG_DWORD_OFFSET, 0 }, /* ax : 3 */
{ REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */ { REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */
{ REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */ { REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */
{ REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */ { REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */
{ REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */ { REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */
{ REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */ { REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */
{ REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */ { REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */
{ REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */ { REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */
{ REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */ { REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */
{ REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */ { REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */
{ REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */ { REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */
{ REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */ { REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */
{ REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */ { REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */
{ REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */ { REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */
{ REG_EIP_INDEX, 0 }, /* ip : 17 */ { REG_EIP_INDEX, 0 }, /* ip : 17 */
{ REG_FPU_OFFSET, 0 }, /* mm0 : 18 */ { REG_FPU_OFFSET, 0 }, /* mm0 : 18 */
{ REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */ { REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */
{ REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */ { REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */
{ REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */ { REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */
{ REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */ { REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */
{ REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */ { REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */
{ REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */ { REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */
{ REG_FPU_OFFSET + 7, 0 } /* mm7 : 25 */ { REG_FPU_OFFSET + 7, 0 } /* mm7 : 25 */
}; };
/* REGISTER TABLE: size, type, and name of every register in the /* REGISTER TABLE: size, type, and name of every register in the
* CPU. Does not include MSRs since the are, after all, * CPU. Does not include MSRs since the are, after all,
* model specific. */ * model specific. */
static struct { static struct {
unsigned int size; unsigned int size;
enum x86_reg_type type; enum x86_reg_type type;
unsigned int alias; unsigned int alias;
char mnemonic[8]; char mnemonic[8];
} ia32_reg_table[NUM_X86_REGS + 2] = { } ia32_reg_table[NUM_X86_REGS + 2] = {
{ 0, reg_undef, 0, "" }, { 0, reg_undef, 0, "" },
/* REG_DWORD_OFFSET */ /* REG_DWORD_OFFSET */
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_ret), 0, "eax" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_ret), 0, "eax" },
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_count), 0, "ecx" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_count), 0, "ecx" },
{ REG_DWORD_SIZE, reg_gen, 0, "edx" }, { REG_DWORD_SIZE, reg_gen, 0, "edx" },
{ REG_DWORD_SIZE, reg_gen, 0, "ebx" }, { REG_DWORD_SIZE, reg_gen, 0, "ebx" },
/* REG_ESP_INDEX */ /* REG_ESP_INDEX */
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_sp), 0, "esp" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_sp), 0, "esp" },
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_fp), 0, "ebp" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_fp), 0, "ebp" },
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_src), 0, "esi" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_src), 0, "esi" },
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_dest), 0, "edi" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_dest), 0, "edi" },
/* REG_WORD_OFFSET */ /* REG_WORD_OFFSET */
{ REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_ret), 3, "ax" }, { REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_ret), 3, "ax" },
{ REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_count), 6, "cx" }, { REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_count), 6, "cx" },
{ REG_WORD_SIZE, reg_gen, 9, "dx" }, { REG_WORD_SIZE, reg_gen, 9, "dx" },
{ REG_WORD_SIZE, reg_gen, 12, "bx" }, { REG_WORD_SIZE, reg_gen, 12, "bx" },
{ REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_sp), 13, "sp" }, { REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_sp), 13, "sp" },
{ REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_fp), 14, "bp" }, { REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_fp), 14, "bp" },
{ REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_src), 15, "si" }, { REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_src), 15, "si" },
{ REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_dest), 16, "di" }, { REG_WORD_SIZE, (x86_reg_type)(reg_gen | reg_dest), 16, "di" },
/* REG_BYTE_OFFSET */ /* REG_BYTE_OFFSET */
{ REG_BYTE_SIZE, reg_gen, 1, "al" }, { REG_BYTE_SIZE, reg_gen, 1, "al" },
{ REG_BYTE_SIZE, reg_gen, 4, "cl" }, { REG_BYTE_SIZE, reg_gen, 4, "cl" },
{ REG_BYTE_SIZE, reg_gen, 7, "dl" }, { REG_BYTE_SIZE, reg_gen, 7, "dl" },
{ REG_BYTE_SIZE, reg_gen, 10, "bl" }, { REG_BYTE_SIZE, reg_gen, 10, "bl" },
{ REG_BYTE_SIZE, reg_gen, 2, "ah" }, { REG_BYTE_SIZE, reg_gen, 2, "ah" },
{ REG_BYTE_SIZE, reg_gen, 5, "ch" }, { REG_BYTE_SIZE, reg_gen, 5, "ch" },
{ REG_BYTE_SIZE, reg_gen, 8, "dh" }, { REG_BYTE_SIZE, reg_gen, 8, "dh" },
{ REG_BYTE_SIZE, reg_gen, 11, "bh" }, { REG_BYTE_SIZE, reg_gen, 11, "bh" },
/* REG_MMX_OFFSET */ /* REG_MMX_OFFSET */
{ REG_MMX_SIZE, reg_simd, 18, "mm0" }, { REG_MMX_SIZE, reg_simd, 18, "mm0" },
{ REG_MMX_SIZE, reg_simd, 19, "mm1" }, { REG_MMX_SIZE, reg_simd, 19, "mm1" },
{ REG_MMX_SIZE, reg_simd, 20, "mm2" }, { REG_MMX_SIZE, reg_simd, 20, "mm2" },
{ REG_MMX_SIZE, reg_simd, 21, "mm3" }, { REG_MMX_SIZE, reg_simd, 21, "mm3" },
{ REG_MMX_SIZE, reg_simd, 22, "mm4" }, { REG_MMX_SIZE, reg_simd, 22, "mm4" },
{ REG_MMX_SIZE, reg_simd, 23, "mm5" }, { REG_MMX_SIZE, reg_simd, 23, "mm5" },
{ REG_MMX_SIZE, reg_simd, 24, "mm6" }, { REG_MMX_SIZE, reg_simd, 24, "mm6" },
{ REG_MMX_SIZE, reg_simd, 25, "mm7" }, { REG_MMX_SIZE, reg_simd, 25, "mm7" },
/* REG_SIMD_OFFSET */ /* REG_SIMD_OFFSET */
{ REG_SIMD_SIZE, reg_simd, 0, "xmm0" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm0" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm1" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm1" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm2" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm2" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm3" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm3" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm4" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm4" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm5" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm5" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm6" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm6" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm7" }, { REG_SIMD_SIZE, reg_simd, 0, "xmm7" },
/* REG_DEBUG_OFFSET */ /* REG_DEBUG_OFFSET */
{ REG_DEBUG_SIZE, reg_sys, 0, "dr0" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr0" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr1" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr1" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr2" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr2" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr3" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr3" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr4" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr4" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr5" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr5" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr6" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr6" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr7" }, { REG_DEBUG_SIZE, reg_sys, 0, "dr7" },
/* REG_CTRL_OFFSET */ /* REG_CTRL_OFFSET */
{ REG_CTRL_SIZE, reg_sys, 0, "cr0" }, { REG_CTRL_SIZE, reg_sys, 0, "cr0" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr1" }, { REG_CTRL_SIZE, reg_sys, 0, "cr1" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr2" }, { REG_CTRL_SIZE, reg_sys, 0, "cr2" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr3" }, { REG_CTRL_SIZE, reg_sys, 0, "cr3" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr4" }, { REG_CTRL_SIZE, reg_sys, 0, "cr4" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr5" }, { REG_CTRL_SIZE, reg_sys, 0, "cr5" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr6" }, { REG_CTRL_SIZE, reg_sys, 0, "cr6" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr7" }, { REG_CTRL_SIZE, reg_sys, 0, "cr7" },
/* REG_TEST_OFFSET */ /* REG_TEST_OFFSET */
{ REG_TEST_SIZE, reg_sys, 0, "tr0" }, { REG_TEST_SIZE, reg_sys, 0, "tr0" },
{ REG_TEST_SIZE, reg_sys, 0, "tr1" }, { REG_TEST_SIZE, reg_sys, 0, "tr1" },
{ REG_TEST_SIZE, reg_sys, 0, "tr2" }, { REG_TEST_SIZE, reg_sys, 0, "tr2" },
{ REG_TEST_SIZE, reg_sys, 0, "tr3" }, { REG_TEST_SIZE, reg_sys, 0, "tr3" },
{ REG_TEST_SIZE, reg_sys, 0, "tr4" }, { REG_TEST_SIZE, reg_sys, 0, "tr4" },
{ REG_TEST_SIZE, reg_sys, 0, "tr5" }, { REG_TEST_SIZE, reg_sys, 0, "tr5" },
{ REG_TEST_SIZE, reg_sys, 0, "tr6" }, { REG_TEST_SIZE, reg_sys, 0, "tr6" },
{ REG_TEST_SIZE, reg_sys, 0, "tr7" }, { REG_TEST_SIZE, reg_sys, 0, "tr7" },
/* REG_SEG_OFFSET */ /* REG_SEG_OFFSET */
{ REG_SEG_SIZE, reg_seg, 0, "es" }, { REG_SEG_SIZE, reg_seg, 0, "es" },
{ REG_SEG_SIZE, reg_seg, 0, "cs" }, { REG_SEG_SIZE, reg_seg, 0, "cs" },
{ REG_SEG_SIZE, reg_seg, 0, "ss" }, { REG_SEG_SIZE, reg_seg, 0, "ss" },
{ REG_SEG_SIZE, reg_seg, 0, "ds" }, { REG_SEG_SIZE, reg_seg, 0, "ds" },
{ REG_SEG_SIZE, reg_seg, 0, "fs" }, { REG_SEG_SIZE, reg_seg, 0, "fs" },
{ REG_SEG_SIZE, reg_seg, 0, "gs" }, { REG_SEG_SIZE, reg_seg, 0, "gs" },
/* REG_LDTR_INDEX */ /* REG_LDTR_INDEX */
{ REG_DWORD_SIZE, reg_sys, 0, "ldtr" }, { REG_DWORD_SIZE, reg_sys, 0, "ldtr" },
/* REG_GDTR_INDEX */ /* REG_GDTR_INDEX */
{ REG_DWORD_SIZE, reg_sys, 0, "gdtr" }, { REG_DWORD_SIZE, reg_sys, 0, "gdtr" },
/* REG_FPU_OFFSET */ /* REG_FPU_OFFSET */
{ REG_FPU_SIZE, reg_fpu, 0, "st(0)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(0)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(1)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(1)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(2)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(2)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(3)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(3)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(4)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(4)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(5)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(5)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(6)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(6)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(7)" }, { REG_FPU_SIZE, reg_fpu, 0, "st(7)" },
/* REG_FLAGS_INDEX : 81 */ /* REG_FLAGS_INDEX : 81 */
{ REG_FLAGS_SIZE, reg_cond, 0, "eflags" }, { REG_FLAGS_SIZE, reg_cond, 0, "eflags" },
/* REG_FPCTRL_INDEX : 82*/ /* REG_FPCTRL_INDEX : 82*/
{ REG_FPCTRL_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpctrl" }, { REG_FPCTRL_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpctrl" },
/* REG_FPSTATUS_INDEX : 83*/ /* REG_FPSTATUS_INDEX : 83*/
{ REG_FPSTATUS_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpstat" }, { REG_FPSTATUS_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpstat" },
/* REG_FPTAG_INDEX : 84 */ /* REG_FPTAG_INDEX : 84 */
{ REG_FPTAG_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fptag" }, { REG_FPTAG_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fptag" },
/* REG_EIP_INDEX : 85 */ /* REG_EIP_INDEX : 85 */
{ REG_EIP_SIZE, reg_pc, 0, "eip" }, { REG_EIP_SIZE, reg_pc, 0, "eip" },
/* REG_IP_INDEX : 86 */ /* REG_IP_INDEX : 86 */
{ REG_IP_SIZE, reg_pc, 17, "ip" }, { REG_IP_SIZE, reg_pc, 17, "ip" },
/* REG_IDTR_INDEX : 87 */ /* REG_IDTR_INDEX : 87 */
{ REG_DWORD_SIZE, reg_sys, 0, "idtr" }, { REG_DWORD_SIZE, reg_sys, 0, "idtr" },
/* REG_MXCSG_INDEX : SSE Control Reg : 88 */ /* REG_MXCSG_INDEX : SSE Control Reg : 88 */
{ REG_DWORD_SIZE, (x86_reg_type)(reg_sys | reg_simd), 0, "mxcsr" }, { REG_DWORD_SIZE, (x86_reg_type)(reg_sys | reg_simd), 0, "mxcsr" },
/* REG_TR_INDEX : Task Register : 89 */ /* REG_TR_INDEX : Task Register : 89 */
{ 16 + 64, reg_sys, 0, "tr" }, { 16 + 64, reg_sys, 0, "tr" },
/* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */ /* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */
{ REG_DWORD_SIZE, reg_sys, 0, "cs_msr" }, { REG_DWORD_SIZE, reg_sys, 0, "cs_msr" },
/* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */ /* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */
{ REG_DWORD_SIZE, reg_sys, 0, "esp_msr" }, { REG_DWORD_SIZE, reg_sys, 0, "esp_msr" },
/* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */ /* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */
{ REG_DWORD_SIZE, reg_sys, 0, "eip_msr" }, { REG_DWORD_SIZE, reg_sys, 0, "eip_msr" },
{ 0 } { 0 }
}; };
static size_t sz_regtable = NUM_X86_REGS + 1; static size_t sz_regtable = NUM_X86_REGS + 1;
void ia32_handle_register( x86_reg_t *reg, size_t id ) { void ia32_handle_register( x86_reg_t *reg, size_t id ) {
unsigned int alias; unsigned int alias;
if (! id || id > sz_regtable ) { if (! id || id > sz_regtable ) {
return; return;
} }
memset( reg, 0, sizeof(x86_reg_t) ); memset( reg, 0, sizeof(x86_reg_t) );
strncpy( reg->name, ia32_reg_table[id].mnemonic, MAX_REGNAME ); strncpy( reg->name, ia32_reg_table[id].mnemonic, MAX_REGNAME );
reg->type = ia32_reg_table[id].type; reg->type = ia32_reg_table[id].type;
reg->size = ia32_reg_table[id].size; reg->size = ia32_reg_table[id].size;
alias = ia32_reg_table[id].alias; alias = ia32_reg_table[id].alias;
if ( alias ) { if ( alias ) {
reg->alias = ia32_reg_aliases[alias].alias; reg->alias = ia32_reg_aliases[alias].alias;
reg->shift = ia32_reg_aliases[alias].shift; reg->shift = ia32_reg_aliases[alias].shift;
} }
reg->id = id; reg->id = id;
return; return;
} }
size_t ia32_true_register_id( size_t id ) { size_t ia32_true_register_id( size_t id ) {
size_t reg; size_t reg;
if (! id || id > sz_regtable ) { if (! id || id > sz_regtable ) {
return 0; return 0;
} }
reg = id; reg = id;
if (ia32_reg_table[reg].alias) { if (ia32_reg_table[reg].alias) {
reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias; reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias;
} }
return reg; return reg;
} }

View File

@ -133,12 +133,12 @@ enum x86_reg_type { /* NOTE: these may be ORed together */
/* x86_reg_t : an X86 CPU register */ /* x86_reg_t : an X86 CPU register */
struct x86_reg_t { struct x86_reg_t {
char name[MAX_REGNAME]; char name[MAX_REGNAME];
enum x86_reg_type type; /* what register is used for */ enum x86_reg_type type; /* what register is used for */
unsigned int size; /* size of register in bytes */ unsigned int size; /* size of register in bytes */
unsigned int id; /* register ID #, for quick compares */ unsigned int id; /* register ID #, for quick compares */
unsigned int alias; /* ID of reg this is an alias for */ unsigned int alias; /* ID of reg this is an alias for */
unsigned int shift; /* amount to shift aliased reg by */ unsigned int shift; /* amount to shift aliased reg by */
x86_reg_t * aliased_reg( ) { x86_reg_t * aliased_reg( ) {
x86_reg_t * reg = (x86_reg_t * )calloc( sizeof(x86_reg_t), 1 ); x86_reg_t * reg = (x86_reg_t * )calloc( sizeof(x86_reg_t), 1 );
reg->x86_reg_from_id( id ); reg->x86_reg_from_id( id );
@ -158,11 +158,11 @@ typedef struct {
/* x86_absolute_t : an X86 segment:offset address (descriptor) */ /* x86_absolute_t : an X86 segment:offset address (descriptor) */
typedef struct { typedef struct {
unsigned short segment; /* loaded directly into CS */ unsigned short segment; /* loaded directly into CS */
union { union {
unsigned short off16; /* loaded directly into IP */ unsigned short off16; /* loaded directly into IP */
uint32_t off32; /* loaded directly into EIP */ uint32_t off32; /* loaded directly into EIP */
} offset; } offset;
} x86_absolute_t; } x86_absolute_t;
enum x86_op_type { /* mutually exclusive */ enum x86_op_type { /* mutually exclusive */
@ -210,7 +210,7 @@ enum x86_op_datatype { /* these use Intel's lame terminology */
op_fpustate32 = 23, /* 108 byte FPU state (env & reg stack) */ op_fpustate32 = 23, /* 108 byte FPU state (env & reg stack) */
op_fpregset = 24, /* 512 bytes: register set */ op_fpregset = 24, /* 512 bytes: register set */
op_fpreg = 25, /* FPU register */ op_fpreg = 25, /* FPU register */
op_none = 0xFF, /* operand without a datatype (INVLPG) */ op_none = 0xFF /* operand without a datatype (INVLPG) */
}; };
enum x86_op_access { /* ORed together */ enum x86_op_access { /* ORed together */
@ -250,49 +250,45 @@ struct x86_op_flags { /* ORed together, but segs are mutually exclusive */
/* x86_op_t : an X86 instruction operand */ /* x86_op_t : an X86 instruction operand */
struct x86_op_t{ struct x86_op_t{
friend struct x86_insn_t; friend struct x86_insn_t;
enum x86_op_type type; /* operand type */ enum x86_op_type type; /* operand type */
enum x86_op_datatype datatype; /* operand size */ enum x86_op_datatype datatype; /* operand size */
enum x86_op_access access; /* operand access [RWX] */ enum x86_op_access access; /* operand access [RWX] */
x86_op_flags flags; /* misc flags */ x86_op_flags flags; /* misc flags */
union { union {
/* sizeof will have to work on these union members! */ /* sizeof will have to work on these union members! */
/* immediate values */ /* immediate values */
char sbyte; char sbyte;
short sword; short sword;
int32_t sdword; int32_t sdword;
qword_t sqword; qword_t sqword;
unsigned char byte; unsigned char byte;
unsigned short word; unsigned short word;
uint32_t dword; uint32_t dword;
qword_t qword; qword_t qword;
float sreal; float sreal;
double dreal; double dreal;
/* misc large/non-native types */ /* misc large/non-native types */
unsigned char extreal[10]; unsigned char extreal[10];
unsigned char bcd[10]; unsigned char bcd[10];
qword_t dqword[2]; qword_t dqword[2];
unsigned char simd[16]; unsigned char simd[16];
unsigned char fpuenv[28]; unsigned char fpuenv[28];
/* offset from segment */ /* offset from segment */
uint32_t offset; uint32_t offset;
/* ID of CPU register */ x86_reg_t reg; /* ID of CPU register */
x86_reg_t reg; char relative_near; /* offsets from current insn */
/* offsets from current insn */ int32_t relative_far;
char relative_near; x86_absolute_t absolute; /* segment:offset */
int32_t relative_far; x86_ea_t expression; /* effective address [expression] */
/* segment:offset */ } data;
x86_absolute_t absolute; /* this is needed to make formatting operands more sane */
/* effective address [expression] */ void * insn; /* pointer to x86_insn_t owning operand */
x86_ea_t expression;
} data;
/* this is needed to make formatting operands more sane */
void * insn; /* pointer to x86_insn_t owning operand */
size_t size() size_t size()
{ {
return x86_operand_size(); return operand_size();
} }
/* get size of operand data in bytes */ /* get size of operand data in bytes */
size_t x86_operand_size(); size_t operand_size();
/* format (sprintf) an operand into 'buf' using specified syntax */ /* format (sprintf) an operand into 'buf' using specified syntax */
int x86_format_operand(char *buf, int len, enum x86_asm_format format ); int x86_format_operand(char *buf, int len, enum x86_asm_format format );
bool is_address( ) { bool is_address( ) {
@ -302,9 +298,9 @@ struct x86_op_t{
return ( type == op_relative_near || type == op_relative_far ); return ( type == op_relative_near || type == op_relative_far );
} }
char * format( enum x86_asm_format format ); char * format( enum x86_asm_format format );
x86_op_t * copy() { x86_op_t * copy()
{
x86_op_t *op = (x86_op_t *) calloc( sizeof(x86_op_t), 1 ); x86_op_t *op = (x86_op_t *) calloc( sizeof(x86_op_t), 1 );
if ( op ) { if ( op ) {
memcpy( op, this, sizeof(x86_op_t) ); memcpy( op, this, sizeof(x86_op_t) );
} }
@ -524,6 +520,7 @@ enum x86_insn_prefix {
/* TODO: maybe provide insn_new/free(), and have disasm return new insn_t */ /* TODO: maybe provide insn_new/free(), and have disasm return new insn_t */
/* FOREACH types: these are used to limit the foreach results to /* FOREACH types: these are used to limit the foreach results to
* operands which match a certain "type" (implicit or explicit) * operands which match a certain "type" (implicit or explicit)
* or which are accessed in certain ways (e.g. read or write). Note * or which are accessed in certain ways (e.g. read or write). Note
@ -575,11 +572,11 @@ private:
void x86_oplist_append(x86_oplist_t *op); void x86_oplist_append(x86_oplist_t *op);
public: public:
/* information about the instruction */ /* information about the instruction */
uint32_t addr; /* load address */ uint32_t addr; /* load address */
uint32_t offset; /* offset into file/buffer */ uint32_t offset; /* offset into file/buffer */
enum x86_insn_group group; /* meta-type, e.g. INS_EXEC */ x86_insn_group group; /* meta-type, e.g. INS_EXEC */
enum x86_insn_type type; /* type, e.g. INS_BRANCH */ x86_insn_type type; /* type, e.g. INS_BRANCH */
enum x86_insn_note note; /* note, e.g. RING0 */ x86_insn_note note; /* note, e.g. RING0 */
unsigned char bytes[MAX_INSN_SIZE]; unsigned char bytes[MAX_INSN_SIZE];
unsigned char size; /* size of insn in bytes */ unsigned char size; /* size of insn in bytes */
/* 16/32-bit mode settings */ /* 16/32-bit mode settings */
@ -607,58 +604,29 @@ public:
void *block; /* code block containing this insn */ void *block; /* code block containing this insn */
void *function; /* function containing this insn */ void *function; /* function containing this insn */
int tag; /* tag the insn as seen/processed */ int tag; /* tag the insn as seen/processed */
x86_op_t *x86_operand_new(); x86_op_t * x86_operand_new();
/* convenience routine: returns count of operands matching 'type' */ size_t x86_operand_count( enum x86_op_foreach_type type );
size_t x86_operand_count( enum x86_op_foreach_type type );
/* accessor functions for the operands */ /* accessor functions for the operands */
x86_op_t * x86_operand_1st( ); x86_op_t * x86_operand_1st( );
x86_op_t * x86_operand_2nd( ); x86_op_t * x86_operand_2nd( );
x86_op_t * x86_operand_3rd( ); x86_op_t * x86_operand_3rd( );
/* Get Relative Offset: return as a sign-extended int32_t the near or far x86_op_t * get_dest();
* relative offset operand, or 0 if there is none. There can be only one int32_t x86_get_rel_offset( );
* relaive offset operand in an instruction. */ x86_op_t * x86_get_branch_target( );
int32_t x86_get_rel_offset( ); x86_op_t * x86_get_imm( );
/* Get Branch Target: return the x86_op_t containing the target of uint8_t * x86_get_raw_imm( );
* a jump or call operand, or NULL if there is no branch target.
* Internally, a 'branch target' is defined as any operand with
* Execute Access set. There can be only one branch target per instruction. */
x86_op_t * x86_get_branch_target( );
/* Get Immediate: return the x86_op_t containing the immediate operand
* for this instruction, or NULL if there is no immediate operand. There
* can be only one immediate operand per instruction */
x86_op_t * x86_get_imm( );
/* Get Raw Immediate Data: returns a pointer to the immediate data encoded
* in the instruction. This is useful for large data types [>32 bits] currently
* not supported by libdisasm, or for determining if the disassembler
* screwed up the conversion of the immediate data. Note that 'imm' in this
* context refers to immediate data encoded at the end of an instruction as
* detailed in the Intel Manual Vol II Chapter 2; it does not refer to the
* 'op_imm' operand (the third operand in instructions like 'mul' */
unsigned char * x86_get_raw_imm( );
/* More accessor fuctions, this time for user-defined info... */ /* More accessor fuctions, this time for user-defined info... */
/* set the address (usually RVA) of the insn */ void x86_set_insn_addr( uint32_t addr );
void x86_set_insn_addr( uint32_t addr ); int x86_format_mnemonic( char *buf, int len, enum x86_asm_format format);
/* format (sprintf) an instruction mnemonic into 'buf' using specified syntax */ int x86_format_insn( char *buf, int len, enum x86_asm_format);
int x86_format_mnemonic( char *buf, int len, enum x86_asm_format format); void x86_oplist_free( );
/* format (sprintf) an instruction into 'buf' using specified syntax; bool is_valid( );
* this includes formatting all operands */
int x86_format_insn( char *buf, int len, enum x86_asm_format);
/* free the operand list associated with an instruction -- useful for
* preventing memory leaks when free()ing an x86_insn_t */
void x86_oplist_free( );
/* returns 0 if an instruction is invalid, 1 if valid */
int x86_insn_is_valid( );
/* Get Address: return the value of an offset operand, or the offset of
* a segment:offset absolute address */
uint32_t x86_get_address( ); uint32_t x86_get_address( );
void make_invalid(unsigned char *buf); void make_invalid(unsigned char *buf);
/* instruction tagging: these routines allow the programmer to mark /* instruction tagging: these routines allow the programmer to mark
* instructions as "seen" in a DFS, for example. libdisasm does not use * instructions as "seen" in a DFS, for example. libdisasm does not use
* the tag field.*/ * the tag field.*/
/* set insn->tag to 1 */
void x86_tag_insn( ); void x86_tag_insn( );
/* return insn->tag */
int x86_insn_is_tagged(); int x86_insn_is_tagged();
/* set insn->tag to 0 */ /* set insn->tag to 0 */
void x86_untag_insn(); void x86_untag_insn();

View File

@ -16,16 +16,16 @@
* only with one argument. * only with one argument.
*/ */
#define STRNCAT( buf, str, len ) do { \ #define STRNCAT( buf, str, len ) do { \
int _i = strlen(str), _blen = strlen(buf), _len = len - 1; \ int _i = strlen(str), _blen = strlen(buf), _len = len - 1; \
if ( len ) { \ if ( len ) { \
strncat( buf, str, _len ); \ strncat( buf, str, _len ); \
if ( _len <= _i ) { \ if ( _len <= _i ) { \
buf[_blen+_len] = '\0'; \ buf[_blen+_len] = '\0'; \
len = 0; \ len = 0; \
} else { \ } else { \
len -= _i; \ len -= _i; \
} \ } \
} \ } \
} while( 0 ) } while( 0 )
#define STRNCATF( buf, fmt, data, len ) do { \ #define STRNCATF( buf, fmt, data, len ) do { \
@ -47,11 +47,11 @@
} while( 0 ) } while( 0 )
static char *prefix_strings[] = { static char *prefix_strings[] = {
"", /* no prefix */ "", /* no prefix */
"repz ", /* the trailing spaces make it easy to prepend to mnemonic */ "repz ", /* the trailing spaces make it easy to prepend to mnemonic */
"repnz ", "repnz ",
"lock ", "lock ",
"branch delay " /* unused in x86 */ "branch delay " /* unused in x86 */
}; };
static int format_insn_prefix_str( enum x86_insn_prefix prefix, char *buf, static int format_insn_prefix_str( enum x86_insn_prefix prefix, char *buf,
@ -163,28 +163,28 @@ static int format_expr( x86_ea_t *ea, char *buf, int len,
char str[MAX_OP_STRING]; char str[MAX_OP_STRING];
if ( format == att_syntax ) { if ( format == att_syntax ) {
if (ea->base.name[0] || ea->index.name[0] || ea->scale) { if (ea->base.name[0] || ea->index.name[0] || ea->scale) {
PRINT_DISPLACEMENT(ea); PRINT_DISPLACEMENT(ea);
STRNCAT( buf, "(", len ); STRNCAT( buf, "(", len );
if ( ea->base.name[0]) { if ( ea->base.name[0]) {
STRNCATF( buf, "%%%s", ea->base.name, len ); STRNCATF( buf, "%%%s", ea->base.name, len );
} }
if ( ea->index.name[0]) { if ( ea->index.name[0]) {
STRNCATF( buf, ",%%%s", ea->index.name, len ); STRNCATF( buf, ",%%%s", ea->index.name, len );
if ( ea->scale > 1 ) { if ( ea->scale > 1 ) {
STRNCATF( buf, ",%d", ea->scale, len ); STRNCATF( buf, ",%d", ea->scale, len );
} }
} }
/* handle the syntactic exception */ /* handle the syntactic exception */
if ( ! ea->base.name[0] && if ( ! ea->base.name[0] &&
! ea->index.name[0] ) { ! ea->index.name[0] ) {
STRNCATF( buf, ",%d", ea->scale, len ); STRNCATF( buf, ",%d", ea->scale, len );
} }
STRNCAT( buf, ")", len ); STRNCAT( buf, ")", len );
} else } else
STRNCATF( buf, "0x%" PRIX32, ea->disp, len ); STRNCATF( buf, "0x%" PRIX32, ea->disp, len );
} else if ( format == xml_syntax ){ } else if ( format == xml_syntax ){
@ -271,7 +271,7 @@ static int format_expr( x86_ea_t *ea, char *buf, int len,
} }
if ( ea->disp_size || (! ea->index.name[0] && if ( ea->disp_size || (! ea->index.name[0] &&
! ea->base.name[0] ) ) ! ea->base.name[0] ) )
{ {
PRINT_DISPLACEMENT(ea); PRINT_DISPLACEMENT(ea);
} }
@ -341,34 +341,34 @@ static char *get_operand_datatype_str( x86_op_t *op ){
"qword", "qword",
"dword", /* 8 */ "dword", /* 8 */
"dqword", "dqword",
"sreal", "sreal",
"dreal", "dreal",
"extreal", /* 12 */ "extreal", /* 12 */
"bcd", "bcd",
"ssimd", "ssimd",
"dsimd", "dsimd",
"sssimd", /* 16 */ "sssimd", /* 16 */
"sdsimd", "sdsimd",
"descr32", "descr32",
"descr16", "descr16",
"pdescr32", /* 20 */ "pdescr32", /* 20 */
"pdescr16", "pdescr16",
"bounds16", "bounds16",
"bounds32", "bounds32",
"fpu_env16", "fpu_env16",
"fpu_env32", /* 25 */ "fpu_env32", /* 25 */
"fpu_state16", "fpu_state16",
"fpu_state32", "fpu_state32",
"fp_reg_set" "fp_reg_set"
}; };
/* handle signed values first */ /* handle signed values first */
if ( op->flags.op_signed ) { if ( op->flags.op_signed ) {
switch (op->datatype) { switch (op->datatype) {
case op_byte: return types[0]; case op_byte: return types[0];
case op_word: return types[1]; case op_word: return types[1];
case op_qword: return types[2]; case op_qword: return types[2];
case op_dqword: return types[4]; case op_dqword: return types[4];
default: return types[3]; default: return types[3];
} }
} }
@ -378,25 +378,25 @@ static char *get_operand_datatype_str( x86_op_t *op ){
case op_word: return types[6]; case op_word: return types[6];
case op_qword: return types[7]; case op_qword: return types[7];
case op_dqword: return types[9]; case op_dqword: return types[9];
case op_sreal: return types[10]; case op_sreal: return types[10];
case op_dreal: return types[11]; case op_dreal: return types[11];
case op_extreal: return types[12]; case op_extreal: return types[12];
case op_bcd: return types[13]; case op_bcd: return types[13];
case op_ssimd: return types[14]; case op_ssimd: return types[14];
case op_dsimd: return types[15]; case op_dsimd: return types[15];
case op_sssimd: return types[16]; case op_sssimd: return types[16];
case op_sdsimd: return types[17]; case op_sdsimd: return types[17];
case op_descr32: return types[18]; case op_descr32: return types[18];
case op_descr16: return types[19]; case op_descr16: return types[19];
case op_pdescr32: return types[20]; case op_pdescr32: return types[20];
case op_pdescr16: return types[21]; case op_pdescr16: return types[21];
case op_bounds16: return types[22]; case op_bounds16: return types[22];
case op_bounds32: return types[23]; case op_bounds32: return types[23];
case op_fpustate16: return types[24]; case op_fpustate16: return types[24];
case op_fpustate32: return types[25]; case op_fpustate32: return types[25];
case op_fpuenv16: return types[26]; case op_fpuenv16: return types[26];
case op_fpuenv32: return types[27]; case op_fpuenv32: return types[27];
case op_fpregset: return types[28]; case op_fpregset: return types[28];
default: return types[8]; default: return types[8];
} }
} }
@ -608,21 +608,21 @@ static char *get_insn_cpu_str( enum x86_insn_cpu cpu ) {
}; };
if ( cpu <= sizeof(intel)/sizeof(intel[0]) ) { if ( cpu <= sizeof(intel)/sizeof(intel[0]) ) {
return intel[cpu]; return intel[cpu];
} else if ( cpu == 16 ) { } else if ( cpu == 16 ) {
return "K6"; return "K6";
} else if ( cpu == 32 ) { } else if ( cpu == 32 ) {
return "K7"; return "K7";
} else if ( cpu == 48 ) { } else if ( cpu == 48 ) {
return "Athlon"; return "Athlon";
} }
return ""; return "";
} }
static char *get_insn_isa_str( enum x86_insn_isa isa ) { static char *get_insn_isa_str( enum x86_insn_isa isa ) {
static char *subset[] = { static char *subset[] = {
NULL, // 0 NULL, // 0
"General Purpose", // 1 "General Purpose", // 1
"Floating Point", // 2 "Floating Point", // 2
"FPU Management", // 3 "FPU Management", // 3
@ -636,7 +636,7 @@ static char *get_insn_isa_str( enum x86_insn_isa isa ) {
if ( isa > sizeof (subset)/sizeof(subset[0]) ) { if ( isa > sizeof (subset)/sizeof(subset[0]) ) {
return ""; return "";
} }
return subset[isa]; return subset[isa];
} }
@ -664,29 +664,29 @@ static int format_operand_att( x86_op_t *op, x86_insn_t *insn, char *buf,
insn->addr + insn->size), len ); insn->addr + insn->size), len );
break; break;
case op_relative_far: case op_relative_far:
if (op->datatype == op_word) { if (op->datatype == op_word) {
STRNCATF( buf, "0x%08X", STRNCATF( buf, "0x%08X",
(unsigned int)(op->data.sword + (unsigned int)(op->data.sword +
insn->addr + insn->size), len ); insn->addr + insn->size), len );
} else { } else {
STRNCATF( buf, "0x%08X", STRNCATF( buf, "0x%08X",
(unsigned int)(op->data.sdword + (unsigned int)(op->data.sdword +
insn->addr + insn->size), len ); insn->addr + insn->size), len );
} }
break; break;
case op_absolute: case op_absolute:
/* ATT uses the syntax $section, $offset */ /* ATT uses the syntax $section, $offset */
STRNCATF( buf, "$0x%04" PRIX16 ", ", op->data.absolute.segment, STRNCATF( buf, "$0x%04" PRIX16 ", ", op->data.absolute.segment,
len ); len );
if (op->datatype == op_descr16) { if (op->datatype == op_descr16) {
STRNCATF( buf, "$0x%04" PRIX16, STRNCATF( buf, "$0x%04" PRIX16,
op->data.absolute.offset.off16, len ); op->data.absolute.offset.off16, len );
} else { } else {
STRNCATF( buf, "$0x%08" PRIX32, STRNCATF( buf, "$0x%08" PRIX32,
op->data.absolute.offset.off32, len ); op->data.absolute.offset.off32, len );
} }
break; break;
case op_offset: case op_offset:
/* ATT requires a '*' before JMP/CALL ops */ /* ATT requires a '*' before JMP/CALL ops */
@ -743,21 +743,21 @@ static int format_operand_native( x86_op_t *op, x86_insn_t *insn, char *buf,
insn->addr + insn->size), len ); insn->addr + insn->size), len );
break; break;
} else { } else {
STRNCATF( buf, "0x%08" PRIX32, op->data.sdword + STRNCATF( buf, "0x%08" PRIX32, op->data.sdword +
insn->addr + insn->size, len ); insn->addr + insn->size, len );
} }
break; break;
case op_absolute: case op_absolute:
STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment, STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment,
len ); len );
if (op->datatype == op_descr16) { if (op->datatype == op_descr16) {
STRNCATF( buf, "0x%04" PRIX16, STRNCATF( buf, "0x%04" PRIX16,
op->data.absolute.offset.off16, len ); op->data.absolute.offset.off16, len );
} else { } else {
STRNCATF( buf, "0x%08" PRIX32, STRNCATF( buf, "0x%08" PRIX32,
op->data.absolute.offset.off32, len ); op->data.absolute.offset.off32, len );
} }
break; break;
case op_offset: case op_offset:
@ -824,25 +824,25 @@ static int format_operand_xml( x86_op_t *op, x86_insn_t *insn, char *buf,
break; break;
} else { } else {
STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n", STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n",
op->data.sdword + insn->addr + insn->size, op->data.sdword + insn->addr + insn->size,
len ); len );
} }
break; break;
case op_absolute: case op_absolute:
STRNCATF( buf, STRNCATF( buf,
"\t\t<absolute_address segment=\"0x%04" PRIX16 "\"", "\t\t<absolute_address segment=\"0x%04" PRIX16 "\"",
op->data.absolute.segment, len ); op->data.absolute.segment, len );
if (op->datatype == op_descr16) { if (op->datatype == op_descr16) {
STRNCATF( buf, "offset=\"0x%04" PRIX16 "\">", STRNCATF( buf, "offset=\"0x%04" PRIX16 "\">",
op->data.absolute.offset.off16, len ); op->data.absolute.offset.off16, len );
} else { } else {
STRNCATF( buf, "offset=\"0x%08" PRIX32 "\">", STRNCATF( buf, "offset=\"0x%08" PRIX32 "\">",
op->data.absolute.offset.off32, len ); op->data.absolute.offset.off32, len );
} }
STRNCAT( buf, "\t\t</absolute_address>\n", len ); STRNCAT( buf, "\t\t</absolute_address>\n", len );
break; break;
@ -884,7 +884,7 @@ static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf,
int len){ int len){
char str[MAX_OP_RAW_STRING]; char str[MAX_OP_RAW_STRING];
char *datatype = get_operand_datatype_str(op); char *datatype = get_operand_datatype_str(op);
switch (op->type) { switch (op->type) {
case op_register: case op_register:
@ -909,9 +909,9 @@ static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf,
break; break;
case op_relative_near: case op_relative_near:
/* NOTE: in raw format, we print the /* NOTE: in raw format, we print the
* relative offset, not the actual * relative offset, not the actual
* address of the jump target */ * address of the jump target */
STRNCAT( buf, "relative|", len ); STRNCAT( buf, "relative|", len );
STRNCATF( buf, "%s|", datatype, len ); STRNCATF( buf, "%s|", datatype, len );
@ -927,8 +927,8 @@ static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf,
STRNCATF( buf, "%" PRId16 "|", op->data.sword, len); STRNCATF( buf, "%" PRId16 "|", op->data.sword, len);
break; break;
} else { } else {
STRNCATF( buf, "%" PRId32 "|", op->data.sdword, len ); STRNCATF( buf, "%" PRId32 "|", op->data.sdword, len );
} }
break; break;
case op_absolute: case op_absolute:
@ -937,14 +937,14 @@ static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf,
STRNCATF( buf, "%s|", datatype, len ); STRNCATF( buf, "%s|", datatype, len );
STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment, STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment,
len ); len );
if (op->datatype == op_descr16) { if (op->datatype == op_descr16) {
STRNCATF( buf, "0x%04" PRIX16 "|", STRNCATF( buf, "0x%04" PRIX16 "|",
op->data.absolute.offset.off16, len ); op->data.absolute.offset.off16, len );
} else { } else {
STRNCATF( buf, "0x%08" PRIX32 "|", STRNCATF( buf, "0x%08" PRIX32 "|",
op->data.absolute.offset.off32, len ); op->data.absolute.offset.off32, len );
} }
break; break;
@ -981,14 +981,14 @@ static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf,
int x86_op_t::x86_format_operand(char *buf, int len, int x86_op_t::x86_format_operand(char *buf, int len,
enum x86_asm_format format ){ enum x86_asm_format format ){
x86_insn_t *_insn; x86_insn_t *_insn;
if ( ! this || ! buf || len < 1 ) { if ( ! this || ! buf || len < 1 ) {
return(0); return(0);
} }
/* insn is stored in x86_op_t since .21-pre3 */ /* insn is stored in x86_op_t since .21-pre3 */
_insn = (x86_insn_t *) insn; _insn = (x86_insn_t *) insn;
memset( buf, 0, len ); memset( buf, 0, len );
@ -1077,10 +1077,10 @@ static int format_att_mnemonic( x86_insn_t *insn, char *buf, int len) {
)) { )) {
if ( insn->x86_operand_count( op_explicit ) > 0 && if ( insn->x86_operand_count( op_explicit ) > 0 &&
is_memory_op( insn->x86_operand_1st() ) ){ is_memory_op( insn->x86_operand_1st() ) ){
size = insn->x86_operand_1st()->x86_operand_size(); size = insn->x86_operand_1st()->operand_size();
} else if ( insn->x86_operand_count( op_explicit ) > 1 && } else if ( insn->x86_operand_count( op_explicit ) > 1 &&
is_memory_op( insn->x86_operand_2nd() ) ){ is_memory_op( insn->x86_operand_2nd() ) ){
size = insn->x86_operand_2nd()->x86_operand_size(); size = insn->x86_operand_2nd()->operand_size();
} }
} }
@ -1094,6 +1094,7 @@ static int format_att_mnemonic( x86_insn_t *insn, char *buf, int len) {
return ( strlen( buf ) ); return ( strlen( buf ) );
} }
/** format (sprintf) an instruction mnemonic into 'buf' using specified syntax */
int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len, int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len,
enum x86_asm_format format){ enum x86_asm_format format){
char str[MAX_OP_STRING]; char str[MAX_OP_STRING];
@ -1113,24 +1114,24 @@ int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len,
struct op_string { char *buf; size_t len; }; struct op_string { char *buf; size_t len; };
static void format_op_raw( x86_op_t *op, x86_insn_t *insn, void *arg ) { static void format_op_raw( x86_op_t *op, x86_insn_t *insn, void *arg ) {
struct op_string * opstr = (struct op_string *) arg; struct op_string * opstr = (struct op_string *) arg;
format_operand_raw(op, insn, opstr->buf, opstr->len); format_operand_raw(op, insn, opstr->buf, opstr->len);
} }
static int format_insn_note(x86_insn_t *insn, char *buf, int len){ static int format_insn_note(x86_insn_t *insn, char *buf, int len){
char note[32] = {0}; char note[32] = {0};
int len_orig = len, note_len = 32; int len_orig = len, note_len = 32;
if ( insn->note & insn_note_ring0 ) { if ( insn->note & insn_note_ring0 ) {
STRNCATF( note, "%s", "Ring0 ", note_len ); STRNCATF( note, "%s", "Ring0 ", note_len );
} }
if ( insn->note & insn_note_smm ) { if ( insn->note & insn_note_smm ) {
STRNCATF( note, "%s", "SMM ", note_len ); STRNCATF( note, "%s", "SMM ", note_len );
} }
if ( insn->note & insn_note_serial ) { if ( insn->note & insn_note_serial ) {
STRNCATF(note, "%s", "Serialize ", note_len ); STRNCATF(note, "%s", "Serialize ", note_len );
} }
STRNCATF( buf, "%s|", note, len ); STRNCATF( buf, "%s|", note, len );
return( len_orig - len ); return( len_orig - len );
@ -1143,9 +1144,9 @@ static int format_raw_insn( x86_insn_t *insn, char *buf, int len ){
/* RAW style: /* RAW style:
* ADDRESS|OFFSET|SIZE|BYTES| * ADDRESS|OFFSET|SIZE|BYTES|
* PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES| * PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|
* MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED| * MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|
* STACK_MOD|STACK_MOD_VAL * STACK_MOD|STACK_MOD_VAL
* [|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]* * [|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*
* *
* Register values are encoded as: * Register values are encoded as:
* NAME:TYPE:SIZE * NAME:TYPE:SIZE
@ -1222,29 +1223,29 @@ static int format_xml_insn( x86_insn_t *insn, char *buf, int len ) {
len -= format_insn_eflags_str( insn->flags_tested, buf, len ); len -= format_insn_eflags_str( insn->flags_tested, buf, len );
STRNCAT( buf, "\"/>\n\t</flags>\n", len ); STRNCAT( buf, "\"/>\n\t</flags>\n", len );
if ( insn->x86_operand_1st() ) { if ( insn->x86_operand_1st() ) {
insn->x86_operand_1st()->x86_format_operand(str, insn->x86_operand_1st()->x86_format_operand(str,
sizeof str, xml_syntax); sizeof str, xml_syntax);
STRNCAT( buf, "\t<operand name=dest>\n", len ); STRNCAT( buf, "\t<operand name=dest>\n", len );
STRNCAT( buf, str, len ); STRNCAT( buf, str, len );
STRNCAT( buf, "\t</operand>\n", len ); STRNCAT( buf, "\t</operand>\n", len );
} }
if ( insn->x86_operand_2nd() ) { if ( insn->x86_operand_2nd() ) {
insn->x86_operand_2nd()->x86_format_operand(str,sizeof str, insn->x86_operand_2nd()->x86_format_operand(str,sizeof str,
xml_syntax); xml_syntax);
STRNCAT( buf, "\t<operand name=src>\n", len ); STRNCAT( buf, "\t<operand name=src>\n", len );
STRNCAT( buf, str, len ); STRNCAT( buf, str, len );
STRNCAT( buf, "\t</operand>\n", len ); STRNCAT( buf, "\t</operand>\n", len );
} }
if ( insn->x86_operand_3rd() ) { if ( insn->x86_operand_3rd() ) {
insn->x86_operand_3rd()->x86_format_operand(str,sizeof str, insn->x86_operand_3rd()->x86_format_operand(str,sizeof str,
xml_syntax); xml_syntax);
STRNCAT( buf, "\t<operand name=imm>\n", len ); STRNCAT( buf, "\t<operand name=imm>\n", len );
STRNCAT( buf, str, len ); STRNCAT( buf, str, len );
STRNCAT( buf, "\t</operand>\n", len ); STRNCAT( buf, "\t</operand>\n", len );
} }
STRNCAT( buf, "</x86_insn>\n", len ); STRNCAT( buf, "</x86_insn>\n", len );
@ -1266,9 +1267,9 @@ int X86_Disasm::x86_format_header( char *buf, int len, enum x86_asm_format forma
case raw_syntax: case raw_syntax:
snprintf( buf, len, "ADDRESS|OFFSET|SIZE|BYTES|" snprintf( buf, len, "ADDRESS|OFFSET|SIZE|BYTES|"
"PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|" "PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|"
"MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|" "MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|"
"STACK_MOD|STACK_MOD_VAL" "STACK_MOD|STACK_MOD_VAL"
"[|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*" "[|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*"
); );
break; break;
case xml_syntax: case xml_syntax:
@ -1277,11 +1278,11 @@ int X86_Disasm::x86_format_header( char *buf, int len, enum x86_asm_format forma
"<address rva= offset= size= bytes=/>" "<address rva= offset= size= bytes=/>"
"<prefix type= string=/>" "<prefix type= string=/>"
"<mnemonic group= type= string= " "<mnemonic group= type= string= "
"cpu= isa= note= />" "cpu= isa= note= />"
"<flags type=set>" "<flags type=set>"
"<flag name=>" "<flag name=>"
"</flags>" "</flags>"
"<stack_mod val= >" "<stack_mod val= >"
"<flags type=tested>" "<flags type=tested>"
"<flag name=>" "<flag name=>"
"</flags>" "</flags>"
@ -1315,16 +1316,18 @@ int X86_Disasm::x86_format_header( char *buf, int len, enum x86_asm_format forma
"</x86_insn>" "</x86_insn>"
); );
break; break;
case unknown_syntax: case unknown_syntax:
if ( len ) { if ( len ) {
buf[0] = '\0'; buf[0] = '\0';
} }
break; break;
} }
return( strlen(buf) ); return( strlen(buf) );
} }
/** format (sprintf) an instruction into 'buf' using specified syntax;
* this includes formatting all operands */
int x86_insn_t::x86_format_insn( char *buf, int len, int x86_insn_t::x86_format_insn( char *buf, int len,
enum x86_asm_format format ){ enum x86_asm_format format ){
char str[MAX_OP_STRING]; char str[MAX_OP_STRING];

View File

@ -17,7 +17,8 @@ int x86_insn_is_valid( x86_insn_t *insn ) {
return 0; return 0;
} }
int x86_insn_t::x86_insn_is_valid( ) /** \returns false if an instruction is invalid, true if valid */
bool x86_insn_t::is_valid( )
{ {
if ( this && this->type != insn_invalid && this->size > 0 ) if ( this && this->type != insn_invalid && this->size > 0 )
{ {
@ -26,10 +27,15 @@ int x86_insn_t::x86_insn_is_valid( )
return 0; return 0;
} }
uint32_t x86_insn_t::x86_get_address() { /* Get Address: return the value of an offset operand, or the offset of
* a segment:offset absolute address */
uint32_t x86_insn_t::x86_get_address()
{
x86_oplist_t *op_lst; x86_oplist_t *op_lst;
assert(this); assert(this);
if (! operands ) { if (! operands )
{
return 0; return 0;
} }
@ -48,6 +54,9 @@ uint32_t x86_insn_t::x86_get_address() {
return 0; return 0;
} }
/** Get Relative Offset: return as a sign-extended int32_t the near or far
* relative offset operand, or 0 if there is none. There can be only one
* relaive offset operand in an instruction. */
int32_t x86_insn_t::x86_get_rel_offset( ) { int32_t x86_insn_t::x86_get_rel_offset( ) {
x86_oplist_t *op_lst; x86_oplist_t *op_lst;
assert(this); assert(this);
@ -66,6 +75,10 @@ int32_t x86_insn_t::x86_get_rel_offset( ) {
return 0; return 0;
} }
/** Get Branch Target: return the x86_op_t containing the target of
* a jump or call operand, or NULL if there is no branch target.
* Internally, a 'branch target' is defined as any operand with
* Execute Access set. There can be only one branch target per instruction. */
x86_op_t * x86_insn_t::x86_get_branch_target() { x86_op_t * x86_insn_t::x86_get_branch_target() {
x86_oplist_t *op_lst; x86_oplist_t *op_lst;
assert(this); assert(this);
@ -81,6 +94,24 @@ x86_op_t * x86_insn_t::x86_get_branch_target() {
return NULL; return NULL;
} }
x86_op_t * x86_insn_t::get_dest() {
x86_oplist_t *op_lst;
assert(this);
if ( ! operands ) {
return NULL;
}
assert(this->x86_operand_count(op_dest)==1);
for (op_lst = operands; op_lst; op_lst = op_lst->next ) {
if ( op_lst->op.access & op_write)
return &(op_lst->op);
}
return NULL;
}
/** \brief Get Immediate: return the x86_op_t containing the immediate operand
for this instruction, or NULL if there is no immediate operand. There
can be only one immediate operand per instruction */
x86_op_t * x86_insn_t::x86_get_imm() { x86_op_t * x86_insn_t::x86_get_imm() {
x86_oplist_t *op_lst; x86_oplist_t *op_lst;
assert(this); assert(this);
@ -101,9 +132,15 @@ x86_op_t * x86_insn_t::x86_get_imm() {
x->op.type == op_immediate && ! (x->op.flags.op_hardcode) x->op.type == op_immediate && ! (x->op.flags.op_hardcode)
/* if there is an immediate value in the instruction, return a pointer to /** \brief if there is an immediate value in the instruction, return a pointer to it
* it */ * Get Raw Immediate Data: returns a pointer to the immediate data encoded
unsigned char * x86_insn_t::x86_get_raw_imm() { * in the instruction. This is useful for large data types [>32 bits] currently
* not supported by libdisasm, or for determining if the disassembler
* screwed up the conversion of the immediate data. Note that 'imm' in this
* context refers to immediate data encoded at the end of an instruction as
* detailed in the Intel Manual Vol II Chapter 2; it does not refer to the
* 'op_imm' operand (the third operand in instructions like 'mul' */
uint8_t *x86_insn_t::x86_get_raw_imm() {
int size, offset; int size, offset;
x86_op_t *op = NULL; x86_op_t *op = NULL;
assert(this); assert(this);
@ -128,13 +165,13 @@ unsigned char * x86_insn_t::x86_get_raw_imm() {
} }
/* immediate data is at the end of the insn */ /* immediate data is at the end of the insn */
size = op->x86_operand_size(); size = op->operand_size();
offset = size - size; offset = size - size;
return( &bytes[offset] ); return( &bytes[offset] );
} }
size_t x86_op_t::x86_operand_size() { size_t x86_op_t::operand_size() {
switch (datatype ) { switch (datatype ) {
case op_byte: return 1; case op_byte: return 1;
case op_word: return 2; case op_word: return 2;
@ -166,6 +203,7 @@ size_t x86_op_t::x86_operand_size() {
return(4); /* default size */ return(4); /* default size */
} }
/** set the address (usually RVA) of the insn */
void x86_insn_t::x86_set_insn_addr( uint32_t _addr ) { void x86_insn_t::x86_set_insn_addr( uint32_t _addr ) {
addr = _addr; addr = _addr;
} }
@ -182,6 +220,7 @@ void x86_insn_t::x86_set_insn_block( void * _block ){
block = _block; block = _block;
} }
/** set insn->tag to 1 */
void x86_insn_t::x86_tag_insn(){ void x86_insn_t::x86_tag_insn(){
tag = 1; tag = 1;
} }
@ -190,6 +229,7 @@ void x86_insn_t::x86_untag_insn(){
tag = 0; tag = 0;
} }
/** \return insn->tag */
int x86_insn_t::x86_insn_is_tagged(){ int x86_insn_t::x86_insn_is_tagged(){
return tag; return tag;
} }

View File

@ -4,31 +4,31 @@
void x86_insn_t::x86_oplist_append( x86_oplist_t *op ) { void x86_insn_t::x86_oplist_append( x86_oplist_t *op ) {
x86_oplist_t *list; x86_oplist_t *list;
assert(this); assert(this);
list = operands; list = operands;
if (! list ) { if (! list ) {
operand_count = 1; operand_count = 1;
/* Note that we have no way of knowing if this is an /* Note that we have no way of knowing if this is an
* exlicit operand or not, since the caller fills * exlicit operand or not, since the caller fills
* the x86_op_t after we return. We increase the * the x86_op_t after we return. We increase the
* explicit count automatically, and ia32_insn_implicit_ops * explicit count automatically, and ia32_insn_implicit_ops
* decrements it */ * decrements it */
explicit_count = 1; explicit_count = 1;
operands = op; operands = op;
return;
}
/* get to end of list */
for ( ; list->next; list = list->next )
;
operand_count = operand_count + 1;
explicit_count = explicit_count + 1;
list->next = op;
return; return;
}
/* get to end of list */
for ( ; list->next; list = list->next )
;
operand_count = operand_count + 1;
explicit_count = explicit_count + 1;
list->next = op;
return;
} }
bool x86_insn_t::containsFlag(x86_eflags tofind, x86_flag_status in) bool x86_insn_t::containsFlag(x86_eflags tofind, x86_flag_status in)
@ -48,7 +48,7 @@ bool x86_insn_t::containsFlag(x86_eflags tofind, x86_flag_status in)
return (in & (insn_dir_set | insn_dir_clear))!=0; return (in & (insn_dir_set | insn_dir_clear))!=0;
case insn_eflag_sign: case insn_eflag_sign:
return (in & (insn_sign_set | insn_sign_clear | insn_zero_set_or_sign_ne_oflow | return (in & (insn_sign_set | insn_sign_clear | insn_zero_set_or_sign_ne_oflow |
insn_sign_eq_oflow | insn_sign_ne_oflow))!=0; insn_sign_eq_oflow | insn_sign_ne_oflow))!=0;
case insn_eflag_parity: case insn_eflag_parity:
return (in & (insn_parity_set | insn_parity_clear))!=0; return (in & (insn_parity_set | insn_parity_clear))!=0;
} }
@ -56,151 +56,154 @@ bool x86_insn_t::containsFlag(x86_eflags tofind, x86_flag_status in)
} }
x86_op_t * x86_insn_t::x86_operand_new( ) { x86_op_t * x86_insn_t::x86_operand_new( ) {
x86_oplist_t *op; x86_oplist_t *op;
assert(this); assert(this);
op = (x86_oplist_t *)calloc( sizeof(x86_oplist_t), 1 ); op = (x86_oplist_t *)calloc( sizeof(x86_oplist_t), 1 );
op->op.insn = this; op->op.insn = this;
x86_oplist_append( op ); x86_oplist_append( op );
return( &(op->op) ); return( &(op->op) );
} }
/** free the operand list associated with an instruction -- useful for
* preventing memory leaks when free()ing an x86_insn_t */
void x86_insn_t::x86_oplist_free( ) void x86_insn_t::x86_oplist_free( )
{ {
x86_oplist_t *op, *list; x86_oplist_t *op, *list;
assert(this); assert(this);
for ( list = operands; list; ) { for ( list = operands; list; ) {
op = list; op = list;
list = list->next; list = list->next;
free(op); free(op);
} }
operands = NULL; operands = NULL;
operand_count = 0; operand_count = 0;
explicit_count = 0; explicit_count = 0;
return; return;
} }
/* ================================================== LIBDISASM API */ /* ================================================== LIBDISASM API */
/* these could probably just be #defines, but that means exposing the /* these could probably just be #defines, but that means exposing the
enum... yet one more confusing thing in the API */ enum... yet one more confusing thing in the API */
int x86_insn_t::x86_operand_foreach( x86_operand_fn func, void *arg, int x86_insn_t::x86_operand_foreach( x86_operand_fn func, void *arg, enum x86_op_foreach_type type )
enum x86_op_foreach_type type ){ {
x86_oplist_t *list; x86_oplist_t *list;
char _explicit = 1, implicit = 1; char _explicit = 1, implicit = 1;
assert(this); assert(this);
if ( ! func ) { if ( ! func ) {
return 0; return 0;
} }
/* note: explicit and implicit can be ORed together to /* note: explicit and implicit can be ORed together to
* allow an "all" limited by access type, even though the * allow an "all" limited by access type, even though the
* user is stupid to do this since it is default behavior :) */ * user is stupid to do this since it is default behavior :) */
if ( (type & op_explicit) && ! (type & op_implicit) ) { if ( (type & op_explicit) && ! (type & op_implicit) ) {
implicit = 0; implicit = 0;
} }
if ( (type & op_implicit) && ! (type & op_explicit) ) { if ( (type & op_implicit) && ! (type & op_explicit) ) {
_explicit = 0; _explicit = 0;
}
type = (x86_op_foreach_type)((int)type & 0x0F); /* mask out explicit/implicit operands */
for ( list = operands; list; list = list->next ) {
if (! implicit && (list->op.flags.op_implied) ) {
/* operand is implicit */
continue;
} }
type = (x86_op_foreach_type)((int)type & 0x0F); /* mask out explicit/implicit operands */ if (! _explicit && ! (list->op.flags.op_implied) ) {
/* operand is not implicit */
for ( list = operands; list; list = list->next ) { continue;
if (! implicit && (list->op.flags.op_implied) ) {
/* operand is implicit */
continue;
}
if (! _explicit && ! (list->op.flags.op_implied) ) {
/* operand is not implicit */
continue;
}
switch ( type ) {
case op_any:
break;
case op_dest:
if (! (list->op.access & op_write) ) {
continue;
}
break;
case op_src:
if (! (list->op.access & op_read) ) {
continue;
}
break;
case op_ro:
if (! (list->op.access & op_read) ||
(list->op.access & op_write ) ) {
continue;
}
break;
case op_wo:
if (! (list->op.access & op_write) ||
(list->op.access & op_read ) ) {
continue;
}
break;
case op_xo:
if (! (list->op.access & op_execute) ) {
continue;
}
break;
case op_rw:
if (! (list->op.access & op_write) ||
! (list->op.access & op_read ) ) {
continue;
}
break;
case op_implicit: case op_explicit: /* make gcc happy */
break;
}
/* any non-continue ends up here: invoke the callback */
(*func)( &list->op, this, arg );
} }
return 1; switch ( type ) {
case op_any:
break;
case op_dest:
if (! (list->op.access & op_write) ) {
continue;
}
break;
case op_src:
if (! (list->op.access & op_read) ) {
continue;
}
break;
case op_ro:
if (! (list->op.access & op_read) ||
(list->op.access & op_write ) ) {
continue;
}
break;
case op_wo:
if (! (list->op.access & op_write) ||
(list->op.access & op_read ) ) {
continue;
}
break;
case op_xo:
if (! (list->op.access & op_execute) ) {
continue;
}
break;
case op_rw:
if (! (list->op.access & op_write) ||
! (list->op.access & op_read ) ) {
continue;
}
break;
case op_implicit: case op_explicit: /* make gcc happy */
break;
}
/* any non-continue ends up here: invoke the callback */
(*func)( &list->op, this, arg );
}
return 1;
} }
static void count_operand( x86_op_t *op, x86_insn_t *insn, void *arg ) { static void count_operand( x86_op_t *op, x86_insn_t *insn, void *arg ) {
size_t * count = (size_t *) arg; size_t * count = (size_t *) arg;
*count = *count + 1; *count = *count + 1;
} }
/** convenience routine: returns count of operands matching 'type' */
size_t x86_insn_t::x86_operand_count( enum x86_op_foreach_type type ) { size_t x86_insn_t::x86_operand_count( enum x86_op_foreach_type type ) {
size_t count = 0; size_t count = 0;
/* save us a list traversal for common counts... */ /* save us a list traversal for common counts... */
if ( type == op_any ) { if ( type == op_any ) {
return operand_count; return operand_count;
} else if ( type == op_explicit ) { } else if ( type == op_explicit ) {
return explicit_count; return explicit_count;
} }
x86_operand_foreach( count_operand, &count, type ); x86_operand_foreach( count_operand, &count, type );
return count; return count;
} }
/* accessor functions */ /* accessor functions */
x86_op_t * x86_insn_t::x86_operand_1st() { x86_op_t * x86_insn_t::x86_operand_1st() {
if (! explicit_count ) { if (! explicit_count ) {
return NULL; return NULL;
} }
return &(operands->op); return &(operands->op);
} }
x86_op_t * x86_insn_t::x86_operand_2nd( ) { x86_op_t * x86_insn_t::x86_operand_2nd( ) {
if ( explicit_count < 2 ) { if ( explicit_count < 2 ) {
return NULL; return NULL;
} }
return &(operands->next->op); return &(operands->next->op);
} }
x86_op_t * x86_insn_t::x86_operand_3rd( ) { x86_op_t * x86_insn_t::x86_operand_3rd( ) {
if ( explicit_count < 3 ) { if ( explicit_count < 3 ) {
return NULL; return NULL;
} }
return &(operands->next->next->op); return &(operands->next->next->op);
} }