fxos/fxos/disassembly.cpp

140 lines
2.8 KiB
C++

#include "fxos-cli.h"
#include <fxos/disassembly.h>
#include <fxos/memory.h>
#include <fxos/target.h>
#include <fxos/util.h>
#include <fxos/log.h>
#include <fxos/os.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>
using namespace FxOS;
using namespace FxOS::Log;
int disassembly(Library &library, Target &target, char const *ref,
std::vector<std::string> passes)
{
Disassembly disasm(target);
/* Observe the target only if it has an OS mapped */
std::unique_ptr<OS> os;
if(target.covers(MemoryRegion::ROM))
os = std::make_unique<OS>(target);
uint32_t address;
int syscall_id;
int len = 0;
/* Parse different flavors of references. %<hexa>: syscall */
if(sscanf(ref, "%%%x", &syscall_id) == 1)
{
if(!os)
{
log(ERR "cannot disassemble syscall %s: target does "
"not have an OS mapped", ref);
return 1;
}
if(syscall_id >= os->syscall_count())
{
log(ERR "this OS only has %#x syscalls",
os->syscall_count());
return 1;
}
address = os->syscall(syscall_id);
}
/* Pure hexa: address */
else if(sscanf(ref, "%x%n", &address, &len) == 1 && !ref[len])
{
}
/* Anything else: look up symbols */
else
{
bool found = false;
std::string name = ref;
Symbol sym;
for(auto const &symtable: library.sym_tables())
{
std::optional<Symbol> s = symtable.lookup(name);
if(!s) continue;
found = true;
sym = *s;
break;
}
if(!found)
{
log(ERR "cannot interpret '%s' (not syscall id, not "
"address, and no such symbol in library)",ref);
return 1;
}
switch(sym.type)
{
case Symbol::Syscall:
if(!os)
{
log(ERR "cannot disassemble syscall %s: target"
" does not have an OS mapped", ref);
return 1;
}
if(syscall_id >= os->syscall_count())
{
log(ERR "this OS only has %#x syscalls",
os->syscall_count());
return 1;
}
address = os->syscall(sym.value);
break;
case Symbol::Address:
address = sym.value;
break;
}
}
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(address);
}
else if(pass == "syscall")
{
SyscallPass p(disasm, os.get());
p.run(address);
}
else if(pass == "print")
{
PrintPass p(disasm, library.sym_tables());
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.run();
}
log(LOG "%s", timer_format(timer_end(start)));
}
return 0;
}