• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
format_insn_prefix_str(enum x86_insn_prefix prefix,char * buf,int len)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  */
get_operand_data_str(x86_op_t * op,char * str,int len)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  */
get_operand_regtype_str(int regtype,char * str,int len)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 
format_expr(x86_ea_t * ea,char * buf,int len,enum x86_asm_format format)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 
format_seg(x86_op_t * op,char * buf,int len,enum x86_asm_format format)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 
get_operand_datatype_str(x86_op_t * op)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 
format_insn_eflags_str(enum x86_flag_status flags,char * buf,int len)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 
get_insn_group_str(enum x86_insn_group gp)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 
get_insn_type_str(enum x86_insn_type type)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 
get_insn_cpu_str(enum x86_insn_cpu cpu)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 
get_insn_isa_str(enum x86_insn_isa isa)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 
format_operand_att(x86_op_t * op,x86_insn_t * insn,char * buf,int len)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 
format_operand_native(x86_op_t * op,x86_insn_t * insn,char * buf,int len)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 
format_operand_xml(x86_op_t * op,x86_insn_t * insn,char * buf,int len)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 
format_operand_raw(x86_op_t * op,x86_insn_t * insn,char * buf,int len)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 
x86_format_operand(x86_op_t * op,char * buf,int len,enum x86_asm_format format)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 
format_att_mnemonic(x86_insn_t * insn,char * buf,int len)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 
x86_format_mnemonic(x86_insn_t * insn,char * buf,int len,enum x86_asm_format format)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 
format_op_raw(x86_op_t * op,x86_insn_t * insn,void * arg)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 
format_insn_note(x86_insn_t * insn,char * buf,int len)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 
format_raw_insn(x86_insn_t * insn,char * buf,int len)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 
format_xml_insn(x86_insn_t * insn,char * buf,int len)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 
x86_format_header(char * buf,int len,enum x86_asm_format format)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 
x86_format_insn(x86_insn_t * insn,char * buf,int len,enum x86_asm_format format)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