fxos/lib/passes/cfg.cpp

85 lines
2.2 KiB
C++

//---
// fxos.passes.cfg: Control Flow Graph construction
//---
#include <fxos/disasm-passes/cfg.h>
#include <fxos/disassembly.h>
#include <fxos/errors.h>
#include <fxos/log.h>
#include <cassert>
using namespace FxOS::Log;
namespace FxOS {
CfgPass::CfgPass(Disassembly &disasm):
DisassemblyPass(disasm, "cfg")
{
}
void CfgPass::analyze(uint32_t pc, ConcreteInstruction &ci)
{
/* Don't explore successors if the instruction cannot be decoded, not
even pc+2. This will prevent wild overshoot. */
if(!ci.inst) return;
/* 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(ci.inst->isjump() || ci.inst->iscondjump())
{
auto &args = ci.inst->args;
if(ci.inst->arg_count != 1 || args[0].kind != Argument::PcJump)
throw LangError(pc, "invalid jump instruction");
jmptarget = (pc+4) + args[0].disp;
/* Make the target of the jump a leader */
ConcreteInstruction &target = m_disasm.readins(jmptarget);
target.leader = true;
/* Check that it's not in a delay slot */
if(target.delayslot)
throw LimitError("jump into a delay slot!");
}
/* 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(ci.delayslot)
{
if(!ci.inst->isvaliddelayslot())
throw LangError(pc, "invalid delay slot");
}
/* Handle normal instructions */
else if(!ci.inst->isdelayed())
{
ci.terminal = ci.inst->isterminal();
ci.jump = ci.inst->isjump();
ci.condjump = ci.inst->iscondjump();
ci.jmptarget = jmptarget;
}
/* Create a new delay slot */
else
{
ConcreteInstruction &slot = m_disasm.readins(pc+2);
if(slot.leader)
throw LimitError("leader in a delay slot!");
if(!slot.inst->isvaliddelayslot())
throw LangError(pc+2, "invalid delay slot");
slot.delayslot = true;
slot.terminal = ci.inst->isterminal();
slot.jump = ci.inst->isjump();
slot.condjump = ci.inst->iscondjump();
slot.jmptarget = jmptarget;
}
enqueue_unseen_successors(pc, ci);
}
} /* namespace FxOS */