xref: /OK3568_Linux_fs/kernel/arch/x86/tools/insn_decoder_test.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) IBM Corporation, 2009
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <stdlib.h>
8*4882a593Smuzhiyun #include <stdio.h>
9*4882a593Smuzhiyun #include <string.h>
10*4882a593Smuzhiyun #include <assert.h>
11*4882a593Smuzhiyun #include <unistd.h>
12*4882a593Smuzhiyun #include <stdarg.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define unlikely(cond) (cond)
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <asm/insn.h>
17*4882a593Smuzhiyun #include <inat.c>
18*4882a593Smuzhiyun #include <insn.c>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun  * Test of instruction analysis in general and insn_get_length() in
22*4882a593Smuzhiyun  * particular.  See if insn_get_length() and the disassembler agree
23*4882a593Smuzhiyun  * on the length of each instruction in an elf disassembly.
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * Usage: objdump -d a.out | awk -f objdump_reformat.awk | ./insn_decoder_test
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun const char *prog;
29*4882a593Smuzhiyun static int verbose;
30*4882a593Smuzhiyun static int x86_64;
31*4882a593Smuzhiyun 
usage(void)32*4882a593Smuzhiyun static void usage(void)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	fprintf(stderr, "Usage: objdump -d a.out | awk -f objdump_reformat.awk"
35*4882a593Smuzhiyun 		" | %s [-y|-n] [-v]\n", prog);
36*4882a593Smuzhiyun 	fprintf(stderr, "\t-y	64bit mode\n");
37*4882a593Smuzhiyun 	fprintf(stderr, "\t-n	32bit mode\n");
38*4882a593Smuzhiyun 	fprintf(stderr, "\t-v	verbose mode\n");
39*4882a593Smuzhiyun 	exit(1);
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun 
malformed_line(const char * line,int line_nr)42*4882a593Smuzhiyun static void malformed_line(const char *line, int line_nr)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	fprintf(stderr, "%s: error: malformed line %d:\n%s",
45*4882a593Smuzhiyun 		prog, line_nr, line);
46*4882a593Smuzhiyun 	exit(3);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
pr_warn(const char * fmt,...)49*4882a593Smuzhiyun static void pr_warn(const char *fmt, ...)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	va_list ap;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	fprintf(stderr, "%s: warning: ", prog);
54*4882a593Smuzhiyun 	va_start(ap, fmt);
55*4882a593Smuzhiyun 	vfprintf(stderr, fmt, ap);
56*4882a593Smuzhiyun 	va_end(ap);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
dump_field(FILE * fp,const char * name,const char * indent,struct insn_field * field)59*4882a593Smuzhiyun static void dump_field(FILE *fp, const char *name, const char *indent,
60*4882a593Smuzhiyun 		       struct insn_field *field)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	fprintf(fp, "%s.%s = {\n", indent, name);
63*4882a593Smuzhiyun 	fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
64*4882a593Smuzhiyun 		indent, field->value, field->bytes[0], field->bytes[1],
65*4882a593Smuzhiyun 		field->bytes[2], field->bytes[3]);
66*4882a593Smuzhiyun 	fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
67*4882a593Smuzhiyun 		field->got, field->nbytes);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
dump_insn(FILE * fp,struct insn * insn)70*4882a593Smuzhiyun static void dump_insn(FILE *fp, struct insn *insn)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	fprintf(fp, "Instruction = {\n");
73*4882a593Smuzhiyun 	dump_field(fp, "prefixes", "\t",	&insn->prefixes);
74*4882a593Smuzhiyun 	dump_field(fp, "rex_prefix", "\t",	&insn->rex_prefix);
75*4882a593Smuzhiyun 	dump_field(fp, "vex_prefix", "\t",	&insn->vex_prefix);
76*4882a593Smuzhiyun 	dump_field(fp, "opcode", "\t",		&insn->opcode);
77*4882a593Smuzhiyun 	dump_field(fp, "modrm", "\t",		&insn->modrm);
78*4882a593Smuzhiyun 	dump_field(fp, "sib", "\t",		&insn->sib);
79*4882a593Smuzhiyun 	dump_field(fp, "displacement", "\t",	&insn->displacement);
80*4882a593Smuzhiyun 	dump_field(fp, "immediate1", "\t",	&insn->immediate1);
81*4882a593Smuzhiyun 	dump_field(fp, "immediate2", "\t",	&insn->immediate2);
82*4882a593Smuzhiyun 	fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
83*4882a593Smuzhiyun 		insn->attr, insn->opnd_bytes, insn->addr_bytes);
84*4882a593Smuzhiyun 	fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
85*4882a593Smuzhiyun 		insn->length, insn->x86_64, insn->kaddr);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
parse_args(int argc,char ** argv)88*4882a593Smuzhiyun static void parse_args(int argc, char **argv)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	int c;
91*4882a593Smuzhiyun 	prog = argv[0];
92*4882a593Smuzhiyun 	while ((c = getopt(argc, argv, "ynv")) != -1) {
93*4882a593Smuzhiyun 		switch (c) {
94*4882a593Smuzhiyun 		case 'y':
95*4882a593Smuzhiyun 			x86_64 = 1;
96*4882a593Smuzhiyun 			break;
97*4882a593Smuzhiyun 		case 'n':
98*4882a593Smuzhiyun 			x86_64 = 0;
99*4882a593Smuzhiyun 			break;
100*4882a593Smuzhiyun 		case 'v':
101*4882a593Smuzhiyun 			verbose = 1;
102*4882a593Smuzhiyun 			break;
103*4882a593Smuzhiyun 		default:
104*4882a593Smuzhiyun 			usage();
105*4882a593Smuzhiyun 		}
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #define BUFSIZE 256
110*4882a593Smuzhiyun 
main(int argc,char ** argv)111*4882a593Smuzhiyun int main(int argc, char **argv)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	char line[BUFSIZE], sym[BUFSIZE] = "<unknown>";
114*4882a593Smuzhiyun 	unsigned char insn_buff[16];
115*4882a593Smuzhiyun 	struct insn insn;
116*4882a593Smuzhiyun 	int insns = 0;
117*4882a593Smuzhiyun 	int warnings = 0;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	parse_args(argc, argv);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	while (fgets(line, BUFSIZE, stdin)) {
122*4882a593Smuzhiyun 		char copy[BUFSIZE], *s, *tab1, *tab2;
123*4882a593Smuzhiyun 		int nb = 0;
124*4882a593Smuzhiyun 		unsigned int b;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 		if (line[0] == '<') {
127*4882a593Smuzhiyun 			/* Symbol line */
128*4882a593Smuzhiyun 			strcpy(sym, line);
129*4882a593Smuzhiyun 			continue;
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		insns++;
133*4882a593Smuzhiyun 		memset(insn_buff, 0, 16);
134*4882a593Smuzhiyun 		strcpy(copy, line);
135*4882a593Smuzhiyun 		tab1 = strchr(copy, '\t');
136*4882a593Smuzhiyun 		if (!tab1)
137*4882a593Smuzhiyun 			malformed_line(line, insns);
138*4882a593Smuzhiyun 		s = tab1 + 1;
139*4882a593Smuzhiyun 		s += strspn(s, " ");
140*4882a593Smuzhiyun 		tab2 = strchr(s, '\t');
141*4882a593Smuzhiyun 		if (!tab2)
142*4882a593Smuzhiyun 			malformed_line(line, insns);
143*4882a593Smuzhiyun 		*tab2 = '\0';	/* Characters beyond tab2 aren't examined */
144*4882a593Smuzhiyun 		while (s < tab2) {
145*4882a593Smuzhiyun 			if (sscanf(s, "%x", &b) == 1) {
146*4882a593Smuzhiyun 				insn_buff[nb++] = (unsigned char) b;
147*4882a593Smuzhiyun 				s += 3;
148*4882a593Smuzhiyun 			} else
149*4882a593Smuzhiyun 				break;
150*4882a593Smuzhiyun 		}
151*4882a593Smuzhiyun 		/* Decode an instruction */
152*4882a593Smuzhiyun 		insn_init(&insn, insn_buff, sizeof(insn_buff), x86_64);
153*4882a593Smuzhiyun 		insn_get_length(&insn);
154*4882a593Smuzhiyun 		if (insn.length != nb) {
155*4882a593Smuzhiyun 			warnings++;
156*4882a593Smuzhiyun 			pr_warn("Found an x86 instruction decoder bug, "
157*4882a593Smuzhiyun 				"please report this.\n", sym);
158*4882a593Smuzhiyun 			pr_warn("%s", line);
159*4882a593Smuzhiyun 			pr_warn("objdump says %d bytes, but insn_get_length() "
160*4882a593Smuzhiyun 				"says %d\n", nb, insn.length);
161*4882a593Smuzhiyun 			if (verbose)
162*4882a593Smuzhiyun 				dump_insn(stderr, &insn);
163*4882a593Smuzhiyun 		}
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 	if (warnings)
166*4882a593Smuzhiyun 		pr_warn("Decoded and checked %d instructions with %d "
167*4882a593Smuzhiyun 			"failures\n", insns, warnings);
168*4882a593Smuzhiyun 	else
169*4882a593Smuzhiyun 		fprintf(stdout, "%s: success: Decoded and checked %d"
170*4882a593Smuzhiyun 			" instructions\n", prog, insns);
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173