//--- // 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 pass and abstract interpretater //--- /* Location in CPU or memory, if that can be determined */ Location location; /* Pointed value. If the exact value can't be determined, this object evaluates to false. Sometimes, the type can be determined anyway, and in this case its [type] attribute below is not null even though the object evaluates to false. */ DataValue value; //--- // Data set by the and 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 const &inst); /* What instruction this is. Note that this does not determine all the properties below. Placement and delay slots greatly alter them. */ Instruction const &inst; /* Argument information (contains data set by several passes) */ ConcreteInstructionArg args[2]; //--- // Data set by the cfg pass //--- /* Whether this instruction is a leader. This is always set by another instruction jumping into this one. */ bool leader; /* Whether this instruction is in a delay slot. This is always set by the preceding delayed instruction. */ bool delayslot; /* Whether this instruction is: -> Terminal, ie. has no successors and is the end of the function. -> An unconditional jump of target [jmptarget]. -> A conditional jump that can hit [jmptarget] and pc+2. If delayslot==false, these attributes are set when analyzing this instruction. If delayslot==true, they are set when the preceding delayed instruction is analyzed. */ bool terminal; bool jump; bool condjump; /* The jump target, used if jump==true or condjump==true. */ uint32_t jmptarget; }; /* 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); /* For other access patterns (careful with write accesses!) */ std::map &instructions() noexcept { return m_instructions; } /* Access to memory */ Target &target() noexcept { return m_target; } 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; }; } /* namespace FxOS */ #endif /* LIBFXOS_DISASSEMBLY_H */