Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *
0004  * Copyright (C) IBM Corporation, 2009
0005  */
0006 
0007 #include <stdlib.h>
0008 #include <stdio.h>
0009 #include <string.h>
0010 #include <assert.h>
0011 #include <unistd.h>
0012 #include <stdarg.h>
0013 
0014 #define unlikely(cond) (cond)
0015 
0016 #include <asm/insn.h>
0017 #include <inat.c>
0018 #include <insn.c>
0019 
0020 /*
0021  * Test of instruction analysis in general and insn_get_length() in
0022  * particular.  See if insn_get_length() and the disassembler agree
0023  * on the length of each instruction in an elf disassembly.
0024  *
0025  * Usage: objdump -d a.out | awk -f objdump_reformat.awk | ./insn_decoder_test
0026  */
0027 
0028 const char *prog;
0029 static int verbose;
0030 static int x86_64;
0031 
0032 static void usage(void)
0033 {
0034     fprintf(stderr, "Usage: objdump -d a.out | awk -f objdump_reformat.awk"
0035         " | %s [-y|-n] [-v]\n", prog);
0036     fprintf(stderr, "\t-y   64bit mode\n");
0037     fprintf(stderr, "\t-n   32bit mode\n");
0038     fprintf(stderr, "\t-v   verbose mode\n");
0039     exit(1);
0040 }
0041 
0042 static void malformed_line(const char *line, int line_nr)
0043 {
0044     fprintf(stderr, "%s: error: malformed line %d:\n%s",
0045         prog, line_nr, line);
0046     exit(3);
0047 }
0048 
0049 static void pr_warn(const char *fmt, ...)
0050 {
0051     va_list ap;
0052 
0053     fprintf(stderr, "%s: warning: ", prog);
0054     va_start(ap, fmt);
0055     vfprintf(stderr, fmt, ap);
0056     va_end(ap);
0057 }
0058 
0059 static void dump_field(FILE *fp, const char *name, const char *indent,
0060                struct insn_field *field)
0061 {
0062     fprintf(fp, "%s.%s = {\n", indent, name);
0063     fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
0064         indent, field->value, field->bytes[0], field->bytes[1],
0065         field->bytes[2], field->bytes[3]);
0066     fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
0067         field->got, field->nbytes);
0068 }
0069 
0070 static void dump_insn(FILE *fp, struct insn *insn)
0071 {
0072     fprintf(fp, "Instruction = {\n");
0073     dump_field(fp, "prefixes", "\t",    &insn->prefixes);
0074     dump_field(fp, "rex_prefix", "\t",  &insn->rex_prefix);
0075     dump_field(fp, "vex_prefix", "\t",  &insn->vex_prefix);
0076     dump_field(fp, "opcode", "\t",      &insn->opcode);
0077     dump_field(fp, "modrm", "\t",       &insn->modrm);
0078     dump_field(fp, "sib", "\t",     &insn->sib);
0079     dump_field(fp, "displacement", "\t",    &insn->displacement);
0080     dump_field(fp, "immediate1", "\t",  &insn->immediate1);
0081     dump_field(fp, "immediate2", "\t",  &insn->immediate2);
0082     fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
0083         insn->attr, insn->opnd_bytes, insn->addr_bytes);
0084     fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
0085         insn->length, insn->x86_64, insn->kaddr);
0086 }
0087 
0088 static void parse_args(int argc, char **argv)
0089 {
0090     int c;
0091     prog = argv[0];
0092     while ((c = getopt(argc, argv, "ynv")) != -1) {
0093         switch (c) {
0094         case 'y':
0095             x86_64 = 1;
0096             break;
0097         case 'n':
0098             x86_64 = 0;
0099             break;
0100         case 'v':
0101             verbose = 1;
0102             break;
0103         default:
0104             usage();
0105         }
0106     }
0107 }
0108 
0109 #define BUFSIZE 256
0110 
0111 int main(int argc, char **argv)
0112 {
0113     char line[BUFSIZE], sym[BUFSIZE] = "<unknown>";
0114     unsigned char insn_buff[16];
0115     struct insn insn;
0116     int insns = 0;
0117     int warnings = 0;
0118 
0119     parse_args(argc, argv);
0120 
0121     while (fgets(line, BUFSIZE, stdin)) {
0122         char copy[BUFSIZE], *s, *tab1, *tab2;
0123         int nb = 0, ret;
0124         unsigned int b;
0125 
0126         if (line[0] == '<') {
0127             /* Symbol line */
0128             strcpy(sym, line);
0129             continue;
0130         }
0131 
0132         insns++;
0133         memset(insn_buff, 0, 16);
0134         strcpy(copy, line);
0135         tab1 = strchr(copy, '\t');
0136         if (!tab1)
0137             malformed_line(line, insns);
0138         s = tab1 + 1;
0139         s += strspn(s, " ");
0140         tab2 = strchr(s, '\t');
0141         if (!tab2)
0142             malformed_line(line, insns);
0143         *tab2 = '\0';   /* Characters beyond tab2 aren't examined */
0144         while (s < tab2) {
0145             if (sscanf(s, "%x", &b) == 1) {
0146                 insn_buff[nb++] = (unsigned char) b;
0147                 s += 3;
0148             } else
0149                 break;
0150         }
0151 
0152         /* Decode an instruction */
0153         ret = insn_decode(&insn, insn_buff, sizeof(insn_buff),
0154                   x86_64 ? INSN_MODE_64 : INSN_MODE_32);
0155 
0156         if (ret < 0 || insn.length != nb) {
0157             warnings++;
0158             pr_warn("Found an x86 instruction decoder bug, "
0159                 "please report this.\n", sym);
0160             pr_warn("%s", line);
0161             pr_warn("objdump says %d bytes, but insn_get_length() "
0162                 "says %d\n", nb, insn.length);
0163             if (verbose)
0164                 dump_insn(stderr, &insn);
0165         }
0166     }
0167     if (warnings)
0168         pr_warn("Decoded and checked %d instructions with %d "
0169             "failures\n", insns, warnings);
0170     else
0171         fprintf(stdout, "%s: success: Decoded and checked %d"
0172             " instructions\n", prog, insns);
0173     return 0;
0174 }