mirror of
https://github.com/mrkite/regs.git
synced 2024-12-01 16:52:30 +00:00
195 lines
5.0 KiB
C++
195 lines
5.0 KiB
C++
/** @copyright 2020 Sean Kasun */
|
|
|
|
#include <argp.h>
|
|
#include <iostream>
|
|
#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<struct arguments *>(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<Fingerprints>();
|
|
for (auto s : api.symbols) {
|
|
if (s.second->kind == symbol::isFunction) {
|
|
auto f = std::static_pointer_cast<symbol::Function>(s.second);
|
|
if (f->signature.size() >= 2) {
|
|
if (f->signature[0] >= 0) { // tool
|
|
// ldx tool, jsl e1/0000
|
|
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> sig5 = { 0x20, 0x0d, 0xc5, 0x00 };
|
|
std::vector<uint8_t> 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());
|
|
}
|