/** @copyright 2020 Sean Kasun */ #include #include #include "disasm.h" #include "omf.h" #include "api.h" #include "iigs.h" const char *argp_program_version = "regs 1.1"; const char *argp_program_bug_address = "sean@seancode.com"; static char doc[] = "Disassemble Apple IIgs software"; static char args_doc[] = "FILE"; static struct argp_option options[] = { {"org", 'o', "ADDRESS", 0, "Starting address of the binary file"}, {"m", 'm', 0, OPTION_ARG_OPTIONAL, "Start with 8-bit accumulator"}, {"x", 'x', 0, OPTION_ARG_OPTIONAL, "Start with 8-bit indices"}, {"e", 'e', 0, OPTION_ARG_OPTIONAL, "Start in emulation mode"}, {"l", 'l', "KEYWORD", 0, "Search API for KEYWORD"}, { 0 }, }; struct arguments { const char *filename; uint32_t org; uint32_t flags; const char *keyword; }; static inline uint32_t parseNum(const char *s) { uint32_t bank = 0; uint32_t res = 0; while (isspace(*s)) { s++; } bool ishex = false; if (s[0] == '0' && s[1] == 'x') { s += 2; ishex = true; } else if (s[0] == '$') { s++; ishex = true; } if (ishex) { while (isxdigit(*s) || *s == '/') { if (*s == '/') { s++; bank = res; res = 0; continue; } res <<= 4; if (isdigit(*s)) { res |= *s - '0'; } else if (*s >= 'a' && *s <= 'f') { res |= *s - 'a' + 10; } else { res |= *s - 'A' + 10; } s++; } } else { while (isdigit(*s)) { res *= 10; res += *s - '0'; s++; } } return (bank << 16) | res; } static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = static_cast(state->input); switch (key) { case 'o': if (arg) { arguments->org = parseNum(arg); } break; case 'm': if (arg) { arguments->flags |= IsM8; } break; case 'x': if (arg) { arguments->flags |= IsX8; } break; case 'e': if (arg) { arguments->flags |= IsEmu; } break; case 'l': arguments->keyword = arg; break; case ARGP_KEY_ARG: if (state->arg_num >= 1) { argp_usage(state); } arguments->filename = arg; break; case ARGP_KEY_END: if (state->arg_num < 1 && !arguments->keyword) { argp_usage(state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp argp = { options, parse_opt, args_doc, doc }; int main(int argc, char **argv) { API api(iigs_dat, iigs_dat_len); struct arguments arguments; arguments.filename = ""; arguments.keyword = nullptr; arguments.org = 0; arguments.flags = 0; argp_parse(&argp, argc, argv, 0, 0, &arguments); if (arguments.keyword) { api.search(arguments.keyword, arguments.org); return 0; } // load map if it exists Map map(arguments.filename, arguments.org); OMF omf; if (!omf.load(arguments.filename, map.org)) { std::cerr << "Failed to load " << arguments.filename << std::endl; return -1; } auto segments = omf.get(); if (map.needsEntry()) { for (auto &s : segments) { if ((s.kind & 0x1f) == 0) { // first code map.addEntry(s.mapped + s.entry, arguments.flags); break; } } } // note that we save the map here.. before we add a bunch of symbols // from the api map.save(); auto prints = std::make_shared(); for (auto s : api.symbols) { if (s.second->kind == symbol::isFunction) { auto f = std::static_pointer_cast(s.second); if (f->signature.size() >= 2) { if (f->signature[0] >= 0) { // tool // ldx tool, jsl e1/0000 std::vector sig = { 0xa2, 0x00, 0x00, 0x22, 0x00, 0x00, 0xe1 }; sig[1] = f->signature[0]; sig[2] = f->signature[1]; prints->add(sig, f->name); } else if (f->signature[0] == -1) { // p16/gsos // jsl e1/00a8 std::vector sig = { 0x22, 0xa8, 0x00, 0xe1, 0x00, 0x00 }; sig[4] = f->signature[2] & 0xff; sig[5] = f->signature[2] >> 8; prints->add(sig, f->name, f->signature[1] & 0xff); } else if (f->signature[0] == -2) { // p8 // jsr bf00 std::vector sig = { 0x20, 0x00, 0xbf, 0x00 }; sig[3] = f->signature[2]; prints->add(sig, f->name, f->signature[1] & 0xff); } else if (f->signature[0] == -3) { // smartport // jsr c50d std::vector sig5 = { 0x20, 0x0d, 0xc5, 0x00 }; std::vector sig7 = { 0x20, 0x0d, 0xc7, 0x00 }; sig5[3] = f->signature[2]; sig7[3] = f->signature[2]; prints->add(sig5, f->name, f->signature[1]); prints->add(sig7, f->name, f->signature[1]); } else if (f->signature[0] == -4) { // symbol map.addSymbol(f->signature[1], f->name); } } } } Disassembler d(prints, map.getSymbols()); d.disassemble(segments, map.getEntries()); }