| OLD | NEW |
| (Empty) |
| 1 #include <stdio.h> | |
| 2 #include <stdlib.h> | |
| 3 #include <string.h> | |
| 4 #include "qword.h" | |
| 5 | |
| 6 #include "ia32_insn.h" | |
| 7 #include "ia32_opcode_tables.h" | |
| 8 | |
| 9 #include "ia32_reg.h" | |
| 10 #include "ia32_operand.h" | |
| 11 #include "ia32_implicit.h" | |
| 12 #include "ia32_settings.h" | |
| 13 | |
| 14 #include "libdis.h" | |
| 15 | |
| 16 extern ia32_table_desc_t ia32_tables[]; | |
| 17 extern ia32_settings_t ia32_settings; | |
| 18 | |
| 19 #define IS_SP( op ) (op->type == op_register && \ | |
| 20 (op->data.reg.id == REG_ESP_INDEX || \ | |
| 21 op->data.reg.alias == REG_ESP_INDEX) ) | |
| 22 #define IS_IMM( op ) (op->type == op_immediate ) | |
| 23 | |
| 24 #ifdef WIN32 | |
| 25 # define INLINE | |
| 26 #else | |
| 27 # define INLINE inline | |
| 28 #endif | |
| 29 | |
| 30 /* for calculating stack modification based on an operand */ | |
| 31 static INLINE int32_t long_from_operand( x86_op_t *op ) { | |
| 32 | |
| 33 if (! IS_IMM(op) ) { | |
| 34 return 0L; | |
| 35 } | |
| 36 | |
| 37 switch ( op->datatype ) { | |
| 38 case op_byte: | |
| 39 return (int32_t) op->data.sbyte; | |
| 40 case op_word: | |
| 41 return (int32_t) op->data.sword; | |
| 42 case op_qword: | |
| 43 return (int32_t) op->data.sqword; | |
| 44 case op_dword: | |
| 45 return op->data.sdword; | |
| 46 default: | |
| 47 /* these are not used in stack insn */ | |
| 48 break; | |
| 49 } | |
| 50 | |
| 51 return 0L; | |
| 52 } | |
| 53 | |
| 54 | |
| 55 /* determine what this insn does to the stack */ | |
| 56 static void ia32_stack_mod(x86_insn_t *insn) { | |
| 57 x86_op_t *dest, *src = NULL; | |
| 58 | |
| 59 if (! insn || ! insn->operands ) { | |
| 60 return; | |
| 61 } | |
| 62 | |
| 63 dest = &insn->operands->op; | |
| 64 if ( dest ) { | |
| 65 src = &insn->operands->next->op; | |
| 66 } | |
| 67 | |
| 68 insn->stack_mod = 0; | |
| 69 insn->stack_mod_val = 0; | |
| 70 | |
| 71 switch ( insn->type ) { | |
| 72 case insn_call: | |
| 73 case insn_callcc: | |
| 74 insn->stack_mod = 1; | |
| 75 insn->stack_mod_val = insn->addr_size * -1; | |
| 76 break; | |
| 77 case insn_push: | |
| 78 insn->stack_mod = 1; | |
| 79 insn->stack_mod_val = insn->addr_size * -1; | |
| 80 break; | |
| 81 case insn_return: | |
| 82 insn->stack_mod = 1; | |
| 83 insn->stack_mod_val = insn->addr_size; | |
| 84 case insn_int: case insn_intcc: | |
| 85 case insn_iret: | |
| 86 break; | |
| 87 case insn_pop: | |
| 88 insn->stack_mod = 1; | |
| 89 if (! IS_SP( dest ) ) { | |
| 90 insn->stack_mod_val = insn->op_size; | |
| 91 } /* else we don't know the stack change in a pop esp */ | |
| 92 break; | |
| 93 case insn_enter: | |
| 94 insn->stack_mod = 1; | |
| 95 insn->stack_mod_val = 0; /* TODO : FIX */ | |
| 96 break; | |
| 97 case insn_leave: | |
| 98 insn->stack_mod = 1; | |
| 99 insn->stack_mod_val = 0; /* TODO : FIX */ | |
| 100 break; | |
| 101 case insn_pushregs: | |
| 102 insn->stack_mod = 1; | |
| 103 insn->stack_mod_val = 0; /* TODO : FIX */ | |
| 104 break; | |
| 105 case insn_popregs: | |
| 106 insn->stack_mod = 1; | |
| 107 insn->stack_mod_val = 0; /* TODO : FIX */ | |
| 108 break; | |
| 109 case insn_pushflags: | |
| 110 insn->stack_mod = 1; | |
| 111 insn->stack_mod_val = 0; /* TODO : FIX */ | |
| 112 break; | |
| 113 case insn_popflags: | |
| 114 insn->stack_mod = 1; | |
| 115 insn->stack_mod_val = 0; /* TODO : FIX */ | |
| 116 break; | |
| 117 case insn_add: | |
| 118 if ( IS_SP( dest ) ) { | |
| 119 insn->stack_mod = 1; | |
| 120 insn->stack_mod_val = long_from_operand( src ); | |
| 121 } | |
| 122 break; | |
| 123 case insn_sub: | |
| 124 if ( IS_SP( dest ) ) { | |
| 125 insn->stack_mod = 1; | |
| 126 insn->stack_mod_val = long_from_operand( src ); | |
| 127 insn->stack_mod_val *= -1; | |
| 128 } | |
| 129 break; | |
| 130 case insn_inc: | |
| 131 if ( IS_SP( dest ) ) { | |
| 132 insn->stack_mod = 1; | |
| 133 insn->stack_mod_val = 1; | |
| 134 } | |
| 135 break; | |
| 136 case insn_dec: | |
| 137 if ( IS_SP( dest ) ) { | |
| 138 insn->stack_mod = 1; | |
| 139 insn->stack_mod_val = 1; | |
| 140 } | |
| 141 break; | |
| 142 case insn_mov: case insn_movcc: | |
| 143 case insn_xchg: case insn_xchgcc: | |
| 144 case insn_mul: case insn_div: | |
| 145 case insn_shl: case insn_shr: | |
| 146 case insn_rol: case insn_ror: | |
| 147 case insn_and: case insn_or: | |
| 148 case insn_not: case insn_neg: | |
| 149 case insn_xor: | |
| 150 if ( IS_SP( dest ) ) { | |
| 151 insn->stack_mod = 1; | |
| 152 } | |
| 153 break; | |
| 154 default: | |
| 155 break; | |
| 156 } | |
| 157 if (! strcmp("enter", insn->mnemonic) ) { | |
| 158 insn->stack_mod = 1; | |
| 159 } else if (! strcmp("leave", insn->mnemonic) ) { | |
| 160 insn->stack_mod = 1; | |
| 161 } | |
| 162 | |
| 163 /* for mov, etc we return 0 -- unknown stack mod */ | |
| 164 | |
| 165 return; | |
| 166 } | |
| 167 | |
| 168 /* get the cpu details for this insn from cpu flags int */ | |
| 169 static void ia32_handle_cpu( x86_insn_t *insn, unsigned int cpu ) { | |
| 170 insn->cpu = (enum x86_insn_cpu) CPU_MODEL(cpu); | |
| 171 insn->isa = (enum x86_insn_isa) (ISA_SUBSET(cpu)) >> 16; | |
| 172 return; | |
| 173 } | |
| 174 | |
| 175 /* handle mnemonic type and group */ | |
| 176 static void ia32_handle_mnemtype(x86_insn_t *insn, unsigned int mnemtype) { | |
| 177 unsigned int type = mnemtype & ~INS_FLAG_MASK; | |
| 178 insn->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12; | |
| 179 insn->type = (enum x86_insn_type) INS_TYPE(type); | |
| 180 | |
| 181 return; | |
| 182 } | |
| 183 | |
| 184 static void ia32_handle_notes(x86_insn_t *insn, unsigned int notes) { | |
| 185 insn->note = (enum x86_insn_note) notes; | |
| 186 return; | |
| 187 } | |
| 188 | |
| 189 static void ia32_handle_eflags( x86_insn_t *insn, unsigned int eflags) { | |
| 190 unsigned int flags; | |
| 191 | |
| 192 /* handle flags effected */ | |
| 193 flags = INS_FLAGS_TEST(eflags); | |
| 194 /* handle weird OR cases */ | |
| 195 /* these are either JLE (ZF | SF<>OF) or JBE (CF | ZF) */ | |
| 196 if (flags & INS_TEST_OR) { | |
| 197 flags &= ~INS_TEST_OR; | |
| 198 if ( flags & INS_TEST_ZERO ) { | |
| 199 flags &= ~INS_TEST_ZERO; | |
| 200 if ( flags & INS_TEST_CARRY ) { | |
| 201 flags &= ~INS_TEST_CARRY ; | |
| 202 flags |= (int)insn_carry_or_zero_set; | |
| 203 } else if ( flags & INS_TEST_SFNEOF ) { | |
| 204 flags &= ~INS_TEST_SFNEOF; | |
| 205 flags |= (int)insn_zero_set_or_sign_ne_oflow; | |
| 206 } | |
| 207 } | |
| 208 } | |
| 209 insn->flags_tested = (enum x86_flag_status) flags; | |
| 210 | |
| 211 insn->flags_set = (enum x86_flag_status) INS_FLAGS_SET(eflags) >> 16; | |
| 212 | |
| 213 return; | |
| 214 } | |
| 215 | |
| 216 static void ia32_handle_prefix( x86_insn_t *insn, unsigned int prefixes ) { | |
| 217 | |
| 218 insn->prefix = (enum x86_insn_prefix) prefixes & PREFIX_MASK; // >> 20; | |
| 219 if (! (insn->prefix & PREFIX_PRINT_MASK) ) { | |
| 220 /* no printable prefixes */ | |
| 221 insn->prefix = insn_no_prefix; | |
| 222 } | |
| 223 | |
| 224 /* concat all prefix strings */ | |
| 225 if ( (unsigned int)insn->prefix & PREFIX_LOCK ) { | |
| 226 strncat(insn->prefix_string, "lock ", 32 - | |
| 227 strlen(insn->prefix_string)); | |
| 228 } | |
| 229 | |
| 230 if ( (unsigned int)insn->prefix & PREFIX_REPNZ ) { | |
| 231 strncat(insn->prefix_string, "repnz ", 32 - | |
| 232 strlen(insn->prefix_string)); | |
| 233 } else if ( (unsigned int)insn->prefix & PREFIX_REPZ ) { | |
| 234 strncat(insn->prefix_string, "repz ", 32 - | |
| 235 strlen(insn->prefix_string)); | |
| 236 } | |
| 237 | |
| 238 return; | |
| 239 } | |
| 240 | |
| 241 | |
| 242 static void reg_32_to_16( x86_op_t *op, x86_insn_t *insn, void *arg ) { | |
| 243 | |
| 244 /* if this is a 32-bit register and it is a general register ... */ | |
| 245 if ( op->type == op_register && op->data.reg.size == 4 && | |
| 246 (op->data.reg.type & reg_gen) ) { | |
| 247 /* WORD registers are 8 indices off from DWORD registers */ | |
| 248 ia32_handle_register( &(op->data.reg), | |
| 249 op->data.reg.id + 8 ); | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 static void handle_insn_metadata( x86_insn_t *insn, ia32_insn_t *raw_insn ) { | |
| 254 ia32_handle_mnemtype( insn, raw_insn->mnem_flag ); | |
| 255 ia32_handle_notes( insn, raw_insn->notes ); | |
| 256 ia32_handle_eflags( insn, raw_insn->flags_effected ); | |
| 257 ia32_handle_cpu( insn, raw_insn->cpu ); | |
| 258 ia32_stack_mod( insn ); | |
| 259 } | |
| 260 | |
| 261 static size_t ia32_decode_insn( unsigned char *buf, size_t buf_len, | |
| 262 ia32_insn_t *raw_insn, x86_insn_t *insn, | |
| 263 unsigned int prefixes ) { | |
| 264 size_t size, op_size; | |
| 265 unsigned char modrm; | |
| 266 | |
| 267 /* this should never happen, but just in case... */ | |
| 268 if ( raw_insn->mnem_flag == INS_INVALID ) { | |
| 269 return 0; | |
| 270 } | |
| 271 | |
| 272 if (ia32_settings.options & opt_16_bit) { | |
| 273 insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2; | |
| 274 insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2; | |
| 275 } else { | |
| 276 insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4; | |
| 277 insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4; | |
| 278 } | |
| 279 | |
| 280 | |
| 281 /* ++++ 1. Copy mnemonic and mnemonic-flags to CODE struct */ | |
| 282 if ((ia32_settings.options & opt_att_mnemonics) && raw_insn->mnemonic_at
t[0]) { | |
| 283 strncpy( insn->mnemonic, raw_insn->mnemonic_att, 16 ); | |
| 284 } | |
| 285 else { | |
| 286 strncpy( insn->mnemonic, raw_insn->mnemonic, 16 ); | |
| 287 } | |
| 288 ia32_handle_prefix( insn, prefixes ); | |
| 289 | |
| 290 handle_insn_metadata( insn, raw_insn ); | |
| 291 | |
| 292 /* prefetch the next byte in case it is a modr/m byte -- saves | |
| 293 * worrying about whether the 'mod/rm' operand or the 'reg' operand | |
| 294 * occurs first */ | |
| 295 modrm = GET_BYTE( buf, buf_len ); | |
| 296 | |
| 297 /* ++++ 2. Decode Explicit Operands */ | |
| 298 /* Intel uses up to 3 explicit operands in its instructions; | |
| 299 * the first is 'dest', the second is 'src', and the third | |
| 300 * is an additional source value (usually an immediate value, | |
| 301 * e.g. in the MUL instructions). These three explicit operands | |
| 302 * are encoded in the opcode tables, even if they are not used | |
| 303 * by the instruction. Additional implicit operands are stored | |
| 304 * in a supplemental table and are handled later. */ | |
| 305 | |
| 306 op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->dest, | |
| 307 raw_insn->dest_flag, prefixes, modrm ); | |
| 308 /* advance buffer, increase size if necessary */ | |
| 309 buf += op_size; | |
| 310 buf_len -= op_size; | |
| 311 size = op_size; | |
| 312 | |
| 313 op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->src, | |
| 314 raw_insn->src_flag, prefixes, modrm ); | |
| 315 buf += op_size; | |
| 316 buf_len -= op_size; | |
| 317 size += op_size; | |
| 318 | |
| 319 op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->aux, | |
| 320 raw_insn->aux_flag, prefixes, modrm ); | |
| 321 size += op_size; | |
| 322 | |
| 323 | |
| 324 /* ++++ 3. Decode Implicit Operands */ | |
| 325 /* apply implicit operands */ | |
| 326 ia32_insn_implicit_ops( insn, raw_insn->implicit_ops ); | |
| 327 /* we have one small inelegant hack here, to deal with | |
| 328 * the two prefixes that have implicit operands. If Intel | |
| 329 * adds more, we'll change the algorithm to suit :) */ | |
| 330 if ( (prefixes & PREFIX_REPZ) || (prefixes & PREFIX_REPNZ) ) { | |
| 331 ia32_insn_implicit_ops( insn, IDX_IMPLICIT_REP ); | |
| 332 } | |
| 333 | |
| 334 | |
| 335 /* 16-bit hack: foreach operand, if 32-bit reg, make 16-bit reg */ | |
| 336 if ( insn->op_size == 2 ) { | |
| 337 x86_operand_foreach( insn, reg_32_to_16, NULL, op_any ); | |
| 338 } | |
| 339 | |
| 340 return size; | |
| 341 } | |
| 342 | |
| 343 | |
| 344 /* convenience routine */ | |
| 345 #define USES_MOD_RM(flag) \ | |
| 346 (flag == ADDRMETH_E || flag == ADDRMETH_M || flag == ADDRMETH_Q || \ | |
| 347 flag == ADDRMETH_W || flag == ADDRMETH_R) | |
| 348 | |
| 349 static int uses_modrm_flag( unsigned int flag ) { | |
| 350 unsigned int meth; | |
| 351 if ( flag == ARG_NONE ) { | |
| 352 return 0; | |
| 353 } | |
| 354 meth = (flag & ADDRMETH_MASK); | |
| 355 if ( USES_MOD_RM(meth) ) { | |
| 356 return 1; | |
| 357 } | |
| 358 | |
| 359 return 0; | |
| 360 } | |
| 361 | |
| 362 /* This routine performs the actual byte-by-byte opcode table lookup. | |
| 363 * Originally it was pretty simple: get a byte, adjust it to a proper | |
| 364 * index into the table, then check the table row at that index to | |
| 365 * determine what to do next. But is anything that simple with Intel? | |
| 366 * This is now a huge, convoluted mess, mostly of bitter comments. */ | |
| 367 /* buf: pointer to next byte to read from stream | |
| 368 * buf_len: length of buf | |
| 369 * table: index of table to use for lookups | |
| 370 * raw_insn: output pointer that receives opcode definition | |
| 371 * prefixes: output integer that is encoded with prefixes in insn | |
| 372 * returns : number of bytes consumed from stream during lookup */ | |
| 373 size_t ia32_table_lookup( unsigned char *buf, size_t buf_len, | |
| 374 unsigned int table, ia32_insn_t **raw_insn, | |
| 375 unsigned int *prefixes ) { | |
| 376 unsigned char *next, op = buf[0]; /* byte value -- 'opcode' */ | |
| 377 size_t size = 1, sub_size = 0, next_len; | |
| 378 ia32_table_desc_t *table_desc; | |
| 379 unsigned int subtable, prefix = 0, recurse_table = 0; | |
| 380 | |
| 381 table_desc = &ia32_tables[table]; | |
| 382 | |
| 383 op = GET_BYTE( buf, buf_len ); | |
| 384 | |
| 385 if ( table_desc->type == tbl_fpu && op > table_desc->maxlim) { | |
| 386 /* one of the fucking FPU tables out of the 00-BH range */ | |
| 387 /* OK,. this is a bit of a hack -- the proper way would | |
| 388 * have been to use subtables in the 00-BF FPU opcode tables, | |
| 389 * but that is rather wasteful of space... */ | |
| 390 table_desc = &ia32_tables[table +1]; | |
| 391 } | |
| 392 | |
| 393 /* PERFORM TABLE LOOKUP */ | |
| 394 | |
| 395 /* ModR/M trick: shift extension bits into lowest bits of byte */ | |
| 396 /* Note: non-ModR/M tables have a shift value of 0 */ | |
| 397 op >>= table_desc->shift; | |
| 398 | |
| 399 /* ModR/M trick: mask out high bits to turn extension into an index */ | |
| 400 /* Note: non-ModR/M tables have a mask value of 0xFF */ | |
| 401 op &= table_desc->mask; | |
| 402 | |
| 403 | |
| 404 /* Sparse table trick: check that byte is <= max value */ | |
| 405 /* Note: full (256-entry) tables have a maxlim of 155 */ | |
| 406 if ( op > table_desc->maxlim ) { | |
| 407 /* this is a partial table, truncated at the tail, | |
| 408 and op is out of range! */ | |
| 409 return INVALID_INSN; | |
| 410 } | |
| 411 | |
| 412 /* Sparse table trick: check that byte is >= min value */ | |
| 413 /* Note: full (256-entry) tables have a minlim of 0 */ | |
| 414 if ( table_desc->minlim > op ) { | |
| 415 /* this is a partial table, truncated at the head, | |
| 416 and op is out of range! */ | |
| 417 return INVALID_INSN; | |
| 418 } | |
| 419 /* adjust op to be an offset from table index 0 */ | |
| 420 op -= table_desc->minlim; | |
| 421 | |
| 422 /* Yay! 'op' is now fully adjusted to be an index into 'table' */ | |
| 423 *raw_insn = &(table_desc->table[op]); | |
| 424 //printf("BYTE %X TABLE %d OP %X\n", buf[0], table, op ); | |
| 425 | |
| 426 if ( (*raw_insn)->mnem_flag & INS_FLAG_PREFIX ) { | |
| 427 prefix = (*raw_insn)->mnem_flag & PREFIX_MASK; | |
| 428 } | |
| 429 | |
| 430 | |
| 431 /* handle escape to a multibyte/coproc/extension/etc table */ | |
| 432 /* NOTE: if insn is a prefix and has a subtable, then we | |
| 433 * only recurse if this is the first prefix byte -- | |
| 434 * that is, if *prefixes is 0. | |
| 435 * NOTE also that suffix tables are handled later */ | |
| 436 subtable = (*raw_insn)->table; | |
| 437 | |
| 438 if ( subtable && ia32_tables[subtable].type != tbl_suffix && | |
| 439 (! prefix || ! *prefixes) ) { | |
| 440 | |
| 441 if ( ia32_tables[subtable].type == tbl_ext_ext || | |
| 442 ia32_tables[subtable].type == tbl_fpu_ext ) { | |
| 443 /* opcode extension: reuse current byte in buffer */ | |
| 444 next = buf; | |
| 445 next_len = buf_len; | |
| 446 } else { | |
| 447 /* "normal" opcode: advance to next byte in buffer */ | |
| 448 if ( buf_len > 1 ) { | |
| 449 next = &buf[1]; | |
| 450 next_len = buf_len - 1; | |
| 451 } | |
| 452 else { | |
| 453 // buffer is truncated | |
| 454 return INVALID_INSN; | |
| 455 } | |
| 456 } | |
| 457 /* we encountered a multibyte opcode: recurse using the | |
| 458 * table specified in the opcode definition */ | |
| 459 sub_size = ia32_table_lookup( next, next_len, subtable, | |
| 460 raw_insn, prefixes ); | |
| 461 | |
| 462 /* SSE/prefix hack: if the original opcode def was a | |
| 463 * prefix that specified a subtable, and the subtable | |
| 464 * lookup returned a valid insn, then we have encountered | |
| 465 * an SSE opcode definition; otherwise, we pretend we | |
| 466 * never did the subtable lookup, and deal with the | |
| 467 * prefix normally later */ | |
| 468 if ( prefix && ( sub_size == INVALID_INSN || | |
| 469 INS_TYPE((*raw_insn)->mnem_flag) == INS_INVALID ) ) { | |
| 470 /* this is a prefix, not an SSE insn : | |
| 471 * lookup next byte in main table, | |
| 472 * subsize will be reset during the | |
| 473 * main table lookup */ | |
| 474 recurse_table = 1; | |
| 475 } else { | |
| 476 /* this is either a subtable (two-byte) insn | |
| 477 * or an invalid insn: either way, set prefix | |
| 478 * to NULL and end the opcode lookup */ | |
| 479 prefix = 0; | |
| 480 // short-circuit lookup on invalid insn | |
| 481 if (sub_size == INVALID_INSN) return INVALID_INSN; | |
| 482 } | |
| 483 } else if ( prefix ) { | |
| 484 recurse_table = 1; | |
| 485 } | |
| 486 | |
| 487 /* by default, we assume that we have the opcode definition, | |
| 488 * and there is no need to recurse on the same table, but | |
| 489 * if we do then a prefix was encountered... */ | |
| 490 if ( recurse_table ) { | |
| 491 /* this must have been a prefix: use the same table for | |
| 492 * lookup of the next byte */ | |
| 493 sub_size = ia32_table_lookup( &buf[1], buf_len - 1, table, | |
| 494 raw_insn, prefixes ); | |
| 495 | |
| 496 // short-circuit lookup on invalid insn | |
| 497 if (sub_size == INVALID_INSN) return INVALID_INSN; | |
| 498 | |
| 499 /* a bit of a hack for branch hints */ | |
| 500 if ( prefix & BRANCH_HINT_MASK ) { | |
| 501 if ( INS_GROUP((*raw_insn)->mnem_flag) == INS_EXEC ) { | |
| 502 /* segment override prefixes are invalid for | |
| 503 * all branch instructions, so delete them */ | |
| 504 prefix &= ~PREFIX_REG_MASK; | |
| 505 } else { | |
| 506 prefix &= ~BRANCH_HINT_MASK; | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 /* apply prefix to instruction */ | |
| 511 | |
| 512 /* TODO: implement something enforcing prefix groups */ | |
| 513 (*prefixes) |= prefix; | |
| 514 } | |
| 515 | |
| 516 /* if this lookup was in a ModR/M table, then an opcode byte is | |
| 517 * NOT consumed: subtract accordingly. NOTE that if none of the | |
| 518 * operands used the ModR/M, then we need to consume the byte | |
| 519 * here, but ONLY in the 'top-level' opcode extension table */ | |
| 520 | |
| 521 if ( table_desc->type == tbl_ext_ext ) { | |
| 522 /* extensions-to-extensions never consume a byte */ | |
| 523 --size; | |
| 524 } else if ( (table_desc->type == tbl_extension || | |
| 525 table_desc->type == tbl_fpu || | |
| 526 table_desc->type == tbl_fpu_ext ) && | |
| 527 /* extensions that have an operand encoded in ModR/M | |
| 528 * never consume a byte */ | |
| 529 (uses_modrm_flag((*raw_insn)->dest_flag) || | |
| 530 uses_modrm_flag((*raw_insn)->src_flag) ) ) { | |
| 531 --size; | |
| 532 } | |
| 533 | |
| 534 size += sub_size; | |
| 535 | |
| 536 return size; | |
| 537 } | |
| 538 | |
| 539 static size_t handle_insn_suffix( unsigned char *buf, size_t buf_len, | |
| 540 ia32_insn_t *raw_insn, x86_insn_t * insn ) { | |
| 541 ia32_insn_t *sfx_insn; | |
| 542 size_t size; | |
| 543 unsigned int prefixes = 0; | |
| 544 | |
| 545 size = ia32_table_lookup( buf, buf_len, raw_insn->table, &sfx_insn, | |
| 546 &prefixes ); | |
| 547 if (size == INVALID_INSN || sfx_insn->mnem_flag == INS_INVALID ) { | |
| 548 return 0; | |
| 549 } | |
| 550 | |
| 551 strncpy( insn->mnemonic, sfx_insn->mnemonic, 16 ); | |
| 552 handle_insn_metadata( insn, sfx_insn ); | |
| 553 | |
| 554 return 1; | |
| 555 } | |
| 556 | |
| 557 /* invalid instructions are handled by returning 0 [error] from the | |
| 558 * function, setting the size of the insn to 1 byte, and copying | |
| 559 * the byte at the start of the invalid insn into the x86_insn_t. | |
| 560 * if the caller is saving the x86_insn_t for invalid instructions, | |
| 561 * instead of discarding them, this will maintain a consistent | |
| 562 * address space in the x86_insn_ts */ | |
| 563 | |
| 564 /* this function is called by the controlling disassembler, so its name and | |
| 565 * calling convention cannot be changed */ | |
| 566 /* buf points to the loc of the current opcode (start of the | |
| 567 * instruction) in the instruction stream. The instruction | |
| 568 * stream is assumed to be a buffer of bytes read directly | |
| 569 * from the file for the purpose of disassembly; a mem-mapped | |
| 570 * file is ideal for * this. | |
| 571 * insn points to a code structure to be filled by instr_decode | |
| 572 * returns the size of the decoded instruction in bytes */ | |
| 573 size_t ia32_disasm_addr( unsigned char * buf, size_t buf_len, | |
| 574 x86_insn_t *insn ) { | |
| 575 ia32_insn_t *raw_insn = NULL; | |
| 576 unsigned int prefixes = 0; | |
| 577 size_t size, sfx_size; | |
| 578 | |
| 579 if ( (ia32_settings.options & opt_ignore_nulls) && buf_len > 3 && | |
| 580 !buf[0] && !buf[1] && !buf[2] && !buf[3]) { | |
| 581 /* IF IGNORE_NULLS is set AND | |
| 582 * first 4 bytes in the intruction stream are NULL | |
| 583 * THEN return 0 (END_OF_DISASSEMBLY) */ | |
| 584 /* TODO: set errno */ | |
| 585 MAKE_INVALID( insn, buf ); | |
| 586 return 0; /* 4 00 bytes in a row? This isn't code! */ | |
| 587 } | |
| 588 | |
| 589 /* Perform recursive table lookup starting with main table (0) */ | |
| 590 size = ia32_table_lookup(buf, buf_len, idx_Main, &raw_insn, &prefixes); | |
| 591 if ( size == INVALID_INSN || size > buf_len || raw_insn->mnem_flag == IN
S_INVALID ) { | |
| 592 MAKE_INVALID( insn, buf ); | |
| 593 /* TODO: set errno */ | |
| 594 return 0; | |
| 595 } | |
| 596 | |
| 597 /* We now have the opcode itself figured out: we can decode | |
| 598 * the rest of the instruction. */ | |
| 599 size += ia32_decode_insn( &buf[size], buf_len - size, raw_insn, insn, | |
| 600 prefixes ); | |
| 601 if ( raw_insn->mnem_flag & INS_FLAG_SUFFIX ) { | |
| 602 /* AMD 3DNow! suffix -- get proper operand type here */ | |
| 603 sfx_size = handle_insn_suffix( &buf[size], buf_len - size, | |
| 604 raw_insn, insn ); | |
| 605 if (! sfx_size ) { | |
| 606 /* TODO: set errno */ | |
| 607 MAKE_INVALID( insn, buf ); | |
| 608 return 0; | |
| 609 } | |
| 610 | |
| 611 size += sfx_size; | |
| 612 } | |
| 613 | |
| 614 if (! size ) { | |
| 615 /* invalid insn */ | |
| 616 MAKE_INVALID( insn, buf ); | |
| 617 return 0; | |
| 618 } | |
| 619 | |
| 620 | |
| 621 insn->size = size; | |
| 622 return size; /* return size of instruction in bytes */ | |
| 623 } | |
| OLD | NEW |