xref: /linux/arch/x86/tools/insn_decoder_test.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26b63dd11SMasami Hiramatsu /*
36b63dd11SMasami Hiramatsu  *
46b63dd11SMasami Hiramatsu  * Copyright (C) IBM Corporation, 2009
56b63dd11SMasami Hiramatsu  */
66b63dd11SMasami Hiramatsu 
76b63dd11SMasami Hiramatsu #include <stdlib.h>
86b63dd11SMasami Hiramatsu #include <stdio.h>
96b63dd11SMasami Hiramatsu #include <string.h>
106b63dd11SMasami Hiramatsu #include <assert.h>
116b63dd11SMasami Hiramatsu #include <unistd.h>
1210c91577SMasami Hiramatsu #include <stdarg.h>
136b63dd11SMasami Hiramatsu 
146b63dd11SMasami Hiramatsu #define unlikely(cond) (cond)
156b63dd11SMasami Hiramatsu 
166b63dd11SMasami Hiramatsu #include <asm/insn.h>
176b63dd11SMasami Hiramatsu #include <inat.c>
186b63dd11SMasami Hiramatsu #include <insn.c>
196b63dd11SMasami Hiramatsu 
206b63dd11SMasami Hiramatsu /*
216b63dd11SMasami Hiramatsu  * Test of instruction analysis in general and insn_get_length() in
226b63dd11SMasami Hiramatsu  * particular.  See if insn_get_length() and the disassembler agree
236b63dd11SMasami Hiramatsu  * on the length of each instruction in an elf disassembly.
246b63dd11SMasami Hiramatsu  *
2598fe07fcSMasami Hiramatsu  * Usage: objdump -d a.out | awk -f objdump_reformat.awk | ./insn_decoder_test
266b63dd11SMasami Hiramatsu  */
276b63dd11SMasami Hiramatsu 
286b63dd11SMasami Hiramatsu const char *prog;
296b63dd11SMasami Hiramatsu static int verbose;
306b63dd11SMasami Hiramatsu static int x86_64;
316b63dd11SMasami Hiramatsu 
usage(void)326b63dd11SMasami Hiramatsu static void usage(void)
336b63dd11SMasami Hiramatsu {
3498fe07fcSMasami Hiramatsu 	fprintf(stderr, "Usage: objdump -d a.out | awk -f objdump_reformat.awk"
3598fe07fcSMasami Hiramatsu 		" | %s [-y|-n] [-v]\n", prog);
366b63dd11SMasami Hiramatsu 	fprintf(stderr, "\t-y	64bit mode\n");
376b63dd11SMasami Hiramatsu 	fprintf(stderr, "\t-n	32bit mode\n");
386b63dd11SMasami Hiramatsu 	fprintf(stderr, "\t-v	verbose mode\n");
396b63dd11SMasami Hiramatsu 	exit(1);
406b63dd11SMasami Hiramatsu }
416b63dd11SMasami Hiramatsu 
malformed_line(const char * line,int line_nr)426b63dd11SMasami Hiramatsu static void malformed_line(const char *line, int line_nr)
436b63dd11SMasami Hiramatsu {
4410c91577SMasami Hiramatsu 	fprintf(stderr, "%s: error: malformed line %d:\n%s",
4510c91577SMasami Hiramatsu 		prog, line_nr, line);
466b63dd11SMasami Hiramatsu 	exit(3);
476b63dd11SMasami Hiramatsu }
486b63dd11SMasami Hiramatsu 
pr_warn(const char * fmt,...)4910c91577SMasami Hiramatsu static void pr_warn(const char *fmt, ...)
5010c91577SMasami Hiramatsu {
5110c91577SMasami Hiramatsu 	va_list ap;
5210c91577SMasami Hiramatsu 
5310c91577SMasami Hiramatsu 	fprintf(stderr, "%s: warning: ", prog);
5410c91577SMasami Hiramatsu 	va_start(ap, fmt);
5510c91577SMasami Hiramatsu 	vfprintf(stderr, fmt, ap);
5610c91577SMasami Hiramatsu 	va_end(ap);
5710c91577SMasami Hiramatsu }
5810c91577SMasami Hiramatsu 
dump_field(FILE * fp,const char * name,const char * indent,struct insn_field * field)596b63dd11SMasami Hiramatsu static void dump_field(FILE *fp, const char *name, const char *indent,
606b63dd11SMasami Hiramatsu 		       struct insn_field *field)
616b63dd11SMasami Hiramatsu {
626b63dd11SMasami Hiramatsu 	fprintf(fp, "%s.%s = {\n", indent, name);
636b63dd11SMasami Hiramatsu 	fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
646b63dd11SMasami Hiramatsu 		indent, field->value, field->bytes[0], field->bytes[1],
656b63dd11SMasami Hiramatsu 		field->bytes[2], field->bytes[3]);
666b63dd11SMasami Hiramatsu 	fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
676b63dd11SMasami Hiramatsu 		field->got, field->nbytes);
686b63dd11SMasami Hiramatsu }
696b63dd11SMasami Hiramatsu 
dump_insn(FILE * fp,struct insn * insn)706b63dd11SMasami Hiramatsu static void dump_insn(FILE *fp, struct insn *insn)
716b63dd11SMasami Hiramatsu {
726b63dd11SMasami Hiramatsu 	fprintf(fp, "Instruction = {\n");
736b63dd11SMasami Hiramatsu 	dump_field(fp, "prefixes", "\t",	&insn->prefixes);
746b63dd11SMasami Hiramatsu 	dump_field(fp, "rex_prefix", "\t",	&insn->rex_prefix);
756b63dd11SMasami Hiramatsu 	dump_field(fp, "vex_prefix", "\t",	&insn->vex_prefix);
766b63dd11SMasami Hiramatsu 	dump_field(fp, "opcode", "\t",		&insn->opcode);
776b63dd11SMasami Hiramatsu 	dump_field(fp, "modrm", "\t",		&insn->modrm);
786b63dd11SMasami Hiramatsu 	dump_field(fp, "sib", "\t",		&insn->sib);
796b63dd11SMasami Hiramatsu 	dump_field(fp, "displacement", "\t",	&insn->displacement);
806b63dd11SMasami Hiramatsu 	dump_field(fp, "immediate1", "\t",	&insn->immediate1);
816b63dd11SMasami Hiramatsu 	dump_field(fp, "immediate2", "\t",	&insn->immediate2);
826b63dd11SMasami Hiramatsu 	fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
836b63dd11SMasami Hiramatsu 		insn->attr, insn->opnd_bytes, insn->addr_bytes);
846b63dd11SMasami Hiramatsu 	fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
856b63dd11SMasami Hiramatsu 		insn->length, insn->x86_64, insn->kaddr);
866b63dd11SMasami Hiramatsu }
876b63dd11SMasami Hiramatsu 
parse_args(int argc,char ** argv)886b63dd11SMasami Hiramatsu static void parse_args(int argc, char **argv)
896b63dd11SMasami Hiramatsu {
906b63dd11SMasami Hiramatsu 	int c;
916b63dd11SMasami Hiramatsu 	prog = argv[0];
926b63dd11SMasami Hiramatsu 	while ((c = getopt(argc, argv, "ynv")) != -1) {
936b63dd11SMasami Hiramatsu 		switch (c) {
946b63dd11SMasami Hiramatsu 		case 'y':
956b63dd11SMasami Hiramatsu 			x86_64 = 1;
966b63dd11SMasami Hiramatsu 			break;
976b63dd11SMasami Hiramatsu 		case 'n':
986b63dd11SMasami Hiramatsu 			x86_64 = 0;
996b63dd11SMasami Hiramatsu 			break;
1006b63dd11SMasami Hiramatsu 		case 'v':
1016b63dd11SMasami Hiramatsu 			verbose = 1;
1026b63dd11SMasami Hiramatsu 			break;
1036b63dd11SMasami Hiramatsu 		default:
1046b63dd11SMasami Hiramatsu 			usage();
1056b63dd11SMasami Hiramatsu 		}
1066b63dd11SMasami Hiramatsu 	}
1076b63dd11SMasami Hiramatsu }
1086b63dd11SMasami Hiramatsu 
1096b63dd11SMasami Hiramatsu #define BUFSIZE 256
1106b63dd11SMasami Hiramatsu 
main(int argc,char ** argv)1116b63dd11SMasami Hiramatsu int main(int argc, char **argv)
1126b63dd11SMasami Hiramatsu {
1136b63dd11SMasami Hiramatsu 	char line[BUFSIZE], sym[BUFSIZE] = "<unknown>";
1141fc654cfSIngo Molnar 	unsigned char insn_buff[16];
1156b63dd11SMasami Hiramatsu 	struct insn insn;
1166b63dd11SMasami Hiramatsu 	int insns = 0;
1176b63dd11SMasami Hiramatsu 	int warnings = 0;
1186b63dd11SMasami Hiramatsu 
1196b63dd11SMasami Hiramatsu 	parse_args(argc, argv);
1206b63dd11SMasami Hiramatsu 
1216b63dd11SMasami Hiramatsu 	while (fgets(line, BUFSIZE, stdin)) {
1226b63dd11SMasami Hiramatsu 		char copy[BUFSIZE], *s, *tab1, *tab2;
123*0c925c61SBorislav Petkov 		int nb = 0, ret;
1246b63dd11SMasami Hiramatsu 		unsigned int b;
1256b63dd11SMasami Hiramatsu 
1266b63dd11SMasami Hiramatsu 		if (line[0] == '<') {
1276b63dd11SMasami Hiramatsu 			/* Symbol line */
1286b63dd11SMasami Hiramatsu 			strcpy(sym, line);
1296b63dd11SMasami Hiramatsu 			continue;
1306b63dd11SMasami Hiramatsu 		}
1316b63dd11SMasami Hiramatsu 
1326b63dd11SMasami Hiramatsu 		insns++;
1331fc654cfSIngo Molnar 		memset(insn_buff, 0, 16);
1346b63dd11SMasami Hiramatsu 		strcpy(copy, line);
1356b63dd11SMasami Hiramatsu 		tab1 = strchr(copy, '\t');
1366b63dd11SMasami Hiramatsu 		if (!tab1)
1376b63dd11SMasami Hiramatsu 			malformed_line(line, insns);
1386b63dd11SMasami Hiramatsu 		s = tab1 + 1;
1396b63dd11SMasami Hiramatsu 		s += strspn(s, " ");
1406b63dd11SMasami Hiramatsu 		tab2 = strchr(s, '\t');
1416b63dd11SMasami Hiramatsu 		if (!tab2)
1426b63dd11SMasami Hiramatsu 			malformed_line(line, insns);
1436b63dd11SMasami Hiramatsu 		*tab2 = '\0';	/* Characters beyond tab2 aren't examined */
1446b63dd11SMasami Hiramatsu 		while (s < tab2) {
1456b63dd11SMasami Hiramatsu 			if (sscanf(s, "%x", &b) == 1) {
1461fc654cfSIngo Molnar 				insn_buff[nb++] = (unsigned char) b;
1476b63dd11SMasami Hiramatsu 				s += 3;
1486b63dd11SMasami Hiramatsu 			} else
1496b63dd11SMasami Hiramatsu 				break;
1506b63dd11SMasami Hiramatsu 		}
151*0c925c61SBorislav Petkov 
1526b63dd11SMasami Hiramatsu 		/* Decode an instruction */
153*0c925c61SBorislav Petkov 		ret = insn_decode(&insn, insn_buff, sizeof(insn_buff),
154*0c925c61SBorislav Petkov 				  x86_64 ? INSN_MODE_64 : INSN_MODE_32);
155*0c925c61SBorislav Petkov 
156*0c925c61SBorislav Petkov 		if (ret < 0 || insn.length != nb) {
1576b63dd11SMasami Hiramatsu 			warnings++;
15810c91577SMasami Hiramatsu 			pr_warn("Found an x86 instruction decoder bug, "
15910c91577SMasami Hiramatsu 				"please report this.\n", sym);
16010c91577SMasami Hiramatsu 			pr_warn("%s", line);
16110c91577SMasami Hiramatsu 			pr_warn("objdump says %d bytes, but insn_get_length() "
16210c91577SMasami Hiramatsu 				"says %d\n", nb, insn.length);
1636b63dd11SMasami Hiramatsu 			if (verbose)
1646b63dd11SMasami Hiramatsu 				dump_insn(stderr, &insn);
1656b63dd11SMasami Hiramatsu 		}
1666b63dd11SMasami Hiramatsu 	}
1676b63dd11SMasami Hiramatsu 	if (warnings)
16810c91577SMasami Hiramatsu 		pr_warn("Decoded and checked %d instructions with %d "
16910c91577SMasami Hiramatsu 			"failures\n", insns, warnings);
1706b63dd11SMasami Hiramatsu 	else
17110c91577SMasami Hiramatsu 		fprintf(stdout, "%s: success: Decoded and checked %d"
17210c91577SMasami Hiramatsu 			" instructions\n", prog, insns);
1736b63dd11SMasami Hiramatsu 	return 0;
1746b63dd11SMasami Hiramatsu }
175