//--- // fxos.disassembly: Disassembler //--- #ifndef LIBFXOS_DISASSEMBLY_H #define LIBFXOS_DISASSEMBLY_H #include #include #include #include #include #include #include #include namespace FxOS { /* Register an instruction. @inst Instruction with [opcode] set to the binary pattern Typically this is called by loader functions from data tables describing instructions with parameters, not manually. See . */ void register_instruction(Instruction ins); /* An argument for a concrete instruction. */ struct ConcreteInstructionArg { ConcreteInstructionArg(); //--- // Data set by the abstract interpretation passes //--- /* Location in CPU or memory, if that can be determined */ std::optional loc; /* Alternatively, data type, which can sometimes be determined uniquely even if the location is not constant */ std::optional type; //--- // Data set by the syscall and regs passes //--- /* If the value is a syscall address, the syscall's id */ int syscall_id; /* If the value is a peripheral register, its address */ uint32_t reg_address; }; /* A loaded and annotated instruction. */ struct ConcreteInstruction { ConcreteInstruction(Instruction &inst); /* What instruction it is */ Instruction &inst; /* Argument information (contains data set by several passes) */ ConcreteInstructionArg args[2]; //--- // Data set by the pcrel pass //--- /* Jump targets, used for jump instructions only. The target might either be that of an inconditional jump, or the non-trivial target of a conditional jump. In many situations the jump is forced on a general instruction by a preceding delated branch. */ uint32_t jmptarget; /* Whether the instruction is terminal. Be careful, as this attribute is often forced onto delayed slot instructions. It is thus NOT the same as isterminal(), which tells whether the mnemonic implies a function exit. Said exit is generally delayed. */ bool terminal; //--- // Data set by the cfg pass //--- /* Whether this instruction is a basic block leader */ bool leader; //--- // Methods and utilities //--- bool isterminal() const noexcept { return inst.isterminal(); } bool isjump() const noexcept { return inst.isjump(); } bool iscondjump() const noexcept { return inst.iscondjump(); } bool isdelayed() const noexcept { return inst.isdelayed(); } }; /* Short aliases */ using CI = ConcreteInstruction; using CIArg = ConcreteInstructionArg; /* Disassembly interface that automatically loads code from a target */ class Disassembly { public: Disassembly(Target &target); /* Check whether an instruction has been visited so far */ bool hasins(uint32_t pc); /* Get the minimum and maximum loaded instruction addresses */ uint32_t minpc(); uint32_t maxpc(); /* Get the storage to any concrete instruction. The instruction will be loaded and initialized if it had not been read before. */ ConcreteInstruction &readins(uint32_t pc); private: /* Underlying target */ Target &m_target; /* Loaded instructions by address */ std::map m_instructions; }; //--- // Disassembler passes //--- class DisassemblyPass { public: DisassemblyPass(Disassembly &disasm); /* Analyze a single instruction, probably updating the annotations and the state of the pass itself. Should return true if the state of the instruction changed. */ virtual void analyze(uint32_t pc, ConcreteInstruction &inst) = 0; /* Run the pass from the given entry point */ void run(uint32_t entry_pc); protected: /* Add an instruction to the queue to analyze next */ void enqueue(uint32_t pc); /* Add the next loaded instruction in address space */ void enqueue_next(uint32_t pc); /* Enqueue the unseen successors of this instruction */ void enqueue_unseen_successors(uint32_t pc, ConcreteInstruction &inst); /* Enqueue all the success of this instruction */ void enqueue_all_successors(uint32_t pc, ConcreteInstruction &inst); /* Underlying disassembly */ Disassembly &m_disasm; private: /* Blocks to visit next, ordered for uniqueness */ std::set m_next; std::priority_queue m_queue; /* Visited blocks */ std::set m_seen; }; class PcrelPass: public DisassemblyPass { PcrelPass(Disassembly &disasm); void analyze(uint32_t pc, ConcreteInstruction &inst) override; }; class PrintPass: public DisassemblyPass { PrintPass(Disassembly &disasm); void analyze(uint32_t pc, ConcreteInstruction &inst) override; }; } /* namespace FxOS */ #endif /* LIBFXOS_DISASSEMBLY_H */