//--- // fxos.vspace: A virtual space where code is being studied //--- #ifndef LIBFXOS_VSPACE_H #define LIBFXOS_VSPACE_H #include #include #include #include #include #include #include #include namespace FxOS { /* A common interface for simulated memory */ class AbstractMemory { public: /* Checks if an address or interval is simulated */ virtual bool covers(uint32_t addr, int size=1) const noexcept = 0; /* Check if a full region is simulated */ virtual bool covers(MemoryRegion const ®ion) const noexcept; /* Returns the data located at the provided virtual address, nullptr if it is not entirely covered. */ virtual char const *translate(uint32_t addr, int size=1) const = 0; /* Returns the data located at the provided virtual address, and indicates how much is available in *size. */ virtual char const *translate_dynamic(uint32_t addr, int *size) const = 0; /* Read data from the memory. The following methods read data of various types. (Not a template because of the restriction about template specialization in non-namespaces scopes still in g++.) When reading data, provide a virtual address. The address is saved in the returned object for later printing or inspection. The returned object Addressable automatically converts to T when used, and supports operator & which returns the original address. The size parameter is only meaningful for variable-sized types such as string, and ignored for fixed-size types such as integers. If the desired object is not within the range of the simulated memory, throws std::out_of_range. */ /* Read integers with signed or unsigned extension. These functions do not check alignment, because exceptionally the processor supports unaligned operations (eg. movual.l). */ Addressable read_i8 (uint32_t addr) const; Addressable read_u8 (uint32_t addr) const; Addressable read_i16(uint32_t addr) const; Addressable read_u16(uint32_t addr) const; Addressable read_i32(uint32_t addr) const; Addressable read_u32(uint32_t addr) const; /* Read a non-NUL-terminated string */ Addressable read_str(uint32_t addr, size_t len) const; /* Search a binary pattern in the specified area. Returns the virtual address of the first occurrence if any is found, [end] otherwise (including if the range is empty or exceeds simulated memory). */ virtual uint32_t search(uint32_t start, uint32_t end, void const *pattern, int size) const = 0; }; /* A binding of a data buffer into a memory region of the target. */ struct Binding: public AbstractMemory { /* Constructor from data buffer. An error is raised if the buffer is not at least of the size of the region. In this case, a new buffer can be constructed with the required size. */ Binding(MemoryRegion region, Buffer buffer); /* Targeted region, might overlap with other bindings */ MemoryRegion region; /* Underlying buffer (copy of the original one) */ Buffer buffer; bool covers(uint32_t addr, int size=1) const noexcept override; bool covers(MemoryRegion const ®ion) const noexcept override; char const *translate(uint32_t addr, int size=1) const override; char const *translate_dynamic(uint32_t addr, int *size) const override; uint32_t search(uint32_t start, uint32_t end, void const *pattern, int size) const override; }; /* A target description in the database; loadable, but not loaded yet */ struct Target { /* Just a list of bindings to be formed */ using Binding = std::pair; std::vector bindings; /* Also the MPU to be set */ std::string mpu; }; /* A composite space where regions can be bound dynamically */ class VirtualSpace: public AbstractMemory { public: /* Create an empty space with no regions */ VirtualSpace(); /* Create a new virtual space with a target loaded. */ VirtualSpace(Target const &target,std::vector const &folders); /* MPU used by this target, or an empty string if unspecified */ std::string mpu; /* List of bindings */ std::vector const &bindings() const { return m_bindings; } /* OS analysis; performed on-demand. Returns the new or cached OS analysis, and nullptr only if OS cannot be analyzed */ OS *os_analysis(bool force=false); /* Cursor position, used by the interactive shell */ uint32_t cursor; /* Symbol table */ SymbolTable symbols; /* Bind a memory region from a buffer. The region can either be standard (see ) or custom. If several loaded regions overlap on some addresses, *the last loaded region will be used*. Thus, new regions can be loaded to selectively override parts of the target. An error is raised if the buffer is smaller than the region being bound. */ void bind_region(MemoryRegion const ®ion, Buffer const &buffer); bool covers(uint32_t addr, int size=1) const noexcept override; bool covers(MemoryRegion const ®ion) const noexcept override; char const *translate(uint32_t addr, int size=1) const override; char const *translate_dynamic(uint32_t addr, int *size) const override; uint32_t search(uint32_t start, uint32_t end, void const *pattern, int size) const override; private: /* Bound regions (in order of binding) */ std::vector m_bindings; /* Buffers owned by the target (when loaded from description) */ std::vector m_buffers; /* Current OS analyzer */ std::unique_ptr m_os; }; } /* namespace FxOS */ #endif /* LIBFXOS_VSPACE_H */