OLD | NEW |
| (Empty) |
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.s
egment, | |
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.se
gment, | |
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, l
en); | |
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.se
gment, | |
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 x86_format_header( 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_implie
d) ) { | |
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 | |
OLD | NEW |