fxos/include/fxos/disassembly.h

177 lines
4.6 KiB
C++

//---
// fxos.disassembly: Disassembler
//---
#ifndef LIBFXOS_DISASSEMBLY_H
#define LIBFXOS_DISASSEMBLY_H
#include <fxos/lang.h>
#include <fxos/target.h>
#include <fxos/semantics.h>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <optional>
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 <fxos/load.h>. */
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<Location> loc;
/* Alternatively, data type, which can sometimes be determined uniquely
even if the location is not constant */
std::optional<DataType> 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<uint32_t, ConcreteInstruction> 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<uint32_t> m_next;
std::priority_queue<uint32_t> m_queue;
/* Visited blocks */
std::set<uint32_t> 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 */