fxos/include/fxos/vspace.h

164 lines
5.5 KiB
C++

//---
// fxos.vspace: A virtual space where code is being studied
//---
#ifndef LIBFXOS_VSPACE_H
#define LIBFXOS_VSPACE_H
#include <fxos/memory.h>
#include <fxos/util.h>
#include <fxos/os.h>
#include <fxos/symbols.h>
#include <optional>
#include <vector>
#include <cstdint>
#include <memory>
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 &region) 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<T> 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<int8_t> read_i8 (uint32_t addr) const;
Addressable<uint8_t> read_u8 (uint32_t addr) const;
Addressable<int16_t> read_i16(uint32_t addr) const;
Addressable<uint16_t> read_u16(uint32_t addr) const;
Addressable<int32_t> read_i32(uint32_t addr) const;
Addressable<uint32_t> read_u32(uint32_t addr) const;
/* Read a non-NUL-terminated string */
Addressable<std::string> 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 &region) 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<MemoryRegion,std::string>;
std::vector<Binding> 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<std::string> const &folders);
/* MPU used by this target, or an empty string if unspecified */
std::string mpu;
/* List of bindings */
std::vector<Binding> 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 <fxos/memory.h>) 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 &region, Buffer const &buffer);
bool covers(uint32_t addr, int size=1) const noexcept override;
bool covers(MemoryRegion const &region) 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<Binding> m_bindings;
/* Buffers owned by the target (when loaded from description) */
std::vector<Buffer> m_buffers;
/* Current OS analyzer */
std::unique_ptr<OS> m_os;
};
} /* namespace FxOS */
#endif /* LIBFXOS_VSPACE_H */