#include #include #include #include namespace FxOS { /* Instruction map */ static std::array,65536> insmap; /* Register an instruction at a given opcode. */ void register_instruction(Instruction ins) { uint16_t opcode = ins.opcode; if(insmap[opcode]) { throw std::logic_error("opcode collision"); } insmap[opcode] = ins; } //--- // Concrete (instantiated) arguments and instructions //--- ConcreteInstructionArg::ConcreteInstructionArg(): value(), syscall_id(-1) { location = RelConstDomain().bottom(); } ConcreteInstruction::ConcreteInstruction(Instruction const &inst): inst(inst), args(), leader(false), delayslot(false), terminal(false), jump(false), condjump(false), jmptarget(0xffffffff) { } //--- // Disassembler interface //--- Disassembly::Disassembly(Target &target): passes {}, m_target {target}, m_instructions {} { } bool Disassembly::hasins(uint32_t pc) { return m_instructions.count(pc) > 0; } uint32_t Disassembly::minpc() { uint32_t min = 0xffffffff; for(auto &it: m_instructions) { if(it.first < min) min = it.first; } return min; } uint32_t Disassembly::maxpc() { uint32_t max = 0x00000000; for(auto &it: m_instructions) { if(it.first > max) max = it.first; } return max; } ConcreteInstruction &Disassembly::readins(uint32_t pc) { if(pc & 1) throw std::runtime_error("Disassembly::readins at odd PC"); try { return m_instructions.at(pc); } catch(std::out_of_range &e) { uint16_t opcode = m_target.read_u16(pc); if(!insmap[opcode]) { throw std::runtime_error("No instruction for opcode"); } Instruction const &inst = *insmap[opcode]; ConcreteInstruction ci(inst); m_instructions.emplace(pc, ci); return m_instructions.at(pc); } } //--- // Base pass //--- DisassemblyPass::DisassemblyPass(Disassembly &disasm, std::string name): m_disasm(disasm), m_name(name) { } void DisassemblyPass::enqueue(uint32_t pc) { if(m_next.count(pc)) return; m_next.insert(pc); m_queue.push(pc); } void DisassemblyPass::enqueue_next(uint32_t pc) { /* TODO: DisassemblyPass::enqueue_next is inefficient */ do pc += 2; while(!m_disasm.hasins(pc)); enqueue(pc); } void DisassemblyPass::enqueue_unseen_successors(uint32_t pc, ConcreteInstruction &inst) { if(!inst.terminal && !inst.jump) { if(pc == 0x80000078) printf("t%d j%d\n", inst.terminal, inst.jump); if(!m_seen.count(pc + 2)) enqueue(pc + 2); } if(inst.jump || inst.condjump) { if(!m_seen.count(inst.jmptarget)) enqueue(inst.jmptarget); } } void DisassemblyPass::enqueue_all_successors(uint32_t pc, ConcreteInstruction &inst) { if(!inst.terminal && !inst.jump) { enqueue(pc + 2); } if(inst.jump || inst.condjump) { enqueue(inst.jmptarget); } } void DisassemblyPass::run(uint32_t entry_pc) { enqueue(entry_pc); while(m_queue.size()) { uint32_t pc = m_queue.top(); m_queue.pop(); m_next.erase(m_next.find(pc)); ConcreteInstruction &ci = m_disasm.readins(pc); analyze(pc, ci); m_seen.insert(pc); } if(m_name != "") m_disasm.passes.insert(m_name); } //--- // Base instruction-level pass //--- InstructionDisassemblyPass::InstructionDisassemblyPass(Disassembly &disasm, std::string name): DisassemblyPass(disasm, name) { } void InstructionDisassemblyPass::run() { for(auto &pair: m_disasm.instructions()) { analyze(pair.first, pair.second); } } } /* namespace FxOS */