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