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:
parent
fcdcdba423
commit
2a3f1845de
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
37
shell/a.cpp
37
shell/a.cpp
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
13
shell/d.cpp
13
shell/d.cpp
|
@ -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)) {
|
||||
|
|
34
shell/e.cpp
34
shell/e.cpp
|
@ -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.
|
||||
)");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
379
shell/i.cpp
379
shell/i.cpp
|
@ -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.
|
||||
)");
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
18
shell/s.cpp
18
shell/s.cpp
|
@ -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> ®ions)
|
||||
{
|
||||
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();
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue