toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,313 @@
     1.4 +#include <stdlib.h>
     1.5 +#include <string.h>
     1.6 +
     1.7 +#include "ia32_invariant.h"
     1.8 +#include "ia32_insn.h"
     1.9 +#include "ia32_settings.h"
    1.10 +
    1.11 +extern ia32_table_desc_t *ia32_tables;
    1.12 +extern ia32_settings_t ia32_settings;
    1.13 +
    1.14 +extern size_t ia32_table_lookup( unsigned char *buf, size_t buf_len,
    1.15 +		unsigned int table, ia32_insn_t **raw_insn,
    1.16 +		 unsigned int *prefixes );
    1.17 +
    1.18 +
    1.19 +/* -------------------------------- ModR/M, SIB */
    1.20 +/* Convenience flags */
    1.21 +#define MODRM_EA  1                     /* ModR/M is an effective addr */
    1.22 +#define MODRM_reg 2                     /* ModR/M is a register */
    1.23 +
    1.24 +/* ModR/M flags */
    1.25 +#define MODRM_RM_SIB            0x04    /* R/M == 100 */
    1.26 +#define MODRM_RM_NOREG          0x05    /* R/B == 101 */
    1.27 +/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
    1.28 +#define MODRM_MOD_NODISP        0x00    /* mod == 00 */
    1.29 +#define MODRM_MOD_DISP8         0x01    /* mod == 01 */
    1.30 +#define MODRM_MOD_DISP32        0x02    /* mod == 10 */
    1.31 +#define MODRM_MOD_NOEA          0x03    /* mod == 11 */
    1.32 +/* 16-bit modrm flags */
    1.33 +#define MOD16_MOD_NODISP      0
    1.34 +#define MOD16_MOD_DISP8       1
    1.35 +#define MOD16_MOD_DISP16      2
    1.36 +#define MOD16_MOD_REG         3
    1.37 +
    1.38 +#define MOD16_RM_BXSI         0
    1.39 +#define MOD16_RM_BXDI         1
    1.40 +#define MOD16_RM_BPSI         2
    1.41 +#define MOD16_RM_BPDI         3
    1.42 +#define MOD16_RM_SI           4
    1.43 +#define MOD16_RM_DI           5
    1.44 +#define MOD16_RM_BP           6
    1.45 +#define MOD16_RM_BX           7
    1.46 +
    1.47 +/* SIB flags */
    1.48 +#define SIB_INDEX_NONE       0x04
    1.49 +#define SIB_BASE_EBP       0x05
    1.50 +#define SIB_SCALE_NOBASE    0x00
    1.51 +
    1.52 +/* Convenience struct for modR/M bitfield */
    1.53 +struct modRM_byte {  
    1.54 +   unsigned int mod : 2;
    1.55 +   unsigned int reg : 3;
    1.56 +   unsigned int rm  : 3; 
    1.57 +};
    1.58 +
    1.59 +/* Convenience struct for SIB bitfield */
    1.60 +struct SIB_byte {
    1.61 +   unsigned int scale : 2;
    1.62 +   unsigned int index : 3;
    1.63 +   unsigned int base  : 3;
    1.64 +};
    1.65 +
    1.66 +#ifdef WIN32
    1.67 +static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
    1.68 +#else
    1.69 +static inline void byte_decode(unsigned char b, struct modRM_byte *modrm) {
    1.70 +#endif
    1.71 +	/* generic bitfield-packing routine */
    1.72 +
    1.73 +	modrm->mod = b >> 6;	/* top 2 bits */
    1.74 +	modrm->reg = (b & 56) >> 3;	/* middle 3 bits */
    1.75 +	modrm->rm = b & 7;	/* bottom 3 bits */
    1.76 +}
    1.77 +static int ia32_invariant_modrm( unsigned char *in, unsigned char *out,
    1.78 +				 unsigned int mode_16, x86_invariant_op_t *op) {
    1.79 +	struct modRM_byte modrm;
    1.80 +	struct SIB_byte sib;
    1.81 +	unsigned char *c, *cin;
    1.82 +	unsigned short *s;
    1.83 +	unsigned int *i;
    1.84 +	int size = 0;	/* modrm byte is already counted */
    1.85 +
    1.86 +
    1.87 +	byte_decode(*in, &modrm);	/* get bitfields */
    1.88 +
    1.89 +	out[0] = in[0];	/* save modrm byte */
    1.90 +	cin = &in[1];
    1.91 +	c = &out[1];
    1.92 +	s = (unsigned short *)&out[1];
    1.93 +	i = (unsigned int *)&out[1];
    1.94 +
    1.95 +	op->type = op_expression;
    1.96 +	op->flags |= op_pointer;
    1.97 +	if ( ! mode_16 && modrm.rm == MODRM_RM_SIB && 
    1.98 +			      modrm.mod != MODRM_MOD_NOEA ) {
    1.99 +		size ++;
   1.100 +		byte_decode(*cin, (struct modRM_byte *)(void*)&sib);
   1.101 +
   1.102 +		out[1] = in[1];	/* save sib byte */
   1.103 +		cin = &in[2];
   1.104 +		c = &out[2];
   1.105 +		s = (unsigned short *)&out[2];
   1.106 +		i = (unsigned int *)&out[2];
   1.107 +
   1.108 +		if ( sib.base == SIB_BASE_EBP && ! modrm.mod ) {
   1.109 +			/* disp 32 is variant! */
   1.110 +			memset( i, X86_WILDCARD_BYTE, 4 );
   1.111 +			size += 4;
   1.112 +		}
   1.113 +	}
   1.114 +
   1.115 +	if (! modrm.mod && modrm.rm == 101) {
   1.116 +		if ( mode_16 ) {	/* straight RVA in disp */
   1.117 +			memset( s, X86_WILDCARD_BYTE, 2 );
   1.118 +			size += 2;
   1.119 +		} else {
   1.120 +			memset( i, X86_WILDCARD_BYTE, 2 );
   1.121 +			size += 4;
   1.122 +		}
   1.123 +	} else if (modrm.mod && modrm.mod < 3) {
   1.124 +		if (modrm.mod == MODRM_MOD_DISP8) {	 /* offset in disp */
   1.125 +			*c = *cin;	
   1.126 +			size += 1;
   1.127 +		} else if ( mode_16 ) {
   1.128 +			*s = (* ((unsigned short *) cin));
   1.129 +			size += 2;
   1.130 +		} else {
   1.131 +			*i = (*((unsigned int *) cin));
   1.132 +			size += 4;
   1.133 +		}
   1.134 +	} else if ( modrm.mod == 3 ) {
   1.135 +		op->type = op_register;
   1.136 +		op->flags &= ~op_pointer;
   1.137 +	}
   1.138 +
   1.139 +	return (size);
   1.140 +}
   1.141 +
   1.142 +
   1.143 +static int ia32_decode_invariant( unsigned char *buf, size_t buf_len, 
   1.144 +				ia32_insn_t *t, unsigned char *out, 
   1.145 +				unsigned int prefixes, x86_invariant_t *inv) {
   1.146 +
   1.147 +	unsigned int addr_size, op_size, mode_16;
   1.148 +	unsigned int op_flags[3] = { t->dest_flag, t->src_flag, t->aux_flag };
   1.149 +	int x, type, bytes = 0, size = 0, modrm = 0;
   1.150 +
   1.151 +	/* set addressing mode */
   1.152 +	if (ia32_settings.options & opt_16_bit) {
   1.153 +		op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2;
   1.154 +		addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2;
   1.155 +		mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 0 : 1;
   1.156 +	} else {
   1.157 +		op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4;
   1.158 +		addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4;
   1.159 +		mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 1 : 0;
   1.160 +	}
   1.161 +
   1.162 +	for (x = 0; x < 3; x++) {
   1.163 +		inv->operands[x].access = (enum x86_op_access) 
   1.164 +						OP_PERM(op_flags[x]);
   1.165 +		inv->operands[x].flags = (enum x86_op_flags) 
   1.166 +						(OP_FLAGS(op_flags[x]) >> 12);
   1.167 +
   1.168 +		switch (op_flags[x] & OPTYPE_MASK) {
   1.169 +			case OPTYPE_c:
   1.170 +				size = (op_size == 4) ? 2 : 1;
   1.171 +				break;
   1.172 +			case OPTYPE_a: case OPTYPE_v:
   1.173 +				size = (op_size == 4) ? 4 : 2;
   1.174 +				break;
   1.175 +			case OPTYPE_p:
   1.176 +				size = (op_size == 4) ? 6 : 4;
   1.177 +				break;
   1.178 +			case OPTYPE_b:
   1.179 +				size = 1;
   1.180 +				break;
   1.181 +			case OPTYPE_w:
   1.182 +				size = 2;
   1.183 +				break;
   1.184 +			case OPTYPE_d: case OPTYPE_fs: case OPTYPE_fd:
   1.185 +			case OPTYPE_fe: case OPTYPE_fb: case OPTYPE_fv:
   1.186 +			case OPTYPE_si: case OPTYPE_fx:
   1.187 +				size = 4;
   1.188 +				break;
   1.189 +			case OPTYPE_s:
   1.190 +				size = 6;
   1.191 +				break;
   1.192 +			case OPTYPE_q: case OPTYPE_pi:
   1.193 +				size = 8;
   1.194 +				break;
   1.195 +			case OPTYPE_dq: case OPTYPE_ps: case OPTYPE_ss:
   1.196 +			case OPTYPE_pd: case OPTYPE_sd:
   1.197 +				size = 16;
   1.198 +				break;
   1.199 +			case OPTYPE_m:	
   1.200 +				size = (addr_size == 4) ? 4 : 2;
   1.201 +				break;
   1.202 +			default:
   1.203 +				break;
   1.204 +		}
   1.205 +
   1.206 +		type = op_flags[x] & ADDRMETH_MASK;
   1.207 +		switch (type) {
   1.208 +			case ADDRMETH_E: case ADDRMETH_M: case ADDRMETH_Q:
   1.209 +			case ADDRMETH_R: case ADDRMETH_W:
   1.210 +				modrm = 1;	
   1.211 +				bytes += ia32_invariant_modrm( buf, out, 
   1.212 +						mode_16, &inv->operands[x]);
   1.213 +				break;
   1.214 +			case ADDRMETH_C: case ADDRMETH_D: case ADDRMETH_G:
   1.215 +			case ADDRMETH_P: case ADDRMETH_S: case ADDRMETH_T:
   1.216 +			case ADDRMETH_V:
   1.217 +				inv->operands[x].type = op_register;
   1.218 +				modrm = 1;
   1.219 +				break;
   1.220 +			case ADDRMETH_A: case ADDRMETH_O:
   1.221 +				/* pad with xF4's */
   1.222 +				memset( &out[bytes + modrm], X86_WILDCARD_BYTE, 
   1.223 +					size );
   1.224 +				bytes += size;
   1.225 +				inv->operands[x].type = op_offset;
   1.226 +				if ( type == ADDRMETH_O ) {
   1.227 +					inv->operands[x].flags |= op_signed |
   1.228 +								  op_pointer;
   1.229 +				}
   1.230 +				break;
   1.231 +			case ADDRMETH_I: case ADDRMETH_J:
   1.232 +				/* grab imm value */
   1.233 +				if ((op_flags[x] & OPTYPE_MASK) == OPTYPE_v) {
   1.234 +					/* assume this is an address */
   1.235 +					memset( &out[bytes + modrm], 
   1.236 +						X86_WILDCARD_BYTE, size );
   1.237 +				} else {
   1.238 +					memcpy( &out[bytes + modrm], 
   1.239 +						&buf[bytes + modrm], size );
   1.240 +				}
   1.241 +					
   1.242 +				bytes += size;
   1.243 +				if ( type == ADDRMETH_J ) {
   1.244 +					if ( size == 1 ) {
   1.245 +						inv->operands[x].type = 
   1.246 +							op_relative_near;
   1.247 +					} else {
   1.248 +						inv->operands[x].type = 
   1.249 +							op_relative_far;
   1.250 +					}
   1.251 +					inv->operands[x].flags |= op_signed;
   1.252 +				} else {
   1.253 +					inv->operands[x].type = op_immediate;
   1.254 +				}
   1.255 +				break;
   1.256 +			case ADDRMETH_F:
   1.257 +				inv->operands[x].type = op_register;
   1.258 +				break;
   1.259 +			case ADDRMETH_X:
   1.260 +				inv->operands[x].flags |= op_signed |
   1.261 +					  op_pointer | op_ds_seg | op_string;
   1.262 +				break;
   1.263 +			case ADDRMETH_Y:
   1.264 +				inv->operands[x].flags |= op_signed |
   1.265 +					  op_pointer | op_es_seg | op_string;
   1.266 +				break;
   1.267 +			case ADDRMETH_RR:	
   1.268 +				inv->operands[x].type = op_register;
   1.269 +				break;
   1.270 +			case ADDRMETH_II:	
   1.271 +				inv->operands[x].type = op_immediate;
   1.272 +				break;
   1.273 +			default:
   1.274 +				inv->operands[x].type = op_unused;
   1.275 +				break;
   1.276 +		}
   1.277 +	}
   1.278 +
   1.279 +	return (bytes + modrm);
   1.280 +}
   1.281 +
   1.282 +size_t ia32_disasm_invariant( unsigned char * buf, size_t buf_len, 
   1.283 +		x86_invariant_t *inv ) {
   1.284 +	ia32_insn_t *raw_insn = NULL;
   1.285 +	unsigned int prefixes;
   1.286 +	unsigned int type;
   1.287 +	size_t size;
   1.288 +	
   1.289 +	/* Perform recursive table lookup starting with main table (0) */
   1.290 +	size = ia32_table_lookup( buf, buf_len, 0, &raw_insn, &prefixes );
   1.291 +	if ( size == INVALID_INSN || size > buf_len ) {
   1.292 +		/* TODO: set errno */
   1.293 +		return 0;
   1.294 +	}
   1.295 +
   1.296 +	/* copy opcode bytes to buffer */
   1.297 +	memcpy( inv->bytes, buf, size );
   1.298 +
   1.299 +	/* set mnemonic type and group */
   1.300 +	type = raw_insn->mnem_flag & ~INS_FLAG_MASK;
   1.301 +        inv->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12;
   1.302 +        inv->type = (enum x86_insn_type) INS_TYPE(type);
   1.303 +
   1.304 +	/* handle operands */
   1.305 +	size += ia32_decode_invariant( buf + size, buf_len - size, raw_insn, 
   1.306 +					&buf[size - 1], prefixes, inv );
   1.307 +
   1.308 +	inv->size = size;
   1.309 +
   1.310 +	return size;		/* return size of instruction in bytes */
   1.311 +}
   1.312 +
   1.313 +size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ) {
   1.314 +	x86_invariant_t inv = { {0} };
   1.315 +	return( ia32_disasm_invariant( buf, buf_len, &inv ) );
   1.316 +}

mercurial