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 +}