//---------------------------------------------------------------------------// // 1100101 |_ mov #0, r4 __ // // 11 |_ <0xb380 %5c4> / _|_ _____ ___ // // 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // // |_ base# + offset |_| /_\_\___/__/ // //---------------------------------------------------------------------------// #include #include #include #include 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 */