11ec454baSMasami Hiramatsu /* 21ec454baSMasami Hiramatsu * x86 decoder sanity test - based on test_get_insn.c 31ec454baSMasami Hiramatsu * 41ec454baSMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 51ec454baSMasami Hiramatsu * it under the terms of the GNU General Public License as published by 61ec454baSMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 71ec454baSMasami Hiramatsu * (at your option) any later version. 81ec454baSMasami Hiramatsu * 91ec454baSMasami Hiramatsu * This program is distributed in the hope that it will be useful, 101ec454baSMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 111ec454baSMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121ec454baSMasami Hiramatsu * GNU General Public License for more details. 131ec454baSMasami Hiramatsu * 141ec454baSMasami Hiramatsu * You should have received a copy of the GNU General Public License 151ec454baSMasami Hiramatsu * along with this program; if not, write to the Free Software 161ec454baSMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 171ec454baSMasami Hiramatsu * 181ec454baSMasami Hiramatsu * Copyright (C) IBM Corporation, 2009 191ec454baSMasami Hiramatsu * Copyright (C) Hitachi, Ltd., 2011 201ec454baSMasami Hiramatsu */ 211ec454baSMasami Hiramatsu 221ec454baSMasami Hiramatsu #include <stdlib.h> 231ec454baSMasami Hiramatsu #include <stdio.h> 241ec454baSMasami Hiramatsu #include <string.h> 251ec454baSMasami Hiramatsu #include <assert.h> 261ec454baSMasami Hiramatsu #include <unistd.h> 271ec454baSMasami Hiramatsu #include <sys/types.h> 281ec454baSMasami Hiramatsu #include <sys/stat.h> 291ec454baSMasami Hiramatsu #include <fcntl.h> 301ec454baSMasami Hiramatsu 311ec454baSMasami Hiramatsu #define unlikely(cond) (cond) 321ec454baSMasami Hiramatsu #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) 331ec454baSMasami Hiramatsu 341ec454baSMasami Hiramatsu #include <asm/insn.h> 351ec454baSMasami Hiramatsu #include <inat.c> 361ec454baSMasami Hiramatsu #include <insn.c> 371ec454baSMasami Hiramatsu 381ec454baSMasami Hiramatsu /* 391ec454baSMasami Hiramatsu * Test of instruction analysis against tampering. 401ec454baSMasami Hiramatsu * Feed random binary to instruction decoder and ensure not to 411ec454baSMasami Hiramatsu * access out-of-instruction-buffer. 421ec454baSMasami Hiramatsu */ 431ec454baSMasami Hiramatsu 441ec454baSMasami Hiramatsu #define DEFAULT_MAX_ITER 10000 451ec454baSMasami Hiramatsu #define INSN_NOP 0x90 461ec454baSMasami Hiramatsu 471ec454baSMasami Hiramatsu static const char *prog; /* Program name */ 481ec454baSMasami Hiramatsu static int verbose; /* Verbosity */ 491ec454baSMasami Hiramatsu static int x86_64; /* x86-64 bit mode flag */ 501ec454baSMasami Hiramatsu static unsigned int seed; /* Random seed */ 511ec454baSMasami Hiramatsu static unsigned long iter_start; /* Start of iteration number */ 521ec454baSMasami Hiramatsu static unsigned long iter_end = DEFAULT_MAX_ITER; /* End of iteration number */ 531ec454baSMasami Hiramatsu static FILE *input_file; /* Input file name */ 541ec454baSMasami Hiramatsu 551ec454baSMasami Hiramatsu static void usage(const char *err) 561ec454baSMasami Hiramatsu { 571ec454baSMasami Hiramatsu if (err) 581ec454baSMasami Hiramatsu fprintf(stderr, "Error: %s\n\n", err); 591ec454baSMasami Hiramatsu fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog); 601ec454baSMasami Hiramatsu fprintf(stderr, "\t-y 64bit mode\n"); 611ec454baSMasami Hiramatsu fprintf(stderr, "\t-n 32bit mode\n"); 629dde9dc0SMasami Hiramatsu fprintf(stderr, "\t-v Verbosity(-vv dumps any decoded result)\n"); 631ec454baSMasami Hiramatsu fprintf(stderr, "\t-s Give a random seed (and iteration number)\n"); 641ec454baSMasami Hiramatsu fprintf(stderr, "\t-m Give a maximum iteration number\n"); 651ec454baSMasami Hiramatsu fprintf(stderr, "\t-i Give an input file with decoded binary\n"); 661ec454baSMasami Hiramatsu exit(1); 671ec454baSMasami Hiramatsu } 681ec454baSMasami Hiramatsu 691ec454baSMasami Hiramatsu static void dump_field(FILE *fp, const char *name, const char *indent, 701ec454baSMasami Hiramatsu struct insn_field *field) 711ec454baSMasami Hiramatsu { 721ec454baSMasami Hiramatsu fprintf(fp, "%s.%s = {\n", indent, name); 731ec454baSMasami Hiramatsu fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n", 741ec454baSMasami Hiramatsu indent, field->value, field->bytes[0], field->bytes[1], 751ec454baSMasami Hiramatsu field->bytes[2], field->bytes[3]); 761ec454baSMasami Hiramatsu fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent, 771ec454baSMasami Hiramatsu field->got, field->nbytes); 781ec454baSMasami Hiramatsu } 791ec454baSMasami Hiramatsu 801ec454baSMasami Hiramatsu static void dump_insn(FILE *fp, struct insn *insn) 811ec454baSMasami Hiramatsu { 821ec454baSMasami Hiramatsu fprintf(fp, "Instruction = {\n"); 831ec454baSMasami Hiramatsu dump_field(fp, "prefixes", "\t", &insn->prefixes); 841ec454baSMasami Hiramatsu dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix); 851ec454baSMasami Hiramatsu dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix); 861ec454baSMasami Hiramatsu dump_field(fp, "opcode", "\t", &insn->opcode); 871ec454baSMasami Hiramatsu dump_field(fp, "modrm", "\t", &insn->modrm); 881ec454baSMasami Hiramatsu dump_field(fp, "sib", "\t", &insn->sib); 891ec454baSMasami Hiramatsu dump_field(fp, "displacement", "\t", &insn->displacement); 901ec454baSMasami Hiramatsu dump_field(fp, "immediate1", "\t", &insn->immediate1); 911ec454baSMasami Hiramatsu dump_field(fp, "immediate2", "\t", &insn->immediate2); 921ec454baSMasami Hiramatsu fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n", 931ec454baSMasami Hiramatsu insn->attr, insn->opnd_bytes, insn->addr_bytes); 941ec454baSMasami Hiramatsu fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n", 951ec454baSMasami Hiramatsu insn->length, insn->x86_64, insn->kaddr); 961ec454baSMasami Hiramatsu } 971ec454baSMasami Hiramatsu 981ec454baSMasami Hiramatsu static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter, 991ec454baSMasami Hiramatsu unsigned char *insn_buf, struct insn *insn) 1001ec454baSMasami Hiramatsu { 1011ec454baSMasami Hiramatsu int i; 1021ec454baSMasami Hiramatsu 1031ec454baSMasami Hiramatsu fprintf(fp, "%s:\n", msg); 1041ec454baSMasami Hiramatsu 105e70825fcSMasami Hiramatsu dump_insn(fp, insn); 1061ec454baSMasami Hiramatsu 1071ec454baSMasami Hiramatsu fprintf(fp, "You can reproduce this with below command(s);\n"); 1081ec454baSMasami Hiramatsu 1091ec454baSMasami Hiramatsu /* Input a decoded instruction sequence directly */ 1101ec454baSMasami Hiramatsu fprintf(fp, " $ echo "); 1111ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE; i++) 1121ec454baSMasami Hiramatsu fprintf(fp, " %02x", insn_buf[i]); 1131ec454baSMasami Hiramatsu fprintf(fp, " | %s -i -\n", prog); 1141ec454baSMasami Hiramatsu 1151ec454baSMasami Hiramatsu if (!input_file) { 1161ec454baSMasami Hiramatsu fprintf(fp, "Or \n"); 1171ec454baSMasami Hiramatsu /* Give a seed and iteration number */ 1181ec454baSMasami Hiramatsu fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter); 1191ec454baSMasami Hiramatsu } 1201ec454baSMasami Hiramatsu } 1211ec454baSMasami Hiramatsu 1221ec454baSMasami Hiramatsu static void init_random_seed(void) 1231ec454baSMasami Hiramatsu { 1241ec454baSMasami Hiramatsu int fd; 1251ec454baSMasami Hiramatsu 1261ec454baSMasami Hiramatsu fd = open("/dev/urandom", O_RDONLY); 1271ec454baSMasami Hiramatsu if (fd < 0) 1281ec454baSMasami Hiramatsu goto fail; 1291ec454baSMasami Hiramatsu 1301ec454baSMasami Hiramatsu if (read(fd, &seed, sizeof(seed)) != sizeof(seed)) 1311ec454baSMasami Hiramatsu goto fail; 1321ec454baSMasami Hiramatsu 1331ec454baSMasami Hiramatsu close(fd); 1341ec454baSMasami Hiramatsu return; 1351ec454baSMasami Hiramatsu fail: 1361ec454baSMasami Hiramatsu usage("Failed to open /dev/urandom"); 1371ec454baSMasami Hiramatsu } 1381ec454baSMasami Hiramatsu 1391ec454baSMasami Hiramatsu /* Read given instruction sequence from the input file */ 1401ec454baSMasami Hiramatsu static int read_next_insn(unsigned char *insn_buf) 1411ec454baSMasami Hiramatsu { 1421ec454baSMasami Hiramatsu char buf[256] = "", *tmp; 1431ec454baSMasami Hiramatsu int i; 1441ec454baSMasami Hiramatsu 1451ec454baSMasami Hiramatsu tmp = fgets(buf, ARRAY_SIZE(buf), input_file); 1461ec454baSMasami Hiramatsu if (tmp == NULL || feof(input_file)) 1471ec454baSMasami Hiramatsu return 0; 1481ec454baSMasami Hiramatsu 1491ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE; i++) { 1501ec454baSMasami Hiramatsu insn_buf[i] = (unsigned char)strtoul(tmp, &tmp, 16); 1511ec454baSMasami Hiramatsu if (*tmp != ' ') 1521ec454baSMasami Hiramatsu break; 1531ec454baSMasami Hiramatsu } 1541ec454baSMasami Hiramatsu 1551ec454baSMasami Hiramatsu return i; 1561ec454baSMasami Hiramatsu } 1571ec454baSMasami Hiramatsu 1581ec454baSMasami Hiramatsu static int generate_insn(unsigned char *insn_buf) 1591ec454baSMasami Hiramatsu { 1601ec454baSMasami Hiramatsu int i; 1611ec454baSMasami Hiramatsu 1621ec454baSMasami Hiramatsu if (input_file) 1631ec454baSMasami Hiramatsu return read_next_insn(insn_buf); 1641ec454baSMasami Hiramatsu 1651ec454baSMasami Hiramatsu /* Fills buffer with random binary up to MAX_INSN_SIZE */ 1661ec454baSMasami Hiramatsu for (i = 0; i < MAX_INSN_SIZE - 1; i += 2) 1671ec454baSMasami Hiramatsu *(unsigned short *)(&insn_buf[i]) = random() & 0xffff; 1681ec454baSMasami Hiramatsu 1691ec454baSMasami Hiramatsu while (i < MAX_INSN_SIZE) 1701ec454baSMasami Hiramatsu insn_buf[i++] = random() & 0xff; 1711ec454baSMasami Hiramatsu 1721ec454baSMasami Hiramatsu return i; 1731ec454baSMasami Hiramatsu } 1741ec454baSMasami Hiramatsu 1751ec454baSMasami Hiramatsu static void parse_args(int argc, char **argv) 1761ec454baSMasami Hiramatsu { 1771ec454baSMasami Hiramatsu int c; 1781ec454baSMasami Hiramatsu char *tmp = NULL; 1791ec454baSMasami Hiramatsu int set_seed = 0; 1801ec454baSMasami Hiramatsu 1811ec454baSMasami Hiramatsu prog = argv[0]; 1821ec454baSMasami Hiramatsu while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) { 1831ec454baSMasami Hiramatsu switch (c) { 1841ec454baSMasami Hiramatsu case 'y': 1851ec454baSMasami Hiramatsu x86_64 = 1; 1861ec454baSMasami Hiramatsu break; 1871ec454baSMasami Hiramatsu case 'n': 1881ec454baSMasami Hiramatsu x86_64 = 0; 1891ec454baSMasami Hiramatsu break; 1901ec454baSMasami Hiramatsu case 'v': 1919dde9dc0SMasami Hiramatsu verbose++; 1921ec454baSMasami Hiramatsu break; 1931ec454baSMasami Hiramatsu case 'i': 1941ec454baSMasami Hiramatsu if (strcmp("-", optarg) == 0) 1951ec454baSMasami Hiramatsu input_file = stdin; 1961ec454baSMasami Hiramatsu else 1971ec454baSMasami Hiramatsu input_file = fopen(optarg, "r"); 1981ec454baSMasami Hiramatsu if (!input_file) 1991ec454baSMasami Hiramatsu usage("Failed to open input file"); 2001ec454baSMasami Hiramatsu break; 2011ec454baSMasami Hiramatsu case 's': 2021ec454baSMasami Hiramatsu seed = (unsigned int)strtoul(optarg, &tmp, 0); 2031ec454baSMasami Hiramatsu if (*tmp == ',') { 2041ec454baSMasami Hiramatsu optarg = tmp + 1; 2051ec454baSMasami Hiramatsu iter_start = strtoul(optarg, &tmp, 0); 2061ec454baSMasami Hiramatsu } 2071ec454baSMasami Hiramatsu if (*tmp != '\0' || tmp == optarg) 2081ec454baSMasami Hiramatsu usage("Failed to parse seed"); 2091ec454baSMasami Hiramatsu set_seed = 1; 2101ec454baSMasami Hiramatsu break; 2111ec454baSMasami Hiramatsu case 'm': 2121ec454baSMasami Hiramatsu iter_end = strtoul(optarg, &tmp, 0); 2131ec454baSMasami Hiramatsu if (*tmp != '\0' || tmp == optarg) 2141ec454baSMasami Hiramatsu usage("Failed to parse max_iter"); 2151ec454baSMasami Hiramatsu break; 2161ec454baSMasami Hiramatsu default: 2171ec454baSMasami Hiramatsu usage(NULL); 2181ec454baSMasami Hiramatsu } 2191ec454baSMasami Hiramatsu } 2201ec454baSMasami Hiramatsu 2211ec454baSMasami Hiramatsu /* Check errors */ 2221ec454baSMasami Hiramatsu if (iter_end < iter_start) 2231ec454baSMasami Hiramatsu usage("Max iteration number must be bigger than iter-num"); 2241ec454baSMasami Hiramatsu 2251ec454baSMasami Hiramatsu if (set_seed && input_file) 2261ec454baSMasami Hiramatsu usage("Don't use input file (-i) with random seed (-s)"); 2271ec454baSMasami Hiramatsu 2281ec454baSMasami Hiramatsu /* Initialize random seed */ 2291ec454baSMasami Hiramatsu if (!input_file) { 2301ec454baSMasami Hiramatsu if (!set_seed) /* No seed is given */ 2311ec454baSMasami Hiramatsu init_random_seed(); 2321ec454baSMasami Hiramatsu srand(seed); 2331ec454baSMasami Hiramatsu } 2341ec454baSMasami Hiramatsu } 2351ec454baSMasami Hiramatsu 2361ec454baSMasami Hiramatsu int main(int argc, char **argv) 2371ec454baSMasami Hiramatsu { 2381ec454baSMasami Hiramatsu struct insn insn; 2391ec454baSMasami Hiramatsu int insns = 0; 2401ec454baSMasami Hiramatsu int errors = 0; 2411ec454baSMasami Hiramatsu unsigned long i; 2421ec454baSMasami Hiramatsu unsigned char insn_buf[MAX_INSN_SIZE * 2]; 2431ec454baSMasami Hiramatsu 2441ec454baSMasami Hiramatsu parse_args(argc, argv); 2451ec454baSMasami Hiramatsu 2461ec454baSMasami Hiramatsu /* Prepare stop bytes with NOPs */ 2471ec454baSMasami Hiramatsu memset(insn_buf + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE); 2481ec454baSMasami Hiramatsu 2491ec454baSMasami Hiramatsu for (i = 0; i < iter_end; i++) { 2501ec454baSMasami Hiramatsu if (generate_insn(insn_buf) <= 0) 2511ec454baSMasami Hiramatsu break; 2521ec454baSMasami Hiramatsu 2531ec454baSMasami Hiramatsu if (i < iter_start) /* Skip to given iteration number */ 2541ec454baSMasami Hiramatsu continue; 2551ec454baSMasami Hiramatsu 2561ec454baSMasami Hiramatsu /* Decode an instruction */ 2571ec454baSMasami Hiramatsu insn_init(&insn, insn_buf, x86_64); 2581ec454baSMasami Hiramatsu insn_get_length(&insn); 2591ec454baSMasami Hiramatsu 2601ec454baSMasami Hiramatsu if (insn.next_byte <= insn.kaddr || 2611ec454baSMasami Hiramatsu insn.kaddr + MAX_INSN_SIZE < insn.next_byte) { 2621ec454baSMasami Hiramatsu /* Access out-of-range memory */ 263e70825fcSMasami Hiramatsu dump_stream(stderr, "Error: Found an access violation", i, insn_buf, &insn); 2641ec454baSMasami Hiramatsu errors++; 265bfbe9015SMasami Hiramatsu } else if (verbose && !insn_complete(&insn)) 266bfbe9015SMasami Hiramatsu dump_stream(stdout, "Info: Found an undecodable input", i, insn_buf, &insn); 2679dde9dc0SMasami Hiramatsu else if (verbose >= 2) 2689dde9dc0SMasami Hiramatsu dump_insn(stdout, &insn); 2691ec454baSMasami Hiramatsu insns++; 2701ec454baSMasami Hiramatsu } 2711ec454baSMasami Hiramatsu 2721ec454baSMasami Hiramatsu fprintf(stdout, "%s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", (errors) ? "Failure" : "Success", insns, (input_file) ? "given" : "random", errors, seed); 2731ec454baSMasami Hiramatsu 2741ec454baSMasami Hiramatsu return errors ? 1 : 0; 2751ec454baSMasami Hiramatsu } 276