xref: /openbmc/linux/arch/x86/tools/insn_sanity.c (revision 1ec454baf1245df4fdb5dae728da3363630ce6de)
1*1ec454baSMasami Hiramatsu /*
2*1ec454baSMasami Hiramatsu  * x86 decoder sanity test - based on test_get_insn.c
3*1ec454baSMasami Hiramatsu  *
4*1ec454baSMasami Hiramatsu  * This program is free software; you can redistribute it and/or modify
5*1ec454baSMasami Hiramatsu  * it under the terms of the GNU General Public License as published by
6*1ec454baSMasami Hiramatsu  * the Free Software Foundation; either version 2 of the License, or
7*1ec454baSMasami Hiramatsu  * (at your option) any later version.
8*1ec454baSMasami Hiramatsu  *
9*1ec454baSMasami Hiramatsu  * This program is distributed in the hope that it will be useful,
10*1ec454baSMasami Hiramatsu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*1ec454baSMasami Hiramatsu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*1ec454baSMasami Hiramatsu  * GNU General Public License for more details.
13*1ec454baSMasami Hiramatsu  *
14*1ec454baSMasami Hiramatsu  * You should have received a copy of the GNU General Public License
15*1ec454baSMasami Hiramatsu  * along with this program; if not, write to the Free Software
16*1ec454baSMasami Hiramatsu  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*1ec454baSMasami Hiramatsu  *
18*1ec454baSMasami Hiramatsu  * Copyright (C) IBM Corporation, 2009
19*1ec454baSMasami Hiramatsu  * Copyright (C) Hitachi, Ltd., 2011
20*1ec454baSMasami Hiramatsu  */
21*1ec454baSMasami Hiramatsu 
22*1ec454baSMasami Hiramatsu #include <stdlib.h>
23*1ec454baSMasami Hiramatsu #include <stdio.h>
24*1ec454baSMasami Hiramatsu #include <string.h>
25*1ec454baSMasami Hiramatsu #include <assert.h>
26*1ec454baSMasami Hiramatsu #include <unistd.h>
27*1ec454baSMasami Hiramatsu #include <sys/types.h>
28*1ec454baSMasami Hiramatsu #include <sys/stat.h>
29*1ec454baSMasami Hiramatsu #include <fcntl.h>
30*1ec454baSMasami Hiramatsu 
31*1ec454baSMasami Hiramatsu #define unlikely(cond) (cond)
32*1ec454baSMasami Hiramatsu #define ARRAY_SIZE(a)	(sizeof(a)/sizeof(a[0]))
33*1ec454baSMasami Hiramatsu 
34*1ec454baSMasami Hiramatsu #include <asm/insn.h>
35*1ec454baSMasami Hiramatsu #include <inat.c>
36*1ec454baSMasami Hiramatsu #include <insn.c>
37*1ec454baSMasami Hiramatsu 
38*1ec454baSMasami Hiramatsu /*
39*1ec454baSMasami Hiramatsu  * Test of instruction analysis against tampering.
40*1ec454baSMasami Hiramatsu  * Feed random binary to instruction decoder and ensure not to
41*1ec454baSMasami Hiramatsu  * access out-of-instruction-buffer.
42*1ec454baSMasami Hiramatsu  */
43*1ec454baSMasami Hiramatsu 
44*1ec454baSMasami Hiramatsu #define DEFAULT_MAX_ITER	10000
45*1ec454baSMasami Hiramatsu #define INSN_NOP 0x90
46*1ec454baSMasami Hiramatsu 
47*1ec454baSMasami Hiramatsu static const char	*prog;		/* Program name */
48*1ec454baSMasami Hiramatsu static int		verbose;	/* Verbosity */
49*1ec454baSMasami Hiramatsu static int		x86_64;		/* x86-64 bit mode flag */
50*1ec454baSMasami Hiramatsu static unsigned int	seed;		/* Random seed */
51*1ec454baSMasami Hiramatsu static unsigned long	iter_start;	/* Start of iteration number */
52*1ec454baSMasami Hiramatsu static unsigned long	iter_end = DEFAULT_MAX_ITER;	/* End of iteration number */
53*1ec454baSMasami Hiramatsu static FILE		*input_file;	/* Input file name */
54*1ec454baSMasami Hiramatsu 
55*1ec454baSMasami Hiramatsu static void usage(const char *err)
56*1ec454baSMasami Hiramatsu {
57*1ec454baSMasami Hiramatsu 	if (err)
58*1ec454baSMasami Hiramatsu 		fprintf(stderr, "Error: %s\n\n", err);
59*1ec454baSMasami Hiramatsu 	fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog);
60*1ec454baSMasami Hiramatsu 	fprintf(stderr, "\t-y	64bit mode\n");
61*1ec454baSMasami Hiramatsu 	fprintf(stderr, "\t-n	32bit mode\n");
62*1ec454baSMasami Hiramatsu 	fprintf(stderr, "\t-v	Verbose mode\n");
63*1ec454baSMasami Hiramatsu 	fprintf(stderr, "\t-s	Give a random seed (and iteration number)\n");
64*1ec454baSMasami Hiramatsu 	fprintf(stderr, "\t-m	Give a maximum iteration number\n");
65*1ec454baSMasami Hiramatsu 	fprintf(stderr, "\t-i	Give an input file with decoded binary\n");
66*1ec454baSMasami Hiramatsu 	exit(1);
67*1ec454baSMasami Hiramatsu }
68*1ec454baSMasami Hiramatsu 
69*1ec454baSMasami Hiramatsu static void dump_field(FILE *fp, const char *name, const char *indent,
70*1ec454baSMasami Hiramatsu 		       struct insn_field *field)
71*1ec454baSMasami Hiramatsu {
72*1ec454baSMasami Hiramatsu 	fprintf(fp, "%s.%s = {\n", indent, name);
73*1ec454baSMasami Hiramatsu 	fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
74*1ec454baSMasami Hiramatsu 		indent, field->value, field->bytes[0], field->bytes[1],
75*1ec454baSMasami Hiramatsu 		field->bytes[2], field->bytes[3]);
76*1ec454baSMasami Hiramatsu 	fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
77*1ec454baSMasami Hiramatsu 		field->got, field->nbytes);
78*1ec454baSMasami Hiramatsu }
79*1ec454baSMasami Hiramatsu 
80*1ec454baSMasami Hiramatsu static void dump_insn(FILE *fp, struct insn *insn)
81*1ec454baSMasami Hiramatsu {
82*1ec454baSMasami Hiramatsu 	fprintf(fp, "Instruction = {\n");
83*1ec454baSMasami Hiramatsu 	dump_field(fp, "prefixes", "\t",	&insn->prefixes);
84*1ec454baSMasami Hiramatsu 	dump_field(fp, "rex_prefix", "\t",	&insn->rex_prefix);
85*1ec454baSMasami Hiramatsu 	dump_field(fp, "vex_prefix", "\t",	&insn->vex_prefix);
86*1ec454baSMasami Hiramatsu 	dump_field(fp, "opcode", "\t",		&insn->opcode);
87*1ec454baSMasami Hiramatsu 	dump_field(fp, "modrm", "\t",		&insn->modrm);
88*1ec454baSMasami Hiramatsu 	dump_field(fp, "sib", "\t",		&insn->sib);
89*1ec454baSMasami Hiramatsu 	dump_field(fp, "displacement", "\t",	&insn->displacement);
90*1ec454baSMasami Hiramatsu 	dump_field(fp, "immediate1", "\t",	&insn->immediate1);
91*1ec454baSMasami Hiramatsu 	dump_field(fp, "immediate2", "\t",	&insn->immediate2);
92*1ec454baSMasami Hiramatsu 	fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
93*1ec454baSMasami Hiramatsu 		insn->attr, insn->opnd_bytes, insn->addr_bytes);
94*1ec454baSMasami Hiramatsu 	fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
95*1ec454baSMasami Hiramatsu 		insn->length, insn->x86_64, insn->kaddr);
96*1ec454baSMasami Hiramatsu }
97*1ec454baSMasami Hiramatsu 
98*1ec454baSMasami Hiramatsu static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter,
99*1ec454baSMasami Hiramatsu 			unsigned char *insn_buf, struct insn *insn)
100*1ec454baSMasami Hiramatsu {
101*1ec454baSMasami Hiramatsu 	int i;
102*1ec454baSMasami Hiramatsu 
103*1ec454baSMasami Hiramatsu 	fprintf(fp, "%s:\n", msg);
104*1ec454baSMasami Hiramatsu 
105*1ec454baSMasami Hiramatsu 	dump_insn(stderr, insn);
106*1ec454baSMasami Hiramatsu 
107*1ec454baSMasami Hiramatsu 	fprintf(fp, "You can reproduce this with below command(s);\n");
108*1ec454baSMasami Hiramatsu 
109*1ec454baSMasami Hiramatsu 	/* Input a decoded instruction sequence directly */
110*1ec454baSMasami Hiramatsu 	fprintf(fp, " $ echo ");
111*1ec454baSMasami Hiramatsu 	for (i = 0; i < MAX_INSN_SIZE; i++)
112*1ec454baSMasami Hiramatsu 		fprintf(fp, " %02x", insn_buf[i]);
113*1ec454baSMasami Hiramatsu 	fprintf(fp, " | %s -i -\n", prog);
114*1ec454baSMasami Hiramatsu 
115*1ec454baSMasami Hiramatsu 	if (!input_file) {
116*1ec454baSMasami Hiramatsu 		fprintf(fp, "Or \n");
117*1ec454baSMasami Hiramatsu 		/* Give a seed and iteration number */
118*1ec454baSMasami Hiramatsu 		fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter);
119*1ec454baSMasami Hiramatsu 	}
120*1ec454baSMasami Hiramatsu }
121*1ec454baSMasami Hiramatsu 
122*1ec454baSMasami Hiramatsu static void init_random_seed(void)
123*1ec454baSMasami Hiramatsu {
124*1ec454baSMasami Hiramatsu 	int fd;
125*1ec454baSMasami Hiramatsu 
126*1ec454baSMasami Hiramatsu 	fd = open("/dev/urandom", O_RDONLY);
127*1ec454baSMasami Hiramatsu 	if (fd < 0)
128*1ec454baSMasami Hiramatsu 		goto fail;
129*1ec454baSMasami Hiramatsu 
130*1ec454baSMasami Hiramatsu 	if (read(fd, &seed, sizeof(seed)) != sizeof(seed))
131*1ec454baSMasami Hiramatsu 		goto fail;
132*1ec454baSMasami Hiramatsu 
133*1ec454baSMasami Hiramatsu 	close(fd);
134*1ec454baSMasami Hiramatsu 	return;
135*1ec454baSMasami Hiramatsu fail:
136*1ec454baSMasami Hiramatsu 	usage("Failed to open /dev/urandom");
137*1ec454baSMasami Hiramatsu }
138*1ec454baSMasami Hiramatsu 
139*1ec454baSMasami Hiramatsu /* Read given instruction sequence from the input file */
140*1ec454baSMasami Hiramatsu static int read_next_insn(unsigned char *insn_buf)
141*1ec454baSMasami Hiramatsu {
142*1ec454baSMasami Hiramatsu 	char buf[256]  = "", *tmp;
143*1ec454baSMasami Hiramatsu 	int i;
144*1ec454baSMasami Hiramatsu 
145*1ec454baSMasami Hiramatsu 	tmp = fgets(buf, ARRAY_SIZE(buf), input_file);
146*1ec454baSMasami Hiramatsu 	if (tmp == NULL || feof(input_file))
147*1ec454baSMasami Hiramatsu 		return 0;
148*1ec454baSMasami Hiramatsu 
149*1ec454baSMasami Hiramatsu 	for (i = 0; i < MAX_INSN_SIZE; i++) {
150*1ec454baSMasami Hiramatsu 		insn_buf[i] = (unsigned char)strtoul(tmp, &tmp, 16);
151*1ec454baSMasami Hiramatsu 		if (*tmp != ' ')
152*1ec454baSMasami Hiramatsu 			break;
153*1ec454baSMasami Hiramatsu 	}
154*1ec454baSMasami Hiramatsu 
155*1ec454baSMasami Hiramatsu 	return i;
156*1ec454baSMasami Hiramatsu }
157*1ec454baSMasami Hiramatsu 
158*1ec454baSMasami Hiramatsu static int generate_insn(unsigned char *insn_buf)
159*1ec454baSMasami Hiramatsu {
160*1ec454baSMasami Hiramatsu 	int i;
161*1ec454baSMasami Hiramatsu 
162*1ec454baSMasami Hiramatsu 	if (input_file)
163*1ec454baSMasami Hiramatsu 		return read_next_insn(insn_buf);
164*1ec454baSMasami Hiramatsu 
165*1ec454baSMasami Hiramatsu 	/* Fills buffer with random binary up to MAX_INSN_SIZE */
166*1ec454baSMasami Hiramatsu 	for (i = 0; i < MAX_INSN_SIZE - 1; i += 2)
167*1ec454baSMasami Hiramatsu 		*(unsigned short *)(&insn_buf[i]) = random() & 0xffff;
168*1ec454baSMasami Hiramatsu 
169*1ec454baSMasami Hiramatsu 	while (i < MAX_INSN_SIZE)
170*1ec454baSMasami Hiramatsu 		insn_buf[i++] = random() & 0xff;
171*1ec454baSMasami Hiramatsu 
172*1ec454baSMasami Hiramatsu 	return i;
173*1ec454baSMasami Hiramatsu }
174*1ec454baSMasami Hiramatsu 
175*1ec454baSMasami Hiramatsu static void parse_args(int argc, char **argv)
176*1ec454baSMasami Hiramatsu {
177*1ec454baSMasami Hiramatsu 	int c;
178*1ec454baSMasami Hiramatsu 	char *tmp = NULL;
179*1ec454baSMasami Hiramatsu 	int set_seed = 0;
180*1ec454baSMasami Hiramatsu 
181*1ec454baSMasami Hiramatsu 	prog = argv[0];
182*1ec454baSMasami Hiramatsu 	while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) {
183*1ec454baSMasami Hiramatsu 		switch (c) {
184*1ec454baSMasami Hiramatsu 		case 'y':
185*1ec454baSMasami Hiramatsu 			x86_64 = 1;
186*1ec454baSMasami Hiramatsu 			break;
187*1ec454baSMasami Hiramatsu 		case 'n':
188*1ec454baSMasami Hiramatsu 			x86_64 = 0;
189*1ec454baSMasami Hiramatsu 			break;
190*1ec454baSMasami Hiramatsu 		case 'v':
191*1ec454baSMasami Hiramatsu 			verbose = 1;
192*1ec454baSMasami Hiramatsu 			break;
193*1ec454baSMasami Hiramatsu 		case 'i':
194*1ec454baSMasami Hiramatsu 			if (strcmp("-", optarg) == 0)
195*1ec454baSMasami Hiramatsu 				input_file = stdin;
196*1ec454baSMasami Hiramatsu 			else
197*1ec454baSMasami Hiramatsu 				input_file = fopen(optarg, "r");
198*1ec454baSMasami Hiramatsu 			if (!input_file)
199*1ec454baSMasami Hiramatsu 				usage("Failed to open input file");
200*1ec454baSMasami Hiramatsu 			break;
201*1ec454baSMasami Hiramatsu 		case 's':
202*1ec454baSMasami Hiramatsu 			seed = (unsigned int)strtoul(optarg, &tmp, 0);
203*1ec454baSMasami Hiramatsu 			if (*tmp == ',') {
204*1ec454baSMasami Hiramatsu 				optarg = tmp + 1;
205*1ec454baSMasami Hiramatsu 				iter_start = strtoul(optarg, &tmp, 0);
206*1ec454baSMasami Hiramatsu 			}
207*1ec454baSMasami Hiramatsu 			if (*tmp != '\0' || tmp == optarg)
208*1ec454baSMasami Hiramatsu 				usage("Failed to parse seed");
209*1ec454baSMasami Hiramatsu 			set_seed = 1;
210*1ec454baSMasami Hiramatsu 			break;
211*1ec454baSMasami Hiramatsu 		case 'm':
212*1ec454baSMasami Hiramatsu 			iter_end = strtoul(optarg, &tmp, 0);
213*1ec454baSMasami Hiramatsu 			if (*tmp != '\0' || tmp == optarg)
214*1ec454baSMasami Hiramatsu 				usage("Failed to parse max_iter");
215*1ec454baSMasami Hiramatsu 			break;
216*1ec454baSMasami Hiramatsu 		default:
217*1ec454baSMasami Hiramatsu 			usage(NULL);
218*1ec454baSMasami Hiramatsu 		}
219*1ec454baSMasami Hiramatsu 	}
220*1ec454baSMasami Hiramatsu 
221*1ec454baSMasami Hiramatsu 	/* Check errors */
222*1ec454baSMasami Hiramatsu 	if (iter_end < iter_start)
223*1ec454baSMasami Hiramatsu 		usage("Max iteration number must be bigger than iter-num");
224*1ec454baSMasami Hiramatsu 
225*1ec454baSMasami Hiramatsu 	if (set_seed && input_file)
226*1ec454baSMasami Hiramatsu 		usage("Don't use input file (-i) with random seed (-s)");
227*1ec454baSMasami Hiramatsu 
228*1ec454baSMasami Hiramatsu 	/* Initialize random seed */
229*1ec454baSMasami Hiramatsu 	if (!input_file) {
230*1ec454baSMasami Hiramatsu 		if (!set_seed)	/* No seed is given */
231*1ec454baSMasami Hiramatsu 			init_random_seed();
232*1ec454baSMasami Hiramatsu 		srand(seed);
233*1ec454baSMasami Hiramatsu 	}
234*1ec454baSMasami Hiramatsu }
235*1ec454baSMasami Hiramatsu 
236*1ec454baSMasami Hiramatsu int main(int argc, char **argv)
237*1ec454baSMasami Hiramatsu {
238*1ec454baSMasami Hiramatsu 	struct insn insn;
239*1ec454baSMasami Hiramatsu 	int insns = 0;
240*1ec454baSMasami Hiramatsu 	int errors = 0;
241*1ec454baSMasami Hiramatsu 	unsigned long i;
242*1ec454baSMasami Hiramatsu 	unsigned char insn_buf[MAX_INSN_SIZE * 2];
243*1ec454baSMasami Hiramatsu 
244*1ec454baSMasami Hiramatsu 	parse_args(argc, argv);
245*1ec454baSMasami Hiramatsu 
246*1ec454baSMasami Hiramatsu 	/* Prepare stop bytes with NOPs */
247*1ec454baSMasami Hiramatsu 	memset(insn_buf + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE);
248*1ec454baSMasami Hiramatsu 
249*1ec454baSMasami Hiramatsu 	for (i = 0; i < iter_end; i++) {
250*1ec454baSMasami Hiramatsu 		if (generate_insn(insn_buf) <= 0)
251*1ec454baSMasami Hiramatsu 			break;
252*1ec454baSMasami Hiramatsu 
253*1ec454baSMasami Hiramatsu 		if (i < iter_start)	/* Skip to given iteration number */
254*1ec454baSMasami Hiramatsu 			continue;
255*1ec454baSMasami Hiramatsu 
256*1ec454baSMasami Hiramatsu 		/* Decode an instruction */
257*1ec454baSMasami Hiramatsu 		insn_init(&insn, insn_buf, x86_64);
258*1ec454baSMasami Hiramatsu 		insn_get_length(&insn);
259*1ec454baSMasami Hiramatsu 
260*1ec454baSMasami Hiramatsu 		if (verbose && !insn_complete(&insn))
261*1ec454baSMasami Hiramatsu 			dump_stream(stdout, "Info: Found an undecodable input", i, insn_buf, &insn);
262*1ec454baSMasami Hiramatsu 
263*1ec454baSMasami Hiramatsu 		if (insn.next_byte <= insn.kaddr ||
264*1ec454baSMasami Hiramatsu 		    insn.kaddr + MAX_INSN_SIZE < insn.next_byte) {
265*1ec454baSMasami Hiramatsu 			/* Access out-of-range memory */
266*1ec454baSMasami Hiramatsu 			dump_stream(stdout, "Error: Found an access violation", i, insn_buf, &insn);
267*1ec454baSMasami Hiramatsu 			errors++;
268*1ec454baSMasami Hiramatsu 		}
269*1ec454baSMasami Hiramatsu 		insns++;
270*1ec454baSMasami Hiramatsu 	}
271*1ec454baSMasami Hiramatsu 
272*1ec454baSMasami 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);
273*1ec454baSMasami Hiramatsu 
274*1ec454baSMasami Hiramatsu 	return errors ? 1 : 0;
275*1ec454baSMasami Hiramatsu }
276