//---------------------------------------------------------------------------// // 1100101 |_ mov #0, r4 __ // // 11 |_ <0xb380 %5c4> / _|_ _____ ___ // // 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // // |_ base# + offset |_| /_\_\___/__/ // //---------------------------------------------------------------------------// #include #include #include #include #include namespace FxOS { /* Instruction map */ static std::array, 65536> insmap; void register_instruction(AsmInstruction const &ins) { uint16_t opcode = ins.opcode; if(insmap[opcode]) FxOS_log(ERR, "opcode collision between a %s and a %s at %04x", insmap[opcode]->mnemonic, ins.mnemonic, opcode); else insmap[opcode] = ins; } //--- // Concrete (instantiated) arguments and instructions //--- Argument::Argument() { location = RelConstDomain().bottom(); value = location; syscall_id = -1; } Instruction::Instruction(AsmInstruction const *inst): inst {inst}, args {}, opcode {inst->opcode}, leader {false}, delayslot {false}, terminal {false}, jump {false}, condjump {false}, jmptarget {0xffffffff} { } Instruction::Instruction(uint16_t opcode): inst {nullptr}, args {}, opcode {opcode}, leader {false}, delayslot {false}, terminal {false}, jump {false}, condjump {false}, jmptarget {0xffffffff} { } //--- // Disassembler interface //--- Disassembly::Disassembly(VirtualSpace &_space): instructions {}, functions {}, space {_space} { } bool Disassembly::hasins(uint32_t pc) { return this->instructions.count(pc) > 0; } uint32_t Disassembly::minpc() { if(this->instructions.empty()) return 0xffffffff; return this->instructions.cbegin()->first; } uint32_t Disassembly::maxpc() { if(this->instructions.empty()) return 0xffffffff; return this->instructions.crbegin()->first; } Instruction &Disassembly::readins(uint32_t pc) { if(pc & 1) { FxOS_log(ERR, "reading instruction for disassembly at %08x", pc); pc &= -2; } try { return this->instructions.at(pc); } catch(std::out_of_range &e) { uint16_t opcode = this->space.read_u16(pc); Instruction ci(opcode); if(insmap[opcode]) ci = Instruction(&*insmap[opcode]); this->instructions.emplace(pc, ci); return this->instructions.at(pc); } } Function *Disassembly::getFunctionAt(uint32_t pc) { auto it = this->functions.find(pc); if(it == this->functions.end()) return nullptr; else return &it->second; } //--- // DisassemblyPass //--- DisassemblyPass::DisassemblyPass(Disassembly &disasm): m_disasm {disasm} { } //--- // FunctionPass //--- FunctionPass::FunctionPass(Disassembly &disasm): DisassemblyPass(disasm) { } bool FunctionPass::analyzeAllFunctions() { bool ok = true; for(auto &pair: m_disasm.functions) ok &= this->analyzeFunction(pair.second); return ok; } bool FunctionPass::analyzeFunction(uint32_t pc) { Function *func = m_disasm.getFunctionAt(pc); if(!func) { FxOS_log(ERR, "no function at %08x", pc); return false; } return this->analyzeFunction(*func); } bool FunctionPass::analyzeFunctionRecursively(Function &func) { return this->analyzeFunctionRecursively(func.address); } bool FunctionPass::analyzeFunctionRecursively(uint32_t pc) { bool ok = true; m_queue.enqueue(pc); while(!m_queue.empty()) { uint32_t pc = m_queue.pop(); Function *next = m_disasm.getFunctionAt(pc); ok &= this->analyzeFunction(*next); this->enqueueSubfunctions(*next); } return ok; } void FunctionPass::enqueueSubfunctions(Function &func) { for(uint32_t pc: func.callTargets) m_queue.enqueue(pc); } void FunctionPass::updateSubfunctions(Function &func) { for(uint32_t pc: func.callTargets) m_queue.update(pc); } //--- // InstructionPass //--- InstructionPass::InstructionPass(Disassembly &disasm): DisassemblyPass(disasm) { } bool InstructionPass::analyzeAllInstructions() { bool ok = true; for(auto &pair: m_disasm.instructions) ok &= this->analyzeInstruction(pair.first, pair.second); return ok; } bool InstructionPass::analyzeFunction(uint32_t pc) { bool ok = true; m_queue.enqueue(pc); while(!m_queue.empty()) { uint32_t pc = m_queue.pop(); if(!m_disasm.instructions.count(pc)) { FxOS_log(ERR, "no instruction at %08x", pc); continue; } Instruction &i = m_disasm.instructions.at(pc); ok &= this->analyzeInstruction(pc, i); this->enqueueSuccessors(pc, i); } return ok; } void InstructionPass::enqueueSuccessors(uint32_t pc, Instruction &i) { if(!i.terminal && !i.jump) m_queue.enqueue(pc + 2); if(i.jump || i.condjump) m_queue.enqueue(i.jmptarget); } void InstructionPass::updateSuccessors(uint32_t pc, Instruction &i) { if(!i.terminal && !i.jump) m_queue.update(pc + 2); if(i.jump || i.condjump) m_queue.update(i.jmptarget); } } /* namespace FxOS */