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.
* */
static struct {
unsigned char alias; /* id of register this is an alias for */
unsigned char shift; /* # of bits register must be shifted */
unsigned char alias; /* id of register this is an alias for */
unsigned char shift; /* # of bits register must be shifted */
} ia32_reg_aliases[] = {
{ 0,0 },
{ REG_DWORD_OFFSET, 0 }, /* al : 1 */
{ REG_DWORD_OFFSET, 8 }, /* ah : 2 */
{ REG_DWORD_OFFSET, 0 }, /* ax : 3 */
{ REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */
{ REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */
{ REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */
{ REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */
{ REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */
{ REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */
{ REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */
{ REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */
{ REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */
{ REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */
{ REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */
{ REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */
{ REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */
{ REG_EIP_INDEX, 0 }, /* ip : 17 */
{ REG_FPU_OFFSET, 0 }, /* mm0 : 18 */
{ REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */
{ REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */
{ REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */
{ REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */
{ REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */
{ REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */
{ REG_FPU_OFFSET + 7, 0 } /* mm7 : 25 */
{ 0,0 },
{ REG_DWORD_OFFSET, 0 }, /* al : 1 */
{ REG_DWORD_OFFSET, 8 }, /* ah : 2 */
{ REG_DWORD_OFFSET, 0 }, /* ax : 3 */
{ REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */
{ REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */
{ REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */
{ REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */
{ REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */
{ REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */
{ REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */
{ REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */
{ REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */
{ REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */
{ REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */
{ REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */
{ REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */
{ REG_EIP_INDEX, 0 }, /* ip : 17 */
{ REG_FPU_OFFSET, 0 }, /* mm0 : 18 */
{ REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */
{ REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */
{ REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */
{ REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */
{ REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */
{ REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */
{ 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,
* model specific. */
static struct {
unsigned int size;
enum x86_reg_type type;
unsigned int alias;
char mnemonic[8];
unsigned int size;
enum x86_reg_type type;
unsigned int alias;
char mnemonic[8];
} ia32_reg_table[NUM_X86_REGS + 2] = {
{ 0, reg_undef, 0, "" },
/* REG_DWORD_OFFSET */
{ REG_DWORD_SIZE, (x86_reg_type)(reg_gen | reg_ret), 0, "eax" },
{ 0, reg_undef, 0, "" },
/* REG_DWORD_OFFSET */
{ 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, reg_gen, 0, "edx" },
{ REG_DWORD_SIZE, reg_gen, 0, "ebx" },
/* REG_ESP_INDEX */
{ REG_DWORD_SIZE, reg_gen, 0, "edx" },
{ REG_DWORD_SIZE, reg_gen, 0, "ebx" },
/* REG_ESP_INDEX */
{ 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_src), 0, "esi" },
{ 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_count), 6, "cx" },
{ REG_WORD_SIZE, reg_gen, 9, "dx" },
{ REG_WORD_SIZE, reg_gen, 12, "bx" },
{ REG_WORD_SIZE, reg_gen, 9, "dx" },
{ 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_fp), 14, "bp" },
{ 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_BYTE_OFFSET */
{ REG_BYTE_SIZE, reg_gen, 1, "al" },
{ REG_BYTE_SIZE, reg_gen, 4, "cl" },
{ REG_BYTE_SIZE, reg_gen, 7, "dl" },
{ REG_BYTE_SIZE, reg_gen, 10, "bl" },
{ REG_BYTE_SIZE, reg_gen, 2, "ah" },
{ REG_BYTE_SIZE, reg_gen, 5, "ch" },
{ REG_BYTE_SIZE, reg_gen, 8, "dh" },
{ REG_BYTE_SIZE, reg_gen, 11, "bh" },
/* REG_MMX_OFFSET */
{ REG_MMX_SIZE, reg_simd, 18, "mm0" },
{ REG_MMX_SIZE, reg_simd, 19, "mm1" },
{ REG_MMX_SIZE, reg_simd, 20, "mm2" },
{ REG_MMX_SIZE, reg_simd, 21, "mm3" },
{ REG_MMX_SIZE, reg_simd, 22, "mm4" },
{ REG_MMX_SIZE, reg_simd, 23, "mm5" },
{ REG_MMX_SIZE, reg_simd, 24, "mm6" },
{ REG_MMX_SIZE, reg_simd, 25, "mm7" },
/* REG_SIMD_OFFSET */
{ REG_SIMD_SIZE, reg_simd, 0, "xmm0" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm1" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm2" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm3" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm4" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm5" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm6" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm7" },
/* REG_DEBUG_OFFSET */
{ REG_DEBUG_SIZE, reg_sys, 0, "dr0" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr1" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr2" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr3" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr4" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr5" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr6" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr7" },
/* REG_CTRL_OFFSET */
{ REG_CTRL_SIZE, reg_sys, 0, "cr0" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr1" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr2" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr3" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr4" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr5" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr6" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr7" },
/* REG_TEST_OFFSET */
{ REG_TEST_SIZE, reg_sys, 0, "tr0" },
{ REG_TEST_SIZE, reg_sys, 0, "tr1" },
{ REG_TEST_SIZE, reg_sys, 0, "tr2" },
{ REG_TEST_SIZE, reg_sys, 0, "tr3" },
{ REG_TEST_SIZE, reg_sys, 0, "tr4" },
{ REG_TEST_SIZE, reg_sys, 0, "tr5" },
{ REG_TEST_SIZE, reg_sys, 0, "tr6" },
{ REG_TEST_SIZE, reg_sys, 0, "tr7" },
/* REG_SEG_OFFSET */
{ REG_SEG_SIZE, reg_seg, 0, "es" },
{ REG_SEG_SIZE, reg_seg, 0, "cs" },
{ REG_SEG_SIZE, reg_seg, 0, "ss" },
{ REG_SEG_SIZE, reg_seg, 0, "ds" },
{ REG_SEG_SIZE, reg_seg, 0, "fs" },
{ REG_SEG_SIZE, reg_seg, 0, "gs" },
/* REG_LDTR_INDEX */
{ REG_DWORD_SIZE, reg_sys, 0, "ldtr" },
/* REG_GDTR_INDEX */
{ REG_DWORD_SIZE, reg_sys, 0, "gdtr" },
/* REG_FPU_OFFSET */
{ REG_FPU_SIZE, reg_fpu, 0, "st(0)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(1)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(2)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(3)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(4)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(5)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(6)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(7)" },
/* REG_FLAGS_INDEX : 81 */
{ REG_FLAGS_SIZE, reg_cond, 0, "eflags" },
/* REG_FPCTRL_INDEX : 82*/
{ REG_FPCTRL_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpctrl" },
/* REG_FPSTATUS_INDEX : 83*/
/* REG_BYTE_OFFSET */
{ REG_BYTE_SIZE, reg_gen, 1, "al" },
{ REG_BYTE_SIZE, reg_gen, 4, "cl" },
{ REG_BYTE_SIZE, reg_gen, 7, "dl" },
{ REG_BYTE_SIZE, reg_gen, 10, "bl" },
{ REG_BYTE_SIZE, reg_gen, 2, "ah" },
{ REG_BYTE_SIZE, reg_gen, 5, "ch" },
{ REG_BYTE_SIZE, reg_gen, 8, "dh" },
{ REG_BYTE_SIZE, reg_gen, 11, "bh" },
/* REG_MMX_OFFSET */
{ REG_MMX_SIZE, reg_simd, 18, "mm0" },
{ REG_MMX_SIZE, reg_simd, 19, "mm1" },
{ REG_MMX_SIZE, reg_simd, 20, "mm2" },
{ REG_MMX_SIZE, reg_simd, 21, "mm3" },
{ REG_MMX_SIZE, reg_simd, 22, "mm4" },
{ REG_MMX_SIZE, reg_simd, 23, "mm5" },
{ REG_MMX_SIZE, reg_simd, 24, "mm6" },
{ REG_MMX_SIZE, reg_simd, 25, "mm7" },
/* REG_SIMD_OFFSET */
{ REG_SIMD_SIZE, reg_simd, 0, "xmm0" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm1" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm2" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm3" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm4" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm5" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm6" },
{ REG_SIMD_SIZE, reg_simd, 0, "xmm7" },
/* REG_DEBUG_OFFSET */
{ REG_DEBUG_SIZE, reg_sys, 0, "dr0" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr1" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr2" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr3" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr4" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr5" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr6" },
{ REG_DEBUG_SIZE, reg_sys, 0, "dr7" },
/* REG_CTRL_OFFSET */
{ REG_CTRL_SIZE, reg_sys, 0, "cr0" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr1" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr2" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr3" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr4" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr5" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr6" },
{ REG_CTRL_SIZE, reg_sys, 0, "cr7" },
/* REG_TEST_OFFSET */
{ REG_TEST_SIZE, reg_sys, 0, "tr0" },
{ REG_TEST_SIZE, reg_sys, 0, "tr1" },
{ REG_TEST_SIZE, reg_sys, 0, "tr2" },
{ REG_TEST_SIZE, reg_sys, 0, "tr3" },
{ REG_TEST_SIZE, reg_sys, 0, "tr4" },
{ REG_TEST_SIZE, reg_sys, 0, "tr5" },
{ REG_TEST_SIZE, reg_sys, 0, "tr6" },
{ REG_TEST_SIZE, reg_sys, 0, "tr7" },
/* REG_SEG_OFFSET */
{ REG_SEG_SIZE, reg_seg, 0, "es" },
{ REG_SEG_SIZE, reg_seg, 0, "cs" },
{ REG_SEG_SIZE, reg_seg, 0, "ss" },
{ REG_SEG_SIZE, reg_seg, 0, "ds" },
{ REG_SEG_SIZE, reg_seg, 0, "fs" },
{ REG_SEG_SIZE, reg_seg, 0, "gs" },
/* REG_LDTR_INDEX */
{ REG_DWORD_SIZE, reg_sys, 0, "ldtr" },
/* REG_GDTR_INDEX */
{ REG_DWORD_SIZE, reg_sys, 0, "gdtr" },
/* REG_FPU_OFFSET */
{ REG_FPU_SIZE, reg_fpu, 0, "st(0)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(1)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(2)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(3)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(4)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(5)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(6)" },
{ REG_FPU_SIZE, reg_fpu, 0, "st(7)" },
/* REG_FLAGS_INDEX : 81 */
{ REG_FLAGS_SIZE, reg_cond, 0, "eflags" },
/* REG_FPCTRL_INDEX : 82*/
{ REG_FPCTRL_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpctrl" },
/* REG_FPSTATUS_INDEX : 83*/
{ REG_FPSTATUS_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fpstat" },
/* REG_FPTAG_INDEX : 84 */
{ REG_FPTAG_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fptag" },
/* REG_EIP_INDEX : 85 */
{ REG_EIP_SIZE, reg_pc, 0, "eip" },
/* REG_IP_INDEX : 86 */
{ REG_IP_SIZE, reg_pc, 17, "ip" },
/* REG_IDTR_INDEX : 87 */
{ REG_DWORD_SIZE, reg_sys, 0, "idtr" },
/* REG_MXCSG_INDEX : SSE Control Reg : 88 */
/* REG_FPTAG_INDEX : 84 */
{ REG_FPTAG_SIZE, (x86_reg_type)(reg_fpu | reg_sys), 0, "fptag" },
/* REG_EIP_INDEX : 85 */
{ REG_EIP_SIZE, reg_pc, 0, "eip" },
/* REG_IP_INDEX : 86 */
{ REG_IP_SIZE, reg_pc, 17, "ip" },
/* REG_IDTR_INDEX : 87 */
{ REG_DWORD_SIZE, reg_sys, 0, "idtr" },
/* REG_MXCSG_INDEX : SSE Control Reg : 88 */
{ REG_DWORD_SIZE, (x86_reg_type)(reg_sys | reg_simd), 0, "mxcsr" },
/* REG_TR_INDEX : Task Register : 89 */
{ 16 + 64, reg_sys, 0, "tr" },
/* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */
{ REG_DWORD_SIZE, reg_sys, 0, "cs_msr" },
/* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */
{ REG_DWORD_SIZE, reg_sys, 0, "esp_msr" },
/* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */
{ REG_DWORD_SIZE, reg_sys, 0, "eip_msr" },
{ 0 }
};
/* REG_TR_INDEX : Task Register : 89 */
{ 16 + 64, reg_sys, 0, "tr" },
/* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */
{ REG_DWORD_SIZE, reg_sys, 0, "cs_msr" },
/* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */
{ REG_DWORD_SIZE, reg_sys, 0, "esp_msr" },
/* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */
{ REG_DWORD_SIZE, reg_sys, 0, "eip_msr" },
{ 0 }
};
static size_t sz_regtable = NUM_X86_REGS + 1;
void ia32_handle_register( x86_reg_t *reg, size_t id ) {
unsigned int alias;
if (! id || id > sz_regtable ) {
return;
}
unsigned int alias;
if (! id || id > sz_regtable ) {
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 );
reg->type = ia32_reg_table[id].type;
reg->size = ia32_reg_table[id].size;
alias = ia32_reg_table[id].alias;
if ( alias ) {
reg->alias = ia32_reg_aliases[alias].alias;
reg->shift = ia32_reg_aliases[alias].shift;
}
alias = ia32_reg_table[id].alias;
if ( alias ) {
reg->alias = ia32_reg_aliases[alias].alias;
reg->shift = ia32_reg_aliases[alias].shift;
}
reg->id = id;
return;
return;
}
size_t ia32_true_register_id( size_t id ) {
size_t reg;
size_t reg;
if (! id || id > sz_regtable ) {
return 0;
}
if (! id || id > sz_regtable ) {
return 0;
}
reg = id;
if (ia32_reg_table[reg].alias) {
reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias;
}
return reg;
reg = id;
if (ia32_reg_table[reg].alias) {
reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias;
}
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 */
struct x86_reg_t {
char name[MAX_REGNAME];
enum x86_reg_type type; /* what register is used for */
unsigned int size; /* size of register in bytes */
unsigned int id; /* register ID #, for quick compares */
unsigned int alias; /* ID of reg this is an alias for */
unsigned int shift; /* amount to shift aliased reg by */
char name[MAX_REGNAME];
enum x86_reg_type type; /* what register is used for */
unsigned int size; /* size of register in bytes */
unsigned int id; /* register ID #, for quick compares */
unsigned int alias; /* ID of reg this is an alias for */
unsigned int shift; /* amount to shift aliased reg by */
x86_reg_t * aliased_reg( ) {
x86_reg_t * reg = (x86_reg_t * )calloc( sizeof(x86_reg_t), 1 );
reg->x86_reg_from_id( id );
@ -158,11 +158,11 @@ typedef struct {
/* x86_absolute_t : an X86 segment:offset address (descriptor) */
typedef struct {
unsigned short segment; /* loaded directly into CS */
union {
unsigned short off16; /* loaded directly into IP */
uint32_t off32; /* loaded directly into EIP */
} offset;
unsigned short segment; /* loaded directly into CS */
union {
unsigned short off16; /* loaded directly into IP */
uint32_t off32; /* loaded directly into EIP */
} offset;
} x86_absolute_t;
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_fpregset = 24, /* 512 bytes: register set */
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 */
@ -250,49 +250,45 @@ struct x86_op_flags { /* ORed together, but segs are mutually exclusive */
/* x86_op_t : an X86 instruction operand */
struct x86_op_t{
friend struct x86_insn_t;
enum x86_op_type type; /* operand type */
enum x86_op_datatype datatype; /* operand size */
enum x86_op_access access; /* operand access [RWX] */
x86_op_flags flags; /* misc flags */
union {
/* sizeof will have to work on these union members! */
/* immediate values */
char sbyte;
short sword;
int32_t sdword;
qword_t sqword;
unsigned char byte;
unsigned short word;
uint32_t dword;
qword_t qword;
float sreal;
double dreal;
/* misc large/non-native types */
unsigned char extreal[10];
unsigned char bcd[10];
qword_t dqword[2];
unsigned char simd[16];
unsigned char fpuenv[28];
/* offset from segment */
uint32_t offset;
/* ID of CPU register */
x86_reg_t reg;
/* offsets from current insn */
char relative_near;
int32_t relative_far;
/* segment:offset */
x86_absolute_t absolute;
/* effective address [expression] */
x86_ea_t expression;
} data;
/* this is needed to make formatting operands more sane */
void * insn; /* pointer to x86_insn_t owning operand */
enum x86_op_type type; /* operand type */
enum x86_op_datatype datatype; /* operand size */
enum x86_op_access access; /* operand access [RWX] */
x86_op_flags flags; /* misc flags */
union {
/* sizeof will have to work on these union members! */
/* immediate values */
char sbyte;
short sword;
int32_t sdword;
qword_t sqword;
unsigned char byte;
unsigned short word;
uint32_t dword;
qword_t qword;
float sreal;
double dreal;
/* misc large/non-native types */
unsigned char extreal[10];
unsigned char bcd[10];
qword_t dqword[2];
unsigned char simd[16];
unsigned char fpuenv[28];
/* offset from segment */
uint32_t offset;
x86_reg_t reg; /* ID of CPU register */
char relative_near; /* offsets from current insn */
int32_t relative_far;
x86_absolute_t absolute; /* segment:offset */
x86_ea_t expression; /* effective address [expression] */
} data;
/* this is needed to make formatting operands more sane */
void * insn; /* pointer to x86_insn_t owning operand */
size_t size()
{
return x86_operand_size();
return operand_size();
}
/* 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 */
int x86_format_operand(char *buf, int len, enum x86_asm_format format );
bool is_address( ) {
@ -302,9 +298,9 @@ struct x86_op_t{
return ( type == op_relative_near || type == op_relative_far );
}
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 );
if ( op ) {
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 */
/* FOREACH types: these are used to limit the foreach results to
* operands which match a certain "type" (implicit or explicit)
* 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);
public:
/* information about the instruction */
uint32_t addr; /* load address */
uint32_t offset; /* offset into file/buffer */
enum x86_insn_group group; /* meta-type, e.g. INS_EXEC */
enum x86_insn_type type; /* type, e.g. INS_BRANCH */
enum x86_insn_note note; /* note, e.g. RING0 */
uint32_t addr; /* load address */
uint32_t offset; /* offset into file/buffer */
x86_insn_group group; /* meta-type, e.g. INS_EXEC */
x86_insn_type type; /* type, e.g. INS_BRANCH */
x86_insn_note note; /* note, e.g. RING0 */
unsigned char bytes[MAX_INSN_SIZE];
unsigned char size; /* size of insn in bytes */
/* 16/32-bit mode settings */
@ -607,58 +604,29 @@ public:
void *block; /* code block containing this insn */
void *function; /* function containing this insn */
int tag; /* tag the insn as seen/processed */
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 );
x86_op_t * x86_operand_new();
size_t x86_operand_count( enum x86_op_foreach_type type );
/* accessor functions for the operands */
x86_op_t * x86_operand_1st( );
x86_op_t * x86_operand_2nd( );
x86_op_t * x86_operand_3rd( );
/* 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_get_rel_offset( );
/* 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_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( );
x86_op_t * x86_operand_1st( );
x86_op_t * x86_operand_2nd( );
x86_op_t * x86_operand_3rd( );
x86_op_t * get_dest();
int32_t x86_get_rel_offset( );
x86_op_t * x86_get_branch_target( );
x86_op_t * x86_get_imm( );
uint8_t * x86_get_raw_imm( );
/* 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 );
/* format (sprintf) an instruction mnemonic into 'buf' using specified syntax */
int x86_format_mnemonic( char *buf, int len, enum x86_asm_format format);
/* format (sprintf) an instruction into 'buf' using specified syntax;
* 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 */
void x86_set_insn_addr( uint32_t addr );
int x86_format_mnemonic( char *buf, int len, enum x86_asm_format format);
int x86_format_insn( char *buf, int len, enum x86_asm_format);
void x86_oplist_free( );
bool is_valid( );
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
* instructions as "seen" in a DFS, for example. libdisasm does not use
* the tag field.*/
/* set insn->tag to 1 */
void x86_tag_insn( );
/* return insn->tag */
int x86_insn_is_tagged();
/* set insn->tag to 0 */
void x86_untag_insn();

View File

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

View File

@ -17,7 +17,8 @@ int x86_insn_is_valid( x86_insn_t *insn ) {
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 )
{
@ -26,10 +27,15 @@ int x86_insn_t::x86_insn_is_valid( )
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;
assert(this);
if (! operands ) {
if (! operands )
{
return 0;
}
@ -48,6 +54,9 @@ uint32_t x86_insn_t::x86_get_address() {
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( ) {
x86_oplist_t *op_lst;
assert(this);
@ -66,6 +75,10 @@ int32_t x86_insn_t::x86_get_rel_offset( ) {
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_oplist_t *op_lst;
assert(this);
@ -81,6 +94,24 @@ x86_op_t * x86_insn_t::x86_get_branch_target() {
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_oplist_t *op_lst;
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)
/* if there is an immediate value in the instruction, return a pointer to
* it */
unsigned char * x86_insn_t::x86_get_raw_imm() {
/** \brief if there is an immediate value in the instruction, return a pointer to it
* 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' */
uint8_t *x86_insn_t::x86_get_raw_imm() {
int size, offset;
x86_op_t *op = NULL;
assert(this);
@ -128,13 +165,13 @@ unsigned char * x86_insn_t::x86_get_raw_imm() {
}
/* immediate data is at the end of the insn */
size = op->x86_operand_size();
size = op->operand_size();
offset = size - size;
return( &bytes[offset] );
}
size_t x86_op_t::x86_operand_size() {
size_t x86_op_t::operand_size() {
switch (datatype ) {
case op_byte: return 1;
case op_word: return 2;
@ -166,6 +203,7 @@ size_t x86_op_t::x86_operand_size() {
return(4); /* default size */
}
/** set the address (usually RVA) of the insn */
void x86_insn_t::x86_set_insn_addr( uint32_t _addr ) {
addr = _addr;
}
@ -182,6 +220,7 @@ void x86_insn_t::x86_set_insn_block( void * _block ){
block = _block;
}
/** set insn->tag to 1 */
void x86_insn_t::x86_tag_insn(){
tag = 1;
}
@ -190,6 +229,7 @@ void x86_insn_t::x86_untag_insn(){
tag = 0;
}
/** \return insn->tag */
int x86_insn_t::x86_insn_is_tagged(){
return tag;
}

View File

@ -4,31 +4,31 @@
void x86_insn_t::x86_oplist_append( x86_oplist_t *op ) {
x86_oplist_t *list;
x86_oplist_t *list;
assert(this);
list = operands;
if (! list ) {
operand_count = 1;
/* Note that we have no way of knowing if this is an
list = operands;
if (! list ) {
operand_count = 1;
/* Note that we have no way of knowing if this is an
* exlicit operand or not, since the caller fills
* the x86_op_t after we return. We increase the
* explicit count automatically, and ia32_insn_implicit_ops
* decrements it */
explicit_count = 1;
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;
explicit_count = 1;
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;
}
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;
case insn_eflag_sign:
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:
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_oplist_t *op;
x86_oplist_t *op;
assert(this);
op = (x86_oplist_t *)calloc( sizeof(x86_oplist_t), 1 );
op->op.insn = this;
x86_oplist_append( op );
return( &(op->op) );
op = (x86_oplist_t *)calloc( sizeof(x86_oplist_t), 1 );
op->op.insn = this;
x86_oplist_append( 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( )
{
x86_oplist_t *op, *list;
x86_oplist_t *op, *list;
assert(this);
for ( list = operands; list; ) {
op = list;
list = list->next;
free(op);
}
for ( list = operands; list; ) {
op = list;
list = list->next;
free(op);
}
operands = NULL;
operand_count = 0;
explicit_count = 0;
operands = NULL;
operand_count = 0;
explicit_count = 0;
return;
return;
}
/* ================================================== LIBDISASM API */
/* these could probably just be #defines, but that means exposing the
enum... yet one more confusing thing in the API */
int x86_insn_t::x86_operand_foreach( x86_operand_fn func, void *arg,
enum x86_op_foreach_type type ){
x86_oplist_t *list;
char _explicit = 1, implicit = 1;
int x86_insn_t::x86_operand_foreach( x86_operand_fn func, void *arg, enum x86_op_foreach_type type )
{
x86_oplist_t *list;
char _explicit = 1, implicit = 1;
assert(this);
if ( ! func ) {
return 0;
}
if ( ! func ) {
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
* user is stupid to do this since it is default behavior :) */
if ( (type & op_explicit) && ! (type & op_implicit) ) {
implicit = 0;
}
if ( (type & op_implicit) && ! (type & op_explicit) ) {
_explicit = 0;
if ( (type & op_explicit) && ! (type & op_implicit) ) {
implicit = 0;
}
if ( (type & op_implicit) && ! (type & op_explicit) ) {
_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 */
for ( list = operands; list; list = list->next ) {
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 );
if (! _explicit && ! (list->op.flags.op_implied) ) {
/* operand is not implicit */
continue;
}
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 ) {
size_t * count = (size_t *) arg;
*count = *count + 1;
size_t * count = (size_t *) arg;
*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 count = 0;
size_t count = 0;
/* save us a list traversal for common counts... */
if ( type == op_any ) {
return operand_count;
} else if ( type == op_explicit ) {
return explicit_count;
}
/* save us a list traversal for common counts... */
if ( type == op_any ) {
return operand_count;
} else if ( type == op_explicit ) {
return explicit_count;
}
x86_operand_foreach( count_operand, &count, type );
return count;
x86_operand_foreach( count_operand, &count, type );
return count;
}
/* accessor functions */
x86_op_t * x86_insn_t::x86_operand_1st() {
if (! explicit_count ) {
return NULL;
}
if (! explicit_count ) {
return NULL;
}
return &(operands->op);
return &(operands->op);
}
x86_op_t * x86_insn_t::x86_operand_2nd( ) {
if ( explicit_count < 2 ) {
return NULL;
}
if ( explicit_count < 2 ) {
return NULL;
}
return &(operands->next->op);
return &(operands->next->op);
}
x86_op_t * x86_insn_t::x86_operand_3rd( ) {
if ( explicit_count < 3 ) {
return NULL;
}
return &(operands->next->next->op);
if ( explicit_count < 3 ) {
return NULL;
}
return &(operands->next->next->op);
}