cosmopolitan/tool/decode/x86opinfo.c

226 lines
6.8 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/bits.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#include "third_party/xed/x86.h"
#include "tool/decode/lib/idname.h"
#include "tool/decode/lib/xederrors.h"
const struct IdName kXedModeNames[] = {
{XED_MACHINE_MODE_LONG_64, "long"},
{XED_MACHINE_MODE_LONG_COMPAT_32, "long32"},
{XED_MACHINE_MODE_LONG_COMPAT_16, "long16"},
{XED_MACHINE_MODE_LEGACY_32, "legacy"},
{XED_MACHINE_MODE_LEGACY_16, "legacy16"},
{XED_MACHINE_MODE_REAL, "real"},
{XED_MACHINE_MODE_UNREAL, "unreal"},
};
enum XedMachineMode g_mode;
struct XedDecodedInst g_xedd;
wontreturn void ShowUsage(int rc, FILE *f) {
size_t i;
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(" [-rl] [-m MODE] HEX\n MODE ∊ {", f);
fputs(kXedModeNames[0].name, f);
for (i = 1; i < ARRAYLEN(kXedModeNames); ++i) {
fputc(',', f);
fputs(kXedModeNames[i].name, f);
}
fputs("}\n", f);
exit(rc);
}
void SetMachineMode(const char *s) {
size_t i;
for (i = 0; i < ARRAYLEN(kXedModeNames); ++i) {
if (strcasecmp(s, kXedModeNames[i].name) == 0) {
g_mode = kXedModeNames[i].id;
return;
}
}
fputs("error: bad mode\n", stderr);
ShowUsage(EXIT_FAILURE, stderr);
}
void GetOpts(int argc, char *argv[]) {
int opt;
g_mode = XED_MACHINE_MODE_LONG_64;
while ((opt = getopt(argc, argv, "?hrlm:")) != -1) {
switch (opt) {
case 'r':
g_mode = XED_MACHINE_MODE_REAL;
break;
case 'l':
g_mode = XED_MACHINE_MODE_LEGACY_32;
break;
case 'm':
SetMachineMode(optarg);
break;
case '?':
case 'h':
ShowUsage(EXIT_SUCCESS, stdout);
default:
ShowUsage(EX_USAGE, stderr);
}
}
}
void CheckHex(const char *s) {
size_t i, n;
if ((n = strlen(s)) % 2 == 1) {
ShowUsage(EX_DATAERR, stderr);
}
for (i = 0; i < n; ++i) {
if (!isxdigit(s[i + 0])) {
ShowUsage(EX_DATAERR, stderr);
}
}
}
void ShowField(const char *name, uint64_t value) {
if (value) {
printf("/\t%-20s = %#lx\n", name, value);
}
}
void ShowField2(const char *name, uint64_t value, bool cond) {
if (value || cond) {
printf("/\t%-20s = %#lx\n", name, value);
}
}
void ShowOffset(const char *name, uint64_t off) {
printf("/\t%-20s = %#lx\n", name, off);
}
int main(int argc, char *argv[]) {
int err;
size_t i, j, k;
uint8_t buf[XED_MAX_INSTRUCTION_BYTES];
GetOpts(argc, argv);
for (k = 0, i = optind; i < argc; ++i) {
CheckHex(argv[i]);
for (j = 0; argv[i][j]; j += 2) {
if (++k > XED_MAX_INSTRUCTION_BYTES) ShowUsage(EX_DATAERR, stderr);
buf[k - 1] = hextoint(argv[i][j + 0]) << 4 | hextoint(argv[i][j + 1]);
}
}
xed_decoded_inst_zero_set_mode(&g_xedd, g_mode);
if ((err = xed_instruction_length_decode(&g_xedd, buf, k)) !=
XED_ERROR_NONE) {
fputs("XED_ERROR_", stderr);
fputs(findnamebyid(kXedErrorIdNames, err), stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
#define SHOWOP(F) ShowField(#F, g_xedd.op.F)
#define SHOWOP2(F, C) ShowField2(#F, g_xedd.op.F, C)
printf("/\t%-20s = %d\n", "length", g_xedd.length);
SHOWOP(error);
SHOWOP(lock);
SHOWOP(osz);
SHOWOP(asz);
SHOWOP(rep);
SHOWOP(rex);
SHOWOP(rexb);
SHOWOP(rexr);
SHOWOP(rexrr);
SHOWOP(rexw);
SHOWOP(rexx);
SHOWOP(map);
SHOWOP(opcode);
if (g_xedd.op.has_modrm) {
printf("\n");
printf("/\t%-20s = 0b%02hhb (%d)\n", "mod", g_xedd.op.mod, g_xedd.op.mod);
printf("/\t%-20s = 0b%03hhb (%d)\n", "reg", g_xedd.op.reg, g_xedd.op.reg);
printf("/\t%-20s = 0b%03hhb (%d)\n", "rm", g_xedd.op.rm, g_xedd.op.rm);
printf("\n");
}
if (g_xedd.op.has_sib) {
printf("/\t%-20s = 0b%02hhb (%d)\n", "scale", xed_sib_scale(g_xedd.op.sib),
xed_sib_scale(g_xedd.op.sib));
printf("/\t%-20s = 0b%03hhb (%d)\n", "index", xed_sib_index(g_xedd.op.sib),
xed_sib_index(g_xedd.op.sib));
printf("/\t%-20s = 0b%03hhb (%d)\n", "base", xed_sib_base(g_xedd.op.sib),
xed_sib_base(g_xedd.op.sib));
printf("\n");
}
SHOWOP2(disp, !!g_xedd.op.pos_disp);
SHOWOP2(uimm0, !!g_xedd.op.pos_imm);
SHOWOP2(uimm1, !!g_xedd.op.pos_imm1);
SHOWOP(mode);
SHOWOP(amd3dnow);
SHOWOP(bcrc);
SHOWOP(disp_width);
SHOWOP(hint);
SHOWOP(ild_f2);
SHOWOP(ild_f3);
SHOWOP(imm1_bytes);
SHOWOP(imm_width);
SHOWOP(imm_signed);
SHOWOP(llrc);
SHOWOP(mask);
SHOWOP(max_bytes);
SHOWOP(mode_first_prefix);
SHOWOP(nprefixes);
SHOWOP(nrexes);
SHOWOP(nseg_prefixes);
SHOWOP(out_of_bytes);
SHOWOP(pos_disp);
SHOWOP(pos_imm);
SHOWOP(pos_imm1);
SHOWOP(pos_modrm);
SHOWOP(pos_opcode);
SHOWOP(pos_sib);
SHOWOP(realmode);
SHOWOP(seg_ovd);
SHOWOP(srm);
SHOWOP(ubit);
SHOWOP(vex_prefix);
SHOWOP(vexdest210);
SHOWOP(vexdest3);
SHOWOP(vexdest4);
SHOWOP(vexvalid);
SHOWOP(vl);
SHOWOP(zeroing);
return 0;
}