//---------------------------------------------------------------------------// // 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), 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 CfgPass::resultClaims() { Claim base; base.address = 0xffffffff; base.size = 0; base.type = Claim::Function; base.owner = m_lastFunction; std::set 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 */