1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "libdis.h"
- #include <inttypes.h>
- #ifdef _MSC_VER
- #define snprintf _snprintf
- #define inline __inline
- #endif
- /*
- * concatenation macros. STRNCATF concatenates a format string, buf
- * only with one argument.
- */
- #define STRNCAT( buf, str, len ) do { \
- int _i = strlen(str), _blen = strlen(buf), _len = len - 1; \
- if ( len ) { \
- strncat( buf, str, _len ); \
- if ( _len <= _i ) { \
- buf[_blen+_len] = '\0'; \
- len = 0; \
- } else { \
- len -= _i; \
- } \
- } \
- } while( 0 )
- #define STRNCATF( buf, fmt, data, len ) do { \
- char _tmp[MAX_OP_STRING]; \
- \
- snprintf( _tmp, sizeof _tmp, fmt, data ); \
- STRNCAT( buf, _tmp, len ); \
- } while( 0 )
- #define PRINT_DISPLACEMENT( ea ) do { \
- if ( ea->disp_size && ea->disp ) { \
- if ( ea->disp_sign ) { \
- STRNCATF( buf, "-0x%" PRIX32, -ea->disp, len ); \
- } else { \
- STRNCATF( buf, "0x%" PRIX32, ea->disp, len ); \
- } \
- } \
- } while( 0 )
- static const char *prefix_strings[] = {
- "", /* no prefix */
- "repz ", /* the trailing spaces make it easy to prepend to mnemonic */
- "repnz ",
- "lock ",
- "branch delay " /* unused in x86 */
- };
- static int format_insn_prefix_str( enum x86_insn_prefix prefix, char *buf,
- int len ) {
- int len_orig = len;
- /* concat all prefix strings */
- if ( prefix & 1 ) { STRNCAT( buf, prefix_strings[1], len ); }
- if ( prefix & 2 ) { STRNCAT( buf, prefix_strings[2], len ); }
- if ( prefix & 4 ) { STRNCAT( buf, prefix_strings[3], len ); }
- if ( prefix & 8 ) { STRNCAT( buf, prefix_strings[4], len ); }
- /* return the number of characters added */
- return (len_orig - len);
- }
- /*
- * sprint's an operand's data to string str.
- */
- static void get_operand_data_str( x86_op_t *op, char *str, int len ){
- if ( op->flags.op_signed ) {
- switch ( op->datatype ) {
- case op_byte:
- snprintf( str, len, "%" PRId8, op->data.sbyte );
- return;
- case op_word:
- snprintf( str, len, "%" PRId16, op->data.sword );
- return;
- case op_qword:
- snprintf( str, len, "%" PRId64, op->data.sqword );
- return;
- default:
- snprintf( str, len, "%" PRId32, op->data.sdword );
- return;
- }
- }
- //else
- switch ( op->datatype ) {
- case op_byte:
- snprintf( str, len, "0x%02" PRIX8, op->data.byte );
- return;
- case op_word:
- snprintf( str, len, "0x%04" PRIX16, op->data.word );
- return;
- case op_qword:
- snprintf( str, len, "0x%08" PRIX64,op->data.sqword );
- return;
- default:
- snprintf( str, len, "0x%08" PRIX32, op->data.dword );
- return;
- }
- }
- /*
- * sprints register types to a string. the register types can be ORed
- * together.
- */
- static void get_operand_regtype_str( int regtype, char *str, int len )
- {
- static struct {
- const char *name;
- int value;
- } operand_regtypes[] = {
- {"reg_gen" , 0x00001},
- {"reg_in" , 0x00002},
- {"reg_out" , 0x00004},
- {"reg_local" , 0x00008},
- {"reg_fpu" , 0x00010},
- {"reg_seg" , 0x00020},
- {"reg_simd" , 0x00040},
- {"reg_sys" , 0x00080},
- {"reg_sp" , 0x00100},
- {"reg_fp" , 0x00200},
- {"reg_pc" , 0x00400},
- {"reg_retaddr", 0x00800},
- {"reg_cond" , 0x01000},
- {"reg_zero" , 0x02000},
- {"reg_ret" , 0x04000},
- {"reg_src" , 0x10000},
- {"reg_dest" , 0x20000},
- {"reg_count" , 0x40000},
- {NULL, 0}, //end
- };
- unsigned int i;
- memset( str, 0, len );
- //go thru every type in the enum
- for ( i = 0; operand_regtypes[i].name; i++ ) {
- //skip if type is not set
- if(! (regtype & operand_regtypes[i].value) )
- continue;
- //not the first time around
- if( str[0] ) {
- STRNCAT( str, " ", len );
- }
- STRNCAT(str, operand_regtypes[i].name, len );
- }
- }
- static int format_expr( x86_ea_t *ea, char *buf, int len,
- enum x86_asm_format format ) {
- char str[MAX_OP_STRING];
- if ( format == att_syntax ) {
- if (ea->base.name[0] || ea->index.name[0] || ea->scale) {
- PRINT_DISPLACEMENT(ea);
- STRNCAT( buf, "(", len );
- if ( ea->base.name[0]) {
- STRNCATF( buf, "%%%s", ea->base.name, len );
- }
- if ( ea->index.name[0]) {
- STRNCATF( buf, ",%%%s", ea->index.name, len );
- if ( ea->scale > 1 ) {
- STRNCATF( buf, ",%d", ea->scale, len );
- }
- }
- /* handle the syntactic exception */
- if ( ! ea->base.name[0] &&
- ! ea->index.name[0] ) {
- STRNCATF( buf, ",%d", ea->scale, len );
- }
- STRNCAT( buf, ")", len );
- } else
- STRNCATF( buf, "0x%" PRIX32, ea->disp, len );
- } else if ( format == xml_syntax ){
- if ( ea->base.name[0]) {
- STRNCAT (buf, "\t\t\t<base>\n", len);
- get_operand_regtype_str (ea->base.type, str,
- sizeof str);
- STRNCAT (buf, "\t\t\t\t<register ", len);
- STRNCATF (buf, "name=\"%s\" ", ea->base.name, len);
- STRNCATF (buf, "type=\"%s\" ", str, len);
- STRNCATF (buf, "size=%d/>\n", ea->base.size, len);
- STRNCAT (buf, "\t\t\t</base>\n", len);
- }
- if ( ea->index.name[0]) {
- STRNCAT (buf, "\t\t\t<index>\n", len);
- get_operand_regtype_str (ea->index.type, str,
- sizeof str);
- STRNCAT (buf, "\t\t\t\t<register ", len);
- STRNCATF (buf, "name=\"%s\" ", ea->index.name, len);
- STRNCATF (buf, "type=\"%s\" ", str, len);
- STRNCATF (buf, "size=%d/>\n", ea->index.size, len);
- STRNCAT (buf, "\t\t\t</index>\n", len);
- }
- //scale
- STRNCAT (buf, "\t\t\t<scale>\n", len);
- STRNCAT (buf, "\t\t\t\t<immediate ", len);
- STRNCATF (buf, "value=\"%d\"/>\n", ea->scale, len);
- STRNCAT (buf, "\t\t\t</scale>\n", len);
- if ( ea->disp_size ) {
- STRNCAT (buf, "\t\t\t<displacement>\n", len);
- if ( ea->disp_size > 1 && ! ea->disp_sign ) {
- STRNCAT (buf, "\t\t\t\t<address ", len);
- STRNCATF (buf, "value=\"0x%" PRIX32 "\"/>\n", ea->disp,
- len);
- } else {
- STRNCAT (buf, "\t\t\t\t<immediate ", len);
- STRNCATF (buf, "value=%" PRId32 "/>\n", ea->disp, len);
- }
- STRNCAT (buf, "\t\t\t</displacement>\n", len);
- }
- } else if ( format == raw_syntax ) {
- PRINT_DISPLACEMENT(ea);
- STRNCAT( buf, "(", len );
- STRNCATF( buf, "%s,", ea->base.name, len );
- STRNCATF( buf, "%s,", ea->index.name, len );
- STRNCATF( buf, "%d", ea->scale, len );
- STRNCAT( buf, ")", len );
- } else {
- STRNCAT( buf, "[", len );
- if ( ea->base.name[0] ) {
- STRNCAT( buf, ea->base.name, len );
- if ( ea->index.name[0] ||
- (ea->disp_size && ! ea->disp_sign) ) {
- STRNCAT( buf, "+", len );
- }
- }
- if ( ea->index.name[0] ) {
- STRNCAT( buf, ea->index.name, len );
- if ( ea->scale > 1 )
- {
- STRNCATF( buf, "*%" PRId32, ea->scale, len );
- }
- if ( ea->disp_size && ! ea->disp_sign )
- {
- STRNCAT( buf, "+", len );
- }
- }
- if ( ea->disp_size || (! ea->index.name[0] &&
- ! ea->base.name[0] ) )
- {
- PRINT_DISPLACEMENT(ea);
- }
- STRNCAT( buf, "]", len );
- }
- return( strlen(buf) );
- }
- static int format_seg( x86_op_t *op, char *buf, int len,
- enum x86_asm_format format ) {
- int len_orig = len;
- const char *reg = "";
- if (! op || ! buf || ! len || ! op->flags.whole) {
- return(0);
- }
- if ( op->type != op_offset && op->type != op_expression ){
- return(0);
- }
- if (! (int) op->flags.op_seg) {
- return(0);
- }
- uint16_t seg_ov=uint16_t(op->flags.op_seg)<<8;
- switch (seg_ov)
- {
- case x86_op_flags::op_es_seg: reg = "es"; break;
- case x86_op_flags::op_cs_seg: reg = "cs"; break;
- case x86_op_flags::op_ss_seg: reg = "ss"; break;
- case x86_op_flags::op_ds_seg: reg = "ds"; break;
- case x86_op_flags::op_fs_seg: reg = "fs"; break;
- case x86_op_flags::op_gs_seg: reg = "gs"; break;
- default:
- break;
- }
- if (! reg[0] ) {
- return( 0 );
- }
- switch( format ) {
- case xml_syntax:
- STRNCAT( buf, "\t\t\t<segment ", len );
- STRNCATF( buf, "value=\"%s\"/>\n", reg, len );
- break;
- case att_syntax:
- STRNCATF( buf, "%%%s:", reg, len );
- break;
- default:
- STRNCATF( buf, "%s:", reg, len );
- break;
- }
- return( len_orig - len ); /* return length of appended string */
- }
- static const char *get_operand_datatype_str( x86_op_t *op ){
- static const char *types[] = {
- "sbyte", /* 0 */
- "sword",
- "sqword",
- "sdword",
- "sdqword", /* 4 */
- "byte",
- "word",
- "qword",
- "dword", /* 8 */
- "dqword",
- "sreal",
- "dreal",
- "extreal", /* 12 */
- "bcd",
- "ssimd",
- "dsimd",
- "sssimd", /* 16 */
- "sdsimd",
- "descr32",
- "descr16",
- "pdescr32", /* 20 */
- "pdescr16",
- "bounds16",
- "bounds32",
- "fpu_env16",
- "fpu_env32", /* 25 */
- "fpu_state16",
- "fpu_state32",
- "fp_reg_set"
- };
- /* handle signed values first */
- if ( op->flags.op_signed ) {
- switch (op->datatype) {
- case op_byte: return types[0];
- case op_word: return types[1];
- case op_qword: return types[2];
- case op_dqword: return types[4];
- default: return types[3];
- }
- }
- switch (op->datatype) {
- case op_byte: return types[5];
- case op_word: return types[6];
- case op_qword: return types[7];
- case op_dqword: return types[9];
- case op_sreal: return types[10];
- case op_dreal: return types[11];
- case op_extreal: return types[12];
- case op_bcd: return types[13];
- case op_ssimd: return types[14];
- case op_dsimd: return types[15];
- case op_sssimd: return types[16];
- case op_sdsimd: return types[17];
- case op_descr32: return types[18];
- case op_descr16: return types[19];
- case op_pdescr32: return types[20];
- case op_pdescr16: return types[21];
- case op_bounds16: return types[22];
- case op_bounds32: return types[23];
- case op_fpustate16: return types[24];
- case op_fpustate32: return types[25];
- case op_fpuenv16: return types[26];
- case op_fpuenv32: return types[27];
- case op_fpregset: return types[28];
- default: return types[8];
- }
- }
- static int format_insn_eflags_str( enum x86_flag_status flags, char *buf,
- int len) {
- static struct {
- const char *name;
- int value;
- } insn_flags[] = {
- { "carry_set ", 0x0001 },
- { "zero_set ", 0x0002 },
- { "oflow_set ", 0x0004 },
- { "dir_set ", 0x0008 },
- { "sign_set ", 0x0010 },
- { "parity_set ", 0x0020 },
- { "carry_or_zero_set ", 0x0040 },
- { "zero_set_or_sign_ne_oflow ", 0x0080 },
- { "carry_clear ", 0x0100 },
- { "zero_clear ", 0x0200 },
- { "oflow_clear ", 0x0400 },
- { "dir_clear ", 0x0800 },
- { "sign_clear ", 0x1000 },
- { "parity_clear ", 0x2000 },
- { "sign_eq_oflow ", 0x4000 },
- { "sign_ne_oflow ", 0x8000 },
- { NULL, 0x0000 }, //end
- };
- unsigned int i;
- int len_orig = len;
- for (i = 0; insn_flags[i].name; i++) {
- if (! (flags & insn_flags[i].value) )
- continue;
- STRNCAT( buf, insn_flags[i].name, len );
- }
- return( len_orig - len );
- }
- static const char *get_insn_group_str( enum x86_insn_t::x86_insn_group gp ) {
- static const char *types[] = {
- "", // 0
- "controlflow",// 1
- "arithmetic", // 2
- "logic", // 3
- "stack", // 4
- "comparison", // 5
- "move", // 6
- "string", // 7
- "bit_manip", // 8
- "flag_manip", // 9
- "fpu", // 10
- "", // 11
- "", // 12
- "interrupt", // 13
- "system", // 14
- "other", // 15
- };
- if ( gp > sizeof (types)/sizeof(types[0]) )
- return "";
- return types[gp];
- }
- static const char *get_insn_type_str( enum x86_insn_type type ) {
- static struct {
- const char *name;
- int value;
- } types[] = {
- /* insn_controlflow */
- { "jmp", 0x1001 },
- { "jcc", 0x1002 },
- { "call", 0x1003 },
- { "callcc", 0x1004 },
- { "return", 0x1005 },
- { "loop", 0x1006 },
- /* insn_arithmetic */
- { "add", 0x2001 },
- { "sub", 0x2002 },
- { "mul", 0x2003 },
- { "div", 0x2004 },
- { "inc", 0x2005 },
- { "dec", 0x2006 },
- { "shl", 0x2007 },
- { "shr", 0x2008 },
- { "rol", 0x2009 },
- { "ror", 0x200A },
- /* insn_logic */
- { "and", 0x3001 },
- { "or", 0x3002 },
- { "xor", 0x3003 },
- { "not", 0x3004 },
- { "neg", 0x3005 },
- /* insn_stack */
- { "push", 0x4001 },
- { "pop", 0x4002 },
- { "pushregs", 0x4003 },
- { "popregs", 0x4004 },
- { "pushflags", 0x4005 },
- { "popflags", 0x4006 },
- { "enter", 0x4007 },
- { "leave", 0x4008 },
- /* insn_comparison */
- { "test", 0x5001 },
- { "cmp", 0x5002 },
- /* insn_move */
- { "mov", 0x6001 }, /* move */
- { "movcc", 0x6002 }, /* conditional move */
- { "xchg", 0x6003 }, /* exchange */
- { "xchgcc", 0x6004 }, /* conditional exchange */
- /* insn_string */
- { "strcmp", 0x7001 },
- { "strload", 0x7002 },
- { "strmov", 0x7003 },
- { "strstore", 0x7004 },
- { "translate", 0x7005 }, /* xlat */
- /* insn_bit_manip */
- { "bittest", 0x8001 },
- { "bitset", 0x8002 },
- { "bitclear", 0x8003 },
- /* insn_flag_manip */
- { "clear_carry", 0x9001 },
- { "clear_zero", 0x9002 },
- { "clear_oflow", 0x9003 },
- { "clear_dir", 0x9004 },
- { "clear_sign", 0x9005 },
- { "clear_parity", 0x9006 },
- { "set_carry", 0x9007 },
- { "set_zero", 0x9008 },
- { "set_oflow", 0x9009 },
- { "set_dir", 0x900A },
- { "set_sign", 0x900B },
- { "set_parity", 0x900C },
- { "tog_carry", 0x9010 },
- { "tog_zero", 0x9020 },
- { "tog_oflow", 0x9030 },
- { "tog_dir", 0x9040 },
- { "tog_sign", 0x9050 },
- { "tog_parity", 0x9060 },
- /* insn_fpu */
- { "fmov", 0xA001 },
- { "fmovcc", 0xA002 },
- { "fneg", 0xA003 },
- { "fabs", 0xA004 },
- { "fadd", 0xA005 },
- { "fsub", 0xA006 },
- { "fmul", 0xA007 },
- { "fdiv", 0xA008 },
- { "fsqrt", 0xA009 },
- { "fcmp", 0xA00A },
- { "fcos", 0xA00C },
- { "fldpi", 0xA00D },
- { "fldz", 0xA00E },
- { "ftan", 0xA00F },
- { "fsine", 0xA010 },
- { "fsys", 0xA020 },
- /* insn_interrupt */
- { "int", 0xD001 },
- { "intcc", 0xD002 }, /* not present in x86 ISA */
- { "iret", 0xD003 },
- { "bound", 0xD004 },
- { "debug", 0xD005 },
- { "trace", 0xD006 },
- { "invalid_op", 0xD007 },
- { "oflow", 0xD008 },
- /* insn_system */
- { "halt", 0xE001 },
- { "in", 0xE002 }, /* input from port/bus */
- { "out", 0xE003 }, /* output to port/bus */
- { "cpuid", 0xE004 },
- /* insn_other */
- { "nop", 0xF001 },
- { "bcdconv", 0xF002 }, /* convert to or from BCD */
- { "szconv", 0xF003 }, /* change size of operand */
- { NULL, 0 }, //end
- };
- unsigned int i;
- //go thru every type in the enum
- for ( i = 0; types[i].name; i++ ) {
- if ( types[i].value == type )
- return types[i].name;
- }
- return "";
- }
- static const char *get_insn_cpu_str( enum x86_insn_cpu cpu ) {
- static const char *intel[] = {
- "", // 0
- "8086", // 1
- "80286", // 2
- "80386", // 3
- "80387", // 4
- "80486", // 5
- "Pentium", // 6
- "Pentium Pro", // 7
- "Pentium 2", // 8
- "Pentium 3", // 9
- "Pentium 4" // 10
- };
- if ( cpu <= sizeof(intel)/sizeof(intel[0]) ) {
- return intel[cpu];
- } else if ( cpu == 16 ) {
- return "K6";
- } else if ( cpu == 32 ) {
- return "K7";
- } else if ( cpu == 48 ) {
- return "Athlon";
- }
- return "";
- }
- static const char *get_insn_isa_str( enum x86_insn_isa isa ) {
- static const char *subset[] = {
- NULL, // 0
- "General Purpose", // 1
- "Floating Point", // 2
- "FPU Management", // 3
- "MMX", // 4
- "SSE", // 5
- "SSE2", // 6
- "SSE3", // 7
- "3DNow!", // 8
- "System" // 9
- };
- if ( isa > sizeof (subset)/sizeof(subset[0]) ) {
- return "";
- }
- return subset[isa];
- }
- static int format_operand_att( x86_op_t *op, x86_insn_t *insn, char *buf,
- int len){
- char str[MAX_OP_STRING];
- memset (str, 0, sizeof str);
- switch ( op->type ) {
- case op_register:
- STRNCATF( buf, "%%%s", op->data.reg.name, len );
- break;
- case op_immediate:
- get_operand_data_str( op, str, sizeof str );
- STRNCATF( buf, "$%s", str, len );
- break;
- case op_relative_near:
- STRNCATF( buf, "0x%08X",
- (unsigned int)(op->data.sbyte +
- insn->addr + insn->size), len );
- break;
- case op_relative_far:
- if (op->datatype == op_word) {
- STRNCATF( buf, "0x%08X",
- (unsigned int)(op->data.sword +
- insn->addr + insn->size), len );
- } else {
- STRNCATF( buf, "0x%08X",
- (unsigned int)(op->data.sdword +
- insn->addr + insn->size), len );
- }
- break;
- case op_absolute:
- /* ATT uses the syntax $section, $offset */
- STRNCATF( buf, "$0x%04" PRIX16 ", ", op->data.absolute.segment,
- len );
- if (op->datatype == op_descr16) {
- STRNCATF( buf, "$0x%04" PRIX16,
- op->data.absolute.offset.off16, len );
- } else {
- STRNCATF( buf, "$0x%08" PRIX32,
- op->data.absolute.offset.off32, len );
- }
- break;
- case op_offset:
- /* ATT requires a '*' before JMP/CALL ops */
- if (insn->type == insn_jmp || insn->type == insn_call)
- STRNCAT( buf, "*", len );
- len -= format_seg( op, buf, len, att_syntax );
- STRNCATF( buf, "0x%08" PRIX32, op->data.sdword, len );
- break;
- case op_expression:
- /* ATT requires a '*' before JMP/CALL ops */
- if (insn->type == insn_jmp || insn->type == insn_call)
- STRNCAT( buf, "*", len );
- len -= format_seg( op, buf, len, att_syntax );
- len -= format_expr( &op->data.expression, buf, len,
- att_syntax );
- break;
- case op_unused:
- case op_unknown:
- /* return 0-truncated buffer */
- break;
- }
- return ( strlen( buf ) );
- }
- static int format_operand_native( x86_op_t *op, x86_insn_t *insn, char *buf,
- int len){
- char str[MAX_OP_STRING];
- switch (op->type) {
- case op_register:
- STRNCAT( buf, op->data.reg.name, len );
- break;
- case op_immediate:
- get_operand_data_str( op, str, sizeof str );
- STRNCAT( buf, str, len );
- break;
- case op_relative_near:
- STRNCATF( buf, "0x%08" PRIX32,
- (unsigned int)(op->data.sbyte +
- insn->addr + insn->size), len );
- break;
- case op_relative_far:
- if ( op->datatype == op_word ) {
- STRNCATF( buf, "0x%08" PRIX32,
- (unsigned int)(op->data.sword +
- insn->addr + insn->size), len );
- break;
- } else {
- STRNCATF( buf, "0x%08" PRIX32, op->data.sdword +
- insn->addr + insn->size, len );
- }
- break;
- case op_absolute:
- STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment,
- len );
- if (op->datatype == op_descr16) {
- STRNCATF( buf, "0x%04" PRIX16,
- op->data.absolute.offset.off16, len );
- } else {
- STRNCATF( buf, "0x%08" PRIX32,
- op->data.absolute.offset.off32, len );
- }
- break;
- case op_offset:
- len -= format_seg( op, buf, len, native_syntax );
- STRNCATF( buf, "[0x%08" PRIX32 "]", op->data.sdword, len );
- break;
- case op_expression:
- len -= format_seg( op, buf, len, native_syntax );
- len -= format_expr( &op->data.expression, buf, len,
- native_syntax );
- break;
- case op_unused:
- case op_unknown:
- /* return 0-truncated buffer */
- break;
- }
- return( strlen( buf ) );
- }
- static int format_operand_xml( x86_op_t *op, x86_insn_t *insn, char *buf,
- int len){
- char str[MAX_OP_STRING] = "\0";
- switch (op->type) {
- case op_register:
- get_operand_regtype_str( op->data.reg.type, str,
- sizeof str );
- STRNCAT( buf, "\t\t<register ", len );
- STRNCATF( buf, "name=\"%s\" ", op->data.reg.name, len );
- STRNCATF( buf, "type=\"%s\" ", str, len );
- STRNCATF( buf, "size=%d/>\n", op->data.reg.size, len );
- break;
- case op_immediate:
- get_operand_data_str( op, str, sizeof str );
- STRNCAT( buf, "\t\t<immediate ", len );
- STRNCATF( buf, "type=\"%s\" ",
- get_operand_datatype_str (op), len );
- STRNCATF( buf, "value=\"%s\"/>\n", str, len );
- break;
- case op_relative_near:
- STRNCAT( buf, "\t\t<relative_offset ", len );
- STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n",
- (unsigned int)(op->data.sbyte +
- insn->addr + insn->size), len );
- break;
- case op_relative_far:
- STRNCAT( buf, "\t\t<relative_offset ", len );
- if (op->datatype == op_word) {
- STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n",
- (unsigned int)(op->data.sword +
- insn->addr + insn->size), len);
- break;
- } else {
- STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n",
- op->data.sdword + insn->addr + insn->size,
- len );
- }
- break;
- case op_absolute:
- STRNCATF( buf,
- "\t\t<absolute_address segment=\"0x%04" PRIX16 "\"",
- op->data.absolute.segment, len );
- if (op->datatype == op_descr16) {
- STRNCATF( buf, "offset=\"0x%04" PRIX16 "\">",
- op->data.absolute.offset.off16, len );
- } else {
- STRNCATF( buf, "offset=\"0x%08" PRIX32 "\">",
- op->data.absolute.offset.off32, len );
- }
- STRNCAT( buf, "\t\t</absolute_address>\n", len );
- break;
- case op_expression:
- STRNCAT( buf, "\t\t<address_expression>\n", len );
- len -= format_seg( op, buf, len, xml_syntax );
- len -= format_expr( &op->data.expression, buf, len,
- xml_syntax );
- STRNCAT( buf, "\t\t</address_expression>\n", len );
- break;
- case op_offset:
- STRNCAT( buf, "\t\t<segment_offset>\n", len );
- len -= format_seg( op, buf, len, xml_syntax );
- STRNCAT( buf, "\t\t\t<address ", len);
- STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n",
- op->data.sdword, len );
- STRNCAT( buf, "\t\t</segment_offset>\n", len );
- break;
- case op_unused:
- case op_unknown:
- /* return 0-truncated buffer */
- break;
- }
- return( strlen( buf ) );
- }
- static int format_operand_raw( x86_op_t *op, x86_insn_t */*insn*/, char *buf,
- int len){
- char str[MAX_OP_RAW_STRING];
- const char *datatype = get_operand_datatype_str(op);
- switch (op->type) {
- case op_register:
- get_operand_regtype_str( op->data.reg.type, str,
- sizeof str );
- STRNCAT( buf, "reg|", len );
- STRNCATF( buf, "%s|", datatype, len );
- STRNCATF( buf, "%s:", op->data.reg.name, len );
- STRNCATF( buf, "%s:", str, len );
- STRNCATF( buf, "%d|", op->data.reg.size, len );
- break;
- case op_immediate:
- get_operand_data_str( op, str, sizeof str );
- STRNCAT( buf, "immediate|", len );
- STRNCATF( buf, "%s|", datatype, len );
- STRNCATF( buf, "%s|", str, len );
- break;
- case op_relative_near:
- /* NOTE: in raw format, we print the
- * relative offset, not the actual
- * address of the jump target */
- STRNCAT( buf, "relative|", len );
- STRNCATF( buf, "%s|", datatype, len );
- STRNCATF( buf, "%" PRId8 "|", op->data.sbyte, len );
- break;
- case op_relative_far:
- STRNCAT( buf, "relative|", len );
- STRNCATF( buf, "%s|", datatype, len );
- if (op->datatype == op_word) {
- STRNCATF( buf, "%" PRId16 "|", op->data.sword, len);
- break;
- } else {
- STRNCATF( buf, "%" PRId32 "|", op->data.sdword, len );
- }
- break;
- case op_absolute:
- STRNCAT( buf, "absolute_address|", len );
- STRNCATF( buf, "%s|", datatype, len );
- STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment,
- len );
- if (op->datatype == op_descr16) {
- STRNCATF( buf, "0x%04" PRIX16 "|",
- op->data.absolute.offset.off16, len );
- } else {
- STRNCATF( buf, "0x%08" PRIX32 "|",
- op->data.absolute.offset.off32, len );
- }
- break;
- case op_expression:
- STRNCAT( buf, "address_expression|", len );
- STRNCATF( buf, "%s|", datatype, len );
- len -= format_seg( op, buf, len, native_syntax );
- len -= format_expr( &op->data.expression, buf, len,
- raw_syntax );
- STRNCAT( buf, "|", len );
- break;
- case op_offset:
- STRNCAT( buf, "segment_offset|", len );
- STRNCATF( buf, "%s|", datatype, len );
- len -= format_seg( op, buf, len, xml_syntax );
- STRNCATF( buf, "%08" PRIX32 "|", op->data.sdword, len );
- break;
- case op_unused:
- case op_unknown:
- /* return 0-truncated buffer */
- break;
- }
- return( strlen( buf ) );
- }
- int x86_op_t::x86_format_operand(char *buf, int len,
- enum x86_asm_format format ){
- x86_insn_t *_insn;
- if ( ! this || ! buf || len < 1 ) {
- return(0);
- }
- /* insn is stored in x86_op_t since .21-pre3 */
- _insn = (x86_insn_t *) insn;
- memset( buf, 0, len );
- switch ( format ) {
- case att_syntax:
- return format_operand_att( this, _insn, buf, len );
- case xml_syntax:
- return format_operand_xml( this, _insn, buf, len );
- case raw_syntax:
- return format_operand_raw( this, _insn, buf, len );
- case native_syntax:
- case intel_syntax:
- default:
- return format_operand_native( this, _insn, buf, len );
- }
- }
- char * x86_op_t::format( enum x86_asm_format format ) {
- char *buf, *str;
- size_t len;
- switch ( format ) {
- case xml_syntax:
- len = MAX_OP_XML_STRING;
- break;
- case raw_syntax:
- len = MAX_OP_RAW_STRING;
- break;
- case native_syntax:
- case intel_syntax:
- case att_syntax:
- case unknown_syntax:
- default:
- len = MAX_OP_STRING;
- break;
- }
- buf = (char * ) calloc( len + 1, 1 );
- x86_format_operand( buf, len, format );
- /* drop buffer down to a reasonable size */
- str = strdup( buf );
- free(buf);
- return str;
- }
- #define is_imm_jmp(op) (op->type == op_absolute || \
- op->type == op_immediate || \
- op->type == op_offset)
- #define is_memory_op(op) (op->type == op_absolute || \
- op->type == op_expression || \
- op->type == op_offset)
- static int format_att_mnemonic( x86_insn_t *insn, char *buf, int len) {
- int size = 0;
- const char *suffix;
- if (! insn || ! buf || ! len )
- return(0);
- memset( buf, 0, len );
- /* do long jump/call prefix */
- if ( insn->type == insn_jmp || insn->type == insn_call ) {
- if (! is_imm_jmp( insn->operand_1st() ) ||
- (insn->operand_1st())->datatype != op_byte ) {
- /* far jump/call, use "l" prefix */
- STRNCAT( buf, "l", len );
- }
- STRNCAT( buf, insn->mnemonic, len );
- return ( strlen( buf ) );
- }
- /* do mnemonic */
- STRNCAT( buf, insn->mnemonic, len );
- /* do suffixes for memory operands */
- if (!(insn->note & insn_note_nosuffix) &&
- (insn->group == x86_insn_t::insn_arithmetic ||
- insn->group == x86_insn_t::insn_logic ||
- insn->group == x86_insn_t::insn_move ||
- insn->group == x86_insn_t::insn_stack ||
- insn->group == x86_insn_t::insn_string ||
- insn->group == x86_insn_t::insn_comparison ||
- insn->type == insn_in ||
- insn->type == insn_out
- )) {
- if ( insn->x86_operand_count( op_explicit ) > 0 &&
- is_memory_op( insn->operand_1st() ) ){
- size = insn->operand_1st()->operand_size();
- } else if ( insn->x86_operand_count( op_explicit ) > 1 &&
- is_memory_op( insn->operand_2nd() ) ){
- size = insn->operand_2nd()->operand_size();
- }
- }
- if ( size == 1 ) suffix = "b";
- else if ( size == 2 ) suffix = "w";
- else if ( size == 4 ) suffix = "l";
- else if ( size == 8 ) suffix = "q";
- else suffix = "";
- STRNCAT( buf, suffix, len );
- return ( strlen( buf ) );
- }
- int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len,
- enum x86_asm_format format){
- char str[MAX_OP_STRING];
- memset( buf, 0, len );
- STRNCAT( buf, insn->prefix_string, len );
- if ( format == att_syntax ) {
- format_att_mnemonic( insn, str, sizeof str );
- STRNCAT( buf, str, len );
- } else {
- STRNCAT( buf, insn->mnemonic, len );
- }
- return( strlen( buf ) );
- }
- struct op_string { char *buf; size_t len; };
- static void format_op_raw( x86_op_t *op, x86_insn_t *insn, void *arg ) {
- struct op_string * opstr = (struct op_string *) arg;
- format_operand_raw(op, insn, opstr->buf, opstr->len);
- }
- static int format_insn_note(x86_insn_t *insn, char *buf, int len){
- char note[32] = {0};
- int len_orig = len, note_len = 32;
- if ( insn->note & insn_note_ring0 ) {
- STRNCATF( note, "%s", "Ring0 ", note_len );
- }
- if ( insn->note & insn_note_smm ) {
- STRNCATF( note, "%s", "SMM ", note_len );
- }
- if ( insn->note & insn_note_serial ) {
- STRNCATF(note, "%s", "Serialize ", note_len );
- }
- STRNCATF( buf, "%s|", note, len );
- return( len_orig - len );
- }
- static int format_raw_insn( x86_insn_t *insn, char *buf, size_t len ){
- struct op_string opstr = { buf, len };
- int i;
- /* RAW style:
- * ADDRESS|OFFSET|SIZE|BYTES|
- * PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|
- * MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|
- * STACK_MOD|STACK_MOD_VAL
- * [|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*
- *
- * Register values are encoded as:
- * NAME:TYPE:SIZE
- *
- * Effective addresses are encoded as:
- * disp(base_reg,index_reg,scale)
- */
- STRNCATF( buf, "0x%08" PRIX32 "|", insn->addr , len );
- STRNCATF( buf, "0x%08" PRIX32 "|", insn->offset, len );
- STRNCATF( buf, "%d|" , insn->size , len );
- /* print bytes */
- for ( i = 0; i < insn->size; i++ ) {
- STRNCATF( buf, "%02X ", insn->bytes[i], len );
- }
- STRNCAT( buf, "|", len );
- len -= format_insn_prefix_str( insn->prefix, buf, len );
- STRNCATF( buf, "|%s|", insn->prefix_string , len );
- STRNCATF( buf, "%s|", get_insn_group_str( insn->group ), len );
- STRNCATF( buf, "%s|", get_insn_type_str( insn->type ) , len );
- STRNCATF( buf, "%s|", insn->mnemonic , len );
- STRNCATF( buf, "%s|", get_insn_cpu_str( insn->cpu ) , len );
- STRNCATF( buf, "%s|", get_insn_isa_str( insn->isa ) , len );
- /* insn note */
- len -= format_insn_note( insn, buf, len );
- len -= format_insn_eflags_str( insn->flags_set, buf, len );
- STRNCAT( buf, "|", len );
- len -= format_insn_eflags_str( insn->flags_tested, buf, len );
- STRNCAT( buf, "|", len );
- STRNCATF( buf, "%d|", insn->stack_mod, len );
- STRNCATF( buf, "%" PRId32 "|", insn->stack_mod_val, len );
- opstr.len = len;
- insn->x86_operand_foreach( format_op_raw, &opstr, op_any );
- return( strlen (buf) );
- }
- static int format_xml_insn( x86_insn_t *insn, char *buf, int len ) {
- char str[MAX_OP_XML_STRING];
- int i;
- STRNCAT( buf, "<x86_insn>\n", len );
- STRNCATF( buf, "\t<address rva=\"0x%08" PRIX32 "\" ", insn->addr, len );
- STRNCATF( buf, "offset=\"0x%08" PRIX32 "\" ", insn->offset, len );
- STRNCATF( buf, "size=%d bytes=\"", insn->size, len );
- for ( i = 0; i < insn->size; i++ ) {
- STRNCATF( buf, "%02X ", insn->bytes[i], len );
- }
- STRNCAT( buf, "\"/>\n", len );
- STRNCAT( buf, "\t<prefix type=\"", len );
- len -= format_insn_prefix_str( insn->prefix, buf, len );
- STRNCATF( buf, "\" string=\"%s\"/>\n", insn->prefix_string, len );
- STRNCATF( buf, "\t<mnemonic group=\"%s\" ",
- get_insn_group_str (insn->group), len );
- STRNCATF( buf, "type=\"%s\" ", get_insn_type_str (insn->type), len );
- STRNCATF( buf, "string=\"%s\"/>\n", insn->mnemonic, len );
- STRNCAT( buf, "\t<flags type=set>\n", len );
- STRNCAT( buf, "\t\t<flag name=\"", len );
- len -= format_insn_eflags_str( insn->flags_set, buf, len );
- STRNCAT( buf, "\"/>\n\t</flags>\n", len );
- STRNCAT( buf, "\t<flags type=tested>\n", len );
- STRNCAT( buf, "\t\t<flag name=\"", len );
- len -= format_insn_eflags_str( insn->flags_tested, buf, len );
- STRNCAT( buf, "\"/>\n\t</flags>\n", len );
- if ( insn->operand_1st() ) {
- insn->operand_1st()->x86_format_operand(str,
- sizeof str, xml_syntax);
- STRNCAT( buf, "\t<operand name=dest>\n", len );
- STRNCAT( buf, str, len );
- STRNCAT( buf, "\t</operand>\n", len );
- }
- if ( insn->operand_2nd() ) {
- insn->operand_2nd()->x86_format_operand(str,sizeof str,
- xml_syntax);
- STRNCAT( buf, "\t<operand name=src>\n", len );
- STRNCAT( buf, str, len );
- STRNCAT( buf, "\t</operand>\n", len );
- }
- if ( insn->operand_3rd() ) {
- insn->operand_3rd()->x86_format_operand(str,sizeof str,
- xml_syntax);
- STRNCAT( buf, "\t<operand name=imm>\n", len );
- STRNCAT( buf, str, len );
- STRNCAT( buf, "\t</operand>\n", len );
- }
- STRNCAT( buf, "</x86_insn>\n", len );
- return strlen (buf);
- }
- int X86_Disasm::x86_format_header( char *buf, int len, enum x86_asm_format format ) {
- switch (format) {
- case att_syntax:
- snprintf( buf, len, "MNEMONIC\tSRC, DEST, IMM" );
- break;
- case intel_syntax:
- snprintf( buf, len, "MNEMONIC\tDEST, SRC, IMM" );
- break;
- case native_syntax:
- snprintf( buf, len, "ADDRESS\tBYTES\tMNEMONIC\t"
- "DEST\tSRC\tIMM" );
- break;
- case raw_syntax:
- snprintf( buf, len, "ADDRESS|OFFSET|SIZE|BYTES|"
- "PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|"
- "MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|"
- "STACK_MOD|STACK_MOD_VAL"
- "[|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*"
- );
- break;
- case xml_syntax:
- snprintf( buf, len,
- "<x86_insn>"
- "<address rva= offset= size= bytes=/>"
- "<prefix type= string=/>"
- "<mnemonic group= type= string= "
- "cpu= isa= note= />"
- "<flags type=set>"
- "<flag name=>"
- "</flags>"
- "<stack_mod val= >"
- "<flags type=tested>"
- "<flag name=>"
- "</flags>"
- "<operand name=>"
- "<register name= type= size=/>"
- "<immediate type= value=/>"
- "<relative_offset value=/>"
- "<absolute_address value=>"
- "<segment value=/>"
- "</absolute_address>"
- "<address_expression>"
- "<segment value=/>"
- "<base>"
- "<register name= type= size=/>"
- "</base>"
- "<index>"
- "<register name= type= size=/>"
- "</index>"
- "<scale>"
- "<immediate value=/>"
- "</scale>"
- "<displacement>"
- "<immediate value=/>"
- "<address value=/>"
- "</displacement>"
- "</address_expression>"
- "<segment_offset>"
- "<address value=/>"
- "</segment_offset>"
- "</operand>"
- "</x86_insn>"
- );
- break;
- case unknown_syntax:
- if ( len ) {
- buf[0] = '\0';
- }
- break;
- }
- return( strlen(buf) );
- }
- /** format (sprintf) an instruction into 'buf' using specified syntax;
- * this includes formatting all operands */
- int x86_insn_t::x86_format_insn( char *buf, int len,
- enum x86_asm_format format ){
- char str[MAX_OP_STRING];
- x86_op_t *src, *dst;
- int i;
- memset(buf, 0, len);
- if ( format == intel_syntax ) {
- /* INTEL STYLE: mnemonic dest, src, imm */
- STRNCAT( buf, prefix_string, len );
- STRNCAT( buf, mnemonic, len );
- STRNCAT( buf, "\t", len );
- /* dest */
- if ( (dst = operand_1st()) && !(dst->flags.op_implied) ) {
- dst->x86_format_operand(str, MAX_OP_STRING, format);
- STRNCAT( buf, str, len );
- }
- /* src */
- if ( (src = operand_2nd()) ) {
- if ( !(dst->flags.op_implied) ) {
- STRNCAT( buf, ", ", len );
- }
- src->x86_format_operand( str, MAX_OP_STRING, format);
- STRNCAT( buf, str, len );
- }
- /* imm */
- if ( operand_3rd()) {
- STRNCAT( buf, ", ", len );
- operand_3rd()->x86_format_operand(str, MAX_OP_STRING,format);
- STRNCAT( buf, str, len );
- }
- } else if ( format == att_syntax ) {
- /* ATT STYLE: mnemonic src, dest, imm */
- STRNCAT( buf, prefix_string, len );
- format_att_mnemonic(this, str, MAX_OP_STRING);
- STRNCATF( buf, "%s\t", str, len);
- /* not sure which is correct? sometimes GNU as requires
- * an imm as the first operand, sometimes as the third... */
- /* imm */
- if ( operand_3rd() ) {
- operand_3rd()->x86_format_operand(str, MAX_OP_STRING,format);
- STRNCAT( buf, str, len );
- /* there is always 'dest' operand if there is 'src' */
- STRNCAT( buf, ", ", len );
- }
- if ( (note & insn_note_nonswap ) == 0 ) {
- /* regular AT&T style swap */
- src = operand_2nd();
- dst = operand_1st();
- }
- else {
- /* special-case instructions */
- src = operand_1st();
- dst = operand_2nd();
- }
- /* src */
- if ( src ) {
- src->x86_format_operand(str, MAX_OP_STRING, format);
- STRNCAT( buf, str, len );
- /* there is always 'dest' operand if there is 'src' */
- if ( dst && !(dst->flags.op_implied) ) {
- STRNCAT( buf, ", ", len );
- }
- }
- /* dest */
- if ( dst && !(dst->flags.op_implied) ) {
- dst->x86_format_operand(str, MAX_OP_STRING, format);
- STRNCAT( buf, str, len );
- }
- } else if ( format == raw_syntax ) {
- format_raw_insn( this, buf, len );
- } else if ( format == xml_syntax ) {
- format_xml_insn( this, buf, len );
- } else { /* default to native */
- /* NATIVE style: RVA\tBYTES\tMNEMONIC\tOPERANDS */
- /* print address */
- STRNCATF( buf, "%08" PRIX32 "\t", addr, len );
- /* print bytes */
- for ( i = 0; i < size; i++ ) {
- STRNCATF( buf, "%02X ", bytes[i], len );
- }
- STRNCAT( buf, "\t", len );
- /* print mnemonic */
- STRNCAT( buf, prefix_string, len );
- STRNCAT( buf, mnemonic, len );
- STRNCAT( buf, "\t", len );
- /* print operands */
- /* dest */
- if ( operand_1st() ) {
- operand_1st()->x86_format_operand(str, MAX_OP_STRING,format);
- STRNCATF( buf, "%s\t", str, len );
- }
- /* src */
- if ( operand_2nd() ) {
- operand_2nd()->x86_format_operand(str, MAX_OP_STRING,format);
- STRNCATF( buf, "%s\t", str, len );
- }
- /* imm */
- if ( operand_3rd()) {
- operand_3rd()->x86_format_operand(str, MAX_OP_STRING,format);
- STRNCAT( buf, str, len );
- }
- }
- return( strlen( buf ) );
- }
|