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_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 ); |
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 == INS_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 | } |
624 | |