fxos: remove vspace as a session abstraction

And rewrite all existing commands to read from a binary instead.

The transition to the new data model is *not* complete because a bunch
of data is still hidden in the "Disassembly" inside the binary's virtual
space instead of being managed by the binary itself. Removing these is
the next step.
This commit is contained in:
Lephenixnoir 2023-09-24 20:51:10 +02:00
parent fcdcdba423
commit 2a3f1845de
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
17 changed files with 294 additions and 398 deletions

View File

@ -55,11 +55,18 @@ struct Binary
// TODO: Implement OS analysis
// TODO: Add and manage objects
std::map<u32, std::unique_ptr<BinaryObject>> const &objects() const
std::multimap<u32, std::unique_ptr<BinaryObject>> const &objects() const
{
return m_objects;
}
/* Return the address of an object by name, if it exists. If there are
multiple objects with the same name, returns an arbitrary one. */
std::optional<u32> objectAddress(std::string const &name) const;
/* Locate all objects that intersect an address. */
std::vector<BinaryObject *> objectsCovering(u32 address);
private:
VirtualSpace m_vspace;
@ -67,7 +74,7 @@ private:
std::unique_ptr<OS> m_os;
/* All binary objects */
std::map<u32, std::unique_ptr<BinaryObject>> m_objects;
std::multimap<u32, std::unique_ptr<BinaryObject>> m_objects;
};
/* Base structure for all /binary objets/, ie. program objects that can be

View File

@ -44,6 +44,38 @@ void Binary::deserialize(BSON const &b)
}
}
OS *Binary::OSAnalysis(bool force)
{
if(!m_os || force) {
m_os = std::make_unique<OS>(m_vspace);
/* We don't keep an OS analysis result that failed */
if(m_os->type == OS::UNKNOWN)
m_os = nullptr;
}
return m_os.get();
}
std::optional<u32> Binary::objectAddress(std::string const &name) const
{
for(auto const &[address, obj]: m_objects) {
if(obj->name() == name)
return address;
}
return {};
}
std::vector<BinaryObject *> Binary::objectsCovering(u32 address)
{
std::vector<BinaryObject *> objects;
for(auto const &[obj_address, obj]: m_objects) {
if(obj_address <= address && obj_address + obj->size() < address)
objects.push_back(obj.get());
}
return objects;
}
//=== BinaryObject ===//
bool BinaryObject::intersects(BinaryObject const &other) const

View File

