/*BEGIN_LEGAL Intel Open Source License Copyright (c) 2002-2007 Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. END_LEGAL */ /// @file xed-examples-util.cpp /// @author Mark Charney #include "xed-interface.h" #include "xed-examples-util.h" #include //strlen, memcmp, memset #if defined(__APPLE__) || defined(__linux__) || defined(__linux) # include # include # include # include # include #endif #include #include #include "xed-portability.h" #include "xed-util.h" void xed_decode_file_info_init(xed_decode_file_info_t* p, const xed_state_t* arg_dstate, int arg_ninst, int arg_decode_only) { p->dstate = *arg_dstate; p->ninst = arg_ninst; p->decode_only = arg_decode_only; } typedef struct { xed_uint64_t total_time ; xed_uint64_t total_insts ; xed_uint64_t total_ilen ; xed_uint64_t total_olen ; xed_uint64_t total_shorter ; xed_uint64_t total_longer ; xed_uint64_t bad_times ; xed_uint64_t reset_counter; } xed_decode_stats_t; void xed_decode_stats_reset(xed_decode_stats_t* p, xed_uint64_t t1, xed_uint64_t t2) { if (t2 > t1) p->total_time += (t2-t1); else p->bad_times++; p->total_insts++; p->reset_counter++; if (p->reset_counter == 50) { if (CLIENT_VERBOSE1) printf("\n\nRESETTING STATS\n\n"); // to ignore startup transients paging everything in. p->total_insts=0; p->total_time=0; } } void xed_decode_stats_zero(xed_decode_stats_t* p) { p->total_time = 0; p->total_insts = 0; p->total_ilen = 0; p->total_olen = 0; p->total_shorter = 0; p->total_longer = 0; p->bad_times = 0; p->reset_counter = 0; } static xed_decode_stats_t xed_stats; int xed_syntax = 0; int intel_syntax = 1; int att_syntax = 0; int client_verbose=0; //////////////////////////////////////////////////////////////////////////// static char xed_toupper(char c) { if (c >= 'a' && c <= 'z') return c-'a'+'A'; return c; } char* xed_upcase_buf(char* s) { xed_uint_t len = STATIC_CAST(xed_uint_t,strlen(s)); xed_uint_t i; for(i=0 ; i < len ; i++ ) s[i] = STATIC_CAST(char,xed_toupper(s[i])); return s; } static xed_uint8_t convert_nibble(xed_uint8_t x) { // convert ascii nibble to hex xed_uint8_t rv = 0; if (x >= '0' && x <= '9') rv = x - '0'; else if (x >= 'A' && x <= 'F') rv = x - 'A' + 10; else if (x >= 'a' && x <= 'f') rv = x - 'a' + 10; else { printf("Error converting hex digit. Nibble value 0x%x\n", x); exit(1); } return rv; } xed_int64_t xed_atoi_hex(char* buf) { xed_int64_t o=0; xed_uint_t i; xed_uint_t len = STATIC_CAST(xed_uint_t,strlen(buf)); for(i=0; i>4); buf[2*i+1] = nibble_to_ascii_hex(array[i]&0xF); } buf[2*i]=0; } void xed_print_hex_lines(char* buf, const xed_uint8_t* array, const int length) { int n = length; int i=0,j=0; char* b = buf; for( i=0 ; i< n; i++) { *b++ = nibble_to_ascii_hex(array[i]>>4); *b++ = nibble_to_ascii_hex(array[i]&0xF); j++; if (j == 16) { j = 0; *b++ = '\n'; } } *b++ = '\n'; *b = '0'; } void xedex_derror(const char* s) { printf("[XED CLIENT ERROR] %s\n",s); exit(1); } void xedex_dwarn(const char* s) { printf("[XED CLIENT WARNING] %s\n",s); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// void xed_print_decode_stats() { double cpi; xed_int64_t growth; printf("#Total decode cycles: " XED_FMT_LU "\n", xed_stats.total_time); printf("#Total instructions decoded: " XED_FMT_LU "\n", xed_stats.total_insts); #if defined(_MSC_VER) # if _MSC_VER==1200 # define XCAST(x) STATIC_CAST(xed_int64_t,x) # else # define XCAST(x) (x) # endif #else # define XCAST(x) (x) #endif cpi = 1.0 * XCAST(xed_stats.total_time) / XCAST(xed_stats.total_insts); printf("#Total cycles/instructions decoded: %f\n" , cpi); printf("#Bad times: " XED_FMT_LU "\n", xed_stats.bad_times); printf("#Total input length bytes: " XED_FMT_LU "\n", xed_stats.total_ilen ); printf("#Total output length bytes: " XED_FMT_LU "\n", xed_stats.total_olen ); printf("#Growth bytes: " XED_FMT_LU "\n", xed_stats.total_longer ); printf("#Shrinkage bytes: " XED_FMT_LU "\n", xed_stats.total_shorter ); growth = xed_stats.total_olen - xed_stats.total_ilen; printf("#Growth/Shrinkage bytes: " XED_FMT_LD "\n", growth ); if (xed_stats.total_ilen) { double pct_growth = 100.0 * growth / (double) XCAST(xed_stats.total_ilen); printf("#Code size growth percent: %f\n", pct_growth); } } void xed_map_region(const char* path, void** start, unsigned int* length) { #if defined(_WIN32) FILE* f; size_t t,ilen; xed_uint8_t* p; #if defined(XED_MSVC8) errno_t err; fprintf(stderr,"#Opening %s\n", path); err = fopen_s(&f,path,"rb"); #else int err=0; fprintf(stderr,"#Opening %s\n", path); f = fopen(path,"rb"); err = (f==0); #endif if (err != 0) { fprintf(stderr,"ERROR: Could not open %s\n", path); exit(1); } err = fseek(f, 0, SEEK_END); if (err != 0) { fprintf(stderr,"ERROR: Could not fseek %s\n", path); exit(1); } ilen = ftell(f); fprintf(stderr,"#Trying to read " XED_FMT_SIZET "\n", ilen); p = (xed_uint8_t*)malloc(ilen); t=0; err = fseek(f,0, SEEK_SET); if (err != 0) { fprintf(stderr,"ERROR: Could not fseek to start of file %s\n", path); exit(1); } while(t < ilen) { size_t n; if (feof(f)) { fprintf(stderr, "#Read EOF. Stopping.\n"); break; } n = fread(p+t, 1, ilen-t,f); t = t+n; fprintf(stderr,"#Read " XED_FMT_SIZET " of %d bytes\n", t, ilen); if (ferror(f)) { fprintf(stderr, "Error in file read. Stopping.\n"); break; } } fclose(f); *start = p; *length = (unsigned int)ilen; #else int ilen,fd; fd = open(path, O_RDONLY); if (fd == -1) { printf("Could not open file: %s\n" , path); exit(1); } ilen = lseek(fd, 0, SEEK_END); // find the size. if (ilen == -1) xedex_derror("lseek failed"); else *length = (unsigned int) ilen; lseek(fd, 0, SEEK_SET); // go to the beginning *start = mmap(0, *length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (*start == (void*) -1) xedex_derror("could not map region"); #endif if (CLIENT_VERBOSE1) printf("Mapped " XED_FMT_U " bytes!\n", *length); } //////////////////////////////////////////////////////////////////////////// static int all_zeros(xed_uint8_t* p, unsigned int len) { unsigned int i; for( i=0;i 1024 ) // tlen = 1024; //xed_print_hex_line(p,tlen); m = ninst; // number of things to decode z = a; len = 15; //FIXME // for skipping long strings of zeros skipping = 0; last_all_zeros = 0; for( i=0; i= q) { printf("# end of text section.\n"); break; } if (CLIENT_VERBOSE3) { printf("\n==============================================\n"); printf("Decoding instruction " XED_FMT_U "\n", i); printf("==============================================\n"); } // if we get two full things of 0's in a row, start skipping. if (all_zeros((xed_uint8_t*) z, 15)) { if (skipping) { z = z + 15; continue; } else if (last_all_zeros) { printf("...\n"); z = z + 15; skipping = 1; continue; } else last_all_zeros = 1; } else { skipping = 0; last_all_zeros = 0; } runtime_instruction_address = ((xed_uint64_t)(z-a)) + runtime_vaddr; if (CLIENT_VERBOSE3) { char tbuf[200]; printf("Runtime Address " XED_FMT_LX ,runtime_instruction_address); xed_print_hex_line(tbuf, (xed_uint8_t*) z, 15); printf(" [%s]\n", tbuf); } okay = 0; xed_decoded_inst_zero_set_mode(&xedd, dstate); length = 0; if ( decode_only ) { xed_uint64_t t1 = get_time(); xed_uint64_t t2; xed_error_enum_t xed_error = xed_decode(&xedd, REINTERPRET_CAST(const xed_uint8_t*,z), len); t2 = get_time(); okay = (xed_error == XED_ERROR_NONE); xed_decode_stats_reset(&xed_stats, t1, t2); length = xed_decoded_inst_get_length(&xedd); if (okay && length == 0) { printf("Zero length on decoded instruction!\n"); xed_decode_error( z-a, z, xed_error); xedex_derror("Dieing"); } xed_stats.total_ilen += length; if (okay) { if (CLIENT_VERBOSE1) { char tbuf[1024*3]; xed_decoded_inst_dump(&xedd,tbuf, 1024*3); printf("%s\n",tbuf); } if (CLIENT_VERBOSE) { char buffer[200]; unsigned int dec_len; unsigned int sp; if (symfn) { char* name = (*symfn)(runtime_instruction_address); if (name) printf("\nSYM %s:\n", name); } printf("XDIS " XED_FMT_LX ": ", runtime_instruction_address); printf("%-8s ", xed_category_enum_t2str(xed_decoded_inst_get_category(&xedd))); printf("%-4s ", xed_extension_enum_t2str(xed_decoded_inst_get_extension(&xedd))); dec_len = xed_decoded_inst_get_length(&xedd); xed_print_hex_line(buffer, (xed_uint8_t*) z, dec_len); printf("%s",buffer); // pad out the instruction bytes for ( sp=dec_len; sp < 12; sp++) { printf(" "); } printf(" "); memset(buffer,0,200); disassemble(buffer,200, &xedd, runtime_instruction_address); printf( "%s\n",buffer); } } else { errors++; xed_decode_error( z-a, z, xed_error); // just give a length of 1B to see if we can restart decode... length = 1; } } else { xed_uint64_t t1 = get_time(); xed_uint64_t t2; unsigned int olen = 0; olen = disas_decode_encode_binary(dstate, REINTERPRET_CAST(const xed_uint8_t*,z), len, &xedd); t2=get_time(); okay = (olen != 0); xed_decode_stats_reset(&xed_stats, t1, t2); if (!okay) { errors++; printf("-- Could not decode/encode at offset: %d\n" ,(int)(z-a)); // just give a length of 1B to see if we can restart decode... length = 1; //exit(1); } else { length = xed_decoded_inst_get_length(&xedd); xed_stats.total_ilen += length; xed_stats.total_olen += olen; if (length > olen) xed_stats.total_shorter += (length - olen); else xed_stats.total_longer += (olen - length); } } z = z + length; } printf( "# Errors: " XED_FMT_LU "\n", errors); (void) s; } #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 810 && !defined(_M_IA64) # include # if __INTEL_COMPILER < 1000 # pragma intrinsic(__rdtsc) # endif #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_M_IA64) /* MSVS8 and later */ # include # pragma intrinsic(__rdtsc) #endif xed_uint64_t get_time() { xed_uint64_t ticks; xed_uint32_t lo,hi; #if defined(__GNUC__) # if defined(__i386__) || defined(i386) || defined(i686) || defined(__x86_64__) //asm volatile("rdtsc" : "=A" (ticks) ); //asm volatile("rdtsc" : "=A" (ticks) :: "edx"); asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); ticks = hi; ticks <<=32; ticks |=lo; # define FOUND_RDTSC # endif #endif #if defined(__INTEL_COMPILER) && __INTEL_COMPILER>=810 && !defined(_M_IA64) ticks = __rdtsc(); # define FOUND_RDTSC #endif #if !defined(FOUND_RDTSC) && defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_M_IA64) /* MSVS7, 8 */ ticks = __rdtsc(); # define FOUND_RDTSC #endif #if !defined(FOUND_RDTSC) ticks = 0; #endif return ticks; (void)hi; (void)lo; } xed_uint8_t convert_ascii_nibble(char c) { if (c >= '0' && c <= '9') { return c-'0'; } else if (c >= 'a' && c <= 'f') { return c-'a' + 10; } else if (c >= 'A' && c <= 'F') { return c-'A' + 10; } else { char buffer[200]; char* x; xed_strcpy(buffer,"Invalid character in hex string: "); x= buffer+strlen(buffer); *x++ = c; *x++ = 0; xedex_derror(buffer); return 0; } } xed_uint64_t convert_ascii_hex_to_int(const char* s) { xed_uint64_t retval = 0; const char* p = s; while (*p) { retval = (retval << 4) + convert_ascii_nibble(*p); p++; } return retval; } xed_uint8_t convert_ascii_nibbles(char c1, char c2) { xed_uint8_t a = convert_ascii_nibble(c1) * 16 + convert_ascii_nibble(c2); return a; } unsigned int xed_convert_ascii_to_hex(const char* src, xed_uint8_t* dst, unsigned int max_bytes) { unsigned int j; unsigned int p = 0; unsigned int i = 0; const unsigned int len = STATIC_CAST(unsigned int,strlen(src)); if ((len & 1) != 0) xedex_derror("test string was not an even number of nibbles"); if (len > (max_bytes * 2) ) xedex_derror("test string was too long"); for( j=0;j= '0' && c <= '9') { unsigned int digit = c - '0'; v = v*10 + digit; } else { break; } } return v*sign; } static xed_int64_t convert_base16(const char* buf) { xed_int64_t v = 0; int len = STATIC_CAST(int,strlen(buf)); int start =0 ; int i; if (len > 2 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) { start = 2; } for(i=start;i= '0' && c <= '9') { unsigned int digit = c - '0'; v = v*16 + digit; } else if (c >= 'A' && c <= 'F') { unsigned int digit = c - 'A' + 10; v = v*16 + digit; } else if (c >= 'a' && c <= 'f') { unsigned int digit = c - 'a' + 10; v = v*16 + digit; } else { break; } } return v; } static xed_int64_t xed_internal_strtoll(const char* buf, int base) { switch(base) { case 0: if (strlen(buf) > 2 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) { return convert_base16(buf); } return convert_base10(buf); case 10: return convert_base10(buf); case 16: return convert_base16(buf); default: xed_assert(0); } return 0; } #endif xed_int64_t xed_strtoll(const char* buf, int base) { #if defined(_WIN32) && !defined(__GNUC__) // 64b version missing on some MS compilers return xed_internal_strtoll(buf,base); #else return strtoll(buf,0,base); #endif } //////////////////////////////////////////////////////////////////////////// //Local Variables: //pref: "xed-examples-util.H" //End: