157 lines
4.0 KiB
C++
157 lines
4.0 KiB
C++
#include "commands.h"
|
|
#include "errors.h"
|
|
#include "parser.h"
|
|
#include "shell.h"
|
|
|
|
#include <fmt/core.h>
|
|
|
|
#include <fxos/disassembly.h>
|
|
#include <fxos/passes/cfg.h>
|
|
#include <fxos/passes/pcrel.h>
|
|
#include <fxos/passes/syscall.h>
|
|
#include <fxos/view/assembly.h>
|
|
#include <fxos/function.h>
|
|
#include <fxos/util/Timer.h>
|
|
#include <fxos/util/log.h>
|
|
|
|
static void disassemble(
|
|
Binary &binary, std::vector<std::string> const &passes, u32 address)
|
|
{
|
|
for(auto pass: passes) {
|
|
Timer timer;
|
|
timer.start();
|
|
|
|
bool ok;
|
|
|
|
if(pass == "cfg") {
|
|
CfgPass p(binary);
|
|
ok = p.analyzeAnonymousFunction(address);
|
|
}
|
|
else if(pass == "pcrel") {
|
|
PcrelPass p(binary);
|
|
ok = p.analyzeAllInstructions();
|
|
}
|
|
else if(pass == "syscall") {
|
|
OS *os = binary.OSAnalysis();
|
|
if(os) {
|
|
SyscallPass p(binary, os);
|
|
ok = p.analyzeAllInstructions();
|
|
}
|
|
}
|
|
else if(pass == "print" && address + 1) {
|
|
// viewAssemblyLegacyAddress(binary, address);
|
|
}
|
|
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) {
|
|
FxOS_log(ERR, "pass <%s> failed", pass);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(address + 1) {
|
|
Function f(binary, address);
|
|
f.exploreFunctionAt(address);
|
|
ViewAssemblyOptions opts;
|
|
opts.binary = &binary;
|
|
viewAssemblyFunction(f, &opts);
|
|
}
|
|
}
|
|
|
|
//---
|
|
// d
|
|
//---
|
|
|
|
struct _d_args
|
|
{
|
|
std::variant<long, Range> location;
|
|
};
|
|
|
|
static _d_args parse_d(Session &session, Parser &parser)
|
|
{
|
|
_d_args args;
|
|
|
|
if(!session.currentBinary())
|
|
return {};
|
|
|
|
args.location = parser.expr_or_range(session.currentBinary());
|
|
parser.end();
|
|
return args;
|
|
}
|
|
|
|
void _d(Session &session, std::variant<long, Range> location)
|
|
{
|
|
Binary *b = session.currentBinary();
|
|
if(!b)
|
|
return FxOS_log(ERR, "No current binary!\n");
|
|
|
|
if(std::holds_alternative<Range>(location)) {
|
|
Range range = std::get<Range>(location);
|
|
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)
|
|
b->vspace().disasm.getInstructionAt(pc, true);
|
|
|
|
disassemble(*b, {"pcrel", /*"constprop",*/ "syscall"}, -1);
|
|
|
|
MemoryRegion r;
|
|
r.start = range.start;
|
|
r.end = range.end - 1;
|
|
viewAssemblyLegacyRegion(*b, r);
|
|
}
|
|
else {
|
|
uint32_t address = std::get<long>(location);
|
|
|
|
if(address & 1) {
|
|
fmt::print("address 0x{:08x} is odd, starting at 0x{:08x}\n",
|
|
address, address + 1);
|
|
address++;
|
|
}
|
|
|
|
/* cfg implicitly does pcrel */
|
|
disassemble(*b, {"cfg", /*"constprop",*/ "syscall", "print"}, address);
|
|
}
|
|
}
|
|
|
|
//---
|
|
// Command registration
|
|
//---
|
|
|
|
static ShellCommand _d_cmd(
|
|
"d",
|
|
[](Session &s, Parser &p) {
|
|
auto args = parse_d(s, p);
|
|
_d(s, args.location);
|
|
},
|
|
[](Session &s, Parser &p) { parse_d(s, p); }, "Disassemble", R"(
|
|
d [<address|range>]
|
|
|
|
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
|
|
)");
|