forked from Lephenixnoir/fxos
186 lines
4.3 KiB
C++
186 lines
4.3 KiB
C++
#include "shell.h"
|
|
#include "parser.h"
|
|
#include "commands.h"
|
|
#include "errors.h"
|
|
|
|
#include <fmt/core.h>
|
|
|
|
#include <fxos/disassembly.h>
|
|
#include <fxos/util.h>
|
|
#include <fxos/log.h>
|
|
#include <fxos/disasm-passes/cfg.h>
|
|
#include <fxos/disasm-passes/pcrel.h>
|
|
#include <fxos/disasm-passes/syscall.h>
|
|
#include <fxos/disasm-passes/print.h>
|
|
|
|
static void disassemble(Session &session, Disassembly &disasm,
|
|
std::vector<std::string> const &passes, uint32_t address)
|
|
{
|
|
for(auto pass: passes)
|
|
{
|
|
auto start = timer_start();
|
|
log(LOG "Running pass %s...\\", pass);
|
|
|
|
if(pass == "cfg")
|
|
{
|
|
CfgPass p(disasm);
|
|
p.run(address);
|
|
}
|
|
else if(pass == "pcrel")
|
|
{
|
|
PcrelPass p(disasm);
|
|
p.run();
|
|
}
|
|
else if(pass == "syscall")
|
|
{
|
|
OS *os = session.current_space->os_analysis();
|
|
if(os) {
|
|
SyscallPass p(disasm, os);
|
|
p.run();
|
|
}
|
|
}
|
|
else if(pass == "print")
|
|
{
|
|
PrintPass p(disasm);
|
|
|
|
p.promote_pcjump_loc = PrintPass::Promote;
|
|
p.promote_pcrel_loc = PrintPass::Promote;
|
|
p.promote_pcrel_value = PrintPass::Promote;
|
|
p.promote_syscall = PrintPass::Promote;
|
|
p.promote_syscallname = PrintPass::Append;
|
|
p.promote_symbol = PrintPass::Append;
|
|
p.promote_pcaddr_loc = PrintPass::Promote;
|
|
|
|
p.run();
|
|
}
|
|
log(LOG "%s", timer_format(timer_end(start)));
|
|
}
|
|
}
|
|
|
|
//---
|
|
// d
|
|
//---
|
|
|
|
static uint32_t parse_d(Session &session, Parser &parser)
|
|
{
|
|
uint32_t address = session.current_space->cursor;
|
|
|
|
if(!parser.at_end())
|
|
address = parser.expr(session.current_space);
|
|
|
|
parser.end();
|
|
return address;
|
|
}
|
|
|
|
void _d(Session &session, uint32_t address)
|
|
{
|
|
if(!session.current_space)
|
|
return;
|
|
FxOS::Disassembly disasm(*session.current_space);
|
|
|
|
if(address & 1) {
|
|
fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n",
|
|
address, address+1);
|
|
address++;
|
|
}
|
|
|
|
disassemble(session, disasm,
|
|
{ "cfg", "pcrel", "constprop", "syscall", "print" }, address);
|
|
}
|
|
|
|
//---
|
|
// dr
|
|
//---
|
|
|
|
static Range parse_dr(Session &session, Parser &parser)
|
|
{
|
|
Range range = parser.range(session.current_space);
|
|
parser.end();
|
|
return range;
|
|
}
|
|
|
|
void _dr(Session &session, Range range)
|
|
{
|
|
if(!session.current_space)
|
|
return;
|
|
FxOS::Disassembly disasm(*session.current_space);
|
|
|
|
if(range.start & 1) {
|
|
fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n",
|
|
range.start, range.start+1);
|
|
range.start++;
|
|
}
|
|
if(range.end & 1) {
|
|
fmt::print("address 0x{:08x} is odd, ending at 0x{:08x}\n",
|
|
range.end, range.end-1);
|
|
range.end--;
|
|
}
|
|
|
|
if(range.start >= range.end) return;
|
|
|
|
/* Load the block into memory */
|
|
for(uint32_t pc = range.start; pc < range.end; pc += 2)
|
|
disasm.readins(pc);
|
|
|
|
disassemble(session, disasm, { "pcrel", "constprop", "syscall", "print" },
|
|
-1);
|
|
}
|
|
|
|
//---
|
|
// dtl
|
|
//---
|
|
|
|
static std::string parse_dtl(Session &session, Parser &parser)
|
|
{
|
|
std::string filename = parser.str();
|
|
parser.end();
|
|
return session.file(filename);
|
|
}
|
|
|
|
void _dtl(Session &, std::string filename)
|
|
{
|
|
Buffer buf(filename);
|
|
FxOS::load_instructions(buf);
|
|
}
|
|
|
|
//---
|
|
// Command registration
|
|
//---
|
|
|
|
static ShellCommand _d_cmd("d",
|
|
[](Session &s, Parser &p){ _d(s, parse_d(s, p)); },
|
|
[](Session &s, Parser &p){ parse_d(s, p); },
|
|
"Disassemble", R"(
|
|
d [<address>]
|
|
|
|
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).
|
|
|
|
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...)
|
|
syscall Annotates uses of syscall table entries with the syscall number
|
|
)");
|
|
|
|
static ShellCommand _dr_cmd("dr",
|
|
[](Session &s, Parser &p){ _dr(s, parse_dr(s, p)); },
|
|
[](Session &s, Parser &p){ parse_dr(s, p); },
|
|
"Disassemble Range", R"(
|
|
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.
|
|
)");
|
|
|
|
static ShellCommand _dtl_cmd("dtl",
|
|
[](Session &s, Parser &p){ _dtl(s, parse_dtl(s, p)); },
|
|
[](Session &s, Parser &p){ parse_dtl(s, p); },
|
|
"Disassembly Table Load", R"(
|
|
dtl "<file>"
|
|
|
|
Loads a disassembly table from the specified file. This command is mostly
|
|
designed to be used in startup scripts.
|
|
)");
|