| File: | root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/crashreporter/google-breakpad/src/processor/./../../../../../../toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.c |
| Warning: | line 376, column 23 Value stored to 'op' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 && (op->data.reg.id == 5 || op->data.reg.alias == 5) ) (op->type == op_register && \ |
| 20 | (op->data.reg.id == REG_ESP_INDEX5 || \ |
| 21 | op->data.reg.alias == REG_ESP_INDEX5) ) |
| 22 | #define IS_IMM( op )(op->type == op_immediate ) (op->type == op_immediate ) |
| 23 | |
| 24 | #ifdef WIN32 |
| 25 | # define INLINEinline |
| 26 | #else |
| 27 | # define INLINEinline inline |
| 28 | #endif |
| 29 | |
| 30 | /* for calculating stack modification based on an operand */ |
| 31 | static INLINEinline int32_t long_from_operand( x86_op_t *op ) { |
| 32 | |
| 33 | if (! IS_IMM(op)(op->type == op_immediate ) ) { |
| 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((void*)0); |
| 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 )(dest->type == op_register && (dest->data.reg.id == 5 || dest->data.reg.alias == 5) ) ) { |
| 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 )(dest->type == op_register && (dest->data.reg.id == 5 || dest->data.reg.alias == 5) ) ) { |
| 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 )(dest->type == op_register && (dest->data.reg.id == 5 || dest->data.reg.alias == 5) ) ) { |
| 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 )(dest->type == op_register && (dest->data.reg.id == 5 || dest->data.reg.alias == 5) ) ) { |
| 132 | insn->stack_mod = 1; |
| 133 | insn->stack_mod_val = 1; |
| 134 | } |
| 135 | break; |
| 136 | case insn_dec: |
| 137 | if ( IS_SP( dest )(dest->type == op_register && (dest->data.reg.id == 5 || dest->data.reg.alias == 5) ) ) { |
| 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 )(dest->type == op_register && (dest->data.reg.id == 5 || dest->data.reg.alias == 5) ) ) { |
| 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)(cpu & 0xFFFF); |
| 171 | insn->isa = (enum x86_insn_isa) (ISA_SUBSET(cpu)(cpu & 0xFFFF0000)) >> 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_MASK0xFF000000; |
| 178 | insn->group = (enum x86_insn_group) (INS_GROUP(type)( type & 0xF000 )) >> 12; |
| 179 | insn->type = (enum x86_insn_type) INS_TYPE(type)( type & 0xFFFF ); |
| 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)(eflags & 0x0000FFFF); |
| 194 | /* handle weird OR cases */ |
| 195 | /* these are either JLE (ZF | SF<>OF) or JBE (CF | ZF) */ |
| 196 | if (flags & INS_TEST_OR0x40) { |
| 197 | flags &= ~INS_TEST_OR0x40; |
| 198 | if ( flags & INS_TEST_ZERO0x02 ) { |
| 199 | flags &= ~INS_TEST_ZERO0x02; |
| 200 | if ( flags & INS_TEST_CARRY0x01 ) { |
| 201 | flags &= ~INS_TEST_CARRY0x01 ; |
| 202 | flags |= (int)insn_carry_or_zero_set; |
| 203 | } else if ( flags & INS_TEST_SFNEOF0x8000 ) { |
| 204 | flags &= ~INS_TEST_SFNEOF0x8000; |
| 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)(eflags & 0xFFFF0000) >> 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_MASK0xFFFF; // >> 20; |
| 219 | if (! (insn->prefix & PREFIX_PRINT_MASK0x000F) ) { |
| 220 | /* no printable prefixes */ |
| 221 | insn->prefix = insn_no_prefix; |
| 222 | } |
| 223 | |
| 224 | /* concat all prefix strings */ |
| 225 | if ( (unsigned int)insn->prefix & PREFIX_LOCK0x0004 ) { |
| 226 | strncat(insn->prefix_string, "lock ", 32 - |
| 227 | strlen(insn->prefix_string)); |
| 228 | } |
| 229 | |
| 230 | if ( (unsigned int)insn->prefix & PREFIX_REPNZ0x0002 ) { |
| 231 | strncat(insn->prefix_string, "repnz ", 32 - |
| 232 | strlen(insn->prefix_string)); |
| 233 | } else if ( (unsigned int)insn->prefix & PREFIX_REPZ0x0001 ) { |
| 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_INVALID0 ) { |
| 269 | return 0; |
| 270 | } |
| 271 | |
| 272 | if (ia32_settings.options & opt_16_bit) { |
| 273 | insn->op_size = ( prefixes & PREFIX_OP_SIZE0x0010 ) ? 4 : 2; |
| 274 | insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE0x0020 ) ? 4 : 2; |
| 275 | } else { |
| 276 | insn->op_size = ( prefixes & PREFIX_OP_SIZE0x0010 ) ? 2 : 4; |
| 277 | insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE0x0020 ) ? 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_att[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 )buf_len ? *buf : 0; |
| 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_REPZ0x0001) || (prefixes & PREFIX_REPNZ0x0002) ) { |
| 331 | ia32_insn_implicit_ops( insn, IDX_IMPLICIT_REP41 ); |
| 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((void*)0), op_any ); |
| 338 | } |
| 339 | |
| 340 | return size; |
| 341 | } |
| 342 | |
| 343 | |
| 344 | /* convenience routine */ |
| 345 | #define USES_MOD_RM(flag)(flag == 0x00040000 || flag == 0x00090000 || flag == 0x000C0000 || flag == 0x00110000 || flag == 0x000D0000) \ |
| 346 | (flag == ADDRMETH_E0x00040000 || flag == ADDRMETH_M0x00090000 || flag == ADDRMETH_Q0x000C0000 || \ |
| 347 | flag == ADDRMETH_W0x00110000 || flag == ADDRMETH_R0x000D0000) |
| 348 | |
| 349 | static int uses_modrm_flag( unsigned int flag ) { |
| 350 | unsigned int meth; |
| 351 | if ( flag == ARG_NONE0 ) { |
| 352 | return 0; |
| 353 | } |
| 354 | meth = (flag & ADDRMETH_MASK0x00FF0000); |
| 355 | if ( USES_MOD_RM(meth)(meth == 0x00040000 || meth == 0x00090000 || meth == 0x000C0000 || meth == 0x00110000 || meth == 0x000D0000) ) { |
| 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' */ |
Value stored to 'op' during its initialization is never read | |
| 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 )buf_len ? *buf : 0; |
| 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((size_t) -1); |
| 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((size_t) -1); |
| 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_PREFIX0x10000000 ) { |
| 427 | prefix = (*raw_insn)->mnem_flag & PREFIX_MASK0xFFFF; |
| 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((size_t) -1); |
| 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((size_t) -1) || |
| 469 | INS_TYPE((*raw_insn)->mnem_flag)( (*raw_insn)->mnem_flag & 0xFFFF ) == INS_INVALID0 ) ) { |
| 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((size_t) -1)) return INVALID_INSN((size_t) -1); |
| 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((size_t) -1)) return INVALID_INSN((size_t) -1); |
| 498 | |
| 499 | /* a bit of a hack for branch hints */ |
| 500 | if ( prefix & BRANCH_HINT_MASK0x3000 ) { |
| 501 | if ( INS_GROUP((*raw_insn)->mnem_flag)( (*raw_insn)->mnem_flag & 0xF000 ) == INS_EXEC0x1000 ) { |
| 502 | /* segment override prefixes are invalid for |
| 503 | * all branch instructions, so delete them */ |
| 504 | prefix &= ~PREFIX_REG_MASK0x0F00; |
| 505 | } else { |
| 506 | prefix &= ~BRANCH_HINT_MASK0x3000; |
| 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((size_t) -1) || sfx_insn->mnem_flag == INS_INVALID0 ) { |
| 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((void*)0); |
| 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 )strcpy( insn->mnemonic, "invalid" ); x86_oplist_free( insn ); insn->size = 1; insn->group = insn_none; insn->type = insn_invalid; memcpy( insn->bytes, buf, 1 );; |
| 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_Main0, &raw_insn, &prefixes); |
| 591 | if ( size == INVALID_INSN((size_t) -1) || size > buf_len || raw_insn->mnem_flag == INS_INVALID0 ) { |
| 592 | MAKE_INVALID( insn, buf )strcpy( insn->mnemonic, "invalid" ); x86_oplist_free( insn ); insn->size = 1; insn->group = insn_none; insn->type = insn_invalid; memcpy( insn->bytes, buf, 1 );; |
| 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_SUFFIX0x20000000 ) { |
| 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 )strcpy( insn->mnemonic, "invalid" ); x86_oplist_free( insn ); insn->size = 1; insn->group = insn_none; insn->type = insn_invalid; memcpy( insn->bytes, buf, 1 );; |
| 608 | return 0; |
| 609 | } |
| 610 | |
| 611 | size += sfx_size; |
| 612 | } |
| 613 | |
| 614 | if (! size ) { |
| 615 | /* invalid insn */ |
| 616 | MAKE_INVALID( insn, buf )strcpy( insn->mnemonic, "invalid" ); x86_oplist_free( insn ); insn->size = 1; insn->group = insn_none; insn->type = insn_invalid; memcpy( insn->bytes, buf, 1 );; |
| 617 | return 0; |
| 618 | } |
| 619 | |
| 620 | |
| 621 | insn->size = size; |
| 622 | return size; /* return size of instruction in bytes */ |
| 623 | } |