@ -74,12 +74,13 @@ static void ad_disassemble_all(
static std::vector<uint32_t> parse_ad(Session &session, Parser &parser)
{
if(!session.current_space)
Binary *b = session.currentBinary();
if(!b)
return std::vector<uint32_t>();
std::vector<uint32_t> addresses;
do {
addresses.push_back(parser.expr(session.current_space));
addresses.push_back(parser.expr(b));
}
while(!parser.at_end());
@ -89,32 +90,26 @@ static std::vector<uint32_t> parse_ad(Session &session, Parser &parser)
void _ad(Session &session, std::vector<uint32_t> const &addresses)
{
if(!session.current_space)
return;
VirtualSpace &space = *session.current_space;
ad_disassemble_all(space, addresses, false);
ad_disassemble_all(session.currentBinary()->vspace(), addresses, false);
}
//--
// ads
//---
static void parse_ads(Session &session, Parser &parser)
static void parse_ads(Session &, Parser &parser)
{
if(!session.current_space)
return;
parser.end();
}
void _ads(Session &session)
{
if(!session.current_space)
Binary *b = session.currentBinary();
if(!b)
return;
VirtualSpace &space = *session.current_space;
OS *os = space.os_analysis();
VirtualSpace &space = b->vspace();
OS *os = b->OSAnalysis();
if(!os) {
printf("ads: OS analysis failed, cannot enumerate syscalls");
@ -132,9 +127,11 @@ void _ads(Session &session)
// am
//---
static void _am_cg_main_menu_function(VirtualSpace &vspace)
static void _am_cg_main_menu_function(Binary &b)
{
OS *os = vspace.os_analysis();
VirtualSpace &vspace = b.vspace();
OS *os = b.OSAnalysis();
if(!os) {
FxOS_log(ERR, "no OS analysis");
return;
@ -203,7 +200,7 @@ static void _am_cg_main_menu_function(VirtualSpace &vspace)
static std::string parse_am(Session &session, Parser &parser)
{
if(!session.current_space)
if(!session.currentBinary())
return "";
std::string name = parser.symbol();
@ -214,13 +211,13 @@ static std::string parse_am(Session &session, Parser &parser)
void _am(Session &session, std::string name)
{
if(!session.current_space) {
FxOS_log(ERR, "am: no virtual space");
if(!session.currentBinary()) {
FxOS_log(ERR, "am: no current binary");
return;
}
if(name == "cg_main_menu_function")
_am_cg_main_menu_function(*session.current_space);
_am_cg_main_menu_function(*session.currentBinary());
else
FxOS_log(ERR, "am: unknown misc. command '%s'", name);
}

View File

@ -71,7 +71,7 @@ static _bm_args parse_bm(Session &session, Parser &parser)
/* TODO: bm: Allow specifying address without a size */
do
args.regions.push_back(parser.region(session.current_space));
args.regions.push_back(parser.region(session.currentBinary()));
while(!parser.at_end());
parser.end();

View File

@ -31,7 +31,7 @@ static void disassemble(Session &session, Disassembly &disasm,
ok = p.analyzeAllInstructions();
}
else if(pass == "syscall") {
OS *os = session.current_space->os_analysis();
OS *os = session.currentBinary()->OSAnalysis();
if(os) {
SyscallPass p(disasm, os);
ok = p.analyzeAllInstructions();
@ -78,22 +78,19 @@ static _d_args parse_d(Session &session, Parser &parser)
{
_d_args args;
if(!session.current_space)
if(!session.currentBinary())
return {};
args.location = parser.at_end()
? session.current_space->cursor
: parser.expr_or_range(session.current_space);
args.location = parser.expr_or_range(session.currentBinary());
parser.end();
return args;
}
void _d(Session &session, std::variant<long, Range> location)
{
if(!session.current_space)
if(!session.currentBinary())
return;
FxOS::Disassembly disasm(*session.current_space);
FxOS::Disassembly disasm(session.currentBinary()->vspace());
if(std::holds_alternative<Range>(location)) {

View File

@ -13,7 +13,7 @@
struct _e_args
{
std::string space_name;
std::string binary_name;
std::vector<long> values;
};
@ -21,26 +21,26 @@ static _e_args parse_e(Session &session, Parser &parser)
{
_e_args args {};
parser.option("vspace",
[&args](std::string const &value) { args.space_name = value; });
parser.option("binary",
[&args](std::string const &value) { args.binary_name = value; });
parser.accept_options();
VirtualSpace *space = session.current_space;
if(!args.space_name.empty()) {
space = session.get_space(args.space_name);
if(!space) {
Binary *binary = session.currentBinary();
if(!args.binary_name.empty()) {
binary = session.project().getBinary(args.binary_name);
if(!binary) {
std::string msg
= format("virtual space '%s' does not exist", args.space_name);
= fmt::format("No binary “{}” in project", args.binary_name);
if(parser.completing())
throw Parser::CompletionRequest("_error", msg);
else
FxOS_log(ERR, "%s", msg);
FxOS_log(ERR, "%s", msg.c_str());
}
}
while(!parser.at_end())
args.values.push_back(parser.expr(space));
args.values.push_back(parser.expr(binary));
parser.end();
return args;
@ -67,10 +67,10 @@ static ShellCommand _e_cmd(
"e",
[](Session &s, Parser &p) {
auto const &args = parse_e(s, p);
_e(s, args.space_name, args.values);
_e(s, args.binary_name, args.values);
},
[](Session &s, Parser &p) { parse_e(s, p); }, "Evaluate expression", R"(
e [vspace=<virtual_space>] [<expression>...]
e [binary=<binary_name>] [<expression>...]
Evaluates the specified expressions. The expressions may include syscall
references (%0ab), named symbols (TRA), the current cursor ($), and
@ -80,10 +80,10 @@ The parser doesn't accept arithmetic expressions directly on the command-line;
they must be placed within parentheses.
The resulting values undergo a simple analysis which recovers symbol names and
syscall addresses within the named virtual space, or using the current virtual
space if not provided.
syscall addresses within the named binary, or using the current binary if not
provided.
e TRA ($+2)
Evaluate the address of the TRA register, and the address of the next
instruction.
e TRA (Bdisp_PutDisp_DD+2)
Evaluate the address of the TRA register, and the address of the second
instruction of Bdisp_PutDisp_DD.
)");

View File

@ -18,9 +18,9 @@ static bool is_selected(uint32_t address, Selections const &sel)
void _h_hexdump(Session &session, Range r, Selections sel)
{
if(!session.current_space)
if(!session.currentBinary())
return;
VirtualSpace &v = *session.current_space;
VirtualSpace &v = session.currentBinary()->vspace();
uint32_t start = r.start & ~0xf;
uint32_t end = (r.end + 15) & ~0xf;
@ -71,7 +71,7 @@ void _h_hexdump(Session &session, Range r, Selections sel)
static Range parse_h(Session &session, Parser &parser)
{
Range r = parser.range(session.current_space, 0, 128);
Range r = parser.range(session.currentBinary(), 0, 128);
parser.end();
return r;
}

View File

@ -110,48 +110,6 @@ void _ibs(Session &session, std::vector<std::string> const &args)
}
}
//---
// 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) {
fmt::print("Claim over 0x{:08x}:\n", address);
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);
auto dep = session.current_space->disasm.findClaimsOwnedBy(address);
fmt::print("Claims owned by 0x{:08x}:\n", address);
for(Claim const *c: dep)
fmt::print(" - {}\n", c->str());
if(!dep.size())
fmt::print(" (none)\n");
}
}
//---
// if
//---
@ -166,7 +124,7 @@ static struct _if_args parse_if(Session &session, Parser &parser)
_if_args args;
while(!parser.at_end())
args.addresses.push_back(parser.expr(session.current_space));
args.addresses.push_back(parser.expr(session.currentBinary()));
parser.end();
return args;
@ -174,9 +132,9 @@ static struct _if_args parse_if(Session &session, Parser &parser)
void _if(Session &session, struct _if_args const &args)
{
if(!session.current_space)
if(!session.currentBinary())
return;
Disassembly &disasm = session.current_space->disasm;
Disassembly &disasm = session.currentBinary()->vspace().disasm;
if(!args.addresses.size()) {
fmt::print("{} functions\n", disasm.functions.size());
@ -206,6 +164,94 @@ void _if(Session &session, struct _if_args const &args)
// io
//---
struct _io_args
{
Binary *binary;
std::vector<u32> addresses;
};
static struct _io_args parse_io(Session &session, Parser &parser)
{
_io_args args;
std::string binname = session.currentBinaryName();
parser.option(
"binary", [&binname](std::string const &value) { binname = value; });
parser.accept_options();
args.binary = session.project().getBinary(binname);
if(!args.binary) {
std::string msg = fmt::format("No binary “{}” in project!", binname);
if(parser.completing())
throw Parser::CompletionRequest("_error", msg);
else
FxOS_log(ERR, "%s", msg.c_str());
}
while(!parser.at_end())
args.addresses.push_back(parser.expr(args.binary));
parser.end();
return args;
}
static void print_object(BinaryObject &obj)
{
fmt::print(" 0x{:08x} ({}) ", obj.address(), obj.size());
if(obj.name() != "")
fmt::print("{} ", obj.name());
if(obj.isFunction())
fmt::print("<function> (TODO)\n");
else if(obj.isVariable())
fmt::print("<variable> (TODO)\n");
else if(obj.isMark())
fmt::print("<mark> (TODO)\n");
else
fmt::print("<unknown object kind> o(x_x)o\n");
if(obj.comment() != "")
fmt::print(" {}\n", obj.comment());
}
void _io(Session &, Binary *binary, std::vector<u32> addresses)
{
if(!addresses.size()) {
/* This is always sorted */
for(auto const &[_, object]: binary->objects())
print_object(*object);
return;
}
/* Find all objects related to provided addresses. Each object is indexed
not by its own address but by the address of interest that caused it to
be added to the list. */
std::multimap<u32, BinaryObject *> objects;
for(u32 address: addresses) {
auto [it, end] = binary->objects().equal_range(address);
for(; it != end; ++it)
objects.insert({address, it->second.get()});
auto const &covering = binary->objectsCovering(address);
for(BinaryObject *obj: covering)
objects.insert({address, obj});
}
for(auto [interest, obj]: objects) {
if(obj->address() == interest)
fmt::print("Object defined at {:08x}:\n", interest);
else
fmt::print("Object that covers {:08x}:\n", interest);
print_object(*obj);
}
}
//---
// ios
//---
static char const *info_str
= "OS: type %s version %02d.%02d.%04d\n"
"\n"
@ -232,22 +278,23 @@ static char const *syscall_str
static char const *syscall_nonrom_str = " %%%04x -> %08x (%s memory)\n";
static std::string parse_io(Session &, Parser &parser)
static std::string parse_ios(Session &, Parser &parser)
{
std::string name = parser.at_end() ? "" : parser.symbol("vspace_name");
std::string name = parser.at_end() ? "" : parser.symbol("binary_name");
parser.end();
return name;
}
void _io(Session &session, std::string name)
void _ios(Session &session, std::string name)
{
VirtualSpace *space = session.current_space;
Binary *binary = session.currentBinary();
if(name != "")
space = session.get_space(name);
if(!space)
binary = session.project().getBinary(name);
if(!binary)
return;
OS *os = space->os_analysis();
VirtualSpace &vspace = binary->vspace();
OS *os = binary->OSAnalysis();
if(!os)
throw CommandError("os analysis on '{}' failed", name);
@ -269,7 +316,7 @@ void _io(Session &session, std::string name)
uint32_t syscall_table = os->syscall_table_address();
uint32_t first_noncall
= space->read_u32(syscall_table + 4 * os->syscall_count());
= vspace.read_u32(syscall_table + 4 * os->syscall_count());
printf(syscall_str, (os->type == OS::FX ? 0x8001007c : 0x8002007c),
syscall_table, os->syscall_count(), first_noncall);
@ -343,7 +390,7 @@ void _ip(Session &session)
struct _isc_args
{
std::string vspace_name;
std::string binary_name;
bool sort = false;
std::vector<uint32_t> addresses;
};
@ -354,26 +401,26 @@ static struct _isc_args parse_isc(Session &session, Parser &parser)
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.option("binary",
[&args](std::string const &value) { args.binary_name = value; });
parser.accept_options();
VirtualSpace *space = session.current_space;
if(!args.vspace_name.empty()) {
space = session.get_space(args.vspace_name);
if(!space) {
Binary *binary = session.currentBinary();
if(!args.binary_name.empty()) {
binary = session.project().getBinary(args.binary_name);
if(!binary) {
std::string msg
= format("virtual space '%s' does not exist", args.vspace_name);
= format("No binary “%s” in project!", args.binary_name);
if(parser.completing())
throw Parser::CompletionRequest("_error", msg);
else
FxOS_log(ERR, "%s", msg);
FxOS_log(ERR, "%s", msg.c_str());
}
}
while(!parser.at_end())
args.addresses.push_back(parser.expr(space));
args.addresses.push_back(parser.expr(binary));
parser.end();
return args;
@ -390,27 +437,27 @@ 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,
void _isc(Session &session, std::string binary_name, bool sort,
std::vector<uint32_t> addresses)
{
VirtualSpace *space = session.current_space;
if(!space) {
FxOS_log(ERR, "no virtual space selected");
Binary *binary = session.currentBinary();
if(!binary) {
FxOS_log(ERR, "No current binary!");
return;
}
if(!vspace_name.empty())
space = session.get_space(vspace_name);
if(!binary_name.empty())
binary = session.project().getBinary(binary_name);
if(!space) {
FxOS_log(ERR, "virtual space '%s' does not exist", vspace_name);
if(!binary) {
FxOS_log(ERR, "No binary “%s” in project!", binary_name.c_str());
return;
}
OS *os = space->os_analysis();
OS *os = binary->OSAnalysis();
if(!os) {
if(!vspace_name.empty())
FxOS_log(ERR, "OS analysis on '%s' failed", vspace_name);
if(!binary_name.empty())
FxOS_log(ERR, "OS analysis on '%s' failed", binary_name);
else
FxOS_log(ERR, "OS analysis failed");
return;
@ -449,135 +496,6 @@ void _isc(Session &session, std::string vspace_name, bool sort,
}
}
//---
// is
//---
struct _is_args
{
std::string vspace_name;
std::optional<FxOS::Symbol> symbol;
bool sort;
};
static struct _is_args parse_is(Session &session, Parser &parser)
{
_is_args args;
parser.option("vspace",
[&args](std::string const &value) { args.vspace_name = value; });
parser.option("sort",
[&args](std::string const &value) { args.sort = (value == "true"); });
parser.accept_options();
FxOS::Symbol s;
if(!parser.at_end()) {
if(parser.lookahead().type == T::SYSCALL) {
s.type = FxOS::Symbol::Syscall;
s.value = parser.expect(T::SYSCALL).value.NUM;
}
else {
s.type = FxOS::Symbol::Address;
s.value = parser.expr(session.current_space);
}
args.symbol = s;
}
else {
args.symbol = {};
}
VirtualSpace *space = session.current_space;
if(!args.vspace_name.empty()) {
space = session.get_space(args.vspace_name);
if(!space) {
std::string msg
= format("virtual space '%s' does not exist", args.vspace_name);
if(parser.completing())
throw Parser::CompletionRequest("_error", msg);
else
FxOS_log(ERR, "%s", msg);
}
}
parser.end();
return args;
}
void _is(Session &session, std::string vspace_name,
std::optional<FxOS::Symbol> symbol, bool sort)
{
VirtualSpace *space = session.current_space;
if(!space) {
FxOS_log(ERR, "no virtual space selected");
return;
}
if(!vspace_name.empty())
space = session.get_space(vspace_name);
if(!space) {
FxOS_log(ERR, "virtual space '%s' does not exist", vspace_name);
return;
}
std::vector<FxOS::Symbol> symbols;
if(!symbol.has_value())
symbols = space->symbols.symbols;
else {
FxOS::Symbol s = symbol.value();
std::optional<std::string> name = space->symbols.query(s.type, s.value);
if(name.has_value())
s.name = name.value();
else if(s.type == FxOS::Symbol::Address) {
if(vspace_name.empty())
FxOS_log(ERR,
"no symbol exists for address 0x%08x in current virtual space",
s.value);
else
FxOS_log(ERR,
"no symbol exists for syscall 0x%08x in virtual space '%s'",
s.value, vspace_name);
return;
}
else if(s.type == FxOS::Symbol::Syscall) {
if(vspace_name.empty())
FxOS_log(ERR,
"no symbol exists for syscall %%%04x in current virtual space",
s.value);
else
FxOS_log(ERR,
"no symbol exists for syscall %%%04x in virtual space '%s'",
s.value, vspace_name);
return;
}
symbols = {s};
}
if(sort)
std::sort(&symbols[0], &symbols[symbols.size()]);
for(auto const &s: symbols) {
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
//---
@ -599,16 +517,6 @@ Prints short information about named binaries in the current project. If no
argument is specified, prints information about all binaries.
)");
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 _if_cmd(
"if",
[](Session &s, Parser &p) {
@ -623,9 +531,23 @@ statistics. With arguments, prints detailed function info.
)");
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>]
"io",
[](Session &s, Parser &p) {
auto args = parse_io(s, p);
_io(s, args.binary, args.addresses);
},
[](Session &s, Parser &p) { parse_io(s, p); }, "Info Objects", R"(
io [binary=<binary_name>] [<expr>...]
Lists all objects in the specified binary (default: the current one). If
expressions are provided, instead list objects defined at these addresses or
that cover these addresses. With sort=true, sorts by increasing addresses.
)");
static ShellCommand _ios_cmd(
"ios", [](Session &s, Parser &p) { _ios(s, parse_ios(s, p)); },
[](Session &s, Parser &p) { parse_ios(s, p); }, "Info OS", R"(
ios [<binary_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.
@ -644,27 +566,12 @@ static ShellCommand _isc_cmd(
"isc",
[](Session &s, Parser &p) {
auto args = parse_isc(s, p);
_isc(s, args.vspace_name, args.sort, args.addresses);
_isc(s, args.binary_name, args.sort, args.addresses);
},
[](Session &s, Parser &p) { parse_isc(s, p); }, "Info Syscalls", R"(
isc [sort=true] [vspace=<virtual_space>] [<address>...]
isc [sort=true] [binary=<binary_name>] [<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) {
auto args = parse_is(s, p);
_is(s, args.vspace_name, args.symbol, args.sort);
},
[](Session &s, Parser &p) { parse_is(s, p); }, "Info Symbols", R"(
is [sort=true] [vspace=<virtual_space>] [<address|syscall>]
Lists symbols in the specified virtual space (defaults to the current
one). By default, all symbols are listed, but if an address or syscall is
provided, the symbol associated with it will be printed instead. If sort=true,
symbols will be sorted by syscall number and then address.
Prints the syscall table for the specified binary (default: the current one).
By default, syscalls are enumerated by syscall number. If sort=true is
specified, they are instead sorted by address.
)");

View File

@ -29,7 +29,7 @@ bool legacy_command(Session &session, std::string const &cmd, Parser &parser)
return true;
}
else if(cmd == "vs") {
std::string name = parser.symbol("vspace_name");
std::string name = parser.symbol("legacy_vspace_name");
parser.end();
if(session.legacySpaces.count(name))

View File

@ -1,5 +1,6 @@
#include "parser.h"
#include "shell.h"
#include <fxos/util/log.h>
//---
// ms
@ -15,7 +16,7 @@ static FxOS::Symbol parse_ms(Session &session, Parser &parser)
}
else {
s.type = FxOS::Symbol::Address;
s.value = parser.expr(session.current_space);
s.value = parser.expr(session.currentBinary());
}
s.name = parser.symbol();
@ -26,9 +27,10 @@ static FxOS::Symbol parse_ms(Session &session, Parser &parser)
void _ms(Session &session, Symbol s)
{
if(!session.current_space)
if(!session.currentBinary())
return;
session.current_space->symbols.add(s);
FxOS_log(ERR, "Creating new objects is a TODO o(x_x)o\n");
// session.current_space->symbols.add(s);
}
static ShellCommand _ms_cmd(

View File

@ -59,12 +59,15 @@ std::vector<std::string> complete_command(char const *text)
return options;
}
std::vector<std::string> complete_vspace(char const *text, Session &session)
std::vector<std::string> complete_binary(char const *text, Session &session)
{
std::vector<std::string> options;
for(auto const &it: session.spaces) {
if(!strncmp(it.first.c_str(), text, strlen(text)))
options.push_back(it.first);
if(!session.hasProject())
return options;
for(auto const &[name, _]: session.project().binaries()) {
if(!strncmp(name.c_str(), text, strlen(text)))
options.push_back(name);
}
return options;
}
@ -79,12 +82,13 @@ std::vector<std::string> complete_region(char const *text)
return options;
}
std::vector<std::string> complete_symbol(char const *text, VirtualSpace *space)
std::vector<std::string> complete_symbol(char const *text, Binary *binary)
{
std::vector<std::string> options;
for(auto const &it: space->symbols.symbols) {
if(!strncmp(it.name.c_str(), text, strlen(text)))
options.push_back(it.name);
for(auto const &[address, obj]: binary->objects()) {
std::string name = obj->name();
if(!name.empty() && !strncmp(name.c_str(), text, strlen(text)))
options.push_back(name);
}
return options;
}
@ -129,14 +133,13 @@ char *autocomplete(char const *text, int state)
global_session, rl_line_buffer, rl_point);
if(r.category == "command")
options = complete_command(text);
// TODO: Replace vspace_name with binary_name in autocomplete
// TODO: Add legacy_vspace_name in autocomplete
else if(r.category == "vspace_name")
options = complete_vspace(text, global_session);
else if(r.category == "binary_name")
options = complete_binary(text, global_session);
else if(r.category == "memory_region")
options = complete_region(text);
else if(r.category == "symbol" && r.space != nullptr)
options = complete_symbol(text, r.space);
else if(r.category == "symbol" && r.binary != nullptr)
options = complete_symbol(text, r.binary);
else if(r.category == "_error") {
options.clear();
options.push_back("(ERROR) " + r.value);

View File

@ -96,7 +96,7 @@ void _ps(Session &session, std::string const &new_path)
static std::string parse_pm(Session &, Parser &p)
{
std::string sym = p.symbol("vspace_name");
std::string sym = p.symbol("legacy_vspace_name");
p.end();
return sym;
}

View File

@ -73,7 +73,7 @@ std::string Token::str() const
//---
Parser::Parser(bool complete):
m_complete {complete}, m_la {}, m_expr_space {nullptr}
m_complete {complete}, m_la {}, m_expr_binary {nullptr}
{
}
@ -227,16 +227,16 @@ long Parser::num()
return expect(T::NUM).value.NUM;
}
Range Parser::range(VirtualSpace *space, long before, long after)
Range Parser::range(Binary *binary, long before, long after)
{
long start = expr(space);
long start = expr(binary);
/* Accept non-ranges if (before) and (after) are provided */
if(m_la.type != ':' && m_la.type != '.' && before >= 0 && after >= 0)
return {start - before, start + after};
Token t = expect({':', '.'});
long other = expr(space);
long other = expr(binary);
Range r = {start, (t.type == ':' ? start + other : other)};
if(r.start > r.end)
@ -244,18 +244,18 @@ Range Parser::range(VirtualSpace *space, long before, long after)
return r;
}
std::variant<long, Range> Parser::expr_or_range(VirtualSpace *space)
std::variant<long, Range> Parser::expr_or_range(Binary *binary)
{
long start = expr(space);
long start = expr(binary);
if(m_la.type == ':') {
expect(':');
long length = expr(space);
long length = expr(binary);
return (Range) {start, start + length};
}
else if(m_la.type == '.') {
expect('.');
long end = expr(space);
long end = expr(binary);
return (Range) {start, end};
}
else {
@ -263,11 +263,11 @@ std::variant<long, Range> Parser::expr_or_range(VirtualSpace *space)
}
}
FxOS::MemoryRegion Parser::region(VirtualSpace *space, long before, long after)
FxOS::MemoryRegion Parser::region(Binary *binary, long before, long after)
{
if(m_la.type == '$' || m_la.type == '(' || m_la.type == '-'
|| m_la.type == T::NUM || m_la.type == T::SYSCALL) {
Range r = range(space, before, after);
if(m_la.type == '(' || m_la.type == '-' || m_la.type == T::NUM
|| m_la.type == T::SYSCALL) {
Range r = range(binary, before, after);
return FxOS::MemoryRegion("<anonymous>", r.start, r.end - 1, false);
}
@ -310,24 +310,17 @@ void Parser::accept_options()
long Parser::atom()
{
Token t = expect({'$', '(', '-', T::SYMBOL, T::NUM, T::SYSCALL});
Token t = expect({'(', '-', T::SYMBOL, T::NUM, T::SYSCALL});
if(t.type == T::SYMBOL) {
/* TODO: Specify the space that symbols are taken from */
if(m_complete && m_la.type == T::END)
throw CompletionRequest("symbol", t.value.STRING, m_expr_space);
throw CompletionRequest("symbol", t.value.STRING, m_expr_binary);
long val = 0;
if(m_expr_space) {
auto const &opt = m_expr_space->symbols.lookup(t.value.STRING);
if(opt && opt->type == FxOS::Symbol::Address) {
val = opt->value;
}
else if(opt && opt->type == FxOS::Symbol::Syscall) {
OS *os = m_expr_space->os_analysis();
if(os && (int)opt->value < os->syscall_count())
val = os->syscall(opt->value);
}
if(m_expr_binary) {
auto const &opt = m_expr_binary->objectAddress(t.value.STRING);
if(opt)
val = *opt;
else if(!m_complete)
FxOS_log(ERR, "symbol '%s' is undefined", t.value.STRING);
}
@ -337,16 +330,13 @@ long Parser::atom()
return val;
}
else if(t.type == T::SYSCALL) {
if(!m_expr_space)
if(!m_expr_binary)
return 0;
OS *os = m_expr_space->os_analysis();
OS *os = m_expr_binary->OSAnalysis();
if(!os || t.value.NUM < 0 || t.value.NUM > os->syscall_count())
return 0;
return os->syscall(t.value.NUM);
}
else if(t.type == '$') {
return (m_expr_space ? m_expr_space->cursor : 0);
}
else if(t.type == '-') {
return -atom();
}
@ -394,10 +384,10 @@ long Parser::term()
return v;
}
long Parser::expr(VirtualSpace *space)
long Parser::expr(Binary *binary)
{
m_expr_space = space;
m_expr_binary = binary;
long val = atom();
m_expr_space = nullptr;
m_expr_binary = nullptr;
return val;
}

View File

@ -15,7 +15,7 @@
#include <variant>
#include <fxos/memory.h>
#include <fxos/vspace.h>
#include <fxos/binary.h>
#include "session.h"
@ -141,19 +141,18 @@ public:
std::string symbol(std::string category="");
/* Literal string */
std::string str();
/* Read a numerical constant, or an expression. Expression uses the space
to access the program counter and query symbol values */
/* Read a numerical constant, or an expression. Expression uses the binary
to query symbol values */
long num();
long expr(VirtualSpace *space);
long expr(Binary *b);
/* Read a range; again $ and symbols are interpreted. If (before) and
(after) are both specified, a single value will also be accepted, and
the range [value-before, value+after) will be returned. */
Range range(VirtualSpace *space, long before=-1, long after=-1);
Range range(Binary *b, long before=-1, long after=-1);
/* Read an expression or a range */
std::variant<long, Range> expr_or_range(VirtualSpace *space);
std::variant<long, Range> expr_or_range(Binary *b);
/* Read a memory region (allows both ranges and symbolic names) */
FxOS::MemoryRegion region(VirtualSpace *space, long before=-1,
long after=-1);
FxOS::MemoryRegion region(Binary *b, long before=-1, long after=-1);
/* Read options, if any. Never fails */
void accept_options();
@ -173,10 +172,10 @@ public:
struct CompletionRequest
{
CompletionRequest(std::string const &c, std::string const &v,
VirtualSpace *s=nullptr): category(c), value(v), space(s) {}
Binary *b=nullptr): category(c), value(v), binary(b) {}
std::string category;
std::string value;
VirtualSpace *space;
Binary *binary;
};
//---
@ -200,7 +199,7 @@ private:
/* Virtual space for evaluation of symbols, can only be non-null during
calls to expr() */
VirtualSpace *m_expr_space;
Binary *m_expr_binary;
/* Options (retained until next SEPARATOR or END) */
std::map<std::string, OptionHandler> m_options;

View File

@ -65,9 +65,7 @@ static _sh_args parse_sh(Session &session, Parser &parser)
if(needle.size() == 0 || needle.size() % 2 != 0)
throw CommandError(
"search pattern '{}' should be of even non-zero "
"size",
needle);
"search pattern '{}' should be of even non-zero size", needle);
size_t bad_index = needle.find_first_not_of("0123456789abcdefABCDEF.");
if(bad_index != std::string::npos)
@ -86,8 +84,8 @@ static _sh_args parse_sh(Session &session, Parser &parser)
/* Convert into a reference/pattern form */
args.size = needle.size() / 2;
args.reference.reserve(args.size);
args.pattern.reserve(args.size);
args.reference.resize(args.size, '@');
args.pattern.resize(args.size, '@');
for(size_t i = 0; i < args.size; i++) {
char c1 = needle[2 * i], c2 = needle[2 * i + 1];
@ -103,7 +101,7 @@ static _sh_args parse_sh(Session &session, Parser &parser)
while(!parser.at_end()) {
parser.accept_options();
args.regions.push_back(parser.region(session.current_space));
args.regions.push_back(parser.region(session.currentBinary()));
}
parser.accept_options();
@ -115,7 +113,7 @@ static _sh_args parse_sh(Session &session, Parser &parser)
void _sh(Session &session, char const *reference, char const *pattern,
size_t size, int align, int distance, std::vector<MemoryRegion> &regions)
{
if(!session.current_space)
if(!session.currentBinary())
return;
/* Default values */
@ -124,7 +122,7 @@ void _sh(Session &session, char const *reference, char const *pattern,
if(align <= 0)
align = 1;
VirtualSpace &v = *session.current_space;
VirtualSpace &v = session.currentBinary()->vspace();
/* If no region is specified, explore the regions for all bindings */
if(regions.size() == 0) {
@ -218,10 +216,10 @@ struct _s4_args
static _s4_args parse_s4(Session &session, Parser &parser)
{
_s4_args args;
args.value = parser.expr(session.current_space);
args.value = parser.expr(session.currentBinary());
while(!parser.at_end()) {
args.regions.push_back(parser.region(session.current_space));
args.regions.push_back(parser.region(session.currentBinary()));
}
parser.end();

View File

@ -5,11 +5,6 @@
#include <fxos/util/log.h>
#include <fxos/util/bson.h>
Session::Session(): spaces {}
{
this->current_space = nullptr;
}
void Session::loadConfig(fs::path const &configFile)
{
m_config = configFile;
@ -127,30 +122,17 @@ bool Session::loadProject(std::string const &path)
return true;
}
//---
VirtualSpace *Session::get_space(std::string name)
{
auto const &it = this->spaces.find(name);
return it == this->spaces.end() ? nullptr : it->second.get();
}
std::string Session::legacyGenerateSpaceName(
std::string prefix, bool force_suffix)
{
return generate_space_name(prefix, force_suffix);
}
std::string Session::generate_space_name(std::string prefix, bool force_suffix)
{
if(!force_suffix && this->spaces.count(prefix) == 0)
if(!force_suffix && this->legacySpaces.count(prefix) == 0)
return prefix;
int counter = 0;
while(1) {
std::string name = fmt::format("{}_{}", prefix, counter);
if(!this->spaces.count(name))
if(!this->legacySpaces.count(name))
return name;
counter++;
}

View File

@ -20,7 +20,7 @@ namespace fs = std::filesystem;
struct Session
{
/* Empty session with an empty project. */
Session();
Session() = default;
/* Load a configuration file (no error if it doesn't exist). */
void loadConfig(fs::path const &configFile);
@ -104,24 +104,6 @@ struct Session
std::string legacyGenerateSpaceName(std::string prefix,
bool force_suffix=false);
//---
// Virtual spaces
// TODO: To be replaced with legacy descriptions
//---
/* Virtual spaces organized by name */
std::map<std::string, std::unique_ptr<VirtualSpace>> spaces;
/* Find a virtual space by name */
VirtualSpace *get_space(std::string name);
/* Current virtual space */
VirtualSpace *current_space;
/* Find an unused name from this prefix. If force_suffix is set, always
adds a suffix even if the name itself is free */
std::string generate_space_name(std::string prefix,
bool force_suffix=false);
private:
/* Path to configuration file. */
fs::path m_config;