diff --git a/include/fxos/disassembly.h b/include/fxos/disassembly.h index a4fd710..fdba634 100644 --- a/include/fxos/disassembly.h +++ b/include/fxos/disassembly.h @@ -16,7 +16,6 @@ #define FXOS_DISASSEMBLY_H #include -#include #include #include @@ -26,6 +25,8 @@ namespace FxOS { +class VirtualSpace; + /* Register an instruction. This is called by loader functions from the asm table lexer. [inst] must have its opcode field set. */ void register_instruction(AsmInstruction const &inst); diff --git a/include/fxos/vspace.h b/include/fxos/vspace.h index 0bd6887..a2c14a6 100644 --- a/include/fxos/vspace.h +++ b/include/fxos/vspace.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -63,9 +64,11 @@ public: /* List of bindings (most recent first) */ std::vector bindings; - /* OS analysis; created on-demand. Returns the new or cached OS analysis, - nullptr OS analysis fails. */ - OS *os_analysis(bool force=false); + /* Bind a buffer to a standard or custom memory region. Functions in the + library tend to assume that bindings don't overlap and are not + immediately consecutive in memory. If the buffer is smaller than the + region, it is 0-padded to the proper size. */ + void bind_region(MemoryRegion const ®ion, Buffer const &buffer); /* Cursor position, used by the interactive shell */ uint32_t cursor; @@ -73,15 +76,18 @@ public: /* Symbol table */ SymbolTable symbols; - /* Bind a buffer to a standard or custom memory region. Functions in the - library tend to assume that bindings don't overlap and are not - immediately consecutive in memory. If the buffer is smaller than the - region, it is 0-padded to the proper size. */ - void bind_region(MemoryRegion const ®ion, Buffer const &buffer); - // - AbstractMemory interface char const *translate_dynamic(uint32_t addr, int *size) override; + // Analysis tools and data + + /* Main disassembly; holds disassembled code for large-scale analyses. */ + Disassembly disasm; + + /* OS analysis; created on-demand. Returns the new or cached OS analysis, + nullptr OS analysis fails. */ + OS *os_analysis(bool force=false); + private: /* OS analysis results */ std::unique_ptr m_os; diff --git a/lib/disassembly.cpp b/lib/disassembly.cpp index c935da4..dcd8945 100644 --- a/lib/disassembly.cpp +++ b/lib/disassembly.cpp @@ -6,6 +6,7 @@ //---------------------------------------------------------------------------// #include +#include #include #include #include diff --git a/lib/passes/pcrel.cpp b/lib/passes/pcrel.cpp index fd81c80..6eeb4e5 100644 --- a/lib/passes/pcrel.cpp +++ b/lib/passes/pcrel.cpp @@ -6,6 +6,7 @@ //---------------------------------------------------------------------------// #include +#include namespace FxOS { @@ -18,7 +19,7 @@ bool PcrelPass::analyze(uint32_t pc, Instruction &ci) { AsmInstruction const *i = ci.inst; if(!i) - return false; + return true; for(size_t n = 0; n < i->arg_count; n++) { AsmArgument const &arg = i->args[n]; diff --git a/lib/passes/print.cpp b/lib/passes/print.cpp index 377eec4..d456571 100644 --- a/lib/passes/print.cpp +++ b/lib/passes/print.cpp @@ -6,7 +6,7 @@ //---------------------------------------------------------------------------// #include -#include +#include #include #include diff --git a/lib/passes/syscall.cpp b/lib/passes/syscall.cpp index bc97071..aef6877 100644 --- a/lib/passes/syscall.cpp +++ b/lib/passes/syscall.cpp @@ -24,7 +24,7 @@ bool SyscallPass::analyze(uint32_t pc, Instruction &ci) AsmInstruction const *i = ci.inst; if(!i) - return false; + return true; for(size_t n = 0; n < i->arg_count; n++) { AsmArgument const &arg = i->args[n]; diff --git a/lib/vspace.cpp b/lib/vspace.cpp index e3f2e4c..e2e2946 100644 --- a/lib/vspace.cpp +++ b/lib/vspace.cpp @@ -29,7 +29,7 @@ char const *Binding::translate_dynamic(uint32_t addr, int *size) } VirtualSpace::VirtualSpace(): - mpu {}, bindings {}, m_os {nullptr} + mpu {}, bindings {}, cursor {0}, disasm {*this}, m_os {nullptr} { } diff --git a/shell/a.cpp b/shell/a.cpp index 94048d0..e744428 100644 --- a/shell/a.cpp +++ b/shell/a.cpp @@ -3,6 +3,13 @@ #include "commands.h" #include "errors.h" +#include +#include +#include +#include +#include +#include +#include #include #include @@ -213,6 +220,121 @@ void _af4(Session &session, uint32_t value, std::vector ®ions) _afh(session, (char *)&value_big_endian, pattern, 4, 4, -1, regions); } +//--- +// ad +//--- + +static void ad_disassemble_all(VirtualSpace &space, + std::vector const &addresses, bool force) +{ + std::vector passes = { "cfg", "pcrel", "syscall" }; + + for(auto pass: passes) { + Timer timer; + timer.start(); + + bool ok = true; + uint32_t error_addr = -1; + + if(pass == "cfg") { + CfgPass p(space.disasm); + for(uint32_t addr: addresses) { + ok &= p.run(addr); + if(!ok) { error_addr = addr; break; } + } + } + else if(pass == "pcrel") { + PcrelPass p(space.disasm); + ok = p.run(); + if(!ok) break; + } + else if(pass == "syscall") { + OS *os = space.os_analysis(); + if(os) { + SyscallPass p(space.disasm, os); + ok = p.run(); + if(!ok) break; + } + } + else { + FxOS_log(ERR, "unknown pass <%s>", pass); + ok = false; + } + + timer.stop(); + FxOS_log(LOG, "Finished pass <%s> in %s", pass, timer.format_time()); + + if(!ok) { + if(error_addr != (uint32_t)-1) + FxOS_log(ERR, "entry %08x: pass <%s> failed", error_addr,pass); + else + FxOS_log(ERR, "pass <%s> failed", pass); + if(!force) + break; + } + } +} + +static std::vector parse_ad(Session &session, Parser &parser) +{ + if(!session.current_space) + return std::vector(); + + std::vector addresses; + do { + addresses.push_back(parser.expr(session.current_space)); + } + while(!parser.at_end()); + + parser.end(); + return addresses; +} + +void _ad(Session &session, std::vector const &addresses) +{ + if(!session.current_space) + return; + + VirtualSpace &space = *session.current_space; + ad_disassemble_all(space, addresses, false); +} + +//-- +// ads +//--- + +static void parse_ads(Session &session, Parser &parser) +{ + if(!session.current_space) + return; + + parser.end(); +} + +void _ads(Session &session) +{ + if(!session.current_space) + return; + + VirtualSpace &space = *session.current_space; + OS *os = space.os_analysis(); + + if(!os) { + printf("ads: OS analysis failed, cannot enumerate syscalls"); + return; + } + + std::vector addresses; + for(int i = 0; i < os->syscall_count(); i++) + addresses.push_back(os->syscall(i)); + + ad_disassemble_all(space, addresses, true); +} + +//--- +// Command definitions +//--- + static ShellCommand _af4_cmd("af4", [](Session &s, Parser &p){ auto args = parse_af4(s, p); @@ -261,3 +383,29 @@ afh align=4 "b4..0000" Searches 4-aligned values close to the display interface 0xb4000000 within all currently bound regions. )"); + +static ShellCommand _ad_cmd("ad", + [](Session &s, Parser &p) { + auto addresses = parse_ad(s, p); + _ad(s, addresses); }, + [](Session &s, Parser &p) { parse_ad(s, p); }, + "Analysis Disassemble", R"( +ad [...] + +Disassemble the given set of addresses into the current virtual space's main +disassembly. The main disassembly is used for OS-wide features like cross- +reference search or call graphs. +)"); + +static ShellCommand _ads_cmd("ads", + [](Session &s, Parser &p) { + parse_ads(s, p); + _ads(s); }, + [](Session &s, Parser &p) { parse_ads(s, p); }, + "Analysis Disassemble all Syscalls", R"( +ads + +Disassembles all syscalls entries using ad, which stores the results in the +current virtual space's main disassembly. Unlike ad, this commands continues +even if some syscalls fail to disassemble. +)"); diff --git a/shell/d.cpp b/shell/d.cpp index 4b3bd17..1060fab 100644 --- a/shell/d.cpp +++ b/shell/d.cpp @@ -173,6 +173,10 @@ Disassembles code starting at the specified address, exploring branches until function terminators, invalid instructions, or dynamically-computed jumps. The default address is $ (the cursor of the current virtual space). +This command does not extend the virtual space's main disassembly. It reads +analysis results from the virtual space, but doesn't add new information. Try +as? to disassemble in the space's main disassembly. + The following disassembler passes are run: cfg Explores the code reachable from the start address pcrel Computes PC-relative addresses (eg mov.l, mova, bf, bra...) @@ -188,6 +192,8 @@ dr [] Disassembles an explicit region of memory. This is similar to d, except that the disassembled code is pre-loaded from the region instead of being explored by the cfg pass. See d? for more information. + +Like d, this command does not extend the virtual space's main disassembly. )"); static ShellCommand _dtl_cmd("dtl", diff --git a/shell/main.cpp b/shell/main.cpp index ee6aed5..c2a6362 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -165,7 +165,7 @@ static std::string read_interactive(Session const &s, bool &leave) std::string name = "(none)"; for(auto &it: s.spaces) { - if(&it.second == s.current_space) + if(it.second.get() == s.current_space) name = it.first; } diff --git a/shell/session.cpp b/shell/session.cpp index 785ff20..1e69287 100644 --- a/shell/session.cpp +++ b/shell/session.cpp @@ -13,7 +13,7 @@ Session::Session(): VirtualSpace *Session::get_space(std::string name) { auto const &it = this->spaces.find(name); - return it == this->spaces.end() ? nullptr : &it->second; + return it == this->spaces.end() ? nullptr : it->second.get(); } std::string Session::generate_space_name(std::string prefix, bool force_suffix) diff --git a/shell/session.h b/shell/session.h index 4c9cebc..e80af99 100644 --- a/shell/session.h +++ b/shell/session.h @@ -34,7 +34,7 @@ struct Session //--- /* Virtual spaces organized by name */ - std::map spaces; + std::map> spaces; /* Find a virtual space by name */ VirtualSpace *get_space(std::string name); diff --git a/shell/v.cpp b/shell/v.cpp index e4834b4..537c485 100644 --- a/shell/v.cpp +++ b/shell/v.cpp @@ -38,7 +38,12 @@ static void show_vspace(std::string name, VirtualSpace &s, Session &session) return; } - fmt::print(" Region Start End File\n"); + fmt::print(" Symbol table: {} symbols\n", + s.symbols.symbols.size()); + fmt::print(" Main disassembly: {} instructions\n", + s.disasm.instructions.size()); + + fmt::print(" Region--Start---------End---------File--------------------\n"); for(auto &b: s.bindings) { MemoryRegion const *ref = MemoryRegion::region_for(b.region); fmt::print(" {:<7s} 0x{:08x} .. 0x{:08x}", (ref ? ref->name : ""), @@ -53,12 +58,12 @@ void _vl(Session &session, std::vector const &args) { if(!args.size()) { for(auto &it: session.spaces) - show_vspace(it.first, it.second, session); + show_vspace(it.first, *it.second, session); } else for(auto &name: args) { VirtualSpace *s = session.get_space(name); if(s != nullptr) - show_vspace(name, session.spaces[name], session); + show_vspace(name, *session.spaces[name], session); else fmt::print("Virtual space '{}' does not exist", name); } @@ -80,7 +85,7 @@ void _vs(Session &session, std::string const &name) VirtualSpace *s = session.get_space(name); if(!s) return; - session.current_space = &session.spaces[name]; + session.current_space = session.spaces[name].get(); } //--- @@ -101,7 +106,8 @@ static void _vc(Session &session, std::string name) else name = session.generate_space_name(name, false); /* Create an empty space and select it */ - session.spaces.emplace(name, VirtualSpace {}); + std::unique_ptr space = std::make_unique(); + session.spaces.emplace(name, std::move(space)); _vs(session, name); _g(session, 0x80000000); }