add main disassembly, ad and ads commands
This commit is contained in:
parent
29cd2815ec
commit
59ed0c8621
|
@ -16,7 +16,6 @@
|
|||
#define FXOS_DISASSEMBLY_H
|
||||
|
||||
#include <fxos/lang.h>
|
||||
#include <fxos/vspace.h>
|
||||
#include <fxos/semantics.h>
|
||||
#include <fxos/util/Buffer.h>
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <fxos/memory.h>
|
||||
#include <fxos/os.h>
|
||||
#include <fxos/symbols.h>
|
||||
#include <fxos/disassembly.h>
|
||||
#include <fxos/AbstractMemory.h>
|
||||
#include <fxos/util/Buffer.h>
|
||||
#include <fxos/util/Addressable.h>
|
||||
|
@ -63,9 +64,11 @@ public:
|
|||
/* List of bindings (most recent first) */
|
||||
std::vector<Binding> 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<OS> m_os;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
|
||||
#include <fxos/disassembly.h>
|
||||
#include <fxos/vspace.h>
|
||||
#include <fxos/util/log.h>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
|
||||
#include <fxos/passes/pcrel.h>
|
||||
#include <fxos/vspace.h>
|
||||
|
||||
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];
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
|
||||
#include <fxos/passes/print.h>
|
||||
#include <fxos/disassembly.h>
|
||||
#include <fxos/vspace.h>
|
||||
#include <fxos/util/format.h>
|
||||
|
||||
#include <cstdarg>
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
148
shell/a.cpp
148
shell/a.cpp
|
@ -3,6 +3,13 @@
|
|||
#include "commands.h"
|
||||
#include "errors.h"
|
||||
|
||||
#include <fxos/disassembly.h>
|
||||
#include <fxos/vspace.h>
|
||||
#include <fxos/util/Timer.h>
|
||||
#include <fxos/util/log.h>
|
||||
#include <fxos/passes/cfg.h>
|
||||
#include <fxos/passes/pcrel.h>
|
||||
#include <fxos/passes/syscall.h>
|
||||
#include <fmt/core.h>
|
||||
#include <endian.h>
|
||||
|
||||
|
@ -213,6 +220,121 @@ void _af4(Session &session, uint32_t value, std::vector<MemoryRegion> ®ions)
|
|||
_afh(session, (char *)&value_big_endian, pattern, 4, 4, -1, regions);
|
||||
}
|
||||
|
||||
//---
|
||||
// ad
|
||||
//---
|
||||
|
||||
static void ad_disassemble_all(VirtualSpace &space,
|
||||
std::vector<uint32_t> const &addresses, bool force)
|
||||
{
|
||||
std::vector<std::string> 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<uint32_t> parse_ad(Session &session, Parser &parser)
|
||||
{
|
||||
if(!session.current_space)
|
||||
return std::vector<uint32_t>();
|
||||
|
||||
std::vector<uint32_t> addresses;
|
||||
do {
|
||||
addresses.push_back(parser.expr(session.current_space));
|
||||
}
|
||||
while(!parser.at_end());
|
||||
|
||||
parser.end();
|
||||
return addresses;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//--
|
||||
// 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<uint32_t> 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 [<addresses>...]
|
||||
|
||||
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.
|
||||
)");
|
||||
|
|
|
@ -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 [<range>]
|
|||
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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -34,7 +34,7 @@ struct Session
|
|||
//---
|
||||
|
||||
/* Virtual spaces organized by name */
|
||||
std::map<std::string, VirtualSpace> spaces;
|
||||
std::map<std::string, std::unique_ptr<VirtualSpace>> spaces;
|
||||
/* Find a virtual space by name */
|
||||
VirtualSpace *get_space(std::string name);
|
||||
|
||||
|
|
16
shell/v.cpp
16
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<std::string> 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<VirtualSpace> space = std::make_unique<VirtualSpace>();
|
||||
session.spaces.emplace(name, std::move(space));
|
||||
_vs(session, name);
|
||||
_g(session, 0x80000000);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue