145 lines
4.4 KiB
C++
145 lines
4.4 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), m_claimedInstructions {}
|
|
{
|
|
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 at 0x%08x: 0x%04x", pc, i.opcode);
|
|
return false;
|
|
}
|
|
|
|
m_claimedInstructions.insert(pc);
|
|
|
|
/* 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 0x%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(
|
|
"0x%08x jumps into 0x%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 0x%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(
|
|
"0x%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 0x%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)
|
|
{
|
|
m_lastFunction = pc;
|
|
m_claimedInstructions.clear();
|
|
|
|
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);
|
|
}
|
|
|
|
std::set<Claim> CfgPass::resultClaims()
|
|
{
|
|
Claim base;
|
|
base.address = 0xffffffff;
|
|
base.size = 0;
|
|
base.type = Claim::Function;
|
|
base.owner = m_lastFunction;
|
|
|
|
std::set<Claim> set;
|
|
Claim c = base;
|
|
|
|
for(uint32_t pc: m_claimedInstructions) {
|
|
if(pc == c.address + c.size) {
|
|
c.size += 2;
|
|
}
|
|
else {
|
|
if(c.size > 0)
|
|
set.insert(c);
|
|
c = base;
|
|
c.address = pc;
|
|
c.size = 2;
|
|
}
|
|
}
|
|
|
|
if(c.size > 0)
|
|
set.insert(c);
|
|
|
|
return set;
|
|
}
|
|
|
|
} /* namespace FxOS */
|