65oo2/disas/main.c

381 lines
6.3 KiB
C

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif /* HAVE_LIBGEN_H */
#include "lib/op.h"
#define OP_ADDR_MODE (OP_ADDR_IMPL | OP_ADDR_REL | OP_ADDR_IND \
| OP_ADDR_IMM | OP_ADDR_ABS)
#define COLOR_RED 31
#define COLOR_GREEN 32
#define COLOR_YELLOW 33
#define COLOR_BLUE 34
#define COLOR_RESET 0
char *prg_name;
FILE *input;
FILE *output;
int colorize = 1;
void
term_color(FILE *stream, int color)
{
if (!colorize) return;
fprintf(stream, "\033[%dm", color);
}
uint8_t
readu8(void)
{
uint8_t val;
if (fread(&val, 1, 1, input) != 1)
{
return (-1); /* XXX: TODO */
}
return (val);
}
uint16_t
readu16(void)
{
uint16_t val;
if (fread(&val, 1, 2, input) != 2)
{
return (-1); /* XXX: TODO */
}
return (val);
}
uint32_t
readu32(void)
{
uint32_t val;
if (fread(&val, 1, 4, input) != 4)
{
return (-1); /* XXX: TODO */
}
return (val);
}
int16_t
read16(void)
{
int16_t val;
if (fread(&val, 1, 2, input) != 2)
{
return (-1); /* XXX: TODO */
}
return (val);
}
int32_t
read32(void)
{
int32_t val;
if (fread(&val, 1, 4, input) != 4)
{
return (-1); /* XXX: TODO */
}
return (val);
}
void
fatal(const char *str, ...)
{
va_list ap;
term_color(stderr, COLOR_RED);
fprintf(stderr, "%s: ", prg_name);
va_start(ap, str);
vfprintf(stderr, str, ap);
va_end(ap);
fprintf(stderr, "\n");
term_color(stderr, COLOR_RESET);
exit(EXIT_FAILURE);
}
static void
decode_value(int size, int is_addr)
{
term_color(output, COLOR_GREEN);
if (!is_addr) fprintf(output, "#");
switch (size)
{
case SIZE_BYTE:
fprintf(output, "$%X", readu8());
break;
case SIZE_WORD:
fprintf(output, "$%hX", readu16());
break;
case SIZE_LONG:
fprintf(output, "$%X", readu32());
break;
default:
break;
}
term_color(output, COLOR_RESET);
}
static void
decode_target_suffix(uint8_t attr)
{
fprintf(output, ".");
if (IS_TARGET_ZEXT(attr))
{
fprintf(output, "U");
}
switch (GET_TARGET_SIZE(attr))
{
case SIZE_BYTE:
fprintf(output, "B");
break;
case SIZE_WORD:
fprintf(output, "W");
break;
case SIZE_LONG:
fprintf(output, "L");
break;
}
}
static void
decode_opcode(uint8_t opcode, uint8_t attr)
{
uint8_t addressing;
addressing = opcode_addr[opcode];
term_color(output, COLOR_BLUE);
fprintf(output, "%s", opcode_str[opcode]);
if ((addressing & OP_ADDR_IMPL) == 0
&& (addressing & OP_ADDR_REL) == 0
&& opcode != OP_JMP_abs
&& opcode != OP_JMP_ind
&& opcode != OP_JSR_abs)
{
decode_target_suffix(attr);
}
term_color(output, COLOR_RESET);
}
static void
decode_register(uint8_t opcode)
{
uint8_t addr;
addr = opcode_addr[opcode];
term_color(output, COLOR_YELLOW);
if (addr & OP_ADDR_X)
{
fprintf(output, "X");
}
else if (addr & OP_ADDR_Y)
{
fprintf(output, "Y");
}
term_color(output, COLOR_RESET);
}
void
decode_imm(uint8_t opcode)
{
uint8_t attr;
attr = readu8();
decode_opcode(opcode, attr);
fprintf(output, " ");
decode_value(GET_TARGET_SIZE(attr), 0);
fprintf(output, "\n");
}
void
decode_ind(uint8_t opcode)
{
uint8_t attr;
attr = readu8();
decode_opcode(opcode, attr);
fprintf(output, " ");
if (opcode_addr[opcode] & (OP_ADDR_X | OP_ADDR_Y))
{
fprintf(output, "(");
}
decode_value(GET_ADDRESS_SIZE(attr), 1);
if (opcode_addr[opcode] & OP_ADDR_X)
{
fprintf(output, ", ");
decode_register(opcode);
fprintf(output, ")");
}
else if (opcode_addr[opcode] & OP_ADDR_Y)
{
fprintf(output, "), ");
decode_register(opcode);
}
fprintf(output, "\n");
}
void
decode_abs(uint8_t opcode)
{
uint8_t attr;
attr = readu8();
decode_opcode(opcode, attr);
fprintf(output, " ");
decode_value(GET_ADDRESS_SIZE(attr), 1);
if (opcode_addr[opcode] & (OP_ADDR_X | OP_ADDR_Y))
{
fprintf(output, ", ");
decode_register(opcode);
}
fprintf(output, "\n");
}
void
decode(void)
{
uint8_t opcode;
int16_t relative;
do {
opcode = readu8();
if (feof(input)) return;
switch (opcode_addr[opcode] & OP_ADDR_MODE)
{
case OP_ADDR_IMPL:
decode_opcode(opcode, 0);
if (opcode_addr[opcode] & OP_ADDR_A)
{
term_color(output, COLOR_YELLOW);
fprintf(output, " A");
term_color(output, COLOR_RESET);
}
fprintf(output, "\n");
break;
case OP_ADDR_REL:
decode_opcode(opcode, 0);
fprintf(output, " ");
decode_value(SIZE_WORD, 1);
fprintf(output, "\n");
break;
case OP_ADDR_IMM:
decode_imm(opcode);
break;
case OP_ADDR_IND:
decode_ind(opcode);
break;
case OP_ADDR_ABS:
decode_abs(opcode);
break;
default:
fprintf(output, "???\n", opcode);
break;
}
} while (!feof(input));
}
void
usage(int retcode)
{
if (retcode == EXIT_FAILURE)
{
fprintf(stderr,
"Try '%s -h' for more information.\n", prg_name);
}
else
{
printf("Usage: %s [-hV] [INPUT] [OUTPUT]\n", prg_name);
printf("Disassemble INPUT to OUTPUT\n\n");
printf("With no INPUT read standard input.\n");
printf("With no OUTPUT write standard output.\n\n");
printf("\t-h\tdisplay this help and exit\n");
printf("\t-V\toutput version information\n");
printf("\nReport bugs to <%s>\n", PACKAGE_BUGREPORT);
}
exit(retcode);
}
void
version(void)
{
printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
exit(EXIT_SUCCESS);
}
int
main(int argc, char **argv)
{
char *no_color;
#ifdef HAVE_LIBGEN_H
prg_name = basename(argv[0]);
#else
prg_name = argv[0];
#endif /* HAVE_LIBGEN_H */
input = stdin;
output = stdout;
no_color = getenv("NO_COLOR");
if (no_color != NULL && no_color[0] != '\0')
{
colorize = 0;
}
while ((argc > 1) && (argv[1][0] == '-'))
{
switch (argv[1][1])
{
case 'h':
usage(EXIT_SUCCESS);
break;
case 'V':
version();
break;
default:
usage(EXIT_FAILURE);
break;
}
argv++;
argc--;
}
if (argc > 2)
{
colorize = 0;
output = fopen(argv[2], "w");
if (output == NULL) fatal("can't open %s.", argv[2]);
}
if (argc > 1)
{
input = fopen(argv[1], "rb");
if (input == NULL) fatal("can't open %s.", argv[1]);
}
decode();
return (EXIT_SUCCESS);
}