forked from Lephenixnoir/fxos
100 lines
2.5 KiB
C++
100 lines
2.5 KiB
C++
//---
|
|
// fxos.passes.cfg: Control Flow Graph construction
|
|
//---
|
|
|
|
#include <fxos/disasm-passes/cfg.h>
|
|
#include <fxos/disassembly.h>
|
|
#include <fxos/util/log.h>
|
|
#include <cassert>
|
|
|
|
namespace FxOS {
|
|
|
|
CfgPass::CfgPass(Disassembly &disasm):
|
|
DisassemblyPass(disasm, "cfg")
|
|
{
|
|
}
|
|
|
|
bool 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)
|
|
{
|
|
FxOS_log(ERR, "invalid instruction as %08x: %04x", pc, ci.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(ci.inst->isjump() || ci.inst->iscondjump())
|
|
{
|
|
auto &args = ci.inst->args;
|
|
|
|
if(ci.inst->arg_count != 1 || args[0].kind != Argument::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 */
|
|
ConcreteInstruction &target = m_disasm.readins(jmptarget);
|
|
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(ci.delayslot)
|
|
{
|
|
if(!ci.inst->isvaliddelayslot())
|
|
{
|
|
FxOS_log(ERR, "invalid delay slot at %08x", pc);
|
|
return false;
|
|
}
|
|
}
|
|
/* 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 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 = ci.inst->isterminal();
|
|
slot.jump = ci.inst->isjump();
|
|
slot.condjump = ci.inst->iscondjump();
|
|
slot.jmptarget = jmptarget;
|
|
}
|
|
|
|
enqueue_unseen_successors(pc, ci);
|
|
return true;
|
|
}
|
|
|
|
} /* namespace FxOS */
|