fxos/lib/passes/cfg.cpp

106 lines
3.6 KiB
C++

//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
#include <fxos/passes/cfg.h>
#include <fxos/disassembly.h>
#include <fxos/util/log.h>
#include <cassert>
namespace FxOS {
CfgPass::CfgPass(Disassembly &disasm):
InstructionPass(disasm)
{
this->setAllowDiscovery(true);
}
bool CfgPass::analyzeInstruction(uint32_t pc, Instruction &i)
{
/* Don't explore successors if the instruction cannot be decoded, not
even pc+2. This will prevent wild overshoot. */
if(!i.inst) {
FxOS_log(ERR, "invalid instruction as %08x: %04x", pc, i.opcode);
return false;
}
/* Compute the jump target for jump instructions. This is easy because
they are all trivially computable. (...If they are not we dub them
"terminal" to avoid the computation!) */
uint32_t jmptarget = 0xffffffff;
if(i.inst->isjump() || i.inst->iscondjump()) {
auto &args = i.inst->args;
if(i.inst->arg_count != 1 || args[0].kind != AsmArgument::PcJump) {
FxOS_log(ERR, "invalid jump instruction at %08x", pc);
return false;
}
jmptarget = (pc+4) + args[0].disp;
/* Make the target of the jump a leader */
Instruction &target = *m_disasm.getInstructionAt(jmptarget, true);
target.leader = true;
/* Check that it's not in a delay slot */
if(target.delayslot)
throw std::logic_error(format("%08x jumps into %08x, which is a "
"delay slot - this is unsupported by fxos and will produce "
"garbage analysis! (x_x)", pc, jmptarget));
}
/* If this instruction is in a delay slot, check its type. A valid
delay slot has no branching properties on its own, so nothing new to
set in the properties. */
if(i.delayslot) {
if(!i.inst->isvaliddelayslot()) {
FxOS_log(ERR, "invalid delay slot at %08x", pc);
return false;
}
}
/* If it has a delay slot, create it at the next instruction */
else if(i.inst->isdelayed()) {
Instruction &slot = *m_disasm.getInstructionAt(pc+2, true);
if(slot.leader)
throw std::logic_error(format("%08x is a leader and also a delay "
"slot - this is unsupported by fxos and will produce garbage "
"analysis! (x_x)", pc+2));
if(!slot.inst->isvaliddelayslot()) {
FxOS_log(ERR, "invalid delay slot at %08x", pc+2);
return false;
}
slot.delayslot = true;
slot.terminal = i.inst->isterminal();
slot.jump = i.inst->isjump();
slot.condjump = i.inst->iscondjump();
slot.jmptarget = jmptarget;
}
/* Otherwise, use standard properties */
else if(!i.inst->isdelayed()) {
i.terminal = i.inst->isterminal();
i.jump = i.inst->isjump();
i.condjump = i.inst->iscondjump();
i.jmptarget = jmptarget;
}
return true;
}
bool CfgPass::exploreFunction(uint32_t pc)
{
if(!m_disasm.hasFunctionAt(pc)) {
// TODO: Have proper function creation methods in Disassembly
Function func = { .address=pc, .callTargets={} };
m_disasm.functions[pc] = func;
}
return this->analyzeFunction(pc);
}
} /* namespace FxOS */