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