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