#include "config.h" #include #include #include #include #ifdef HAVE_LIBGEN_H # include #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); }