diff --git a/include/fxos/binary.h b/include/fxos/binary.h index 57311c5..2e99216 100644 --- a/include/fxos/binary.h +++ b/include/fxos/binary.h @@ -55,11 +55,18 @@ struct Binary // TODO: Implement OS analysis // TODO: Add and manage objects - std::map> const &objects() const + std::multimap> 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 objectAddress(std::string const &name) const; + + /* Locate all objects that intersect an address. */ + std::vector objectsCovering(u32 address); + private: VirtualSpace m_vspace; @@ -67,7 +74,7 @@ private: std::unique_ptr m_os; /* All binary objects */ - std::map> m_objects; + std::multimap> m_objects; }; /* Base structure for all /binary objets/, ie. program objects that can be diff --git a/lib/binary.cpp b/lib/binary.cpp index 8b41bf4..71c14a0 100644 --- a/lib/binary.cpp +++ b/lib/binary.cpp @@ -44,6 +44,38 @@ void Binary::deserialize(BSON const &b) } } +OS *Binary::OSAnalysis(bool force) +{ + if(!m_os || force) { + m_os = std::make_unique(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 Binary::objectAddress(std::string const &name) const +{ + for(auto const &[address, obj]: m_objects) { + if(obj->name() == name) + return address; + } + return {}; +} + +std::vector Binary::objectsCovering(u32 address) +{ + std::vector 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 diff --git a/shell/a.cpp b/shell/a.cpp index 39ec594..261fd31 100644 --- a/shell/a.cpp +++ b/shell/a.cpp @@ -74,12 +74,13 @@ static void ad_disassemble_all( static std::vector parse_ad(Session &session, Parser &parser) { - if(!session.current_space) + Binary *b = session.currentBinary(); + if(!b) return std::vector(); std::vector 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 parse_ad(Session &session, Parser &parser) void _ad(Session &session, std::vector 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); } diff --git a/shell/b.cpp b/shell/b.cpp index baa28ad..9f33a33 100644 --- a/shell/b.cpp +++ b/shell/b.cpp @@ -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(); diff --git a/shell/d.cpp b/shell/d.cpp index a3577bb..f6bb674 100644 --- a/shell/d.cpp +++ b/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 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(location)) { diff --git a/shell/e.cpp b/shell/e.cpp index a843e71..025443f 100644 --- a/shell/e.cpp +++ b/shell/e.cpp @@ -13,7 +13,7 @@ struct _e_args { - std::string space_name; + std::string binary_name; std::vector 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=] [...] +e [binary=] [...] 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. )"); diff --git a/shell/h.cpp b/shell/h.cpp index 0c1ae0d..bd9ef15 100644 --- a/shell/h.cpp +++ b/shell/h.cpp @@ -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; } diff --git a/shell/i.cpp b/shell/i.cpp index ceb83aa..d57c585 100644 --- a/shell/i.cpp +++ b/shell/i.cpp @@ -110,48 +110,6 @@ void _ibs(Session &session, std::vector const &args) } } -//--- -// ic -//--- - -struct _ic_args -{ - std::vector 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 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(" (TODO)\n"); + else if(obj.isVariable()) + fmt::print(" (TODO)\n"); + else if(obj.isMark()) + fmt::print(" (TODO)\n"); + else + fmt::print(" o(x_x)o\n"); + + if(obj.comment() != "") + fmt::print(" {}\n", obj.comment()); +} + +void _io(Session &, Binary *binary, std::vector 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 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 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 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 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 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 symbols; - - if(!symbol.has_value()) - symbols = space->symbols.symbols; - else { - FxOS::Symbol s = symbol.value(); - - std::optional 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
... - -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 [] + "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=] [...] + +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 [] 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=] [
...] +isc [sort=true] [binary=] [
...] -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=] [] - -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. )"); diff --git a/shell/legacy.cpp b/shell/legacy.cpp index 834e171..770f499 100644 --- a/shell/legacy.cpp +++ b/shell/legacy.cpp @@ -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)) diff --git a/shell/m.cpp b/shell/m.cpp index a45ef6f..0beadaa 100644 --- a/shell/m.cpp +++ b/shell/m.cpp @@ -1,5 +1,6 @@ #include "parser.h" #include "shell.h" +#include //--- // 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( diff --git a/shell/main.cpp b/shell/main.cpp index 774b6a0..d88e41b 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -59,12 +59,15 @@ std::vector complete_command(char const *text) return options; } -std::vector complete_vspace(char const *text, Session &session) +std::vector complete_binary(char const *text, Session &session) { std::vector 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 complete_region(char const *text) return options; } -std::vector complete_symbol(char const *text, VirtualSpace *space) +std::vector complete_symbol(char const *text, Binary *binary) { std::vector 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); diff --git a/shell/p.cpp b/shell/p.cpp index f4a6ee0..ce69396 100644 --- a/shell/p.cpp +++ b/shell/p.cpp @@ -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; } diff --git a/shell/parser.cpp b/shell/parser.cpp index 015c35c..ba7a249 100644 --- a/shell/parser.cpp +++ b/shell/parser.cpp @@ -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 Parser::expr_or_range(VirtualSpace *space) +std::variant 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 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("", 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; } diff --git a/shell/parser.h b/shell/parser.h index 9887029..0dbb6f9 100644 --- a/shell/parser.h +++ b/shell/parser.h @@ -15,7 +15,7 @@ #include #include -#include +#include #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 expr_or_range(VirtualSpace *space); + std::variant 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 m_options; diff --git a/shell/s.cpp b/shell/s.cpp index b9196c7..7f2d488 100644 --- a/shell/s.cpp +++ b/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 ®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(); diff --git a/shell/session.cpp b/shell/session.cpp index c10b738..2f5ad57 100644 --- a/shell/session.cpp +++ b/shell/session.cpp @@ -5,11 +5,6 @@ #include #include -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++; } diff --git a/shell/session.h b/shell/session.h index f0d1ffd..a02ed2b 100644 --- a/shell/session.h +++ b/shell/session.h @@ -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> 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;