2022-03-28 21:59:30 +02:00
|
|
|
//---------------------------------------------------------------------------//
|
|
|
|
// 1100101 |_ mov #0, r4 __ //
|
|
|
|
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
|
|
|
|
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
|
|
|
|
// |_ base# + offset |_| /_\_\___/__/ //
|
|
|
|
//---------------------------------------------------------------------------//
|
2019-12-28 17:18:13 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
#include <fxos/passes/cfg.h>
|
2019-12-28 17:18:13 +01:00
|
|
|
#include <fxos/disassembly.h>
|
2022-03-27 14:59:49 +02:00
|
|
|
#include <fxos/util/log.h>
|
2019-12-28 17:18:13 +01:00
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
namespace FxOS {
|
|
|
|
|
|
|
|
CfgPass::CfgPass(Disassembly &disasm):
|
2022-03-28 21:59:30 +02:00
|
|
|
DisassemblyPass(disasm, "cfg")
|
2019-12-28 17:18:13 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
bool CfgPass::analyze(uint32_t pc, Instruction &i)
|
2019-12-28 17:18:13 +01:00
|
|
|
{
|
2022-03-28 21:59:30 +02:00
|
|
|
/* 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;
|
|
|
|
}
|
2020-02-29 16:32:25 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
/* 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;
|
2019-12-28 17:18:13 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
if(i.inst->isjump() || i.inst->iscondjump()) {
|
|
|
|
auto &args = i.inst->args;
|
2019-12-28 17:18:13 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
if(i.inst->arg_count != 1 || args[0].kind != AsmArgument::PcJump) {
|
|
|
|
FxOS_log(ERR, "invalid jump instruction at %08x", pc);
|
|
|
|
return false;
|
|
|
|
}
|
2019-12-28 17:18:13 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
jmptarget = (pc+4) + args[0].disp;
|
2020-02-12 07:53:00 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
/* Make the target of the jump a leader */
|
|
|
|
Instruction &target = m_disasm.readins(jmptarget);
|
|
|
|
target.leader = true;
|
2020-02-12 07:53:00 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
/* 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));
|
|
|
|
}
|
2020-02-12 07:53:00 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
/* 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.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;
|
|
|
|
}
|
2020-02-12 07:53:00 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
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;
|
|
|
|
}
|
2019-12-28 17:18:13 +01:00
|
|
|
|
2022-03-28 21:59:30 +02:00
|
|
|
enqueue_unseen_successors(pc, i);
|
|
|
|
return true;
|
2019-12-28 17:18:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} /* namespace FxOS */
|