fxos/shell/d.cpp

121 lines
3.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/pcrel.h>
#include <fxos/passes/syscall.h>
#include <fxos/view/assembly.h>
#include <fxos/function.h>
#include <fxos/analysis.h>
#include <fxos/util/Timer.h>
#include <fxos/util/log.h>
//---
// 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);
PcrelPass p(*b);
p.analyzeAllInstructions();
OS *os = b->OSAnalysis();
if(os) {
SyscallPass p(*b, os);
p.analyzeAllInstructions();
}
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++;
}
Function f(*b, address);
if(f.exploreFunctionAt(address)) {
f.runAnalysis();
ViewAssemblyOptions opts;
opts.binary = b;
opts.printFunctionAnalysis = true;
viewAssemblyFunction(f, &opts);
}
}
}
//---
// 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
)");