| OLD | NEW |
| (Empty) |
| 1 #include <stdio.h> | |
| 2 #include <stdlib.h> | |
| 3 #include <string.h> | |
| 4 | |
| 5 #include "libdis.h" | |
| 6 #include "ia32_insn.h" | |
| 7 #include "ia32_operand.h" | |
| 8 #include "ia32_modrm.h" | |
| 9 #include "ia32_reg.h" | |
| 10 #include "x86_imm.h" | |
| 11 #include "x86_operand_list.h" | |
| 12 | |
| 13 | |
| 14 | |
| 15 /* apply segment override to memory operand in insn */ | |
| 16 static void apply_seg( x86_op_t *op, unsigned int prefixes ) { | |
| 17 if (! prefixes ) return; | |
| 18 | |
| 19 /* apply overrides from prefix */ | |
| 20 switch ( prefixes & PREFIX_REG_MASK ) { | |
| 21 case PREFIX_CS: | |
| 22 op->flags |= op_cs_seg; break; | |
| 23 case PREFIX_SS: | |
| 24 op->flags |= op_ss_seg; break; | |
| 25 case PREFIX_DS: | |
| 26 op->flags |= op_ds_seg; break; | |
| 27 case PREFIX_ES: | |
| 28 op->flags |= op_es_seg; break; | |
| 29 case PREFIX_FS: | |
| 30 op->flags |= op_fs_seg; break; | |
| 31 case PREFIX_GS: | |
| 32 op->flags |= op_gs_seg; break; | |
| 33 } | |
| 34 | |
| 35 return; | |
| 36 } | |
| 37 | |
| 38 static size_t decode_operand_value( unsigned char *buf, size_t buf_len, | |
| 39 x86_op_t *op, x86_insn_t *insn, | |
| 40 unsigned int addr_meth, size_t op_size, | |
| 41 unsigned int op_value, unsigned char modrm, | |
| 42 size_t gen_regs ) { | |
| 43 size_t size = 0; | |
| 44 | |
| 45 /* ++ Do Operand Addressing Method / Decode operand ++ */ | |
| 46 switch (addr_meth) { | |
| 47 /* This sets the operand Size based on the Intel Opcode Map | |
| 48 * (Vol 2, Appendix A). Letter encodings are from section | |
| 49 * A.1.1, 'Codes for Addressing Method' */ | |
| 50 | |
| 51 /* ---------------------- Addressing Method -------------- */ | |
| 52 /* Note that decoding mod ModR/M operand adjusts the size of | |
| 53 * the instruction, but decoding the reg operand does not. | |
| 54 * This should not cause any problems, as every 'reg' operand | |
| 55 * has an associated 'mod' operand. | |
| 56 * Goddamn-Intel-Note: | |
| 57 * Some Intel addressing methods [M, R] specify that modR/M | |
| 58 * byte may only refer to a memory address/may only refer to | |
| 59 * a register -- however Intel provides no clues on what to do | |
| 60 * if, say, the modR/M for an M opcode decodes to a register | |
| 61 * rather than a memory address ... returning 0 is out of the | |
| 62 * question, as this would be an Immediate or a RelOffset, so | |
| 63 * instead these modR/Ms are decoded with total disregard to | |
| 64 * the M, R constraints. */ | |
| 65 | |
| 66 /* MODRM -- mod operand. sets size to at least 1! */ | |
| 67 case ADDRMETH_E: /* ModR/M present, Gen reg or memory */ | |
| 68 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
| 69 gen_regs ); | |
| 70 break; | |
| 71 case ADDRMETH_M: /* ModR/M only refers to memory */ | |
| 72 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
| 73 gen_regs ); | |
| 74 break; | |
| 75 case ADDRMETH_Q: /* ModR/M present, MMX or Memory */ | |
| 76 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
| 77 REG_MMX_OFFSET ); | |
| 78 break; | |
| 79 case ADDRMETH_R: /* ModR/M mod == gen reg */ | |
| 80 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
| 81 gen_regs ); | |
| 82 break; | |
| 83 case ADDRMETH_W: /* ModR/M present, mem or SIMD reg */ | |
| 84 size = ia32_modrm_decode( buf, buf_len, op, insn, | |
| 85 REG_SIMD_OFFSET ); | |
| 86 break; | |
| 87 | |
| 88 /* MODRM -- reg operand. does not effect size! */ | |
| 89 case ADDRMETH_C: /* ModR/M reg == control reg */ | |
| 90 ia32_reg_decode( modrm, op, REG_CTRL_OFFSET ); | |
| 91 break; | |
| 92 case ADDRMETH_D: /* ModR/M reg == debug reg */ | |
| 93 ia32_reg_decode( modrm, op, REG_DEBUG_OFFSET ); | |
| 94 break; | |
| 95 case ADDRMETH_G: /* ModR/M reg == gen-purpose reg */ | |
| 96 ia32_reg_decode( modrm, op, gen_regs ); | |
| 97 break; | |
| 98 case ADDRMETH_P: /* ModR/M reg == qword MMX reg */ | |
| 99 ia32_reg_decode( modrm, op, REG_MMX_OFFSET ); | |
| 100 break; | |
| 101 case ADDRMETH_S: /* ModR/M reg == segment reg */ | |
| 102 ia32_reg_decode( modrm, op, REG_SEG_OFFSET ); | |
| 103 break; | |
| 104 case ADDRMETH_T: /* ModR/M reg == test reg */ | |
| 105 ia32_reg_decode( modrm, op, REG_TEST_OFFSET ); | |
| 106 break; | |
| 107 case ADDRMETH_V: /* ModR/M reg == SIMD reg */ | |
| 108 ia32_reg_decode( modrm, op, REG_SIMD_OFFSET ); | |
| 109 break; | |
| 110 | |
| 111 /* No MODRM : note these set operand type explicitly */ | |
| 112 case ADDRMETH_A: /* No modR/M -- direct addr */ | |
| 113 op->type = op_absolute; | |
| 114 | |
| 115 /* segment:offset address used in far calls */ | |
| 116 x86_imm_sized( buf, buf_len, | |
| 117 &op->data.absolute.segment, 2 ); | |
| 118 if ( insn->addr_size == 4 ) { | |
| 119 x86_imm_sized( buf, buf_len, | |
| 120 &op->data.absolute.offset.off32, 4 ); | |
| 121 size = 6; | |
| 122 } else { | |
| 123 x86_imm_sized( buf, buf_len, | |
| 124 &op->data.absolute.offset.off16, 2 ); | |
| 125 size = 4; | |
| 126 } | |
| 127 | |
| 128 break; | |
| 129 case ADDRMETH_I: /* Immediate val */ | |
| 130 op->type = op_immediate; | |
| 131 /* if it ever becomes legal to have imm as dest and | |
| 132 * there is a src ModR/M operand, we are screwed! */ | |
| 133 if ( op->flags & op_signed ) { | |
| 134 x86_imm_signsized(buf, buf_len, &op->data.byte, | |
| 135 op_size); | |
| 136 } else { | |
| 137 x86_imm_sized(buf, buf_len, &op->data.byte, | |
| 138 op_size); | |
| 139 } | |
| 140 size = op_size; | |
| 141 break; | |
| 142 case ADDRMETH_J: /* Rel offset to add to IP [jmp] */ | |
| 143 /* this fills op->data.near_offset or | |
| 144 op->data.far_offset depending on the size of | |
| 145 the operand */ | |
| 146 op->flags |= op_signed; | |
| 147 if ( op_size == 1 ) { | |
| 148 /* one-byte near offset */ | |
| 149 op->type = op_relative_near; | |
| 150 x86_imm_signsized(buf, buf_len, | |
| 151 &op->data.relative_near, 1); | |
| 152 } else { | |
| 153 /* far offset...is this truly signed? */ | |
| 154 op->type = op_relative_far; | |
| 155 x86_imm_signsized(buf, buf_len, | |
| 156 &op->data.relative_far, op_size ); | |
| 157 } | |
| 158 size = op_size; | |
| 159 break; | |
| 160 case ADDRMETH_O: /* No ModR/M; op is word/dword offset */ | |
| 161 /* NOTE: these are actually RVAs not offsets to seg!! */ | |
| 162 /* note bene: 'O' ADDR_METH uses addr_size to | |
| 163 determine operand size */ | |
| 164 op->type = op_offset; | |
| 165 op->flags |= op_pointer; | |
| 166 x86_imm_sized( buf, buf_len, &op->data.offset, | |
| 167 insn->addr_size ); | |
| 168 | |
| 169 size = insn->addr_size; | |
| 170 break; | |
| 171 | |
| 172 /* Hard-coded: these are specified in the insn definition */ | |
| 173 case ADDRMETH_F: /* EFLAGS register */ | |
| 174 op->type = op_register; | |
| 175 op->flags |= op_hardcode; | |
| 176 ia32_handle_register( &op->data.reg, REG_FLAGS_INDEX ); | |
| 177 break; | |
| 178 case ADDRMETH_X: /* Memory addressed by DS:SI [string] */ | |
| 179 op->type = op_expression; | |
| 180 op->flags |= op_hardcode; | |
| 181 op->flags |= op_ds_seg | op_pointer | op_string; | |
| 182 ia32_handle_register( &op->data.expression.base, | |
| 183 REG_DWORD_OFFSET + 6 ); | |
| 184 break; | |
| 185 case ADDRMETH_Y: /* Memory addressed by ES:DI [string] */ | |
| 186 op->type = op_expression; | |
| 187 op->flags |= op_hardcode; | |
| 188 op->flags |= op_es_seg | op_pointer | op_string; | |
| 189 ia32_handle_register( &op->data.expression.base, | |
| 190 REG_DWORD_OFFSET + 7 ); | |
| 191 break; | |
| 192 case ADDRMETH_RR: /* Gen Register hard-coded in opcode */ | |
| 193 op->type = op_register; | |
| 194 op->flags |= op_hardcode; | |
| 195 ia32_handle_register( &op->data.reg, | |
| 196 op_value + gen_regs ); | |
| 197 break; | |
| 198 case ADDRMETH_RS: /* Seg Register hard-coded in opcode */ | |
| 199 op->type = op_register; | |
| 200 op->flags |= op_hardcode; | |
| 201 ia32_handle_register( &op->data.reg, | |
| 202 op_value + REG_SEG_OFFSET ); | |
| 203 break; | |
| 204 case ADDRMETH_RF: /* FPU Register hard-coded in opcode */ | |
| 205 op->type = op_register; | |
| 206 op->flags |= op_hardcode; | |
| 207 ia32_handle_register( &op->data.reg, | |
| 208 op_value + REG_FPU_OFFSET ); | |
| 209 break; | |
| 210 case ADDRMETH_RT: /* TST Register hard-coded in opcode */ | |
| 211 op->type = op_register; | |
| 212 op->flags |= op_hardcode; | |
| 213 ia32_handle_register( &op->data.reg, | |
| 214 op_value + REG_TEST_OFFSET ); | |
| 215 break; | |
| 216 case ADDRMETH_II: /* Immediate hard-coded in opcode */ | |
| 217 op->type = op_immediate; | |
| 218 op->data.dword = op_value; | |
| 219 op->flags |= op_hardcode; | |
| 220 break; | |
| 221 | |
| 222 case 0: /* Operand is not used */ | |
| 223 default: | |
| 224 /* ignore -- operand not used in this insn */ | |
| 225 op->type = op_unused; /* this shouldn't happen! */ | |
| 226 break; | |
| 227 } | |
| 228 | |
| 229 return size; | |
| 230 } | |
| 231 | |
| 232 static size_t decode_operand_size( unsigned int op_type, x86_insn_t *insn, | |
| 233 x86_op_t *op ){ | |
| 234 size_t size; | |
| 235 | |
| 236 /* ++ Do Operand Type ++ */ | |
| 237 switch (op_type) { | |
| 238 /* This sets the operand Size based on the Intel Opcode Map | |
| 239 * (Vol 2, Appendix A). Letter encodings are from section | |
| 240 * A.1.2, 'Codes for Operand Type' */ | |
| 241 /* NOTE: in this routines, 'size' refers to the size | |
| 242 * of the operand in the raw (encoded) instruction; | |
| 243 * 'datatype' stores the actual size and datatype | |
| 244 * of the operand */ | |
| 245 | |
| 246 /* ------------------------ Operand Type ----------------- */ | |
| 247 case OPTYPE_c: /* byte or word [op size attr] */ | |
| 248 size = (insn->op_size == 4) ? 2 : 1; | |
| 249 op->datatype = (size == 4) ? op_word : op_byte; | |
| 250 break; | |
| 251 case OPTYPE_a: /* 2 word or 2 dword [op size attr] */ | |
| 252 /* pointer to a 16:16 or 32:32 BOUNDS operand */ | |
| 253 size = (insn->op_size == 4) ? 8 : 4; | |
| 254 op->datatype = (size == 4) ? op_bounds32 : op_bounds16; | |
| 255 break; | |
| 256 case OPTYPE_v: /* word or dword [op size attr] */ | |
| 257 size = (insn->op_size == 4) ? 4 : 2; | |
| 258 op->datatype = (size == 4) ? op_dword : op_word; | |
| 259 break; | |
| 260 case OPTYPE_p: /* 32/48-bit ptr [op size attr] */ | |
| 261 /* technically these flags are not accurate: the | |
| 262 * value s a 16:16 pointer or a 16:32 pointer, where | |
| 263 * the first '16' is a segment */ | |
| 264 size = (insn->addr_size == 4) ? 6 : 4; | |
| 265 op->datatype = (size == 4) ? op_descr32 : op_descr16; | |
| 266 break; | |
| 267 case OPTYPE_b: /* byte, ignore op-size */ | |
| 268 size = 1; | |
| 269 op->datatype = op_byte; | |
| 270 break; | |
| 271 case OPTYPE_w: /* word, ignore op-size */ | |
| 272 size = 2; | |
| 273 op->datatype = op_word; | |
| 274 break; | |
| 275 case OPTYPE_d: /* dword , ignore op-size */ | |
| 276 size = 4; | |
| 277 op->datatype = op_dword; | |
| 278 break; | |
| 279 case OPTYPE_s: /* 6-byte psuedo-descriptor */ | |
| 280 /* ptr to 6-byte value which is 32:16 in 32-bit | |
| 281 * mode, or 8:24:16 in 16-bit mode. The high byte | |
| 282 * is ignored in 16-bit mode. */ | |
| 283 size = 6; | |
| 284 op->datatype = (insn->addr_size == 4) ? | |
| 285 op_pdescr32 : op_pdescr16; | |
| 286 break; | |
| 287 case OPTYPE_q: /* qword, ignore op-size */ | |
| 288 size = 8; | |
| 289 op->datatype = op_qword; | |
| 290 break; | |
| 291 case OPTYPE_dq: /* d-qword, ignore op-size */ | |
| 292 size = 16; | |
| 293 op->datatype = op_dqword; | |
| 294 break; | |
| 295 case OPTYPE_ps: /* 128-bit FP data */ | |
| 296 size = 16; | |
| 297 /* really this is 4 packed SP FP values */ | |
| 298 op->datatype = op_ssimd; | |
| 299 break; | |
| 300 case OPTYPE_pd: /* 128-bit FP data */ | |
| 301 size = 16; | |
| 302 /* really this is 2 packed DP FP values */ | |
| 303 op->datatype = op_dsimd; | |
| 304 break; | |
| 305 case OPTYPE_ss: /* Scalar elem of 128-bit FP data */ | |
| 306 size = 16; | |
| 307 /* this only looks at the low dword (4 bytes) | |
| 308 * of the xmmm register passed as a param. | |
| 309 * This is a 16-byte register where only 4 bytes | |
| 310 * are used in the insn. Painful, ain't it? */ | |
| 311 op->datatype = op_sssimd; | |
| 312 break; | |
| 313 case OPTYPE_sd: /* Scalar elem of 128-bit FP data */ | |
| 314 size = 16; | |
| 315 /* this only looks at the low qword (8 bytes) | |
| 316 * of the xmmm register passed as a param. | |
| 317 * This is a 16-byte register where only 8 bytes | |
| 318 * are used in the insn. Painful, again... */ | |
| 319 op->datatype = op_sdsimd; | |
| 320 break; | |
| 321 case OPTYPE_pi: /* qword mmx register */ | |
| 322 size = 8; | |
| 323 op->datatype = op_qword; | |
| 324 break; | |
| 325 case OPTYPE_si: /* dword integer register */ | |
| 326 size = 4; | |
| 327 op->datatype = op_dword; | |
| 328 break; | |
| 329 case OPTYPE_fs: /* single-real */ | |
| 330 size = 4; | |
| 331 op->datatype = op_sreal; | |
| 332 break; | |
| 333 case OPTYPE_fd: /* double real */ | |
| 334 size = 8; | |
| 335 op->datatype = op_dreal; | |
| 336 break; | |
| 337 case OPTYPE_fe: /* extended real */ | |
| 338 size = 10; | |
| 339 op->datatype = op_extreal; | |
| 340 break; | |
| 341 case OPTYPE_fb: /* packed BCD */ | |
| 342 size = 10; | |
| 343 op->datatype = op_bcd; | |
| 344 break; | |
| 345 case OPTYPE_fv: /* pointer to FPU env: 14 or 28-bytes */ | |
| 346 size = (insn->addr_size == 4)? 28 : 14; | |
| 347 op->datatype = (size == 28)? op_fpuenv32: op_fpuenv16; | |
| 348 break; | |
| 349 case OPTYPE_ft: /* pointer to FPU env: 94 or 108 bytes */ | |
| 350 size = (insn->addr_size == 4)? 108 : 94; | |
| 351 op->datatype = (size == 108)? | |
| 352 op_fpustate32: op_fpustate16; | |
| 353 break; | |
| 354 case OPTYPE_fx: /* 512-byte register stack */ | |
| 355 size = 512; | |
| 356 op->datatype = op_fpregset; | |
| 357 break; | |
| 358 case OPTYPE_fp: /* floating point register */ | |
| 359 size = 10; /* double extended precision */ | |
| 360 op->datatype = op_fpreg; | |
| 361 break; | |
| 362 case OPTYPE_m: /* fake operand type used for "lea Gv, M" */ | |
| 363 size = insn->addr_size; | |
| 364 op->datatype = (size == 4) ? op_dword : op_word; | |
| 365 break; | |
| 366 case OPTYPE_none: /* handle weird instructions that have no enco
ding but use a dword datatype, like invlpg */ | |
| 367 size = 0; | |
| 368 op->datatype = op_none; | |
| 369 break; | |
| 370 case 0: | |
| 371 default: | |
| 372 size = insn->op_size; | |
| 373 op->datatype = (size == 4) ? op_dword : op_word; | |
| 374 break; | |
| 375 } | |
| 376 return size; | |
| 377 } | |
| 378 | |
| 379 size_t ia32_decode_operand( unsigned char *buf, size_t buf_len, | |
| 380 x86_insn_t *insn, unsigned int raw_op, | |
| 381 unsigned int raw_flags, unsigned int prefixes, | |
| 382 unsigned char modrm ) { | |
| 383 unsigned int addr_meth, op_type, op_size, gen_regs; | |
| 384 x86_op_t *op; | |
| 385 size_t size; | |
| 386 | |
| 387 /* ++ Yank optype and addr mode out of operand flags */ | |
| 388 addr_meth = raw_flags & ADDRMETH_MASK; | |
| 389 op_type = raw_flags & OPTYPE_MASK; | |
| 390 | |
| 391 if ( raw_flags == ARG_NONE ) { | |
| 392 /* operand is not used in this instruction */ | |
| 393 return 0; | |
| 394 } | |
| 395 | |
| 396 /* allocate a new operand */ | |
| 397 op = x86_operand_new( insn ); | |
| 398 | |
| 399 /* ++ Copy flags from opcode table to x86_insn_t */ | |
| 400 op->access = (enum x86_op_access) OP_PERM(raw_flags); | |
| 401 op->flags = (enum x86_op_flags) (OP_FLAGS(raw_flags) >> 12); | |
| 402 | |
| 403 /* Get size (for decoding) and datatype of operand */ | |
| 404 op_size = decode_operand_size(op_type, insn, op); | |
| 405 | |
| 406 /* override default register set based on Operand Type */ | |
| 407 /* this allows mixing of 8, 16, and 32 bit regs in insn */ | |
| 408 if (op_size == 1) { | |
| 409 gen_regs = REG_BYTE_OFFSET; | |
| 410 } else if (op_size == 2) { | |
| 411 gen_regs = REG_WORD_OFFSET; | |
| 412 } else { | |
| 413 gen_regs = REG_DWORD_OFFSET; | |
| 414 } | |
| 415 | |
| 416 size = decode_operand_value( buf, buf_len, op, insn, addr_meth, | |
| 417 op_size, raw_op, modrm, gen_regs ); | |
| 418 | |
| 419 /* if operand is an address, apply any segment override prefixes */ | |
| 420 if ( op->type == op_expression || op->type == op_offset ) { | |
| 421 apply_seg(op, prefixes); | |
| 422 } | |
| 423 | |
| 424 return size; /* return number of bytes in instruction */ | |
| 425 } | |
| OLD | NEW |