fxos/shell/i.cpp

300 lines
8.2 KiB
C++

#include "shell.h"
#include "parser.h"
#include "commands.h"
#include "errors.h"
#include "theme.h"
#include <algorithm>
#include <fmt/core.h>
#include <fxos/util/log.h>
//---
// ic
//---
struct _ic_args
{
std::vector<uint32_t> addresses;
};
static struct _ic_args parse_ic(Session &session, Parser &parser)
{
_ic_args args;
while(!parser.at_end())
args.addresses.push_back(parser.expr(session.current_space));
parser.end();
return args;
}
void _ic(Session &session, struct _ic_args const &args)
{
if(!session.current_space)
return;
for(uint32_t address: args.addresses) {
Claim const *claim = session.current_space->disasm.getClaimAt(address);
if(claim)
fmt::print("0x{:08x} is claimed by {}\n", address, claim->str());
else
fmt::print("0x{:08x} is not claimed\n", address);
}
}
//---
// 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.address,
os->bootcode_timestamp.value.c_str(), os->bootcode_checksum.address,
os->bootcode_checksum, os->serial_number.address,
os->serial_number.value.c_str(), os->version.address,
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.address,
os->timestamp.value.c_str(), os->checksum.address, 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");
}
//---
// isc
//---
struct _isc_args
{
std::string vspace_name;
bool sort = false;
std::vector<uint32_t> addresses;
};
static struct _isc_args parse_isc(Session &session, Parser &parser)
{
_isc_args args;
parser.option("sort",
[&args](std::string const &value) { args.sort = (value == "true"); });
parser.option("vspace",
[&args](std::string const &value) { args.vspace_name = value; });
parser.accept_options();
while(!parser.at_end())
args.addresses.push_back(parser.expr(session.current_space));
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 _isc(Session &session, std::string vspace_name, bool sort,
std::vector<uint32_t> addresses)
{
VirtualSpace *space = session.current_space;
if(!vspace_name.empty())
space = session.get_space(vspace_name);
if(!space) {
FxOS_log(ERR, "virtual space '%s' does not exist", vspace_name);
return;
}
OS *os = space->os_analysis();
if(!os) {
if(!vspace_name.empty())
FxOS_log(ERR, "OS analysis on '%s' failed", vspace_name);
FxOS_log(ERR, "OS analysis failed");
return;
}
if(!addresses.empty()) {
for(uint32_t address: addresses) {
int syscall = os->find_syscall(address);
if(syscall == -1)
continue;
fmt::print(theme(3), " 0x{:08x}", address);
fmt::print(theme(10), " %{:01x}", syscall);
fmt::print("\n");
}
return;
}
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");
}
}
//---
// is
//---
static void parse_is(Session &, Parser &parser)
{
parser.end();
}
void _is(Session &session)
{
if(!session.current_space)
return;
for(auto const &s: session.current_space->symbols.symbols) {
if(s.type == FxOS::Symbol::Syscall && s.value < 0x1000) {
fmt::print(theme(10), " %{:03x}", s.value);
}
else if(s.type == FxOS::Symbol::Syscall) {
fmt::print(theme(10), " %{:04x}", s.value);
}
else {
fmt::print(" 0x{:08x}", s.value);
}
fmt::print(" {}\n", s.name);
}
}
//---
// Command registration
//---
static ShellCommand _ic_cmd(
"ic", [](Session &s, Parser &p) { _ic(s, parse_ic(s, p)); },
[](Session &s, Parser &p) { parse_ic(s, p); }, "Info Claims", R"(
ic <address>...
Prints information about claims over the specified addresses. Claims are
usually generated by analysis commands and allow sections of the OS to be
marked as part of functions, data, interrupt handlers, etc.
)");
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 _isc_cmd(
"isc",
[](Session &s, Parser &p) {
auto args = parse_isc(s, p);
_isc(s, args.vspace_name, args.sort, args.addresses);
},
[](Session &s, Parser &p) { parse_isc(s, p); }, "Info Syscalls", R"(
isc [sort=true] [vspace=<virtual_space>] [<address>...]
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.
)");
static ShellCommand _is_cmd(
"is",
[](Session &s, Parser &p) {
parse_is(s, p);
_is(s);
},
[](Session &s, Parser &p) { parse_is(s, p); }, "Info Symbols", R"(
is
Lists all symbols in the current virtual space.
)");