| 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 |