121 lines
3.0 KiB
C++
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
|
|
)");
|