fxos/shell/i.cpp

189 lines
5.0 KiB
C++

#include "shell.h"
#include "parser.h"
#include "commands.h"
#include "errors.h"
#include "theme.h"
#include <algorithm>
#include <fmt/core.h>
//---
// io
//---
static char const *info_str =
"OS: type %s version %02d.%02d.%04d\n"
"\n"
"Header information:\n"
" Bootcode timestamp (DateA) (0x%000008x) : %s\n"
" Bootcode checksum (0x%000008x) : 0x%08x\n"
" Serial number (0x%000008x) : %s\n"
" OS version (0x%000008x) : %s\n";
static char const *footer_str =
"\nFooter information:\n"
" Detected footer address : 0x%08x\n"
" Langdata entries found : %d\n"
" OS date (DateO) (0x%000008x) : %s\n"
" OS checksum (0x%000008x) : 0x%08x\n"
" Computed OS checksum : 0x%08x\n";
static char const *syscall_str =
"\nSyscall information:\n"
" Syscall table address (0x%000008x) : 0x%08x\n"
" Entries that point to valid memory : 0x%x\n"
" First seemingly invalid entry : 0x%08x\n"
" Syscall entries outside ROM:\n";
static char const *syscall_nonrom_str =
" %%%03x -> %08x (%s memory)\n";
static std::string parse_io(Session &, Parser &parser)
{
std::string name = parser.at_end() ? "" : parser.symbol("vspace_name");
parser.end();
return name;
}
void _io(Session &session, std::string name)
{
VirtualSpace *space = session.current_space;
if(name != "")
space = session.get_space(name);
if(!space)
return;
OS *os = space->os_analysis();
if(!os) throw CommandError("os analysis on '{}' failed", name);
printf(info_str, (os->type == OS::FX ? "FX" : "CG"),
os->version_major, os->version_minor, os->version_patch,
&os->bootcode_timestamp, os->bootcode_timestamp.value.c_str(),
&os->bootcode_checksum, os->bootcode_checksum,
&os->serial_number, os->serial_number.value.c_str(),
&os->version, os->version.value.c_str());
if(os->footer == (uint32_t)-1)
{
printf("\nFooter could not be found.\n");
}
else
{
printf(footer_str, os->footer, os->langdata,
&os->timestamp, os->timestamp.value.c_str(),
&os->checksum, os->checksum, os->computed_checksum);
}
uint32_t syscall_table = os->syscall_table_address();
uint32_t first_noncall = space->read_u32(syscall_table +
4 * os->syscall_count());
printf(syscall_str, (os->type == OS::FX ? 0x8001007c : 0x8002007c),
syscall_table, os->syscall_count(), first_noncall);
int total = 0;
for(int i = 0; i < os->syscall_count(); i++)
{
uint32_t e = os->syscall(i);
MemoryRegion const *r = MemoryRegion::region_for(e);
if(!r || r->name == "ROM" || r->name == "ROM_P2") continue;
printf(syscall_nonrom_str, i, e, r->name.c_str());
total++;
}
if(!total) printf(" (none)\n");
}
//---
// is
//---
struct _is_args {
std::string vspace_name;
bool sort;
};
static struct _is_args parse_is(Session &, Parser &parser)
{
struct _is_args args {};
parser.option("sort", [&args](std::string const &value){
args.sort = (value == "true");
});
parser.accept_options();
args.vspace_name = parser.at_end() ? "" : parser.symbol("vspace_name");
parser.accept_options();
parser.end();
return args;
}
struct SyscallInfo {
uint32_t address;
int id;
};
bool operator < (const SyscallInfo &left, const SyscallInfo &right)
{
return (left.address < right.address) || (left.id < right.id);
}
void _is(Session &session, std::string vspace_name, bool sort)
{
VirtualSpace *space = session.current_space;
if(vspace_name != "")
space = session.get_space(vspace_name);
if(!space)
return;
// TODO: is <vspace_name> doesn't work
OS *os = space->os_analysis();
if(!os) throw CommandError("os analysis on '{}' failed", vspace_name);
int total = os->syscall_count();
auto info = std::make_unique<SyscallInfo[]>(total);
for(int i = 0; i < total; i++) {
info[i] = (SyscallInfo){ .address = os->syscall(i), .id = i };
}
if(sort) std::sort(&info[0], &info[total]);
for(int i = 0; i < total; i++) {
fmt::print(theme(3), " 0x{:08x}", info[i].address);
fmt::print(theme(10), (total >= 0x1000 ? " %{:04x}":" %{:03x}"),
info[i].id);
fmt::print("\n");
}
}
//---
// Command registration
//---
static ShellCommand _io_cmd("io",
[](Session &s, Parser &p){ _io(s, parse_io(s, p)); },
[](Session &s, Parser &p){ parse_io(s, p); },
"Info OS", R"(
io [<vspace_name>]
Prints information about the OS mapped in the named virtual space (defaults to
the current one). This usually requires an OS binary to be mapped to ROM.
)");
static ShellCommand _is_cmd("is",
[](Session &s, Parser &p){
auto args = parse_is(s, p);
_is(s, args.vspace_name, args.sort); },
[](Session &s, Parser &p){ parse_is(s, p); },
"Info Syscalls", R"(
is [sort=true] [<vspace_name>]
Prints the syscall table for the specified virtual space (defaults to the
current one). By default, syscalls are enumerated by syscall number. If
sort=true is specified, they are instead sorted by address.
)");