1 | #include <stdio.h> |
2 | #include <stdlib.h> |
3 | #include <string.h> |
4 | |
5 | #include "libdis.h" |
6 | #include <inttypes.h> |
7 | |
8 | #ifdef _MSC_VER |
9 | #define snprintf _snprintf |
10 | #define inline __inline |
11 | #endif |
12 | |
13 | |
14 | /* |
15 | * concatenation macros. STRNCATF concatenates a format string, buf |
16 | * only with one argument. |
17 | */ |
18 | #define STRNCAT( buf, str, len ) do { \ |
19 | int _i = strlen(str), _blen = strlen(buf), _len = len - 1; \ |
20 | if ( len ) { \ |
21 | strncat( buf, str, _len ); \ |
22 | if ( _len <= _i ) { \ |
23 | buf[_blen+_len] = '\0'; \ |
24 | len = 0; \ |
25 | } else { \ |
26 | len -= _i; \ |
27 | } \ |
28 | } \ |
29 | } while( 0 ) |
30 | |
31 | #define STRNCATF( buf, fmt, data, len ) do { \ |
32 | char _tmp[MAX_OP_STRING]; \ |
33 | \ |
34 | snprintf( _tmp, sizeof _tmp, fmt, data ); \ |
35 | STRNCAT( buf, _tmp, len ); \ |
36 | } while( 0 ) |
37 | |
38 | |
39 | #define PRINT_DISPLACEMENT( ea ) do { \ |
40 | if ( ea->disp_size && ea->disp ) { \ |
41 | if ( ea->disp_sign ) { \ |
42 | STRNCATF( buf, "-0x%" PRIX32, -ea->disp, len ); \ |
43 | } else { \ |
44 | STRNCATF( buf, "0x%" PRIX32, ea->disp, len ); \ |
45 | } \ |
46 | } \ |
47 | } while( 0 ) |
48 | |
49 | static const char *prefix_strings[] = { |
50 | "" , /* no prefix */ |
51 | "repz " , /* the trailing spaces make it easy to prepend to mnemonic */ |
52 | "repnz " , |
53 | "lock " , |
54 | "branch delay " /* unused in x86 */ |
55 | }; |
56 | |
57 | static int format_insn_prefix_str( enum x86_insn_prefix prefix, char *buf, |
58 | int len ) { |
59 | |
60 | int len_orig = len; |
61 | |
62 | /* concat all prefix strings */ |
63 | if ( prefix & 1 ) { STRNCAT( buf, prefix_strings[1], len ); } |
64 | if ( prefix & 2 ) { STRNCAT( buf, prefix_strings[2], len ); } |
65 | if ( prefix & 4 ) { STRNCAT( buf, prefix_strings[3], len ); } |
66 | if ( prefix & 8 ) { STRNCAT( buf, prefix_strings[4], len ); } |
67 | |
68 | /* return the number of characters added */ |
69 | return (len_orig - len); |
70 | } |
71 | |
72 | /* |
73 | * sprint's an operand's data to string str. |
74 | */ |
75 | static void get_operand_data_str( x86_op_t *op, char *str, int len ){ |
76 | |
77 | if ( op->flags & op_signed ) { |
78 | switch ( op->datatype ) { |
79 | case op_byte: |
80 | snprintf( str, len, "%" PRId8, op->data.sbyte ); |
81 | return; |
82 | case op_word: |
83 | snprintf( str, len, "%" PRId16, op->data.sword ); |
84 | return; |
85 | case op_qword: |
86 | snprintf( str, len, "%" PRId64, op->data.sqword ); |
87 | return; |
88 | default: |
89 | snprintf( str, len, "%" PRId32, op->data.sdword ); |
90 | return; |
91 | } |
92 | } |
93 | |
94 | //else |
95 | switch ( op->datatype ) { |
96 | case op_byte: |
97 | snprintf( str, len, "0x%02" PRIX8, op->data.byte ); |
98 | return; |
99 | case op_word: |
100 | snprintf( str, len, "0x%04" PRIX16, op->data.word ); |
101 | return; |
102 | case op_qword: |
103 | snprintf( str, len, "0x%08" PRIX64,op->data.sqword ); |
104 | return; |
105 | default: |
106 | snprintf( str, len, "0x%08" PRIX32, op->data.dword ); |
107 | return; |
108 | } |
109 | } |
110 | |
111 | /* |
112 | * sprints register types to a string. the register types can be ORed |
113 | * together. |
114 | */ |
115 | static void get_operand_regtype_str( int regtype, char *str, int len ) |
116 | { |
117 | static struct { |
118 | const char *name; |
119 | int value; |
120 | } operand_regtypes[] = { |
121 | {"reg_gen" , 0x00001}, |
122 | {"reg_in" , 0x00002}, |
123 | {"reg_out" , 0x00004}, |
124 | {"reg_local" , 0x00008}, |
125 | {"reg_fpu" , 0x00010}, |
126 | {"reg_seg" , 0x00020}, |
127 | {"reg_simd" , 0x00040}, |
128 | {"reg_sys" , 0x00080}, |
129 | {"reg_sp" , 0x00100}, |
130 | {"reg_fp" , 0x00200}, |
131 | {"reg_pc" , 0x00400}, |
132 | {"reg_retaddr" , 0x00800}, |
133 | {"reg_cond" , 0x01000}, |
134 | {"reg_zero" , 0x02000}, |
135 | {"reg_ret" , 0x04000}, |
136 | {"reg_src" , 0x10000}, |
137 | {"reg_dest" , 0x20000}, |
138 | {"reg_count" , 0x40000}, |
139 | {NULL, 0}, //end |
140 | }; |
141 | |
142 | unsigned int i; |
143 | |
144 | memset( str, 0, len ); |
145 | |
146 | //go thru every type in the enum |
147 | for ( i = 0; operand_regtypes[i].name; i++ ) { |
148 | //skip if type is not set |
149 | if(! (regtype & operand_regtypes[i].value) ) |
150 | continue; |
151 | |
152 | //not the first time around |
153 | if( str[0] ) { |
154 | STRNCAT( str, " " , len ); |
155 | } |
156 | |
157 | STRNCAT(str, operand_regtypes[i].name, len ); |
158 | } |
159 | } |
160 | |
161 | static int format_expr( x86_ea_t *ea, char *buf, int len, |
162 | enum x86_asm_format format ) { |
163 | char str[MAX_OP_STRING]; |
164 | |
165 | if ( format == att_syntax ) { |
166 | if (ea->base.name[0] || ea->index.name[0] || ea->scale) { |
167 | PRINT_DISPLACEMENT(ea); |
168 | STRNCAT( buf, "(" , len ); |
169 | |
170 | if ( ea->base.name[0]) { |
171 | STRNCATF( buf, "%%%s" , ea->base.name, len ); |
172 | } |
173 | if ( ea->index.name[0]) { |
174 | STRNCATF( buf, ",%%%s" , ea->index.name, len ); |
175 | if ( ea->scale > 1 ) { |
176 | STRNCATF( buf, ",%d" , ea->scale, len ); |
177 | } |
178 | } |
179 | /* handle the syntactic exception */ |
180 | if ( ! ea->base.name[0] && |
181 | ! ea->index.name[0] ) { |
182 | STRNCATF( buf, ",%d" , ea->scale, len ); |
183 | } |
184 | |
185 | STRNCAT( buf, ")" , len ); |
186 | } else |
187 | STRNCATF( buf, "0x%" PRIX32, ea->disp, len ); |
188 | |
189 | } else if ( format == xml_syntax ){ |
190 | |
191 | if ( ea->base.name[0]) { |
192 | STRNCAT (buf, "\t\t\t<base>\n" , len); |
193 | |
194 | get_operand_regtype_str (ea->base.type, str, |
195 | sizeof str); |
196 | STRNCAT (buf, "\t\t\t\t<register " , len); |
197 | STRNCATF (buf, "name=\"%s\" " , ea->base.name, len); |
198 | STRNCATF (buf, "type=\"%s\" " , str, len); |
199 | STRNCATF (buf, "size=%d/>\n" , ea->base.size, len); |
200 | |
201 | STRNCAT (buf, "\t\t\t</base>\n" , len); |
202 | } |
203 | |
204 | if ( ea->index.name[0]) { |
205 | STRNCAT (buf, "\t\t\t<index>\n" , len); |
206 | |
207 | get_operand_regtype_str (ea->index.type, str, |
208 | sizeof str); |
209 | |
210 | STRNCAT (buf, "\t\t\t\t<register " , len); |
211 | STRNCATF (buf, "name=\"%s\" " , ea->index.name, len); |
212 | STRNCATF (buf, "type=\"%s\" " , str, len); |
213 | STRNCATF (buf, "size=%d/>\n" , ea->index.size, len); |
214 | |
215 | STRNCAT (buf, "\t\t\t</index>\n" , len); |
216 | } |
217 | |
218 | //scale |
219 | STRNCAT (buf, "\t\t\t<scale>\n" , len); |
220 | STRNCAT (buf, "\t\t\t\t<immediate " , len); |
221 | STRNCATF (buf, "value=\"%d\"/>\n" , ea->scale, len); |
222 | STRNCAT (buf, "\t\t\t</scale>\n" , len); |
223 | |
224 | if ( ea->disp_size ) { |
225 | |
226 | STRNCAT (buf, "\t\t\t<displacement>\n" , len); |
227 | |
228 | if ( ea->disp_size > 1 && ! ea->disp_sign ) { |
229 | STRNCAT (buf, "\t\t\t\t<address " , len); |
230 | STRNCATF (buf, "value=\"0x%" PRIX32 "\"/>\n" , ea->disp, |
231 | len); |
232 | } else { |
233 | STRNCAT (buf, "\t\t\t\t<immediate " , len); |
234 | STRNCATF (buf, "value=%" PRId32 "/>\n" , ea->disp, len); |
235 | } |
236 | |
237 | STRNCAT (buf, "\t\t\t</displacement>\n" , len); |
238 | } |
239 | |
240 | } else if ( format == raw_syntax ) { |
241 | |
242 | PRINT_DISPLACEMENT(ea); |
243 | STRNCAT( buf, "(" , len ); |
244 | |
245 | STRNCATF( buf, "%s," , ea->base.name, len ); |
246 | STRNCATF( buf, "%s," , ea->index.name, len ); |
247 | STRNCATF( buf, "%d" , ea->scale, len ); |
248 | STRNCAT( buf, ")" , len ); |
249 | |
250 | } else { |
251 | |
252 | STRNCAT( buf, "[" , len ); |
253 | |
254 | if ( ea->base.name[0] ) { |
255 | STRNCAT( buf, ea->base.name, len ); |
256 | if ( ea->index.name[0] || |
257 | (ea->disp_size && ! ea->disp_sign) ) { |
258 | STRNCAT( buf, "+" , len ); |
259 | } |
260 | } |
261 | if ( ea->index.name[0] ) { |
262 | STRNCAT( buf, ea->index.name, len ); |
263 | if ( ea->scale > 1 ) |
264 | { |
265 | STRNCATF( buf, "*%" PRId32, ea->scale, len ); |
266 | } |
267 | if ( ea->disp_size && ! ea->disp_sign ) |
268 | { |
269 | STRNCAT( buf, "+" , len ); |
270 | } |
271 | } |
272 | |
273 | if ( ea->disp_size || (! ea->index.name[0] && |
274 | ! ea->base.name[0] ) ) |
275 | { |
276 | PRINT_DISPLACEMENT(ea); |
277 | } |
278 | |
279 | STRNCAT( buf, "]" , len ); |
280 | } |
281 | |
282 | return( strlen(buf) ); |
283 | } |
284 | |
285 | static int format_seg( x86_op_t *op, char *buf, int len, |
286 | enum x86_asm_format format ) { |
287 | int len_orig = len; |
288 | const char *reg = "" ; |
289 | |
290 | if (! op || ! buf || ! len || ! op->flags) { |
291 | return(0); |
292 | } |
293 | if ( op->type != op_offset && op->type != op_expression ){ |
294 | return(0); |
295 | } |
296 | if (! ((int) op->flags & 0xF00) ) { |
297 | return(0); |
298 | } |
299 | |
300 | switch (op->flags & 0xF00) { |
301 | case op_es_seg: reg = "es" ; break; |
302 | case op_cs_seg: reg = "cs" ; break; |
303 | case op_ss_seg: reg = "ss" ; break; |
304 | case op_ds_seg: reg = "ds" ; break; |
305 | case op_fs_seg: reg = "fs" ; break; |
306 | case op_gs_seg: reg = "gs" ; break; |
307 | default: |
308 | break; |
309 | } |
310 | |
311 | if (! reg[0] ) { |
312 | return( 0 ); |
313 | } |
314 | |
315 | switch( format ) { |
316 | case xml_syntax: |
317 | STRNCAT( buf, "\t\t\t<segment " , len ); |
318 | STRNCATF( buf, "value=\"%s\"/>\n" , reg, len ); |
319 | break; |
320 | case att_syntax: |
321 | STRNCATF( buf, "%%%s:" , reg, len ); |
322 | break; |
323 | |
324 | default: |
325 | STRNCATF( buf, "%s:" , reg, len ); |
326 | break; |
327 | } |
328 | |
329 | return( len_orig - len ); /* return length of appended string */ |
330 | } |
331 | |
332 | static const char *get_operand_datatype_str( x86_op_t *op ){ |
333 | |
334 | static const char *types[] = { |
335 | "sbyte" , /* 0 */ |
336 | "sword" , |
337 | "sqword" , |
338 | "sdword" , |
339 | "sdqword" , /* 4 */ |
340 | "byte" , |
341 | "word" , |
342 | "qword" , |
343 | "dword" , /* 8 */ |
344 | "dqword" , |
345 | "sreal" , |
346 | "dreal" , |
347 | "extreal" , /* 12 */ |
348 | "bcd" , |
349 | "ssimd" , |
350 | "dsimd" , |
351 | "sssimd" , /* 16 */ |
352 | "sdsimd" , |
353 | "descr32" , |
354 | "descr16" , |
355 | "pdescr32" , /* 20 */ |
356 | "pdescr16" , |
357 | "bounds16" , |
358 | "bounds32" , |
359 | "fpu_env16" , |
360 | "fpu_env32" , /* 25 */ |
361 | "fpu_state16" , |
362 | "fpu_state32" , |
363 | "fp_reg_set" |
364 | }; |
365 | |
366 | /* handle signed values first */ |
367 | if ( op->flags & op_signed ) { |
368 | switch (op->datatype) { |
369 | case op_byte: return types[0]; |
370 | case op_word: return types[1]; |
371 | case op_qword: return types[2]; |
372 | case op_dqword: return types[4]; |
373 | default: return types[3]; |
374 | } |
375 | } |
376 | |
377 | switch (op->datatype) { |
378 | case op_byte: return types[5]; |
379 | case op_word: return types[6]; |
380 | case op_qword: return types[7]; |
381 | case op_dqword: return types[9]; |
382 | case op_sreal: return types[10]; |
383 | case op_dreal: return types[11]; |
384 | case op_extreal: return types[12]; |
385 | case op_bcd: return types[13]; |
386 | case op_ssimd: return types[14]; |
387 | case op_dsimd: return types[15]; |
388 | case op_sssimd: return types[16]; |
389 | case op_sdsimd: return types[17]; |
390 | case op_descr32: return types[18]; |
391 | case op_descr16: return types[19]; |
392 | case op_pdescr32: return types[20]; |
393 | case op_pdescr16: return types[21]; |
394 | case op_bounds16: return types[22]; |
395 | case op_bounds32: return types[23]; |
396 | case op_fpustate16: return types[24]; |
397 | case op_fpustate32: return types[25]; |
398 | case op_fpuenv16: return types[26]; |
399 | case op_fpuenv32: return types[27]; |
400 | case op_fpregset: return types[28]; |
401 | default: return types[8]; |
402 | } |
403 | } |
404 | |
405 | static int format_insn_eflags_str( enum x86_flag_status flags, char *buf, |
406 | int len) { |
407 | |
408 | static struct { |
409 | const char *name; |
410 | int value; |
411 | } insn_flags[] = { |
412 | { "carry_set " , 0x0001 }, |
413 | { "zero_set " , 0x0002 }, |
414 | { "oflow_set " , 0x0004 }, |
415 | { "dir_set " , 0x0008 }, |
416 | { "sign_set " , 0x0010 }, |
417 | { "parity_set " , 0x0020 }, |
418 | { "carry_or_zero_set " , 0x0040 }, |
419 | { "zero_set_or_sign_ne_oflow " , 0x0080 }, |
420 | { "carry_clear " , 0x0100 }, |
421 | { "zero_clear " , 0x0200 }, |
422 | { "oflow_clear " , 0x0400 }, |
423 | { "dir_clear " , 0x0800 }, |
424 | { "sign_clear " , 0x1000 }, |
425 | { "parity_clear " , 0x2000 }, |
426 | { "sign_eq_oflow " , 0x4000 }, |
427 | { "sign_ne_oflow " , 0x8000 }, |
428 | { NULL, 0x0000 }, //end |
429 | }; |
430 | |
431 | unsigned int i; |
432 | int len_orig = len; |
433 | |
434 | for (i = 0; insn_flags[i].name; i++) { |
435 | if (! (flags & insn_flags[i].value) ) |
436 | continue; |
437 | |
438 | STRNCAT( buf, insn_flags[i].name, len ); |
439 | } |
440 | |
441 | return( len_orig - len ); |
442 | } |
443 | |
444 | static const char *get_insn_group_str( enum x86_insn_group gp ) { |
445 | |
446 | static const char *types[] = { |
447 | "" , // 0 |
448 | "controlflow" ,// 1 |
449 | "arithmetic" , // 2 |
450 | "logic" , // 3 |
451 | "stack" , // 4 |
452 | "comparison" , // 5 |
453 | "move" , // 6 |
454 | "string" , // 7 |
455 | "bit_manip" , // 8 |
456 | "flag_manip" , // 9 |
457 | "fpu" , // 10 |
458 | "" , // 11 |
459 | "" , // 12 |
460 | "interrupt" , // 13 |
461 | "system" , // 14 |
462 | "other" , // 15 |
463 | }; |
464 | |
465 | if ( gp > sizeof (types)/sizeof(types[0]) ) |
466 | return "" ; |
467 | |
468 | return types[gp]; |
469 | } |
470 | |
471 | static const char *get_insn_type_str( enum x86_insn_type type ) { |
472 | |
473 | static struct { |
474 | const char *name; |
475 | int value; |
476 | } types[] = { |
477 | /* insn_controlflow */ |
478 | { "jmp" , 0x1001 }, |
479 | { "jcc" , 0x1002 }, |
480 | { "call" , 0x1003 }, |
481 | { "callcc" , 0x1004 }, |
482 | { "return" , 0x1005 }, |
483 | { "loop" , 0x1006 }, |
484 | /* insn_arithmetic */ |
485 | { "add" , 0x2001 }, |
486 | { "sub" , 0x2002 }, |
487 | { "mul" , 0x2003 }, |
488 | { "div" , 0x2004 }, |
489 | { "inc" , 0x2005 }, |
490 | { "dec" , 0x2006 }, |
491 | { "shl" , 0x2007 }, |
492 | { "shr" , 0x2008 }, |
493 | { "rol" , 0x2009 }, |
494 | { "ror" , 0x200A }, |
495 | /* insn_logic */ |
496 | { "and" , 0x3001 }, |
497 | { "or" , 0x3002 }, |
498 | { "xor" , 0x3003 }, |
499 | { "not" , 0x3004 }, |
500 | { "neg" , 0x3005 }, |
501 | /* insn_stack */ |
502 | { "push" , 0x4001 }, |
503 | { "pop" , 0x4002 }, |
504 | { "pushregs" , 0x4003 }, |
505 | { "popregs" , 0x4004 }, |
506 | { "pushflags" , 0x4005 }, |
507 | { "popflags" , 0x4006 }, |
508 | { "enter" , 0x4007 }, |
509 | { "leave" , 0x4008 }, |
510 | /* insn_comparison */ |
511 | { "test" , 0x5001 }, |
512 | { "cmp" , 0x5002 }, |
513 | /* insn_move */ |
514 | { "mov" , 0x6001 }, /* move */ |
515 | { "movcc" , 0x6002 }, /* conditional move */ |
516 | { "xchg" , 0x6003 }, /* exchange */ |
517 | { "xchgcc" , 0x6004 }, /* conditional exchange */ |
518 | /* insn_string */ |
519 | { "strcmp" , 0x7001 }, |
520 | { "strload" , 0x7002 }, |
521 | { "strmov" , 0x7003 }, |
522 | { "strstore" , 0x7004 }, |
523 | { "translate" , 0x7005 }, /* xlat */ |
524 | /* insn_bit_manip */ |
525 | { "bittest" , 0x8001 }, |
526 | { "bitset" , 0x8002 }, |
527 | { "bitclear" , 0x8003 }, |
528 | /* insn_flag_manip */ |
529 | { "clear_carry" , 0x9001 }, |
530 | { "clear_zero" , 0x9002 }, |
531 | { "clear_oflow" , 0x9003 }, |
532 | { "clear_dir" , 0x9004 }, |
533 | { "clear_sign" , 0x9005 }, |
534 | { "clear_parity" , 0x9006 }, |
535 | { "set_carry" , 0x9007 }, |
536 | { "set_zero" , 0x9008 }, |
537 | { "set_oflow" , 0x9009 }, |
538 | { "set_dir" , 0x900A }, |
539 | { "set_sign" , 0x900B }, |
540 | { "set_parity" , 0x900C }, |
541 | { "tog_carry" , 0x9010 }, |
542 | { "tog_zero" , 0x9020 }, |
543 | { "tog_oflow" , 0x9030 }, |
544 | { "tog_dir" , 0x9040 }, |
545 | { "tog_sign" , 0x9050 }, |
546 | { "tog_parity" , 0x9060 }, |
547 | /* insn_fpu */ |
548 | { "fmov" , 0xA001 }, |
549 | { "fmovcc" , 0xA002 }, |
550 | { "fneg" , 0xA003 }, |
551 | { "fabs" , 0xA004 }, |
552 | { "fadd" , 0xA005 }, |
553 | { "fsub" , 0xA006 }, |
554 | { "fmul" , 0xA007 }, |
555 | { "fdiv" , 0xA008 }, |
556 | { "fsqrt" , 0xA009 }, |
557 | { "fcmp" , 0xA00A }, |
558 | { "fcos" , 0xA00C }, |
559 | { "fldpi" , 0xA00D }, |
560 | { "fldz" , 0xA00E }, |
561 | { "ftan" , 0xA00F }, |
562 | { "fsine" , 0xA010 }, |
563 | { "fsys" , 0xA020 }, |
564 | /* insn_interrupt */ |
565 | { "int" , 0xD001 }, |
566 | { "intcc" , 0xD002 }, /* not present in x86 ISA */ |
567 | { "iret" , 0xD003 }, |
568 | { "bound" , 0xD004 }, |
569 | { "debug" , 0xD005 }, |
570 | { "trace" , 0xD006 }, |
571 | { "invalid_op" , 0xD007 }, |
572 | { "oflow" , 0xD008 }, |
573 | /* insn_system */ |
574 | { "halt" , 0xE001 }, |
575 | { "in" , 0xE002 }, /* input from port/bus */ |
576 | { "out" , 0xE003 }, /* output to port/bus */ |
577 | { "cpuid" , 0xE004 }, |
578 | /* insn_other */ |
579 | { "nop" , 0xF001 }, |
580 | { "bcdconv" , 0xF002 }, /* convert to or from BCD */ |
581 | { "szconv" , 0xF003 }, /* change size of operand */ |
582 | { NULL, 0 }, //end |
583 | }; |
584 | |
585 | unsigned int i; |
586 | |
587 | //go thru every type in the enum |
588 | for ( i = 0; types[i].name; i++ ) { |
589 | if ( types[i].value == type ) |
590 | return types[i].name; |
591 | } |
592 | |
593 | return "" ; |
594 | } |
595 | |
596 | static const char *get_insn_cpu_str( enum x86_insn_cpu cpu ) { |
597 | static const char *intel[] = { |
598 | "" , // 0 |
599 | "8086" , // 1 |
600 | "80286" , // 2 |
601 | "80386" , // 3 |
602 | "80387" , // 4 |
603 | "80486" , // 5 |
604 | "Pentium" , // 6 |
605 | "Pentium Pro" , // 7 |
606 | "Pentium 2" , // 8 |
607 | "Pentium 3" , // 9 |
608 | "Pentium 4" // 10 |
609 | }; |
610 | |
611 | if ( cpu < sizeof(intel)/sizeof(intel[0]) ) { |
612 | return intel[cpu]; |
613 | } else if ( cpu == 16 ) { |
614 | return "K6" ; |
615 | } else if ( cpu == 32 ) { |
616 | return "K7" ; |
617 | } else if ( cpu == 48 ) { |
618 | return "Athlon" ; |
619 | } |
620 | |
621 | return "" ; |
622 | } |
623 | |
624 | static const char *get_insn_isa_str( enum x86_insn_isa isa ) { |
625 | static const char *subset[] = { |
626 | NULL, // 0 |
627 | "General Purpose" , // 1 |
628 | "Floating Point" , // 2 |
629 | "FPU Management" , // 3 |
630 | "MMX" , // 4 |
631 | "SSE" , // 5 |
632 | "SSE2" , // 6 |
633 | "SSE3" , // 7 |
634 | "3DNow!" , // 8 |
635 | "System" // 9 |
636 | }; |
637 | |
638 | if ( isa > sizeof (subset)/sizeof(subset[0]) ) { |
639 | return "" ; |
640 | } |
641 | |
642 | return subset[isa]; |
643 | } |
644 | |
645 | static int format_operand_att( x86_op_t *op, x86_insn_t *insn, char *buf, |
646 | int len){ |
647 | |
648 | char str[MAX_OP_STRING]; |
649 | |
650 | memset (str, 0, sizeof str); |
651 | |
652 | switch ( op->type ) { |
653 | case op_register: |
654 | STRNCATF( buf, "%%%s" , op->data.reg.name, len ); |
655 | break; |
656 | |
657 | case op_immediate: |
658 | get_operand_data_str( op, str, sizeof str ); |
659 | STRNCATF( buf, "$%s" , str, len ); |
660 | break; |
661 | |
662 | case op_relative_near: |
663 | STRNCATF( buf, "0x%08X" , |
664 | (unsigned int)(op->data.sbyte + |
665 | insn->addr + insn->size), len ); |
666 | break; |
667 | |
668 | case op_relative_far: |
669 | if (op->datatype == op_word) { |
670 | STRNCATF( buf, "0x%08X" , |
671 | (unsigned int)(op->data.sword + |
672 | insn->addr + insn->size), len ); |
673 | } else { |
674 | STRNCATF( buf, "0x%08X" , |
675 | (unsigned int)(op->data.sdword + |
676 | insn->addr + insn->size), len ); |
677 | } |
678 | break; |
679 | |
680 | case op_absolute: |
681 | /* ATT uses the syntax $section, $offset */ |
682 | STRNCATF( buf, "$0x%04" PRIX16 ", " , op->data.absolute.segment, |
683 | len ); |
684 | if (op->datatype == op_descr16) { |
685 | STRNCATF( buf, "$0x%04" PRIX16, |
686 | op->data.absolute.offset.off16, len ); |
687 | } else { |
688 | STRNCATF( buf, "$0x%08" PRIX32, |
689 | op->data.absolute.offset.off32, len ); |
690 | } |
691 | break; |
692 | case op_offset: |
693 | /* ATT requires a '*' before JMP/CALL ops */ |
694 | if (insn->type == insn_jmp || insn->type == insn_call) |
695 | STRNCAT( buf, "*" , len ); |
696 | |
697 | len -= format_seg( op, buf, len, att_syntax ); |
698 | STRNCATF( buf, "0x%08" PRIX32, op->data.sdword, len ); |
699 | break; |
700 | |
701 | case op_expression: |
702 | /* ATT requires a '*' before JMP/CALL ops */ |
703 | if (insn->type == insn_jmp || insn->type == insn_call) |
704 | STRNCAT( buf, "*" , len ); |
705 | |
706 | len -= format_seg( op, buf, len, att_syntax ); |
707 | len -= format_expr( &op->data.expression, buf, len, |
708 | att_syntax ); |
709 | break; |
710 | case op_unused: |
711 | case op_unknown: |
712 | /* return 0-truncated buffer */ |
713 | break; |
714 | } |
715 | |
716 | return ( strlen( buf ) ); |
717 | } |
718 | |
719 | static int format_operand_native( x86_op_t *op, x86_insn_t *insn, char *buf, |
720 | int len){ |
721 | |
722 | char str[MAX_OP_STRING]; |
723 | |
724 | switch (op->type) { |
725 | case op_register: |
726 | STRNCAT( buf, op->data.reg.name, len ); |
727 | break; |
728 | |
729 | case op_immediate: |
730 | get_operand_data_str( op, str, sizeof str ); |
731 | STRNCAT( buf, str, len ); |
732 | break; |
733 | |
734 | case op_relative_near: |
735 | STRNCATF( buf, "0x%08" PRIX32, |
736 | (unsigned int)(op->data.sbyte + |
737 | insn->addr + insn->size), len ); |
738 | break; |
739 | |
740 | case op_relative_far: |
741 | if ( op->datatype == op_word ) { |
742 | STRNCATF( buf, "0x%08" PRIX32, |
743 | (unsigned int)(op->data.sword + |
744 | insn->addr + insn->size), len ); |
745 | break; |
746 | } else { |
747 | STRNCATF( buf, "0x%08" PRIX32, op->data.sdword + |
748 | insn->addr + insn->size, len ); |
749 | } |
750 | break; |
751 | |
752 | case op_absolute: |
753 | STRNCATF( buf, "$0x%04" PRIX16 ":" , op->data.absolute.segment, |
754 | len ); |
755 | if (op->datatype == op_descr16) { |
756 | STRNCATF( buf, "0x%04" PRIX16, |
757 | op->data.absolute.offset.off16, len ); |
758 | } else { |
759 | STRNCATF( buf, "0x%08" PRIX32, |
760 | op->data.absolute.offset.off32, len ); |
761 | } |
762 | break; |
763 | |
764 | case op_offset: |
765 | len -= format_seg( op, buf, len, native_syntax ); |
766 | STRNCATF( buf, "[0x%08" PRIX32 "]" , op->data.sdword, len ); |
767 | break; |
768 | |
769 | case op_expression: |
770 | len -= format_seg( op, buf, len, native_syntax ); |
771 | len -= format_expr( &op->data.expression, buf, len, |
772 | native_syntax ); |
773 | break; |
774 | case op_unused: |
775 | case op_unknown: |
776 | /* return 0-truncated buffer */ |
777 | break; |
778 | } |
779 | |
780 | return( strlen( buf ) ); |
781 | } |
782 | |
783 | static int format_operand_xml( x86_op_t *op, x86_insn_t *insn, char *buf, |
784 | int len){ |
785 | |
786 | char str[MAX_OP_STRING] = "\0" ; |
787 | |
788 | switch (op->type) { |
789 | case op_register: |
790 | |
791 | get_operand_regtype_str( op->data.reg.type, str, |
792 | sizeof str ); |
793 | |
794 | STRNCAT( buf, "\t\t<register " , len ); |
795 | STRNCATF( buf, "name=\"%s\" " , op->data.reg.name, len ); |
796 | STRNCATF( buf, "type=\"%s\" " , str, len ); |
797 | STRNCATF( buf, "size=%d/>\n" , op->data.reg.size, len ); |
798 | break; |
799 | |
800 | case op_immediate: |
801 | |
802 | get_operand_data_str( op, str, sizeof str ); |
803 | |
804 | STRNCAT( buf, "\t\t<immediate " , len ); |
805 | STRNCATF( buf, "type=\"%s\" " , |
806 | get_operand_datatype_str (op), len ); |
807 | STRNCATF( buf, "value=\"%s\"/>\n" , str, len ); |
808 | break; |
809 | |
810 | case op_relative_near: |
811 | STRNCAT( buf, "\t\t<relative_offset " , len ); |
812 | |
813 | STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n" , |
814 | (unsigned int)(op->data.sbyte + |
815 | insn->addr + insn->size), len ); |
816 | break; |
817 | |
818 | case op_relative_far: |
819 | STRNCAT( buf, "\t\t<relative_offset " , len ); |
820 | |
821 | if (op->datatype == op_word) { |
822 | STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n" , |
823 | (unsigned int)(op->data.sword + |
824 | insn->addr + insn->size), len); |
825 | break; |
826 | } else { |
827 | |
828 | STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n" , |
829 | op->data.sdword + insn->addr + insn->size, |
830 | len ); |
831 | } |
832 | break; |
833 | |
834 | case op_absolute: |
835 | |
836 | STRNCATF( buf, |
837 | "\t\t<absolute_address segment=\"0x%04" PRIX16 "\"" , |
838 | op->data.absolute.segment, len ); |
839 | |
840 | if (op->datatype == op_descr16) { |
841 | STRNCATF( buf, "offset=\"0x%04" PRIX16 "\">" , |
842 | op->data.absolute.offset.off16, len ); |
843 | } else { |
844 | STRNCATF( buf, "offset=\"0x%08" PRIX32 "\">" , |
845 | op->data.absolute.offset.off32, len ); |
846 | } |
847 | |
848 | STRNCAT( buf, "\t\t</absolute_address>\n" , len ); |
849 | break; |
850 | |
851 | case op_expression: |
852 | |
853 | |
854 | STRNCAT( buf, "\t\t<address_expression>\n" , len ); |
855 | |
856 | len -= format_seg( op, buf, len, xml_syntax ); |
857 | len -= format_expr( &op->data.expression, buf, len, |
858 | xml_syntax ); |
859 | |
860 | STRNCAT( buf, "\t\t</address_expression>\n" , len ); |
861 | break; |
862 | |
863 | case op_offset: |
864 | |
865 | STRNCAT( buf, "\t\t<segment_offset>\n" , len ); |
866 | |
867 | len -= format_seg( op, buf, len, xml_syntax ); |
868 | |
869 | STRNCAT( buf, "\t\t\t<address " , len); |
870 | STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n" , |
871 | op->data.sdword, len ); |
872 | STRNCAT( buf, "\t\t</segment_offset>\n" , len ); |
873 | break; |
874 | |
875 | case op_unused: |
876 | case op_unknown: |
877 | /* return 0-truncated buffer */ |
878 | break; |
879 | } |
880 | |
881 | return( strlen( buf ) ); |
882 | } |
883 | |
884 | static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf, |
885 | int len){ |
886 | |
887 | char str[MAX_OP_RAW_STRING]; |
888 | const char *datatype = get_operand_datatype_str(op); |
889 | |
890 | switch (op->type) { |
891 | case op_register: |
892 | |
893 | get_operand_regtype_str( op->data.reg.type, str, |
894 | sizeof str ); |
895 | |
896 | STRNCAT( buf, "reg|" , len ); |
897 | STRNCATF( buf, "%s|" , datatype, len ); |
898 | STRNCATF( buf, "%s:" , op->data.reg.name, len ); |
899 | STRNCATF( buf, "%s:" , str, len ); |
900 | STRNCATF( buf, "%d|" , op->data.reg.size, len ); |
901 | break; |
902 | |
903 | case op_immediate: |
904 | |
905 | get_operand_data_str( op, str, sizeof str ); |
906 | |
907 | STRNCAT( buf, "immediate|" , len ); |
908 | STRNCATF( buf, "%s|" , datatype, len ); |
909 | STRNCATF( buf, "%s|" , str, len ); |
910 | break; |
911 | |
912 | case op_relative_near: |
913 | /* NOTE: in raw format, we print the |
914 | * relative offset, not the actual |
915 | * address of the jump target */ |
916 | |
917 | STRNCAT( buf, "relative|" , len ); |
918 | STRNCATF( buf, "%s|" , datatype, len ); |
919 | STRNCATF( buf, "%" PRId8 "|" , op->data.sbyte, len ); |
920 | break; |
921 | |
922 | case op_relative_far: |
923 | |
924 | STRNCAT( buf, "relative|" , len ); |
925 | STRNCATF( buf, "%s|" , datatype, len ); |
926 | |
927 | if (op->datatype == op_word) { |
928 | STRNCATF( buf, "%" PRId16 "|" , op->data.sword, len); |
929 | break; |
930 | } else { |
931 | STRNCATF( buf, "%" PRId32 "|" , op->data.sdword, len ); |
932 | } |
933 | break; |
934 | |
935 | case op_absolute: |
936 | |
937 | STRNCAT( buf, "absolute_address|" , len ); |
938 | STRNCATF( buf, "%s|" , datatype, len ); |
939 | |
940 | STRNCATF( buf, "$0x%04" PRIX16 ":" , op->data.absolute.segment, |
941 | len ); |
942 | if (op->datatype == op_descr16) { |
943 | STRNCATF( buf, "0x%04" PRIX16 "|" , |
944 | op->data.absolute.offset.off16, len ); |
945 | } else { |
946 | STRNCATF( buf, "0x%08" PRIX32 "|" , |
947 | op->data.absolute.offset.off32, len ); |
948 | } |
949 | |
950 | break; |
951 | |
952 | case op_expression: |
953 | |
954 | STRNCAT( buf, "address_expression|" , len ); |
955 | STRNCATF( buf, "%s|" , datatype, len ); |
956 | |
957 | len -= format_seg( op, buf, len, native_syntax ); |
958 | len -= format_expr( &op->data.expression, buf, len, |
959 | raw_syntax ); |
960 | |
961 | STRNCAT( buf, "|" , len ); |
962 | break; |
963 | |
964 | case op_offset: |
965 | |
966 | STRNCAT( buf, "segment_offset|" , len ); |
967 | STRNCATF( buf, "%s|" , datatype, len ); |
968 | |
969 | len -= format_seg( op, buf, len, xml_syntax ); |
970 | |
971 | STRNCATF( buf, "%08" PRIX32 "|" , op->data.sdword, len ); |
972 | break; |
973 | |
974 | case op_unused: |
975 | case op_unknown: |
976 | /* return 0-truncated buffer */ |
977 | break; |
978 | } |
979 | |
980 | return( strlen( buf ) ); |
981 | } |
982 | |
983 | int x86_format_operand( x86_op_t *op, char *buf, int len, |
984 | enum x86_asm_format format ){ |
985 | x86_insn_t *insn; |
986 | |
987 | if ( ! op || ! buf || len < 1 ) { |
988 | return(0); |
989 | } |
990 | |
991 | /* insn is stored in x86_op_t since .21-pre3 */ |
992 | insn = (x86_insn_t *) op->insn; |
993 | |
994 | memset( buf, 0, len ); |
995 | |
996 | switch ( format ) { |
997 | case att_syntax: |
998 | return format_operand_att( op, insn, buf, len ); |
999 | case xml_syntax: |
1000 | return format_operand_xml( op, insn, buf, len ); |
1001 | case raw_syntax: |
1002 | return format_operand_raw( op, insn, buf, len ); |
1003 | case native_syntax: |
1004 | case intel_syntax: |
1005 | default: |
1006 | return format_operand_native( op, insn, buf, len ); |
1007 | } |
1008 | } |
1009 | |
1010 | #define is_imm_jmp(op) (op->type == op_absolute || \ |
1011 | op->type == op_immediate || \ |
1012 | op->type == op_offset) |
1013 | #define is_memory_op(op) (op->type == op_absolute || \ |
1014 | op->type == op_expression || \ |
1015 | op->type == op_offset) |
1016 | |
1017 | static int format_att_mnemonic( x86_insn_t *insn, char *buf, int len) { |
1018 | int size = 0; |
1019 | const char *suffix; |
1020 | |
1021 | if (! insn || ! buf || ! len ) |
1022 | return(0); |
1023 | |
1024 | memset( buf, 0, len ); |
1025 | |
1026 | /* do long jump/call prefix */ |
1027 | if ( insn->type == insn_jmp || insn->type == insn_call ) { |
1028 | if (! is_imm_jmp( x86_operand_1st(insn) ) || |
1029 | (x86_operand_1st(insn))->datatype != op_byte ) { |
1030 | /* far jump/call, use "l" prefix */ |
1031 | STRNCAT( buf, "l" , len ); |
1032 | } |
1033 | STRNCAT( buf, insn->mnemonic, len ); |
1034 | |
1035 | return ( strlen( buf ) ); |
1036 | } |
1037 | |
1038 | /* do mnemonic */ |
1039 | STRNCAT( buf, insn->mnemonic, len ); |
1040 | |
1041 | /* do suffixes for memory operands */ |
1042 | if (!(insn->note & insn_note_nosuffix) && |
1043 | (insn->group == insn_arithmetic || |
1044 | insn->group == insn_logic || |
1045 | insn->group == insn_move || |
1046 | insn->group == insn_stack || |
1047 | insn->group == insn_string || |
1048 | insn->group == insn_comparison || |
1049 | insn->type == insn_in || |
1050 | insn->type == insn_out |
1051 | )) { |
1052 | if ( x86_operand_count( insn, op_explicit ) > 0 && |
1053 | is_memory_op( x86_operand_1st(insn) ) ){ |
1054 | size = x86_operand_size( x86_operand_1st( insn ) ); |
1055 | } else if ( x86_operand_count( insn, op_explicit ) > 1 && |
1056 | is_memory_op( x86_operand_2nd(insn) ) ){ |
1057 | size = x86_operand_size( x86_operand_2nd( insn ) ); |
1058 | } |
1059 | } |
1060 | |
1061 | if ( size == 1 ) suffix = "b" ; |
1062 | else if ( size == 2 ) suffix = "w" ; |
1063 | else if ( size == 4 ) suffix = "l" ; |
1064 | else if ( size == 8 ) suffix = "q" ; |
1065 | else suffix = "" ; |
1066 | |
1067 | STRNCAT( buf, suffix, len ); |
1068 | return ( strlen( buf ) ); |
1069 | } |
1070 | |
1071 | int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len, |
1072 | enum x86_asm_format format){ |
1073 | char str[MAX_OP_STRING]; |
1074 | |
1075 | memset( buf, 0, len ); |
1076 | STRNCAT( buf, insn->prefix_string, len ); |
1077 | if ( format == att_syntax ) { |
1078 | format_att_mnemonic( insn, str, sizeof str ); |
1079 | STRNCAT( buf, str, len ); |
1080 | } else { |
1081 | STRNCAT( buf, insn->mnemonic, len ); |
1082 | } |
1083 | |
1084 | return( strlen( buf ) ); |
1085 | } |
1086 | |
1087 | struct op_string { char *buf; size_t len; }; |
1088 | |
1089 | static void format_op_raw( x86_op_t *op, x86_insn_t *insn, void *arg ) { |
1090 | struct op_string * opstr = (struct op_string *) arg; |
1091 | |
1092 | format_operand_raw(op, insn, opstr->buf, opstr->len); |
1093 | } |
1094 | |
1095 | static int format_insn_note(x86_insn_t *insn, char *buf, int len){ |
1096 | char note[32] = {0}; |
1097 | int len_orig = len, note_len = 32; |
1098 | |
1099 | if ( insn->note & insn_note_ring0 ) { |
1100 | STRNCATF( note, "%s" , "Ring0 " , note_len ); |
1101 | } |
1102 | if ( insn->note & insn_note_smm ) { |
1103 | STRNCATF( note, "%s" , "SMM " , note_len ); |
1104 | } |
1105 | if ( insn->note & insn_note_serial ) { |
1106 | STRNCATF(note, "%s" , "Serialize " , note_len ); |
1107 | } |
1108 | STRNCATF( buf, "%s|" , note, len ); |
1109 | |
1110 | return( len_orig - len ); |
1111 | } |
1112 | |
1113 | static int format_raw_insn( x86_insn_t *insn, char *buf, int len ){ |
1114 | struct op_string opstr = { buf, len }; |
1115 | int i; |
1116 | |
1117 | /* RAW style: |
1118 | * ADDRESS|OFFSET|SIZE|BYTES| |
1119 | * PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES| |
1120 | * MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED| |
1121 | * STACK_MOD|STACK_MOD_VAL |
1122 | * [|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]* |
1123 | * |
1124 | * Register values are encoded as: |
1125 | * NAME:TYPE:SIZE |
1126 | * |
1127 | * Effective addresses are encoded as: |
1128 | * disp(base_reg,index_reg,scale) |
1129 | */ |
1130 | STRNCATF( buf, "0x%08" PRIX32 "|" , insn->addr , len ); |
1131 | STRNCATF( buf, "0x%08" PRIX32 "|" , insn->offset, len ); |
1132 | STRNCATF( buf, "%d|" , insn->size , len ); |
1133 | |
1134 | /* print bytes */ |
1135 | for ( i = 0; i < insn->size; i++ ) { |
1136 | STRNCATF( buf, "%02X " , insn->bytes[i], len ); |
1137 | } |
1138 | STRNCAT( buf, "|" , len ); |
1139 | |
1140 | len -= format_insn_prefix_str( insn->prefix, buf, len ); |
1141 | STRNCATF( buf, "|%s|" , insn->prefix_string , len ); |
1142 | STRNCATF( buf, "%s|" , get_insn_group_str( insn->group ), len ); |
1143 | STRNCATF( buf, "%s|" , get_insn_type_str( insn->type ) , len ); |
1144 | STRNCATF( buf, "%s|" , insn->mnemonic , len ); |
1145 | STRNCATF( buf, "%s|" , get_insn_cpu_str( insn->cpu ) , len ); |
1146 | STRNCATF( buf, "%s|" , get_insn_isa_str( insn->isa ) , len ); |
1147 | |
1148 | /* insn note */ |
1149 | len -= format_insn_note( insn, buf, len ); |
1150 | |
1151 | len -= format_insn_eflags_str( insn->flags_set, buf, len ); |
1152 | STRNCAT( buf, "|" , len ); |
1153 | len -= format_insn_eflags_str( insn->flags_tested, buf, len ); |
1154 | STRNCAT( buf, "|" , len ); |
1155 | STRNCATF( buf, "%d|" , insn->stack_mod, len ); |
1156 | STRNCATF( buf, "%" PRId32 "|" , insn->stack_mod_val, len ); |
1157 | |
1158 | opstr.len = len; |
1159 | x86_operand_foreach( insn, format_op_raw, &opstr, op_any ); |
1160 | |
1161 | return( strlen (buf) ); |
1162 | } |
1163 | |
1164 | static int format_xml_insn( x86_insn_t *insn, char *buf, int len ) { |
1165 | char str[MAX_OP_XML_STRING]; |
1166 | int i; |
1167 | |
1168 | STRNCAT( buf, "<x86_insn>\n" , len ); |
1169 | |
1170 | STRNCATF( buf, "\t<address rva=\"0x%08" PRIX32 "\" " , insn->addr, len ); |
1171 | STRNCATF( buf, "offset=\"0x%08" PRIX32 "\" " , insn->offset, len ); |
1172 | STRNCATF( buf, "size=%d bytes=\"" , insn->size, len ); |
1173 | |
1174 | for ( i = 0; i < insn->size; i++ ) { |
1175 | STRNCATF( buf, "%02X " , insn->bytes[i], len ); |
1176 | } |
1177 | STRNCAT( buf, "\"/>\n" , len ); |
1178 | |
1179 | STRNCAT( buf, "\t<prefix type=\"" , len ); |
1180 | len -= format_insn_prefix_str( insn->prefix, buf, len ); |
1181 | STRNCATF( buf, "\" string=\"%s\"/>\n" , insn->prefix_string, len ); |
1182 | |
1183 | STRNCATF( buf, "\t<mnemonic group=\"%s\" " , |
1184 | get_insn_group_str (insn->group), len ); |
1185 | STRNCATF( buf, "type=\"%s\" " , get_insn_type_str (insn->type), len ); |
1186 | STRNCATF( buf, "string=\"%s\"/>\n" , insn->mnemonic, len ); |
1187 | |
1188 | STRNCAT( buf, "\t<flags type=set>\n" , len ); |
1189 | STRNCAT( buf, "\t\t<flag name=\"" , len ); |
1190 | len -= format_insn_eflags_str( insn->flags_set, buf, len ); |
1191 | STRNCAT( buf, "\"/>\n\t</flags>\n" , len ); |
1192 | |
1193 | |
1194 | STRNCAT( buf, "\t<flags type=tested>\n" , len ); |
1195 | STRNCAT( buf, "\t\t<flag name=\"" , len ); |
1196 | len -= format_insn_eflags_str( insn->flags_tested, buf, len ); |
1197 | STRNCAT( buf, "\"/>\n\t</flags>\n" , len ); |
1198 | |
1199 | if ( x86_operand_1st( insn ) ) { |
1200 | x86_format_operand( x86_operand_1st(insn), str, |
1201 | sizeof str, xml_syntax); |
1202 | STRNCAT( buf, "\t<operand name=dest>\n" , len ); |
1203 | STRNCAT( buf, str, len ); |
1204 | STRNCAT( buf, "\t</operand>\n" , len ); |
1205 | } |
1206 | |
1207 | if ( x86_operand_2nd( insn ) ) { |
1208 | x86_format_operand( x86_operand_2nd( insn ), str, |
1209 | sizeof str, xml_syntax); |
1210 | STRNCAT( buf, "\t<operand name=src>\n" , len ); |
1211 | STRNCAT( buf, str, len ); |
1212 | STRNCAT( buf, "\t</operand>\n" , len ); |
1213 | } |
1214 | |
1215 | if ( x86_operand_3rd( insn ) ) { |
1216 | x86_format_operand( x86_operand_3rd(insn), str, |
1217 | sizeof str, xml_syntax); |
1218 | STRNCAT( buf, "\t<operand name=imm>\n" , len ); |
1219 | STRNCAT( buf, str, len ); |
1220 | STRNCAT( buf, "\t</operand>\n" , len ); |
1221 | } |
1222 | |
1223 | STRNCAT( buf, "</x86_insn>\n" , len ); |
1224 | |
1225 | return strlen (buf); |
1226 | } |
1227 | |
1228 | int ( char *buf, int len, enum x86_asm_format format ) { |
1229 | switch (format) { |
1230 | case att_syntax: |
1231 | snprintf( buf, len, "MNEMONIC\tSRC, DEST, IMM" ); |
1232 | break; |
1233 | case intel_syntax: |
1234 | snprintf( buf, len, "MNEMONIC\tDEST, SRC, IMM" ); |
1235 | break; |
1236 | case native_syntax: |
1237 | snprintf( buf, len, "ADDRESS\tBYTES\tMNEMONIC\t" |
1238 | "DEST\tSRC\tIMM" ); |
1239 | break; |
1240 | case raw_syntax: |
1241 | snprintf( buf, len, "ADDRESS|OFFSET|SIZE|BYTES|" |
1242 | "PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|" |
1243 | "MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|" |
1244 | "STACK_MOD|STACK_MOD_VAL" |
1245 | "[|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*" |
1246 | ); |
1247 | break; |
1248 | case xml_syntax: |
1249 | snprintf( buf, len, |
1250 | "<x86_insn>" |
1251 | "<address rva= offset= size= bytes=/>" |
1252 | "<prefix type= string=/>" |
1253 | "<mnemonic group= type= string= " |
1254 | "cpu= isa= note= />" |
1255 | "<flags type=set>" |
1256 | "<flag name=>" |
1257 | "</flags>" |
1258 | "<stack_mod val= >" |
1259 | "<flags type=tested>" |
1260 | "<flag name=>" |
1261 | "</flags>" |
1262 | "<operand name=>" |
1263 | "<register name= type= size=/>" |
1264 | "<immediate type= value=/>" |
1265 | "<relative_offset value=/>" |
1266 | "<absolute_address value=>" |
1267 | "<segment value=/>" |
1268 | "</absolute_address>" |
1269 | "<address_expression>" |
1270 | "<segment value=/>" |
1271 | "<base>" |
1272 | "<register name= type= size=/>" |
1273 | "</base>" |
1274 | "<index>" |
1275 | "<register name= type= size=/>" |
1276 | "</index>" |
1277 | "<scale>" |
1278 | "<immediate value=/>" |
1279 | "</scale>" |
1280 | "<displacement>" |
1281 | "<immediate value=/>" |
1282 | "<address value=/>" |
1283 | "</displacement>" |
1284 | "</address_expression>" |
1285 | "<segment_offset>" |
1286 | "<address value=/>" |
1287 | "</segment_offset>" |
1288 | "</operand>" |
1289 | "</x86_insn>" |
1290 | ); |
1291 | break; |
1292 | case unknown_syntax: |
1293 | if ( len ) { |
1294 | buf[0] = '\0'; |
1295 | } |
1296 | break; |
1297 | } |
1298 | |
1299 | return( strlen(buf) ); |
1300 | } |
1301 | |
1302 | int x86_format_insn( x86_insn_t *insn, char *buf, int len, |
1303 | enum x86_asm_format format ){ |
1304 | char str[MAX_OP_STRING]; |
1305 | x86_op_t *src, *dst; |
1306 | int i; |
1307 | |
1308 | memset(buf, 0, len); |
1309 | if ( format == intel_syntax ) { |
1310 | /* INTEL STYLE: mnemonic dest, src, imm */ |
1311 | STRNCAT( buf, insn->prefix_string, len ); |
1312 | STRNCAT( buf, insn->mnemonic, len ); |
1313 | STRNCAT( buf, "\t" , len ); |
1314 | |
1315 | /* dest */ |
1316 | if ( (dst = x86_operand_1st( insn )) && !(dst->flags & op_implied) ) { |
1317 | x86_format_operand( dst, str, MAX_OP_STRING, format); |
1318 | STRNCAT( buf, str, len ); |
1319 | } |
1320 | |
1321 | /* src */ |
1322 | if ( (src = x86_operand_2nd( insn )) ) { |
1323 | if ( !(dst->flags & op_implied) ) { |
1324 | STRNCAT( buf, ", " , len ); |
1325 | } |
1326 | x86_format_operand( src, str, MAX_OP_STRING, format); |
1327 | STRNCAT( buf, str, len ); |
1328 | } |
1329 | |
1330 | /* imm */ |
1331 | if ( x86_operand_3rd( insn )) { |
1332 | STRNCAT( buf, ", " , len ); |
1333 | x86_format_operand( x86_operand_3rd( insn ), |
1334 | str, MAX_OP_STRING, format); |
1335 | STRNCAT( buf, str, len ); |
1336 | } |
1337 | |
1338 | } else if ( format == att_syntax ) { |
1339 | /* ATT STYLE: mnemonic src, dest, imm */ |
1340 | STRNCAT( buf, insn->prefix_string, len ); |
1341 | format_att_mnemonic(insn, str, MAX_OP_STRING); |
1342 | STRNCATF( buf, "%s\t" , str, len); |
1343 | |
1344 | |
1345 | /* not sure which is correct? sometimes GNU as requires |
1346 | * an imm as the first operand, sometimes as the third... */ |
1347 | /* imm */ |
1348 | if ( x86_operand_3rd( insn ) ) { |
1349 | x86_format_operand(x86_operand_3rd( insn ), |
1350 | str, MAX_OP_STRING, format); |
1351 | STRNCAT( buf, str, len ); |
1352 | /* there is always 'dest' operand if there is 'src' */ |
1353 | STRNCAT( buf, ", " , len ); |
1354 | } |
1355 | |
1356 | if ( (insn->note & insn_note_nonswap ) == 0 ) { |
1357 | /* regular AT&T style swap */ |
1358 | src = x86_operand_2nd( insn ); |
1359 | dst = x86_operand_1st( insn ); |
1360 | } |
1361 | else { |
1362 | /* special-case instructions */ |
1363 | src = x86_operand_1st( insn ); |
1364 | dst = x86_operand_2nd( insn ); |
1365 | } |
1366 | |
1367 | /* src */ |
1368 | if ( src ) { |
1369 | x86_format_operand(src, str, MAX_OP_STRING, format); |
1370 | STRNCAT( buf, str, len ); |
1371 | /* there is always 'dest' operand if there is 'src' */ |
1372 | if ( dst && !(dst->flags & op_implied) ) { |
1373 | STRNCAT( buf, ", " , len ); |
1374 | } |
1375 | } |
1376 | |
1377 | /* dest */ |
1378 | if ( dst && !(dst->flags & op_implied) ) { |
1379 | x86_format_operand( dst, str, MAX_OP_STRING, format); |
1380 | STRNCAT( buf, str, len ); |
1381 | } |
1382 | |
1383 | |
1384 | } else if ( format == raw_syntax ) { |
1385 | format_raw_insn( insn, buf, len ); |
1386 | } else if ( format == xml_syntax ) { |
1387 | format_xml_insn( insn, buf, len ); |
1388 | } else { /* default to native */ |
1389 | /* NATIVE style: RVA\tBYTES\tMNEMONIC\tOPERANDS */ |
1390 | /* print address */ |
1391 | STRNCATF( buf, "%08" PRIX32 "\t" , insn->addr, len ); |
1392 | |
1393 | /* print bytes */ |
1394 | for ( i = 0; i < insn->size; i++ ) { |
1395 | STRNCATF( buf, "%02X " , insn->bytes[i], len ); |
1396 | } |
1397 | |
1398 | STRNCAT( buf, "\t" , len ); |
1399 | |
1400 | /* print mnemonic */ |
1401 | STRNCAT( buf, insn->prefix_string, len ); |
1402 | STRNCAT( buf, insn->mnemonic, len ); |
1403 | STRNCAT( buf, "\t" , len ); |
1404 | |
1405 | /* print operands */ |
1406 | /* dest */ |
1407 | if ( x86_operand_1st( insn ) ) { |
1408 | x86_format_operand( x86_operand_1st( insn ), |
1409 | str, MAX_OP_STRING, format); |
1410 | STRNCATF( buf, "%s\t" , str, len ); |
1411 | } |
1412 | |
1413 | /* src */ |
1414 | if ( x86_operand_2nd( insn ) ) { |
1415 | x86_format_operand(x86_operand_2nd( insn ), |
1416 | str, MAX_OP_STRING, format); |
1417 | STRNCATF( buf, "%s\t" , str, len ); |
1418 | } |
1419 | |
1420 | /* imm */ |
1421 | if ( x86_operand_3rd( insn )) { |
1422 | x86_format_operand( x86_operand_3rd( insn ), |
1423 | str, MAX_OP_STRING, format); |
1424 | STRNCAT( buf, str, len ); |
1425 | } |
1426 | } |
1427 | |
1428 | return( strlen( buf ) ); |
1429 | } |
1430 | |
1431 | |