#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(): loc {}, type {}, syscall_id {-1} { reg_address = -1; } ConcreteInstruction::ConcreteInstruction(Instruction &inst): inst {inst}, jmptarget {}, leader {false} { } //--- // Disassembler interface //--- Disassembly::Disassembly(Target &target): 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::ins_read 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 &inst = *insmap[opcode]; ConcreteInstruction ci(inst); m_instructions.emplace(pc, ci); return m_instructions.at(pc); } } //--- // Base pass //--- DisassemblyPass::DisassemblyPass(Disassembly &disasm): m_disasm(disasm) { } 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.isterminal() && !inst.isjump()) { if(!m_seen.count(pc + 2)) enqueue(pc + 2); } if(inst.isjump() || inst.iscondjump()) { if(!m_seen.count(inst.jmptarget)) enqueue(inst.jmptarget); } } void DisassemblyPass::enqueue_all_successors(uint32_t pc, ConcreteInstruction &inst) { if(!inst.isterminal() && !inst.isjump()) { enqueue(pc + 2); } if(inst.isjump() || inst.iscondjump()) { 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); } } } /* namespace FxOS */