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