Index: src/third_party/libdisasm/ia32_insn.c |
diff --git a/src/third_party/libdisasm/ia32_insn.c b/src/third_party/libdisasm/ia32_insn.c |
deleted file mode 100644 |
index cc277608bfabe3e4594ebcf3483e10300b419437..0000000000000000000000000000000000000000 |
--- a/src/third_party/libdisasm/ia32_insn.c |
+++ /dev/null |
@@ -1,623 +0,0 @@ |
-#include <stdio.h> |
-#include <stdlib.h> |
-#include <string.h> |
-#include "qword.h" |
- |
-#include "ia32_insn.h" |
-#include "ia32_opcode_tables.h" |
- |
-#include "ia32_reg.h" |
-#include "ia32_operand.h" |
-#include "ia32_implicit.h" |
-#include "ia32_settings.h" |
- |
-#include "libdis.h" |
- |
-extern ia32_table_desc_t ia32_tables[]; |
-extern ia32_settings_t ia32_settings; |
- |
-#define IS_SP( op ) (op->type == op_register && \ |
- (op->data.reg.id == REG_ESP_INDEX || \ |
- op->data.reg.alias == REG_ESP_INDEX) ) |
-#define IS_IMM( op ) (op->type == op_immediate ) |
- |
-#ifdef WIN32 |
-# define INLINE |
-#else |
-# define INLINE inline |
-#endif |
- |
-/* for calculating stack modification based on an operand */ |
-static INLINE int32_t long_from_operand( x86_op_t *op ) { |
- |
- if (! IS_IMM(op) ) { |
- return 0L; |
- } |
- |
- switch ( op->datatype ) { |
- case op_byte: |
- return (int32_t) op->data.sbyte; |
- case op_word: |
- return (int32_t) op->data.sword; |
- case op_qword: |
- return (int32_t) op->data.sqword; |
- case op_dword: |
- return op->data.sdword; |
- default: |
- /* these are not used in stack insn */ |
- break; |
- } |
- |
- return 0L; |
-} |
- |
- |
-/* determine what this insn does to the stack */ |
-static void ia32_stack_mod(x86_insn_t *insn) { |
- x86_op_t *dest, *src = NULL; |
- |
- if (! insn || ! insn->operands ) { |
- return; |
- } |
- |
- dest = &insn->operands->op; |
- if ( dest ) { |
- src = &insn->operands->next->op; |
- } |
- |
- insn->stack_mod = 0; |
- insn->stack_mod_val = 0; |
- |
- switch ( insn->type ) { |
- case insn_call: |
- case insn_callcc: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = insn->addr_size * -1; |
- break; |
- case insn_push: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = insn->addr_size * -1; |
- break; |
- case insn_return: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = insn->addr_size; |
- case insn_int: case insn_intcc: |
- case insn_iret: |
- break; |
- case insn_pop: |
- insn->stack_mod = 1; |
- if (! IS_SP( dest ) ) { |
- insn->stack_mod_val = insn->op_size; |
- } /* else we don't know the stack change in a pop esp */ |
- break; |
- case insn_enter: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 0; /* TODO : FIX */ |
- break; |
- case insn_leave: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 0; /* TODO : FIX */ |
- break; |
- case insn_pushregs: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 0; /* TODO : FIX */ |
- break; |
- case insn_popregs: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 0; /* TODO : FIX */ |
- break; |
- case insn_pushflags: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 0; /* TODO : FIX */ |
- break; |
- case insn_popflags: |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 0; /* TODO : FIX */ |
- break; |
- case insn_add: |
- if ( IS_SP( dest ) ) { |
- insn->stack_mod = 1; |
- insn->stack_mod_val = long_from_operand( src ); |
- } |
- break; |
- case insn_sub: |
- if ( IS_SP( dest ) ) { |
- insn->stack_mod = 1; |
- insn->stack_mod_val = long_from_operand( src ); |
- insn->stack_mod_val *= -1; |
- } |
- break; |
- case insn_inc: |
- if ( IS_SP( dest ) ) { |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 1; |
- } |
- break; |
- case insn_dec: |
- if ( IS_SP( dest ) ) { |
- insn->stack_mod = 1; |
- insn->stack_mod_val = 1; |
- } |
- break; |
- case insn_mov: case insn_movcc: |
- case insn_xchg: case insn_xchgcc: |
- case insn_mul: case insn_div: |
- case insn_shl: case insn_shr: |
- case insn_rol: case insn_ror: |
- case insn_and: case insn_or: |
- case insn_not: case insn_neg: |
- case insn_xor: |
- if ( IS_SP( dest ) ) { |
- insn->stack_mod = 1; |
- } |
- break; |
- default: |
- break; |
- } |
- if (! strcmp("enter", insn->mnemonic) ) { |
- insn->stack_mod = 1; |
- } else if (! strcmp("leave", insn->mnemonic) ) { |
- insn->stack_mod = 1; |
- } |
- |
- /* for mov, etc we return 0 -- unknown stack mod */ |
- |
- return; |
-} |
- |
-/* get the cpu details for this insn from cpu flags int */ |
-static void ia32_handle_cpu( x86_insn_t *insn, unsigned int cpu ) { |
- insn->cpu = (enum x86_insn_cpu) CPU_MODEL(cpu); |
- insn->isa = (enum x86_insn_isa) (ISA_SUBSET(cpu)) >> 16; |
- return; |
-} |
- |
-/* handle mnemonic type and group */ |
-static void ia32_handle_mnemtype(x86_insn_t *insn, unsigned int mnemtype) { |
- unsigned int type = mnemtype & ~INS_FLAG_MASK; |
- insn->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12; |
- insn->type = (enum x86_insn_type) INS_TYPE(type); |
- |
- return; |
-} |
- |
-static void ia32_handle_notes(x86_insn_t *insn, unsigned int notes) { |
- insn->note = (enum x86_insn_note) notes; |
- return; |
-} |
- |
-static void ia32_handle_eflags( x86_insn_t *insn, unsigned int eflags) { |
- unsigned int flags; |
- |
- /* handle flags effected */ |
- flags = INS_FLAGS_TEST(eflags); |
- /* handle weird OR cases */ |
- /* these are either JLE (ZF | SF<>OF) or JBE (CF | ZF) */ |
- if (flags & INS_TEST_OR) { |
- flags &= ~INS_TEST_OR; |
- if ( flags & INS_TEST_ZERO ) { |
- flags &= ~INS_TEST_ZERO; |
- if ( flags & INS_TEST_CARRY ) { |
- flags &= ~INS_TEST_CARRY ; |
- flags |= (int)insn_carry_or_zero_set; |
- } else if ( flags & INS_TEST_SFNEOF ) { |
- flags &= ~INS_TEST_SFNEOF; |
- flags |= (int)insn_zero_set_or_sign_ne_oflow; |
- } |
- } |
- } |
- insn->flags_tested = (enum x86_flag_status) flags; |
- |
- insn->flags_set = (enum x86_flag_status) INS_FLAGS_SET(eflags) >> 16; |
- |
- return; |
-} |
- |
-static void ia32_handle_prefix( x86_insn_t *insn, unsigned int prefixes ) { |
- |
- insn->prefix = (enum x86_insn_prefix) prefixes & PREFIX_MASK; // >> 20; |
- if (! (insn->prefix & PREFIX_PRINT_MASK) ) { |
- /* no printable prefixes */ |
- insn->prefix = insn_no_prefix; |
- } |
- |
- /* concat all prefix strings */ |
- if ( (unsigned int)insn->prefix & PREFIX_LOCK ) { |
- strncat(insn->prefix_string, "lock ", 32 - |
- strlen(insn->prefix_string)); |
- } |
- |
- if ( (unsigned int)insn->prefix & PREFIX_REPNZ ) { |
- strncat(insn->prefix_string, "repnz ", 32 - |
- strlen(insn->prefix_string)); |
- } else if ( (unsigned int)insn->prefix & PREFIX_REPZ ) { |
- strncat(insn->prefix_string, "repz ", 32 - |
- strlen(insn->prefix_string)); |
- } |
- |
- return; |
-} |
- |
- |
-static void reg_32_to_16( x86_op_t *op, x86_insn_t *insn, void *arg ) { |
- |
- /* if this is a 32-bit register and it is a general register ... */ |
- if ( op->type == op_register && op->data.reg.size == 4 && |
- (op->data.reg.type & reg_gen) ) { |
- /* WORD registers are 8 indices off from DWORD registers */ |
- ia32_handle_register( &(op->data.reg), |
- op->data.reg.id + 8 ); |
- } |
-} |
- |
-static void handle_insn_metadata( x86_insn_t *insn, ia32_insn_t *raw_insn ) { |
- ia32_handle_mnemtype( insn, raw_insn->mnem_flag ); |
- ia32_handle_notes( insn, raw_insn->notes ); |
- ia32_handle_eflags( insn, raw_insn->flags_effected ); |
- ia32_handle_cpu( insn, raw_insn->cpu ); |
- ia32_stack_mod( insn ); |
-} |
- |
-static size_t ia32_decode_insn( unsigned char *buf, size_t buf_len, |
- ia32_insn_t *raw_insn, x86_insn_t *insn, |
- unsigned int prefixes ) { |
- size_t size, op_size; |
- unsigned char modrm; |
- |
- /* this should never happen, but just in case... */ |
- if ( raw_insn->mnem_flag == INS_INVALID ) { |
- return 0; |
- } |
- |
- if (ia32_settings.options & opt_16_bit) { |
- insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2; |
- insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2; |
- } else { |
- insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4; |
- insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4; |
- } |
- |
- |
- /* ++++ 1. Copy mnemonic and mnemonic-flags to CODE struct */ |
- if ((ia32_settings.options & opt_att_mnemonics) && raw_insn->mnemonic_att[0]) { |
- strncpy( insn->mnemonic, raw_insn->mnemonic_att, 16 ); |
- } |
- else { |
- strncpy( insn->mnemonic, raw_insn->mnemonic, 16 ); |
- } |
- ia32_handle_prefix( insn, prefixes ); |
- |
- handle_insn_metadata( insn, raw_insn ); |
- |
- /* prefetch the next byte in case it is a modr/m byte -- saves |
- * worrying about whether the 'mod/rm' operand or the 'reg' operand |
- * occurs first */ |
- modrm = GET_BYTE( buf, buf_len ); |
- |
- /* ++++ 2. Decode Explicit Operands */ |
- /* Intel uses up to 3 explicit operands in its instructions; |
- * the first is 'dest', the second is 'src', and the third |
- * is an additional source value (usually an immediate value, |
- * e.g. in the MUL instructions). These three explicit operands |
- * are encoded in the opcode tables, even if they are not used |
- * by the instruction. Additional implicit operands are stored |
- * in a supplemental table and are handled later. */ |
- |
- op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->dest, |
- raw_insn->dest_flag, prefixes, modrm ); |
- /* advance buffer, increase size if necessary */ |
- buf += op_size; |
- buf_len -= op_size; |
- size = op_size; |
- |
- op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->src, |
- raw_insn->src_flag, prefixes, modrm ); |
- buf += op_size; |
- buf_len -= op_size; |
- size += op_size; |
- |
- op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->aux, |
- raw_insn->aux_flag, prefixes, modrm ); |
- size += op_size; |
- |
- |
- /* ++++ 3. Decode Implicit Operands */ |
- /* apply implicit operands */ |
- ia32_insn_implicit_ops( insn, raw_insn->implicit_ops ); |
- /* we have one small inelegant hack here, to deal with |
- * the two prefixes that have implicit operands. If Intel |
- * adds more, we'll change the algorithm to suit :) */ |
- if ( (prefixes & PREFIX_REPZ) || (prefixes & PREFIX_REPNZ) ) { |
- ia32_insn_implicit_ops( insn, IDX_IMPLICIT_REP ); |
- } |
- |
- |
- /* 16-bit hack: foreach operand, if 32-bit reg, make 16-bit reg */ |
- if ( insn->op_size == 2 ) { |
- x86_operand_foreach( insn, reg_32_to_16, NULL, op_any ); |
- } |
- |
- return size; |
-} |
- |
- |
-/* convenience routine */ |
-#define USES_MOD_RM(flag) \ |
- (flag == ADDRMETH_E || flag == ADDRMETH_M || flag == ADDRMETH_Q || \ |
- flag == ADDRMETH_W || flag == ADDRMETH_R) |
- |
-static int uses_modrm_flag( unsigned int flag ) { |
- unsigned int meth; |
- if ( flag == ARG_NONE ) { |
- return 0; |
- } |
- meth = (flag & ADDRMETH_MASK); |
- if ( USES_MOD_RM(meth) ) { |
- return 1; |
- } |
- |
- return 0; |
-} |
- |
-/* This routine performs the actual byte-by-byte opcode table lookup. |
- * Originally it was pretty simple: get a byte, adjust it to a proper |
- * index into the table, then check the table row at that index to |
- * determine what to do next. But is anything that simple with Intel? |
- * This is now a huge, convoluted mess, mostly of bitter comments. */ |
-/* buf: pointer to next byte to read from stream |
- * buf_len: length of buf |
- * table: index of table to use for lookups |
- * raw_insn: output pointer that receives opcode definition |
- * prefixes: output integer that is encoded with prefixes in insn |
- * returns : number of bytes consumed from stream during lookup */ |
-size_t ia32_table_lookup( unsigned char *buf, size_t buf_len, |
- unsigned int table, ia32_insn_t **raw_insn, |
- unsigned int *prefixes ) { |
- unsigned char *next, op = buf[0]; /* byte value -- 'opcode' */ |
- size_t size = 1, sub_size = 0, next_len; |
- ia32_table_desc_t *table_desc; |
- unsigned int subtable, prefix = 0, recurse_table = 0; |
- |
- table_desc = &ia32_tables[table]; |
- |
- op = GET_BYTE( buf, buf_len ); |
- |
- if ( table_desc->type == tbl_fpu && op > table_desc->maxlim) { |
- /* one of the fucking FPU tables out of the 00-BH range */ |
- /* OK,. this is a bit of a hack -- the proper way would |
- * have been to use subtables in the 00-BF FPU opcode tables, |
- * but that is rather wasteful of space... */ |
- table_desc = &ia32_tables[table +1]; |
- } |
- |
- /* PERFORM TABLE LOOKUP */ |
- |
- /* ModR/M trick: shift extension bits into lowest bits of byte */ |
- /* Note: non-ModR/M tables have a shift value of 0 */ |
- op >>= table_desc->shift; |
- |
- /* ModR/M trick: mask out high bits to turn extension into an index */ |
- /* Note: non-ModR/M tables have a mask value of 0xFF */ |
- op &= table_desc->mask; |
- |
- |
- /* Sparse table trick: check that byte is <= max value */ |
- /* Note: full (256-entry) tables have a maxlim of 155 */ |
- if ( op > table_desc->maxlim ) { |
- /* this is a partial table, truncated at the tail, |
- and op is out of range! */ |
- return INVALID_INSN; |
- } |
- |
- /* Sparse table trick: check that byte is >= min value */ |
- /* Note: full (256-entry) tables have a minlim of 0 */ |
- if ( table_desc->minlim > op ) { |
- /* this is a partial table, truncated at the head, |
- and op is out of range! */ |
- return INVALID_INSN; |
- } |
- /* adjust op to be an offset from table index 0 */ |
- op -= table_desc->minlim; |
- |
- /* Yay! 'op' is now fully adjusted to be an index into 'table' */ |
- *raw_insn = &(table_desc->table[op]); |
- //printf("BYTE %X TABLE %d OP %X\n", buf[0], table, op ); |
- |
- if ( (*raw_insn)->mnem_flag & INS_FLAG_PREFIX ) { |
- prefix = (*raw_insn)->mnem_flag & PREFIX_MASK; |
- } |
- |
- |
- /* handle escape to a multibyte/coproc/extension/etc table */ |
- /* NOTE: if insn is a prefix and has a subtable, then we |
- * only recurse if this is the first prefix byte -- |
- * that is, if *prefixes is 0. |
- * NOTE also that suffix tables are handled later */ |
- subtable = (*raw_insn)->table; |
- |
- if ( subtable && ia32_tables[subtable].type != tbl_suffix && |
- (! prefix || ! *prefixes) ) { |
- |
- if ( ia32_tables[subtable].type == tbl_ext_ext || |
- ia32_tables[subtable].type == tbl_fpu_ext ) { |
- /* opcode extension: reuse current byte in buffer */ |
- next = buf; |
- next_len = buf_len; |
- } else { |
- /* "normal" opcode: advance to next byte in buffer */ |
- if ( buf_len > 1 ) { |
- next = &buf[1]; |
- next_len = buf_len - 1; |
- } |
- else { |
- // buffer is truncated |
- return INVALID_INSN; |
- } |
- } |
- /* we encountered a multibyte opcode: recurse using the |
- * table specified in the opcode definition */ |
- sub_size = ia32_table_lookup( next, next_len, subtable, |
- raw_insn, prefixes ); |
- |
- /* SSE/prefix hack: if the original opcode def was a |
- * prefix that specified a subtable, and the subtable |
- * lookup returned a valid insn, then we have encountered |
- * an SSE opcode definition; otherwise, we pretend we |
- * never did the subtable lookup, and deal with the |
- * prefix normally later */ |
- if ( prefix && ( sub_size == INVALID_INSN || |
- INS_TYPE((*raw_insn)->mnem_flag) == INS_INVALID ) ) { |
- /* this is a prefix, not an SSE insn : |
- * lookup next byte in main table, |
- * subsize will be reset during the |
- * main table lookup */ |
- recurse_table = 1; |
- } else { |
- /* this is either a subtable (two-byte) insn |
- * or an invalid insn: either way, set prefix |
- * to NULL and end the opcode lookup */ |
- prefix = 0; |
- // short-circuit lookup on invalid insn |
- if (sub_size == INVALID_INSN) return INVALID_INSN; |
- } |
- } else if ( prefix ) { |
- recurse_table = 1; |
- } |
- |
- /* by default, we assume that we have the opcode definition, |
- * and there is no need to recurse on the same table, but |
- * if we do then a prefix was encountered... */ |
- if ( recurse_table ) { |
- /* this must have been a prefix: use the same table for |
- * lookup of the next byte */ |
- sub_size = ia32_table_lookup( &buf[1], buf_len - 1, table, |
- raw_insn, prefixes ); |
- |
- // short-circuit lookup on invalid insn |
- if (sub_size == INVALID_INSN) return INVALID_INSN; |
- |
- /* a bit of a hack for branch hints */ |
- if ( prefix & BRANCH_HINT_MASK ) { |
- if ( INS_GROUP((*raw_insn)->mnem_flag) == INS_EXEC ) { |
- /* segment override prefixes are invalid for |
- * all branch instructions, so delete them */ |
- prefix &= ~PREFIX_REG_MASK; |
- } else { |
- prefix &= ~BRANCH_HINT_MASK; |
- } |
- } |
- |
- /* apply prefix to instruction */ |
- |
- /* TODO: implement something enforcing prefix groups */ |
- (*prefixes) |= prefix; |
- } |
- |
- /* if this lookup was in a ModR/M table, then an opcode byte is |
- * NOT consumed: subtract accordingly. NOTE that if none of the |
- * operands used the ModR/M, then we need to consume the byte |
- * here, but ONLY in the 'top-level' opcode extension table */ |
- |
- if ( table_desc->type == tbl_ext_ext ) { |
- /* extensions-to-extensions never consume a byte */ |
- --size; |
- } else if ( (table_desc->type == tbl_extension || |
- table_desc->type == tbl_fpu || |
- table_desc->type == tbl_fpu_ext ) && |
- /* extensions that have an operand encoded in ModR/M |
- * never consume a byte */ |
- (uses_modrm_flag((*raw_insn)->dest_flag) || |
- uses_modrm_flag((*raw_insn)->src_flag) ) ) { |
- --size; |
- } |
- |
- size += sub_size; |
- |
- return size; |
-} |
- |
-static size_t handle_insn_suffix( unsigned char *buf, size_t buf_len, |
- ia32_insn_t *raw_insn, x86_insn_t * insn ) { |
- ia32_insn_t *sfx_insn; |
- size_t size; |
- unsigned int prefixes = 0; |
- |
- size = ia32_table_lookup( buf, buf_len, raw_insn->table, &sfx_insn, |
- &prefixes ); |
- if (size == INVALID_INSN || sfx_insn->mnem_flag == INS_INVALID ) { |
- return 0; |
- } |
- |
- strncpy( insn->mnemonic, sfx_insn->mnemonic, 16 ); |
- handle_insn_metadata( insn, sfx_insn ); |
- |
- return 1; |
-} |
- |
-/* invalid instructions are handled by returning 0 [error] from the |
- * function, setting the size of the insn to 1 byte, and copying |
- * the byte at the start of the invalid insn into the x86_insn_t. |
- * if the caller is saving the x86_insn_t for invalid instructions, |
- * instead of discarding them, this will maintain a consistent |
- * address space in the x86_insn_ts */ |
- |
-/* this function is called by the controlling disassembler, so its name and |
- * calling convention cannot be changed */ |
-/* buf points to the loc of the current opcode (start of the |
- * instruction) in the instruction stream. The instruction |
- * stream is assumed to be a buffer of bytes read directly |
- * from the file for the purpose of disassembly; a mem-mapped |
- * file is ideal for * this. |
- * insn points to a code structure to be filled by instr_decode |
- * returns the size of the decoded instruction in bytes */ |
-size_t ia32_disasm_addr( unsigned char * buf, size_t buf_len, |
- x86_insn_t *insn ) { |
- ia32_insn_t *raw_insn = NULL; |
- unsigned int prefixes = 0; |
- size_t size, sfx_size; |
- |
- if ( (ia32_settings.options & opt_ignore_nulls) && buf_len > 3 && |
- !buf[0] && !buf[1] && !buf[2] && !buf[3]) { |
- /* IF IGNORE_NULLS is set AND |
- * first 4 bytes in the intruction stream are NULL |
- * THEN return 0 (END_OF_DISASSEMBLY) */ |
- /* TODO: set errno */ |
- MAKE_INVALID( insn, buf ); |
- return 0; /* 4 00 bytes in a row? This isn't code! */ |
- } |
- |
- /* Perform recursive table lookup starting with main table (0) */ |
- size = ia32_table_lookup(buf, buf_len, idx_Main, &raw_insn, &prefixes); |
- if ( size == INVALID_INSN || size > buf_len || raw_insn->mnem_flag == INS_INVALID ) { |
- MAKE_INVALID( insn, buf ); |
- /* TODO: set errno */ |
- return 0; |
- } |
- |
- /* We now have the opcode itself figured out: we can decode |
- * the rest of the instruction. */ |
- size += ia32_decode_insn( &buf[size], buf_len - size, raw_insn, insn, |
- prefixes ); |
- if ( raw_insn->mnem_flag & INS_FLAG_SUFFIX ) { |
- /* AMD 3DNow! suffix -- get proper operand type here */ |
- sfx_size = handle_insn_suffix( &buf[size], buf_len - size, |
- raw_insn, insn ); |
- if (! sfx_size ) { |
- /* TODO: set errno */ |
- MAKE_INVALID( insn, buf ); |
- return 0; |
- } |
- |
- size += sfx_size; |
- } |
- |
- if (! size ) { |
- /* invalid insn */ |
- MAKE_INVALID( insn, buf ); |
- return 0; |
- } |
- |
- |
- insn->size = size; |
- return size; /* return size of instruction in bytes */ |
-} |