//---------------------------------------------------------------------------// // 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 {}, 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); } } //--- // 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, Instruction &i) { if(!i.terminal && !i.jump) { if(!m_seen.count(pc + 2)) enqueue(pc + 2); } if(i.jump || i.condjump) { if(!m_seen.count(i.jmptarget)) enqueue(i.jmptarget); } } void DisassemblyPass::enqueue_all_successors(uint32_t pc, Instruction &i) { if(!i.terminal && !i.jump) enqueue(pc + 2); if(i.jump || i.condjump) enqueue(i.jmptarget); } bool 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)); Instruction &ci = m_disasm.readins(pc); if(!analyze(pc, ci)) return false; m_seen.insert(pc); } return true; } //--- // Base instruction-level pass //--- InstructionDisassemblyPass::InstructionDisassemblyPass(Disassembly &disasm, std::string name): DisassemblyPass(disasm, name) { } bool InstructionDisassemblyPass::run() { for(auto &pair: m_disasm.instructions) { if(!analyze(pair.first, pair.second)) return false; } return true; } } /* namespace FxOS */