old-SuperVM/libvm/expdump.c

288 lines
6.7 KiB
C

#if !defined(__gcc)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdint.h>
#include <stddef.h>
#include "exp.h"
#include "vm.h"
#include <stdio.h>
#include <stdlib.h>
#if defined(_MSC_VER)
#include "getopt.h"
#else
#include <getopt.h>
#endif
#include <string.h>
#include <ctype.h>
#define DEBUG_VAL(x) fprintf(stderr, #x " = %d\n", x)
#include "mnemonics.h"
const char *commandStrings[] =
{
// VM_CMD_COPY 0
"copy",
// VM_CMD_STORE 1
"store",
// VM_CMD_LOAD 2
"load",
// VM_CMD_GET 3
"get",
// VM_CMD_SET 4
"set",
// VM_CMD_BPGET 5
"bpget",
// VM_CMD_BPSET 6
"bpset",
// VM_CMD_CPGET 7
"cpget",
// VM_CMD_MATH 8
"math",
// VM_CMD_SPGET 9
"spget",
// VM_CMD_SPSET 10
"spset",
// VM_CMD_SYSCALL 11
"syscall",
// VM_CMD_HWIO 12
"hwio",
};
int disassembleVerbose = 0;
void disassemble(instruction_t *list, uint32_t count, uint32_t base, FILE *f)
{
int v = disassembleVerbose;
for (int i = 0; i < count; i++)
{
instruction_t instr = list[i];
fprintf(f, "%8X: ", base + i);
const mnemonic_t *knownInstruction = NULL;
for (int j = 0; mnemonics[j].name != NULL; j++)
{
if (memcmp(&instr, &mnemonics[j].instr, sizeof(instruction_t) - sizeof(uint32_t)) == 0) {
knownInstruction = &mnemonics[j];
break;
}
}
if (knownInstruction != NULL)
{
fprintf(f, "%s", knownInstruction->name);
if (instr.argument != 0 || instr.input0 == VM_INPUT_ARG)
{
if(instr.output == VM_OUTPUT_JUMP || instr.output == VM_OUTPUT_JUMPR)
fprintf(f, " 0x%X", instr.argument);
else
fprintf(f, " %d", instr.argument);
}
fprintf(f, "\n");
continue;
}
switch (instr.execN)
{
case VM_EXEC_0: fprintf(f, "[ex(n)=0] "); break;
case VM_EXEC_1: fprintf(f, "[ex(n)=1] "); break;
case VM_EXEC_X: if (v) fprintf(f, "[ex(n)=x] "); break;
}
switch (instr.execZ)
{
case VM_EXEC_0: fprintf(f, "[ex(z)=0] "); break;
case VM_EXEC_1: fprintf(f, "[ex(z)=1] "); break;
case VM_EXEC_X: if (v) fprintf(f, "[ex(z)=x] "); break;
}
switch (instr.input0)
{
case VM_INPUT_ZERO: if (v) fprintf(f, "[i0:zero] "); break;
case VM_INPUT_POP: fprintf(f, "[i0:pop] "); break;
case VM_INPUT_PEEK: fprintf(f, "[i0:peek] "); break;
case VM_INPUT_ARG: fprintf(f, "[i0:arg] "); break;
}
switch (instr.input1)
{
case VM_INPUT_ZERO: if (v) fprintf(f, "[i1:zero] "); break;
case VM_INPUT_POP: fprintf(f, "[i1:pop] "); break;
// case VM_INPUT_PEEK: fprintf(f, "[i1:peek] "); break;
// case VM_INPUT_ARG: fprintf(f, "[i1:arg] "); break;
}
if (instr.command <= 12)
fprintf(f, "%s", commandStrings[instr.command]);
else
fprintf(f, "undefined [cmd:%d]", instr.command);
if (instr.cmdinfo != 0)
{
fprintf(f, " [ci:%d]", instr.cmdinfo);
}
if (instr.argument != 0 || instr.input0 == VM_INPUT_ARG)
{
if (instr.output == VM_OUTPUT_JUMP || instr.output == VM_OUTPUT_JUMPR)
fprintf(f, " 0x%X", instr.argument);
else
fprintf(f, " %d", instr.argument);
}
switch (instr.flags)
{
case VM_FLAG_NO: if (v) fprintf(f, " [f:no]"); break;
case VM_FLAG_YES: fprintf(f, " [f:yes]"); break;
}
switch (instr.output)
{
case VM_OUTPUT_DISCARD: if (v) fprintf(f, " [r:discard]"); break;
case VM_OUTPUT_JUMP: fprintf(f, " [r:jump]"); break;
case VM_OUTPUT_JUMPR: fprintf(f, " [r:jumpr]"); break;
case VM_OUTPUT_PUSH: fprintf(f, " [r:push]"); break;
}
fprintf(f, "\n");
}
}
int main(int argc, char **argv)
{
opterr = 0;
int headers = 0;
int dumpSections = 0;
int dumpMetas = 0;
int disassembleSections = 0;
int c;
while ((c = getopt(argc, argv, "HsmdD")) != -1)
{
switch (c)
{
case 'H': headers = 1; break;
case 's': dumpSections = 1; break;
case 'm': dumpMetas = 1; break;
case 'D': disassembleVerbose = 1;
case 'd': disassembleSections = 1; break;
case '?':
if (optopt == 'o' || optopt == 'c' || optopt == 'd')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
return 1;
default:
abort();
}
}
if(!headers && !dumpSections && !dumpMetas && !disassembleSections) {
headers = 1;
}
for (int index = optind; index < argc; index++)
{
const char *fileName = argv[index];
FILE *f = fopen(fileName, "rb");
if (f == NULL)
{
fprintf(stderr, "Could not open file %s\n", fileName);
continue;
}
///////////////////////////////////////////////////////////////////////////////
expfile_t fileHeader;
if (fread(&fileHeader, 1, sizeof(expfile_t), f) != sizeof(expfile_t))
{
fprintf(stderr, "File %s does not contain a valid header.\n", fileName);
continue;
}
if (fileHeader.magicNumber != EXP_MAGIC)
{
fprintf(stderr, "Invalid magic in %s\n", fileName);
continue;
}
if (fileHeader.majorVersion != 1 && fileHeader.minorVersion == 0)
{
fprintf(
stderr, "Invalid version %s: %d.%d\n",
fileName,
fileHeader.majorVersion, fileHeader.minorVersion);
continue;
}
if(headers)
{
// We should be sane now...
fprintf(stdout, "EXP FILE %s\n", fileName);
fprintf(stdout, "Version: %d.%d\n", fileHeader.majorVersion, fileHeader.minorVersion);
fprintf(stdout, "Sections: %d\n", fileHeader.numSections);
fprintf(stdout, "Metas: %d\n", fileHeader.numMeta);
}
if (dumpSections || disassembleSections)
{
if(dumpSections) fprintf(stdout, "Sections:\n");
for (int i = 0; i < fileHeader.numSections; i++)
{
expsection_t section;
fseek(f, fileHeader.posSections + i * sizeof(expsection_t), SEEK_SET);
fread(&section, 1, sizeof(expsection_t), f);
if(dumpSections)
{
fprintf(stdout, " Section #%d\n", i);
fprintf(stdout, " Name: %s\n", section.name);
fprintf(stdout, " Type: %s\n", (section.type ? "Data" : "Code"));
fprintf(stdout, " Base: 0x%X\n", section.base);
fprintf(stdout, " Start: %d\n", section.start);
fprintf(stdout, " Size: %d\n", section.length);
}
// Call disassembler
if (disassembleSections && section.type == 0)
{
if(dumpSections)
fprintf(stdout, " Disassembly:\n");
else
fprintf(stdout, "; Section '%s'@0x%08X\n", section.name, section.base);
instruction_t *buffer = malloc(section.length);
fseek(f, section.start, SEEK_SET);
int len = fread(buffer, 1, section.length, f);
if (len != section.length)
fprintf(stderr, "Read invalid size.\n");
disassemble(
buffer,
section.length / sizeof(instruction_t),
section.base,
stdout);
free(buffer);
}
}
}
///////////////////////////////////////////////////////////////////////////////
fclose(f);
}
return 0;
}