add main disassembly, ad and ads commands

This commit is contained in:
Lephenixnoir 2022-03-28 22:42:53 +01:00
parent 29cd2815ec
commit 59ed0c8621
Signed by untrusted user: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
13 changed files with 191 additions and 22 deletions

View File

@ -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);

View File

@ -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 &region, 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 &region, 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;

View File

@ -6,6 +6,7 @@
//---------------------------------------------------------------------------//
#include <fxos/disassembly.h>
#include <fxos/vspace.h>
#include <fxos/util/log.h>
#include <optional>
#include <array>

View File

@ -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];

View File

@ -6,7 +6,7 @@
//---------------------------------------------------------------------------//
#include <fxos/passes/print.h>
#include <fxos/disassembly.h>
#include <fxos/vspace.h>
#include <fxos/util/format.h>
#include <cstdarg>

View File

@ -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];

View File

@ -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}
{
}

View File

@ -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> &regions)
_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.
)");

View File

@ -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",

View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View File

@ -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);
}