18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) IBM Corporation, 2009 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <stdlib.h> 88c2ecf20Sopenharmony_ci#include <stdio.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <assert.h> 118c2ecf20Sopenharmony_ci#include <unistd.h> 128c2ecf20Sopenharmony_ci#include <stdarg.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define unlikely(cond) (cond) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/insn.h> 178c2ecf20Sopenharmony_ci#include <inat.c> 188c2ecf20Sopenharmony_ci#include <insn.c> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * Test of instruction analysis in general and insn_get_length() in 228c2ecf20Sopenharmony_ci * particular. See if insn_get_length() and the disassembler agree 238c2ecf20Sopenharmony_ci * on the length of each instruction in an elf disassembly. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Usage: objdump -d a.out | awk -f objdump_reformat.awk | ./insn_decoder_test 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciconst char *prog; 298c2ecf20Sopenharmony_cistatic int verbose; 308c2ecf20Sopenharmony_cistatic int x86_64; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic void usage(void) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci fprintf(stderr, "Usage: objdump -d a.out | awk -f objdump_reformat.awk" 358c2ecf20Sopenharmony_ci " | %s [-y|-n] [-v]\n", prog); 368c2ecf20Sopenharmony_ci fprintf(stderr, "\t-y 64bit mode\n"); 378c2ecf20Sopenharmony_ci fprintf(stderr, "\t-n 32bit mode\n"); 388c2ecf20Sopenharmony_ci fprintf(stderr, "\t-v verbose mode\n"); 398c2ecf20Sopenharmony_ci exit(1); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void malformed_line(const char *line, int line_nr) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci fprintf(stderr, "%s: error: malformed line %d:\n%s", 458c2ecf20Sopenharmony_ci prog, line_nr, line); 468c2ecf20Sopenharmony_ci exit(3); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void pr_warn(const char *fmt, ...) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci va_list ap; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci fprintf(stderr, "%s: warning: ", prog); 548c2ecf20Sopenharmony_ci va_start(ap, fmt); 558c2ecf20Sopenharmony_ci vfprintf(stderr, fmt, ap); 568c2ecf20Sopenharmony_ci va_end(ap); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void dump_field(FILE *fp, const char *name, const char *indent, 608c2ecf20Sopenharmony_ci struct insn_field *field) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci fprintf(fp, "%s.%s = {\n", indent, name); 638c2ecf20Sopenharmony_ci fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n", 648c2ecf20Sopenharmony_ci indent, field->value, field->bytes[0], field->bytes[1], 658c2ecf20Sopenharmony_ci field->bytes[2], field->bytes[3]); 668c2ecf20Sopenharmony_ci fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent, 678c2ecf20Sopenharmony_ci field->got, field->nbytes); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void dump_insn(FILE *fp, struct insn *insn) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci fprintf(fp, "Instruction = {\n"); 738c2ecf20Sopenharmony_ci dump_field(fp, "prefixes", "\t", &insn->prefixes); 748c2ecf20Sopenharmony_ci dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix); 758c2ecf20Sopenharmony_ci dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix); 768c2ecf20Sopenharmony_ci dump_field(fp, "opcode", "\t", &insn->opcode); 778c2ecf20Sopenharmony_ci dump_field(fp, "modrm", "\t", &insn->modrm); 788c2ecf20Sopenharmony_ci dump_field(fp, "sib", "\t", &insn->sib); 798c2ecf20Sopenharmony_ci dump_field(fp, "displacement", "\t", &insn->displacement); 808c2ecf20Sopenharmony_ci dump_field(fp, "immediate1", "\t", &insn->immediate1); 818c2ecf20Sopenharmony_ci dump_field(fp, "immediate2", "\t", &insn->immediate2); 828c2ecf20Sopenharmony_ci fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n", 838c2ecf20Sopenharmony_ci insn->attr, insn->opnd_bytes, insn->addr_bytes); 848c2ecf20Sopenharmony_ci fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n", 858c2ecf20Sopenharmony_ci insn->length, insn->x86_64, insn->kaddr); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void parse_args(int argc, char **argv) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci int c; 918c2ecf20Sopenharmony_ci prog = argv[0]; 928c2ecf20Sopenharmony_ci while ((c = getopt(argc, argv, "ynv")) != -1) { 938c2ecf20Sopenharmony_ci switch (c) { 948c2ecf20Sopenharmony_ci case 'y': 958c2ecf20Sopenharmony_ci x86_64 = 1; 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci case 'n': 988c2ecf20Sopenharmony_ci x86_64 = 0; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case 'v': 1018c2ecf20Sopenharmony_ci verbose = 1; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci default: 1048c2ecf20Sopenharmony_ci usage(); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define BUFSIZE 256 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciint main(int argc, char **argv) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci char line[BUFSIZE], sym[BUFSIZE] = "<unknown>"; 1148c2ecf20Sopenharmony_ci unsigned char insn_buff[16]; 1158c2ecf20Sopenharmony_ci struct insn insn; 1168c2ecf20Sopenharmony_ci int insns = 0; 1178c2ecf20Sopenharmony_ci int warnings = 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci parse_args(argc, argv); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci while (fgets(line, BUFSIZE, stdin)) { 1228c2ecf20Sopenharmony_ci char copy[BUFSIZE], *s, *tab1, *tab2; 1238c2ecf20Sopenharmony_ci int nb = 0; 1248c2ecf20Sopenharmony_ci unsigned int b; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (line[0] == '<') { 1278c2ecf20Sopenharmony_ci /* Symbol line */ 1288c2ecf20Sopenharmony_ci strcpy(sym, line); 1298c2ecf20Sopenharmony_ci continue; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci insns++; 1338c2ecf20Sopenharmony_ci memset(insn_buff, 0, 16); 1348c2ecf20Sopenharmony_ci strcpy(copy, line); 1358c2ecf20Sopenharmony_ci tab1 = strchr(copy, '\t'); 1368c2ecf20Sopenharmony_ci if (!tab1) 1378c2ecf20Sopenharmony_ci malformed_line(line, insns); 1388c2ecf20Sopenharmony_ci s = tab1 + 1; 1398c2ecf20Sopenharmony_ci s += strspn(s, " "); 1408c2ecf20Sopenharmony_ci tab2 = strchr(s, '\t'); 1418c2ecf20Sopenharmony_ci if (!tab2) 1428c2ecf20Sopenharmony_ci malformed_line(line, insns); 1438c2ecf20Sopenharmony_ci *tab2 = '\0'; /* Characters beyond tab2 aren't examined */ 1448c2ecf20Sopenharmony_ci while (s < tab2) { 1458c2ecf20Sopenharmony_ci if (sscanf(s, "%x", &b) == 1) { 1468c2ecf20Sopenharmony_ci insn_buff[nb++] = (unsigned char) b; 1478c2ecf20Sopenharmony_ci s += 3; 1488c2ecf20Sopenharmony_ci } else 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci /* Decode an instruction */ 1528c2ecf20Sopenharmony_ci insn_init(&insn, insn_buff, sizeof(insn_buff), x86_64); 1538c2ecf20Sopenharmony_ci insn_get_length(&insn); 1548c2ecf20Sopenharmony_ci if (insn.length != nb) { 1558c2ecf20Sopenharmony_ci warnings++; 1568c2ecf20Sopenharmony_ci pr_warn("Found an x86 instruction decoder bug, " 1578c2ecf20Sopenharmony_ci "please report this.\n", sym); 1588c2ecf20Sopenharmony_ci pr_warn("%s", line); 1598c2ecf20Sopenharmony_ci pr_warn("objdump says %d bytes, but insn_get_length() " 1608c2ecf20Sopenharmony_ci "says %d\n", nb, insn.length); 1618c2ecf20Sopenharmony_ci if (verbose) 1628c2ecf20Sopenharmony_ci dump_insn(stderr, &insn); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci if (warnings) 1668c2ecf20Sopenharmony_ci pr_warn("Decoded and checked %d instructions with %d " 1678c2ecf20Sopenharmony_ci "failures\n", insns, warnings); 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci fprintf(stdout, "%s: success: Decoded and checked %d" 1708c2ecf20Sopenharmony_ci " instructions\n", prog, insns); 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci} 173