2 Intel Open Source License
4 Copyright (c) 2002-2007 Intel Corporation
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
10 Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer. Redistributions
12 in binary form must reproduce the above copyright notice, this list of
13 conditions and the following disclaimer in the documentation and/or
14 other materials provided with the distribution. Neither the name of
15 the Intel Corporation nor the names of its contributors may be used to
16 endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
23 ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 /// @file xed-examples-util.cpp
32 /// @author Mark Charney <mark.charney@intel.com>
34 #include "xed-interface.h"
35 #include "xed-examples-util.h"
36 #include <string.h> //strlen, memcmp, memset
37 #if defined(__APPLE__) || defined(__linux__) || defined(__linux)
39 # include <sys/mman.h>
40 # include <sys/types.h>
41 # include <sys/stat.h>
46 #include "xed-portability.h"
50 void xed_decode_file_info_init(xed_decode_file_info_t* p,
51 const xed_state_t* arg_dstate,
53 int arg_decode_only) {
54 p->dstate = *arg_dstate;
56 p->decode_only = arg_decode_only;
60 xed_uint64_t total_time ;
61 xed_uint64_t total_insts ;
62 xed_uint64_t total_ilen ;
63 xed_uint64_t total_olen ;
64 xed_uint64_t total_shorter ;
65 xed_uint64_t total_longer ;
66 xed_uint64_t bad_times ;
67 xed_uint64_t reset_counter;
70 void xed_decode_stats_reset(xed_decode_stats_t* p, xed_uint64_t t1, xed_uint64_t t2) {
72 p->total_time += (t2-t1);
77 if (p->reset_counter == 50) {
79 printf("\n\nRESETTING STATS\n\n");
80 // to ignore startup transients paging everything in.
86 void xed_decode_stats_zero(xed_decode_stats_t* p) {
97 static xed_decode_stats_t xed_stats;
101 int client_verbose=0;
103 ////////////////////////////////////////////////////////////////////////////
105 static char xed_toupper(char c) {
106 if (c >= 'a' && c <= 'z')
111 char* xed_upcase_buf(char* s) {
112 xed_uint_t len = STATIC_CAST(xed_uint_t,strlen(s));
114 for(i=0 ; i < len ; i++ )
115 s[i] = STATIC_CAST(char,xed_toupper(s[i]));
119 static xed_uint8_t convert_nibble(xed_uint8_t x) {
120 // convert ascii nibble to hex
122 if (x >= '0' && x <= '9')
124 else if (x >= 'A' && x <= 'F')
126 else if (x >= 'a' && x <= 'f')
129 printf("Error converting hex digit. Nibble value 0x%x\n", x);
136 xed_int64_t xed_atoi_hex(char* buf) {
139 xed_uint_t len = STATIC_CAST(xed_uint_t,strlen(buf));
140 for(i=0; i<len ; i++)
141 o = o*16 + convert_nibble(buf[i]);
145 xed_int64_t xed_atoi_general(char* buf, int mul) {
146 /* mul should be 1000 or 1024 */
151 while(*p && isspace(*p))
155 // exclude hex; octal works just fine
157 if (*q == '-' || *q == '+')
161 if (*q=='0' && (q[1]=='x' || q[1]=='X'))
163 return xed_strtoll(buf,0);
166 b = xed_strtoll(buf,0);
169 while(*p && (*p == '-' || *p == '+'))
173 while(*p && isdigit(*p))
180 if (*p == 'k' || *p == 'K')
184 else if (*p == 'm' || *p == 'M')
188 else if (*p == 'g' || *p == 'G' || *p == 'b' || *p == 'B')
190 b = b * mul * mul * mul;
197 static char nibble_to_ascii_hex(xed_uint8_t i) {
198 if (i<10) return i+'0';
199 if (i<16) return i-10+'A';
202 void xed_print_hex_line(char* buf, const xed_uint8_t* array, const int length) {
206 n = XED_MAX_INSTRUCTION_BYTES;
207 for( i=0 ; i< n; i++) {
208 buf[2*i+0] = nibble_to_ascii_hex(array[i]>>4);
209 buf[2*i+1] = nibble_to_ascii_hex(array[i]&0xF);
214 void xed_print_hex_lines(char* buf, const xed_uint8_t* array, const int length) {
218 for( i=0 ; i< n; i++) {
219 *b++ = nibble_to_ascii_hex(array[i]>>4);
220 *b++ = nibble_to_ascii_hex(array[i]&0xF);
234 void xedex_derror(const char* s) {
235 printf("[XED CLIENT ERROR] %s\n",s);
239 void xedex_dwarn(const char* s) {
240 printf("[XED CLIENT WARNING] %s\n",s);
244 ////////////////////////////////////////////////////////////////////////////
245 ////////////////////////////////////////////////////////////////////////////
250 void xed_print_decode_stats()
254 printf("#Total decode cycles: " XED_FMT_LU "\n", xed_stats.total_time);
255 printf("#Total instructions decoded: " XED_FMT_LU "\n", xed_stats.total_insts);
256 #if defined(_MSC_VER)
258 # define XCAST(x) STATIC_CAST(xed_int64_t,x)
260 # define XCAST(x) (x)
263 # define XCAST(x) (x)
265 cpi = 1.0 * XCAST(xed_stats.total_time) / XCAST(xed_stats.total_insts);
266 printf("#Total cycles/instructions decoded: %f\n" , cpi);
268 printf("#Bad times: " XED_FMT_LU "\n", xed_stats.bad_times);
269 printf("#Total input length bytes: " XED_FMT_LU "\n", xed_stats.total_ilen );
270 printf("#Total output length bytes: " XED_FMT_LU "\n", xed_stats.total_olen );
271 printf("#Growth bytes: " XED_FMT_LU "\n", xed_stats.total_longer );
272 printf("#Shrinkage bytes: " XED_FMT_LU "\n", xed_stats.total_shorter );
273 growth = xed_stats.total_olen - xed_stats.total_ilen;
274 printf("#Growth/Shrinkage bytes: " XED_FMT_LD "\n", growth );
275 if (xed_stats.total_ilen) {
276 double pct_growth = 100.0 * growth / (double) XCAST(xed_stats.total_ilen);
277 printf("#Code size growth percent: %f\n", pct_growth);
283 xed_map_region(const char* path,
285 unsigned int* length)
291 #if defined(XED_MSVC8)
293 fprintf(stderr,"#Opening %s\n", path);
294 err = fopen_s(&f,path,"rb");
297 fprintf(stderr,"#Opening %s\n", path);
298 f = fopen(path,"rb");
302 fprintf(stderr,"ERROR: Could not open %s\n", path);
305 err = fseek(f, 0, SEEK_END);
307 fprintf(stderr,"ERROR: Could not fseek %s\n", path);
311 fprintf(stderr,"#Trying to read " XED_FMT_SIZET "\n", ilen);
312 p = (xed_uint8_t*)malloc(ilen);
314 err = fseek(f,0, SEEK_SET);
316 fprintf(stderr,"ERROR: Could not fseek to start of file %s\n", path);
323 fprintf(stderr, "#Read EOF. Stopping.\n");
326 n = fread(p+t, 1, ilen-t,f);
328 fprintf(stderr,"#Read " XED_FMT_SIZET " of %d bytes\n", t, ilen);
330 fprintf(stderr, "Error in file read. Stopping.\n");
336 *length = (unsigned int)ilen;
340 fd = open(path, O_RDONLY);
342 printf("Could not open file: %s\n" , path);
345 ilen = lseek(fd, 0, SEEK_END); // find the size.
347 xedex_derror("lseek failed");
349 *length = (unsigned int) ilen;
351 lseek(fd, 0, SEEK_SET); // go to the beginning
354 PROT_READ|PROT_WRITE,
358 if (*start == (void*) -1)
359 xedex_derror("could not map region");
362 printf("Mapped " XED_FMT_U " bytes!\n", *length);
366 ////////////////////////////////////////////////////////////////////////////
368 static int all_zeros(xed_uint8_t* p, unsigned int len) {
377 fn_disassemble_xed(xed_syntax_enum_t syntax,
380 xed_decoded_inst_t* xedd,
381 xed_uint64_t runtime_instruction_address) {
385 //memset(buffer,0,BUFLEN);
386 int ok = xed_format(syntax, xedd, buffer, BUFLEN,runtime_instruction_address);
389 blen = xed_strncpy(buf,buffer,buflen);
392 blen = xed_strncpy(buf,"Error disassembling ",blen);
393 blen = xed_strncat(buf, xed_syntax_enum_t2str(syntax),blen);
394 blen = xed_strncat(buf," syntax.",blen);
400 void disassemble(char* buf,
402 xed_decoded_inst_t* xedd,
403 xed_uint64_t runtime_instruction_address)
407 blen = fn_disassemble_xed(XED_SYNTAX_XED, buf, blen, xedd, runtime_instruction_address);
408 if (att_syntax || intel_syntax)
409 blen = xed_strncat(buf, " | ",blen);
412 char* xbuf = buf+strlen(buf);
413 blen = fn_disassemble_xed(XED_SYNTAX_ATT, xbuf, blen, xedd, runtime_instruction_address);
415 blen = xed_strncat(buf, " | ",blen);
418 char* ybuf = buf+strlen(buf);
419 blen = fn_disassemble_xed(XED_SYNTAX_INTEL, ybuf, blen, xedd, runtime_instruction_address);
423 void xed_decode_error(xed_uint64_t offset, const xed_uint8_t* ptr, xed_error_enum_t xed_error) {
425 printf("ERROR: %s Could not decode at offset 0x" XED_FMT_LX ": [",
426 xed_error_enum_t2str(xed_error),
428 xed_print_hex_line(buf, ptr, 15);
432 ///////////////////////////////////////////////////////////////////////////
435 static void print_hex_line(const xed_uint8_t* p, unsigned int length) {
437 unsigned int lim = 128;
440 xed_print_hex_line(buf,p, lim);
444 xed_uint_t disas_decode_binary(const xed_state_t* dstate,
445 const xed_uint8_t* hex_decode_text,
446 const unsigned int bytes,
447 xed_decoded_inst_t* xedd) {
449 xed_error_enum_t xed_error;
452 if (CLIENT_VERBOSE) {
453 print_hex_line(hex_decode_text, bytes);
456 xed_error = xed_decode(xedd, hex_decode_text, bytes);
458 okay = (xed_error == XED_ERROR_NONE);
459 if (CLIENT_VERBOSE3) {
460 xed_uint64_t delta = t2-t1;
461 printf("Decode time = " XED_FMT_LU "\n", delta);
464 #define TBUF_LEN (1024*3)
465 if (CLIENT_VERBOSE1) {
467 xed_decoded_inst_dump(xedd,tbuf,TBUF_LEN);
470 if (CLIENT_VERBOSE) {
472 if (xed_decoded_inst_valid(xedd)) {
473 printf( "ICLASS: %s CATEGORY: %s EXTENSION: %s\n",
474 xed_iclass_enum_t2str(xed_decoded_inst_get_iclass(xedd)),
475 xed_category_enum_t2str(xed_decoded_inst_get_category(xedd)),
476 xed_extension_enum_t2str(xed_decoded_inst_get_extension(xedd)));
478 memset(buf,0,TBUF_LEN);
479 disassemble(buf,TBUF_LEN, xedd,0);
480 printf("SHORT: %s\n", buf);
485 xed_decode_error(0, hex_decode_text, xed_error);
488 (void) dstate; // pacify compiler
491 xed_uint_t disas_decode_encode_binary(const xed_state_t* dstate,
492 const xed_uint8_t* decode_text_binary,
493 const unsigned int bytes,
494 xed_decoded_inst_t* xedd) {
495 // decode then encode
496 unsigned int retval_olen = 0;
498 xed_bool_t decode_okay = disas_decode_binary(dstate, decode_text_binary, bytes, xedd);
500 xed_error_enum_t encode_okay;
501 unsigned int enc_olen, ilen = XED_MAX_INSTRUCTION_BYTES;
502 xed_uint8_t array[XED_MAX_INSTRUCTION_BYTES];
503 xed_encoder_request_t* enc_req = xedd; // they are basically the same now
504 // convert decode structure to proper encode structure
505 xed_encoder_request_init_from_decode(xedd);
507 // encode it again...
508 encode_okay = xed_encode(enc_req, array, ilen, &enc_olen);
509 if (encode_okay != XED_ERROR_NONE) {
510 if (CLIENT_VERBOSE) {
514 xed_encode_request_print(enc_req, buf, 5000);
515 blen = xed_strncpy(buf2,"Could not re-encode: ", blen);
516 blen = xed_strncat(buf2, buf, blen);
517 blen = xed_strncat(buf2,"\nError code was: ",blen);
518 blen = xed_strncat(buf2,xed_error_enum_t2str(encode_okay),blen);
519 blen = xed_strncat(buf2, "\n",blen);
524 retval_olen = enc_olen;
525 // See if it matched the original...
526 if (CLIENT_VERBOSE) {
528 xed_uint_t dec_length;
529 xed_print_hex_line(buf,array, enc_olen);
530 printf("Encodable! %s\n",buf);
531 dec_length = xed_decoded_inst_get_length(xedd);
532 if ((enc_olen != dec_length || memcmp(decode_text_binary, array, enc_olen) )) {
535 printf("Discrepenacy after re-encoding. dec_len= " XED_FMT_U " ", dec_length);
536 xed_print_hex_line(buf, decode_text_binary, dec_length);
537 printf("[%s] ", buf);
538 printf("enc_olen= " XED_FMT_U "", enc_olen);
539 xed_print_hex_line(buf, array, enc_olen);
540 printf(" [%s] ", buf);
541 printf("for instruction: ");
542 xed_decoded_inst_dump(xedd, buf3,5000);
543 printf("%s\n", buf3);
544 printf("vs Encode request: ");
545 xed_encode_request_print(enc_req, buf2, 5000);
546 printf("%s\n", buf2);
549 printf("Identical re-encoding\n");
558 ///////////////////////////////////////////////////////////////////////////
561 xed_disas_test(const xed_state_t* dstate,
562 unsigned char* s, // start of image
563 unsigned char* a, // start of instructions to decode region
564 unsigned char* q, // end of region
566 xed_uint64_t runtime_vaddr, // where this region would live at runtime
568 char* (*symfn)(xed_uint64_t)) // a function to convert addresses to symbols
570 static int first = 1;
571 xed_uint64_t errors = 0;
581 xed_decoded_inst_t xedd;
584 xed_uint64_t runtime_instruction_address;
587 xed_decode_stats_zero(&xed_stats);
591 // print some stuff in hex from the text segment.
592 // unsigned char* p = a;
593 //xed_uint64_t tlen = q-p;
596 //xed_print_hex_line(p,tlen);
598 m = ninst; // number of things to decode
602 // for skipping long strings of zeros
608 printf("# end of text section.\n");
611 if (CLIENT_VERBOSE3) {
612 printf("\n==============================================\n");
613 printf("Decoding instruction " XED_FMT_U "\n", i);
614 printf("==============================================\n");
617 // if we get two full things of 0's in a row, start skipping.
618 if (all_zeros((xed_uint8_t*) z, 15))
624 else if (last_all_zeros) {
639 runtime_instruction_address = ((xed_uint64_t)(z-a)) + runtime_vaddr;
641 if (CLIENT_VERBOSE3) {
643 printf("Runtime Address " XED_FMT_LX ,runtime_instruction_address);
644 xed_print_hex_line(tbuf, (xed_uint8_t*) z, 15);
645 printf(" [%s]\n", tbuf);
648 xed_decoded_inst_zero_set_mode(&xedd, dstate);
652 xed_uint64_t t1 = get_time();
655 xed_error_enum_t xed_error = xed_decode(&xedd,
656 REINTERPRET_CAST(const xed_uint8_t*,z),
659 okay = (xed_error == XED_ERROR_NONE);
660 xed_decode_stats_reset(&xed_stats, t1, t2);
662 length = xed_decoded_inst_get_length(&xedd);
663 if (okay && length == 0) {
664 printf("Zero length on decoded instruction!\n");
665 xed_decode_error( z-a, z, xed_error);
666 xedex_derror("Dieing");
668 xed_stats.total_ilen += length;
671 if (CLIENT_VERBOSE1) {
673 xed_decoded_inst_dump(&xedd,tbuf, 1024*3);
676 if (CLIENT_VERBOSE) {
678 unsigned int dec_len;
681 char* name = (*symfn)(runtime_instruction_address);
683 printf("\nSYM %s:\n", name);
685 printf("XDIS " XED_FMT_LX ": ", runtime_instruction_address);
686 printf("%-8s ", xed_category_enum_t2str(xed_decoded_inst_get_category(&xedd)));
687 printf("%-4s ", xed_extension_enum_t2str(xed_decoded_inst_get_extension(&xedd)));
688 dec_len = xed_decoded_inst_get_length(&xedd);
689 xed_print_hex_line(buffer, (xed_uint8_t*) z, dec_len);
691 // pad out the instruction bytes
692 for ( sp=dec_len; sp < 12; sp++) {
696 memset(buffer,0,200);
697 disassemble(buffer,200, &xedd, runtime_instruction_address);
698 printf( "%s\n",buffer);
703 xed_decode_error( z-a, z, xed_error);
704 // just give a length of 1B to see if we can restart decode...
710 xed_uint64_t t1 = get_time();
712 unsigned int olen = 0;
713 olen = disas_decode_encode_binary(dstate,
714 REINTERPRET_CAST(const xed_uint8_t*,z),
719 xed_decode_stats_reset(&xed_stats, t1, t2);
722 printf("-- Could not decode/encode at offset: %d\n" ,(int)(z-a));
723 // just give a length of 1B to see if we can restart decode...
728 length = xed_decoded_inst_get_length(&xedd);
729 xed_stats.total_ilen += length;
730 xed_stats.total_olen += olen;
732 xed_stats.total_shorter += (length - olen);
734 xed_stats.total_longer += (olen - length);
742 printf( "# Errors: " XED_FMT_LU "\n", errors);
746 #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 810 && !defined(_M_IA64)
747 # include <ia32intrin.h>
748 # if __INTEL_COMPILER < 1000
749 # pragma intrinsic(__rdtsc)
752 #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_M_IA64) /* MSVS8 and later */
754 # pragma intrinsic(__rdtsc)
757 xed_uint64_t get_time()
761 #if defined(__GNUC__)
762 # if defined(__i386__) || defined(i386) || defined(i686) || defined(__x86_64__)
763 //asm volatile("rdtsc" : "=A" (ticks) );
764 //asm volatile("rdtsc" : "=A" (ticks) :: "edx");
765 asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
772 #if defined(__INTEL_COMPILER) && __INTEL_COMPILER>=810 && !defined(_M_IA64)
776 #if !defined(FOUND_RDTSC) && defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_M_IA64) /* MSVS7, 8 */
780 #if !defined(FOUND_RDTSC)
789 convert_ascii_nibble(char c)
791 if (c >= '0' && c <= '9') {
794 else if (c >= 'a' && c <= 'f') {
797 else if (c >= 'A' && c <= 'F') {
803 xed_strcpy(buffer,"Invalid character in hex string: ");
804 x= buffer+strlen(buffer);
807 xedex_derror(buffer);
814 xed_uint64_t convert_ascii_hex_to_int(const char* s) {
815 xed_uint64_t retval = 0;
818 retval = (retval << 4) + convert_ascii_nibble(*p);
825 xed_uint8_t convert_ascii_nibbles(char c1, char c2) {
826 xed_uint8_t a = convert_ascii_nibble(c1) * 16 + convert_ascii_nibble(c2);
831 xed_convert_ascii_to_hex(const char* src, xed_uint8_t* dst, unsigned int max_bytes)
837 const unsigned int len = STATIC_CAST(unsigned int,strlen(src));
839 xedex_derror("test string was not an even number of nibbles");
841 if (len > (max_bytes * 2) )
842 xedex_derror("test string was too long");
844 for( j=0;j<max_bytes;j++)
849 printf("Converting %c & %c\n", src[p], src[p+1]);
850 dst[i] = convert_ascii_nibbles(src[p], src[p+1]);
856 #if defined(_WIN32) && !defined(__GNUC__)
858 convert_base10(const char* buf)
861 xed_int64_t sign = 1;
862 int len = STATIC_CAST(int,strlen(buf));
867 if (i == 0 && c == '-')
871 else if (c >= '0' && c <= '9')
873 unsigned int digit = c - '0';
885 convert_base16(const char* buf)
888 int len = STATIC_CAST(int,strlen(buf));
891 if (len > 2 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
895 for(i=start;i<len;i++)
898 if (c >= '0' && c <= '9')
900 unsigned int digit = c - '0';
903 else if (c >= 'A' && c <= 'F')
905 unsigned int digit = c - 'A' + 10;
908 else if (c >= 'a' && c <= 'f')
910 unsigned int digit = c - 'a' + 10;
922 xed_internal_strtoll(const char* buf, int base)
927 if (strlen(buf) > 2 && buf[0] == '0' &&
928 (buf[1] == 'x' || buf[1] == 'X'))
930 return convert_base16(buf);
932 return convert_base10(buf);
934 return convert_base10(buf);
936 return convert_base16(buf);
945 xed_int64_t xed_strtoll(const char* buf, int base)
947 #if defined(_WIN32) && !defined(__GNUC__)
948 // 64b version missing on some MS compilers
949 return xed_internal_strtoll(buf,base);
951 return strtoll(buf,0,base);
957 ////////////////////////////////////////////////////////////////////////////
959 //pref: "xed-examples-util.H"