toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.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_operand.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,425 @@
     1.4 +#include <stdio.h>
     1.5 +#include <stdlib.h>
     1.6 +#include <string.h>
     1.7 +
     1.8 +#include "libdis.h"
     1.9 +#include "ia32_insn.h"
    1.10 +#include "ia32_operand.h"
    1.11 +#include "ia32_modrm.h"
    1.12 +#include "ia32_reg.h"
    1.13 +#include "x86_imm.h"
    1.14 +#include "x86_operand_list.h"
    1.15 +
    1.16 +
    1.17 +
    1.18 +/* apply segment override to memory operand in insn */
    1.19 +static void apply_seg( x86_op_t *op, unsigned int prefixes ) {
    1.20 +	if (! prefixes ) return;
    1.21 +
    1.22 +	/* apply overrides from prefix */
    1.23 +	switch ( prefixes & PREFIX_REG_MASK ) {
    1.24 +		case PREFIX_CS:
    1.25 +			op->flags |= op_cs_seg; break;
    1.26 +		case PREFIX_SS:
    1.27 +			op->flags |= op_ss_seg; break;
    1.28 +		case PREFIX_DS:
    1.29 +			op->flags |= op_ds_seg; break;
    1.30 +		case PREFIX_ES:
    1.31 +			op->flags |= op_es_seg; break;
    1.32 +		case PREFIX_FS:
    1.33 +			op->flags |= op_fs_seg; break;
    1.34 +		case PREFIX_GS:
    1.35 +			op->flags |= op_gs_seg; break;
    1.36 +	}
    1.37 +
    1.38 +	return;
    1.39 +}
    1.40 +
    1.41 +static size_t decode_operand_value( unsigned char *buf, size_t buf_len,
    1.42 +			    x86_op_t *op, x86_insn_t *insn, 
    1.43 +			    unsigned int addr_meth, size_t op_size, 
    1.44 +			    unsigned int op_value, unsigned char modrm, 
    1.45 +			    size_t gen_regs ) {
    1.46 +	size_t size = 0;
    1.47 +
    1.48 +	/* ++ Do Operand Addressing Method / Decode operand ++ */
    1.49 +	switch (addr_meth) {
    1.50 +		/* This sets the operand Size based on the Intel Opcode Map
    1.51 +		 * (Vol 2, Appendix A). Letter encodings are from section
    1.52 +		 * A.1.1, 'Codes for Addressing Method' */
    1.53 +
    1.54 +		/* ---------------------- Addressing Method -------------- */
    1.55 +		/* Note that decoding mod ModR/M operand adjusts the size of
    1.56 +		 * the instruction, but decoding the reg operand does not. 
    1.57 +		 * This should not cause any problems, as every 'reg' operand 
    1.58 +		 * has an associated 'mod' operand. 
    1.59 +		 * Goddamn-Intel-Note:
    1.60 +		 *   Some Intel addressing methods [M, R] specify that modR/M
    1.61 +		 *   byte may only refer to a memory address/may only refer to
    1.62 +		 *   a register -- however Intel provides no clues on what to do
    1.63 +		 *   if, say, the modR/M for an M opcode decodes to a register
    1.64 +		 *   rather than a memory address ... returning 0 is out of the
    1.65 +		 *   question, as this would be an Immediate or a RelOffset, so
    1.66 +		 *   instead these modR/Ms are decoded with total disregard to 
    1.67 +		 *   the M, R constraints. */
    1.68 +
    1.69 +		/* MODRM -- mod operand. sets size to at least 1! */
    1.70 +		case ADDRMETH_E:	/* ModR/M present, Gen reg or memory  */
    1.71 +			size = ia32_modrm_decode( buf, buf_len, op, insn, 
    1.72 +						  gen_regs );
    1.73 +			break;
    1.74 +		case ADDRMETH_M:	/* ModR/M only refers to memory */
    1.75 +			size = ia32_modrm_decode( buf, buf_len, op, insn, 
    1.76 +						  gen_regs );
    1.77 +			break;
    1.78 +		case ADDRMETH_Q:	/* ModR/M present, MMX or Memory */
    1.79 +			size = ia32_modrm_decode( buf, buf_len, op, insn, 
    1.80 +						  REG_MMX_OFFSET );
    1.81 +			break;
    1.82 +		case ADDRMETH_R:	/* ModR/M mod == gen reg */
    1.83 +			size = ia32_modrm_decode( buf, buf_len, op, insn, 
    1.84 +						  gen_regs );
    1.85 +			break;
    1.86 +		case ADDRMETH_W:	/* ModR/M present, mem or SIMD reg */
    1.87 +			size = ia32_modrm_decode( buf, buf_len, op, insn, 
    1.88 +						  REG_SIMD_OFFSET );
    1.89 +			break;
    1.90 +
    1.91 +		/* MODRM -- reg operand. does not effect size! */
    1.92 +		case ADDRMETH_C:	/* ModR/M reg == control reg */
    1.93 +			ia32_reg_decode( modrm, op, REG_CTRL_OFFSET );
    1.94 +			break;
    1.95 +		case ADDRMETH_D:	/* ModR/M reg == debug reg */
    1.96 +			ia32_reg_decode( modrm, op, REG_DEBUG_OFFSET );
    1.97 +			break;
    1.98 +		case ADDRMETH_G:	/* ModR/M reg == gen-purpose reg */
    1.99 +			ia32_reg_decode( modrm, op, gen_regs );
   1.100 +			break;
   1.101 +		case ADDRMETH_P:	/* ModR/M reg == qword MMX reg */
   1.102 +			ia32_reg_decode( modrm, op, REG_MMX_OFFSET );
   1.103 +			break;
   1.104 +		case ADDRMETH_S:	/* ModR/M reg == segment reg */
   1.105 +			ia32_reg_decode( modrm, op, REG_SEG_OFFSET );
   1.106 +			break;
   1.107 +		case ADDRMETH_T:	/* ModR/M reg == test reg */
   1.108 +			ia32_reg_decode( modrm, op, REG_TEST_OFFSET );
   1.109 +			break;
   1.110 +		case ADDRMETH_V:	/* ModR/M reg == SIMD reg */
   1.111 +			ia32_reg_decode( modrm, op, REG_SIMD_OFFSET );
   1.112 +			break;
   1.113 +
   1.114 +		/* No MODRM : note these set operand type explicitly */
   1.115 +		case ADDRMETH_A:	/* No modR/M -- direct addr */
   1.116 +			op->type = op_absolute;
   1.117 +
   1.118 +			/* segment:offset address used in far calls */
   1.119 +			x86_imm_sized( buf, buf_len, 
   1.120 +				       &op->data.absolute.segment, 2 );
   1.121 +			if ( insn->addr_size == 4 ) {
   1.122 +				x86_imm_sized( buf, buf_len, 
   1.123 +				    &op->data.absolute.offset.off32, 4 );
   1.124 +				size = 6;
   1.125 +			} else {
   1.126 +				x86_imm_sized( buf, buf_len, 
   1.127 +				    &op->data.absolute.offset.off16, 2 );
   1.128 +				size = 4;
   1.129 +			}
   1.130 +
   1.131 +			break;
   1.132 +		case ADDRMETH_I:	/* Immediate val */
   1.133 +			op->type = op_immediate;
   1.134 +			/* if it ever becomes legal to have imm as dest and
   1.135 +			 * there is a src ModR/M operand, we are screwed! */
   1.136 +			if ( op->flags & op_signed ) {
   1.137 +				x86_imm_signsized(buf, buf_len, &op->data.byte, 
   1.138 +						op_size);
   1.139 +			} else {
   1.140 +				x86_imm_sized(buf, buf_len, &op->data.byte, 
   1.141 +						op_size);
   1.142 +			}
   1.143 +			size = op_size;
   1.144 +			break;
   1.145 +		case ADDRMETH_J:	/* Rel offset to add to IP [jmp] */
   1.146 +			/* this fills op->data.near_offset or
   1.147 +			   op->data.far_offset depending on the size of
   1.148 +			   the operand */
   1.149 +			op->flags |= op_signed;
   1.150 +			if ( op_size == 1 ) {
   1.151 +				/* one-byte near offset */
   1.152 +				op->type = op_relative_near;
   1.153 +				x86_imm_signsized(buf, buf_len, 
   1.154 +						&op->data.relative_near, 1);
   1.155 +			} else {
   1.156 +				/* far offset...is this truly signed? */
   1.157 +				op->type = op_relative_far;
   1.158 +				x86_imm_signsized(buf, buf_len, 
   1.159 +					&op->data.relative_far, op_size );
   1.160 +			}
   1.161 +			size = op_size;
   1.162 +			break;
   1.163 +		case ADDRMETH_O:	/* No ModR/M; op is word/dword offset */
   1.164 +			/* NOTE: these are actually RVAs not offsets to seg!! */
   1.165 +			/* note bene: 'O' ADDR_METH uses addr_size  to
   1.166 +			   determine operand size */
   1.167 +			op->type = op_offset;
   1.168 +			op->flags |= op_pointer;
   1.169 +			x86_imm_sized( buf, buf_len, &op->data.offset, 
   1.170 +					insn->addr_size );
   1.171 +
   1.172 +			size = insn->addr_size;
   1.173 +			break;
   1.174 +
   1.175 +		/* Hard-coded: these are specified in the insn definition */
   1.176 +		case ADDRMETH_F:	/* EFLAGS register */
   1.177 +			op->type = op_register;
   1.178 +			op->flags |= op_hardcode;
   1.179 +			ia32_handle_register( &op->data.reg, REG_FLAGS_INDEX );
   1.180 +			break;
   1.181 +		case ADDRMETH_X:	/* Memory addressed by DS:SI [string] */
   1.182 +			op->type = op_expression;
   1.183 +			op->flags |= op_hardcode;
   1.184 +			op->flags |= op_ds_seg | op_pointer | op_string;
   1.185 +			ia32_handle_register( &op->data.expression.base, 
   1.186 +					     REG_DWORD_OFFSET + 6 );
   1.187 +			break;
   1.188 +		case ADDRMETH_Y:	/* Memory addressed by ES:DI [string] */
   1.189 +			op->type = op_expression;
   1.190 +			op->flags |= op_hardcode;
   1.191 +			op->flags |= op_es_seg | op_pointer | op_string;
   1.192 +			ia32_handle_register( &op->data.expression.base, 
   1.193 +					     REG_DWORD_OFFSET + 7 );
   1.194 +			break;
   1.195 +		case ADDRMETH_RR:	/* Gen Register hard-coded in opcode */
   1.196 +			op->type = op_register;
   1.197 +			op->flags |= op_hardcode;
   1.198 +			ia32_handle_register( &op->data.reg, 
   1.199 +						op_value + gen_regs );
   1.200 +			break;
   1.201 +		case ADDRMETH_RS:	/* Seg Register hard-coded in opcode */
   1.202 +			op->type = op_register;
   1.203 +			op->flags |= op_hardcode;
   1.204 +			ia32_handle_register( &op->data.reg, 
   1.205 +						op_value + REG_SEG_OFFSET );
   1.206 +			break;
   1.207 +		case ADDRMETH_RF:	/* FPU Register hard-coded in opcode */
   1.208 +			op->type = op_register;
   1.209 +			op->flags |= op_hardcode;
   1.210 +			ia32_handle_register( &op->data.reg, 
   1.211 +						op_value + REG_FPU_OFFSET );
   1.212 +			break;
   1.213 +		case ADDRMETH_RT:	/* TST Register hard-coded in opcode */
   1.214 +			op->type = op_register;
   1.215 +			op->flags |= op_hardcode;
   1.216 +			ia32_handle_register( &op->data.reg, 
   1.217 +						op_value + REG_TEST_OFFSET );
   1.218 +			break;
   1.219 +		case ADDRMETH_II:	/* Immediate hard-coded in opcode */
   1.220 +			op->type = op_immediate;
   1.221 +			op->data.dword = op_value;
   1.222 +			op->flags |= op_hardcode;
   1.223 +			break;
   1.224 +
   1.225 +		case 0:	/* Operand is not used */
   1.226 +		default:
   1.227 +			/* ignore -- operand not used in this insn */
   1.228 +			op->type = op_unused;	/* this shouldn't happen! */
   1.229 +			break;
   1.230 +	}
   1.231 +
   1.232 +	return size;
   1.233 +}
   1.234 +
   1.235 +static size_t decode_operand_size( unsigned int op_type, x86_insn_t *insn, 
   1.236 +				   x86_op_t *op ){
   1.237 +	size_t size;
   1.238 +
   1.239 +	/* ++ Do Operand Type ++ */
   1.240 +	switch (op_type) {
   1.241 +		/* This sets the operand Size based on the Intel Opcode Map
   1.242 +		 * (Vol 2, Appendix A). Letter encodings are from section
   1.243 +		 * A.1.2, 'Codes for Operand Type' */
   1.244 +		/* NOTE: in this routines, 'size' refers to the size
   1.245 +		 *       of the operand in the raw (encoded) instruction;
   1.246 +		 *       'datatype' stores the actual size and datatype
   1.247 +		 *       of the operand */
   1.248 +
   1.249 +		/* ------------------------ Operand Type ----------------- */
   1.250 +		case OPTYPE_c:	/* byte or word [op size attr] */
   1.251 +			size = (insn->op_size == 4) ? 2 : 1;
   1.252 +			op->datatype = (size == 4) ? op_word : op_byte;
   1.253 +			break;
   1.254 +		case OPTYPE_a:	/* 2 word or 2 dword [op size attr] */
   1.255 +			/* pointer to a 16:16 or 32:32 BOUNDS operand */
   1.256 +			size = (insn->op_size == 4) ? 8 : 4;
   1.257 +			op->datatype = (size == 4) ? op_bounds32 : op_bounds16;
   1.258 +			break;
   1.259 +		case OPTYPE_v:	/* word or dword [op size attr] */
   1.260 +			size = (insn->op_size == 4) ? 4 : 2;
   1.261 +			op->datatype = (size == 4) ? op_dword : op_word;
   1.262 +			break;
   1.263 +		case OPTYPE_p:	/* 32/48-bit ptr [op size attr] */
   1.264 +			/* technically these flags are not accurate: the
   1.265 +			 * value s a 16:16 pointer or a 16:32 pointer, where
   1.266 +			 * the first '16' is a segment */
   1.267 +			size = (insn->addr_size == 4) ? 6 : 4;
   1.268 +			op->datatype = (size == 4) ? op_descr32 : op_descr16;
   1.269 +			break;
   1.270 +		case OPTYPE_b:	/* byte, ignore op-size */
   1.271 +			size = 1;
   1.272 +			op->datatype = op_byte;
   1.273 +			break;
   1.274 +		case OPTYPE_w:	/* word, ignore op-size */
   1.275 +			size = 2;
   1.276 +			op->datatype = op_word;
   1.277 +			break;
   1.278 +		case OPTYPE_d:	/* dword , ignore op-size */
   1.279 +			size = 4;
   1.280 +			op->datatype = op_dword;
   1.281 +			break;
   1.282 +		case OPTYPE_s:	/* 6-byte psuedo-descriptor */
   1.283 +			/* ptr to 6-byte value which is 32:16 in 32-bit
   1.284 +			 * mode, or 8:24:16 in 16-bit mode. The high byte
   1.285 +			 * is ignored in 16-bit mode. */
   1.286 +			size = 6;
   1.287 +			op->datatype = (insn->addr_size == 4) ? 
   1.288 +				op_pdescr32 : op_pdescr16;
   1.289 +			break;
   1.290 +		case OPTYPE_q:	/* qword, ignore op-size */
   1.291 +			size = 8;
   1.292 +			op->datatype = op_qword;
   1.293 +			break;
   1.294 +		case OPTYPE_dq:	/* d-qword, ignore op-size */
   1.295 +			size = 16;
   1.296 +			op->datatype = op_dqword;
   1.297 +			break;
   1.298 +		case OPTYPE_ps:	/* 128-bit FP data */
   1.299 +			size = 16;
   1.300 +			/* really this is 4 packed SP FP values */
   1.301 +			op->datatype = op_ssimd;
   1.302 +			break;
   1.303 +		case OPTYPE_pd:	/* 128-bit FP data */
   1.304 +			size = 16;
   1.305 +			/* really this is 2 packed DP FP values */
   1.306 +			op->datatype = op_dsimd;
   1.307 +			break;
   1.308 +		case OPTYPE_ss:	/* Scalar elem of 128-bit FP data */
   1.309 +			size = 16;
   1.310 +			/* this only looks at the low dword (4 bytes)
   1.311 +			 * of the xmmm register passed as a param. 
   1.312 +			 * This is a 16-byte register where only 4 bytes
   1.313 +			 * are used in the insn. Painful, ain't it? */
   1.314 +			op->datatype = op_sssimd;
   1.315 +			break;
   1.316 +		case OPTYPE_sd:	/* Scalar elem of 128-bit FP data */
   1.317 +			size = 16;
   1.318 +			/* this only looks at the low qword (8 bytes)
   1.319 +			 * of the xmmm register passed as a param. 
   1.320 +			 * This is a 16-byte register where only 8 bytes
   1.321 +			 * are used in the insn. Painful, again... */
   1.322 +			op->datatype = op_sdsimd;
   1.323 +			break;
   1.324 +		case OPTYPE_pi:	/* qword mmx register */
   1.325 +			size = 8;
   1.326 +			op->datatype = op_qword;
   1.327 +			break;
   1.328 +		case OPTYPE_si:	/* dword integer register */
   1.329 +			size = 4;
   1.330 +			op->datatype = op_dword;
   1.331 +			break;
   1.332 +		case OPTYPE_fs:	/* single-real */
   1.333 +			size = 4;
   1.334 +			op->datatype = op_sreal;
   1.335 +			break;
   1.336 +		case OPTYPE_fd:	/* double real */
   1.337 +			size = 8;
   1.338 +			op->datatype = op_dreal;
   1.339 +			break;
   1.340 +		case OPTYPE_fe:	/* extended real */
   1.341 +			size = 10;
   1.342 +			op->datatype = op_extreal;
   1.343 +			break;
   1.344 +		case OPTYPE_fb:	/* packed BCD */
   1.345 +			size = 10;
   1.346 +			op->datatype = op_bcd;
   1.347 +			break;
   1.348 +		case OPTYPE_fv:	/* pointer to FPU env: 14 or 28-bytes */
   1.349 +			size = (insn->addr_size == 4)? 28 : 14;
   1.350 +			op->datatype = (size == 28)?  op_fpuenv32: op_fpuenv16;
   1.351 +			break;
   1.352 +		case OPTYPE_ft:	/* pointer to FPU env: 94 or 108 bytes */
   1.353 +			size = (insn->addr_size == 4)? 108 : 94;
   1.354 +			op->datatype = (size == 108)? 
   1.355 +				op_fpustate32: op_fpustate16;
   1.356 +			break;
   1.357 +		case OPTYPE_fx:	/* 512-byte register stack */
   1.358 +			size = 512;
   1.359 +			op->datatype = op_fpregset;
   1.360 +			break;
   1.361 +		case OPTYPE_fp:	/* floating point register */
   1.362 +			size = 10;	/* double extended precision */
   1.363 +			op->datatype = op_fpreg;
   1.364 +			break;
   1.365 +		case OPTYPE_m:	/* fake operand type used for "lea Gv, M" */
   1.366 +			size = insn->addr_size;
   1.367 +			op->datatype = (size == 4) ?  op_dword : op_word;
   1.368 +			break;
   1.369 +		case OPTYPE_none: /* handle weird instructions that have no encoding but use a dword datatype, like invlpg */
   1.370 +			size = 0;
   1.371 +			op->datatype = op_none;
   1.372 +			break;
   1.373 +		case 0:
   1.374 +		default:
   1.375 +			size = insn->op_size;
   1.376 +			op->datatype = (size == 4) ? op_dword : op_word;
   1.377 +			break;
   1.378 +		}
   1.379 +	return size;
   1.380 +}
   1.381 +
   1.382 +size_t ia32_decode_operand( unsigned char *buf, size_t buf_len,
   1.383 +			      x86_insn_t *insn, unsigned int raw_op, 
   1.384 +			      unsigned int raw_flags, unsigned int prefixes, 
   1.385 +			      unsigned char modrm ) {
   1.386 +	unsigned int addr_meth, op_type, op_size, gen_regs;
   1.387 +	x86_op_t *op;
   1.388 +	size_t size;
   1.389 +
   1.390 +	/* ++ Yank optype and addr mode out of operand flags */
   1.391 +	addr_meth = raw_flags & ADDRMETH_MASK;
   1.392 +	op_type = raw_flags & OPTYPE_MASK;
   1.393 +
   1.394 +	if ( raw_flags == ARG_NONE ) {
   1.395 +		/* operand is not used in this instruction */
   1.396 +		return 0;
   1.397 +	}
   1.398 +
   1.399 +	/* allocate a new operand */
   1.400 +	op = x86_operand_new( insn );
   1.401 +
   1.402 +	/* ++ Copy flags from opcode table to x86_insn_t */
   1.403 +	op->access = (enum x86_op_access) OP_PERM(raw_flags);
   1.404 +	op->flags = (enum x86_op_flags) (OP_FLAGS(raw_flags) >> 12);
   1.405 +
   1.406 +	/* Get size (for decoding)  and datatype of operand */
   1.407 +	op_size = decode_operand_size(op_type, insn, op);
   1.408 +
   1.409 +	/* override default register set based on Operand Type */
   1.410 +	/* this allows mixing of 8, 16, and 32 bit regs in insn */
   1.411 +	if (op_size == 1) {
   1.412 +		gen_regs = REG_BYTE_OFFSET;
   1.413 +	} else if (op_size == 2) {
   1.414 +		gen_regs = REG_WORD_OFFSET;
   1.415 +	} else {
   1.416 +		gen_regs = REG_DWORD_OFFSET;
   1.417 +	}
   1.418 +
   1.419 +	size = decode_operand_value( buf, buf_len, op, insn, addr_meth, 
   1.420 +				      op_size, raw_op, modrm, gen_regs );
   1.421 +
   1.422 +	/* if operand is an address, apply any segment override prefixes */
   1.423 +	if ( op->type == op_expression || op->type == op_offset ) {
   1.424 +		apply_seg(op, prefixes);
   1.425 +	}
   1.426 +
   1.427 +	return size;		/* return number of bytes in instruction */
   1.428 +}

mercurial