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