refactor vspace - remove most memory simulation
All of it can be derived from translate_dynamic().
This commit is contained in:
parent
e90ef447fc
commit
1f475b0863
|
@ -14,6 +14,7 @@ flex_target(LoadAsm lib/load-asm.l
|
|||
"${CMAKE_CURRENT_BINARY_DIR}/load-asm.yy.cpp" COMPILE_FLAGS -s)
|
||||
|
||||
set(fxos_core_SOURCES
|
||||
lib/AbstractMemory.cpp
|
||||
lib/disassembly.cpp
|
||||
lib/lang.cpp
|
||||
lib/memory.cpp
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
// 1100101 |_ mov #0, r4 __ //
|
||||
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
|
||||
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
|
||||
// |_ base# + offset |_| /_\_\___/__/ //
|
||||
//---------------------------------------------------------------------------//
|
||||
// fxos/AbstractMemory: Simulated memory
|
||||
//
|
||||
// This header defines the typeclass for simulated memory within a 32-bit
|
||||
// address space. The class provides functions to identify the simulated range
|
||||
// within the address space, as well as basic read and search operations.
|
||||
//
|
||||
// Suclasses of this only need to implement the translate_dynamic() method
|
||||
// which gives low-level access to part of the simulated memory.
|
||||
//
|
||||
// Note that currently, given the implementation of virtual space bindings and
|
||||
// AbstractMemory methods, most operations only try to translate_dynamic()
|
||||
// once -- which means that they fail if the requested range is not simulated
|
||||
// in a single block. This is usually not a problem because virtual space
|
||||
// bindings simulate small memory areas separated by huge gaps, so they never
|
||||
// extend each other.
|
||||
//---
|
||||
|
||||
#ifndef FXOS_ABSTRACTMEMORY_H
|
||||
#define FXOS_ABSTRACTMEMORY_H
|
||||
|
||||
#include <fxos/memory.h>
|
||||
#include <fxos/util/Addressable.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace FxOS {
|
||||
|
||||
/* A common interface for simulated memory. All non-virtual methods are
|
||||
provided by the base class and need not be implemented. */
|
||||
class AbstractMemory
|
||||
{
|
||||
public:
|
||||
/* Checks if an address or interval is simulated (in its entirety) */
|
||||
bool covers(uint32_t addr, int size=1);
|
||||
|
||||
/* Check if a full region is simulated */
|
||||
bool covers(MemoryRegion const ®ion);
|
||||
|
||||
/* Returns the data located at the provided virtual address, nullptr if it
|
||||
is not entirely covered. */
|
||||
char const *translate(uint32_t addr, int size=1);
|
||||
|
||||
/* Returns the data located at the provided virtual address, and indicates
|
||||
how much is available in *size. The pointer is null if [addr] itself is
|
||||
not covered, in which case *size is also set to 0. */
|
||||
virtual char const *translate_dynamic(uint32_t addr, int *size) = 0;
|
||||
|
||||
/* 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). */
|
||||
uint32_t search(uint32_t start, uint32_t end, void const *pat, int size);
|
||||
|
||||
/* Read a simple object from memory. The following methods all assume that
|
||||
the specified address is simulated, and return a default value if it's
|
||||
not -- you should probably check beforehand! Alignment constraints are
|
||||
not checked either, that's up to you.
|
||||
|
||||
The return type has the value in [.value] and remembers the address in
|
||||
[.address], which is sometimes useful. It implicitly converts to the
|
||||
data type, see <fxos/util/Addressable.h>. */
|
||||
|
||||
/* Various sizes of integers with sign-extension or zero-extension. */
|
||||
Addressable<int8_t> read_i8 (uint32_t addr);
|
||||
Addressable<uint8_t> read_u8 (uint32_t addr);
|
||||
Addressable<int16_t> read_i16(uint32_t addr);
|
||||
Addressable<uint16_t> read_u16(uint32_t addr);
|
||||
Addressable<int32_t> read_i32(uint32_t addr);
|
||||
Addressable<uint32_t> read_u32(uint32_t addr);
|
||||
|
||||
/* Read a non-NUL-terminated string */
|
||||
Addressable<std::string> read_str(uint32_t addr, size_t len);
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
||||
#endif /* FXOS_ABSTRACTMEMORY_H */
|
|
@ -1,13 +1,24 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
// 1100101 |_ mov #0, r4 __ //
|
||||
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
|
||||
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
|
||||
// |_ base# + offset |_| /_\_\___/__/ //
|
||||
//---------------------------------------------------------------------------//
|
||||
// fxos/vspace: Virtual address space with loaded code and analyses
|
||||
//
|
||||
// This is the main structure/entry point of fxos. A Virtu
|
||||
|
||||
//---
|
||||
// fxos.vspace: A virtual space where code is being studied
|
||||
//---
|
||||
|
||||
#ifndef LIBFXOS_VSPACE_H
|
||||
#define LIBFXOS_VSPACE_H
|
||||
#ifndef FXOS_VSPACE_H
|
||||
#define FXOS_VSPACE_H
|
||||
|
||||
#include <fxos/memory.h>
|
||||
#include <fxos/os.h>
|
||||
#include <fxos/symbols.h>
|
||||
#include <fxos/AbstractMemory.h>
|
||||
#include <fxos/util/Buffer.h>
|
||||
#include <fxos/util/Addressable.h>
|
||||
|
||||
|
@ -18,148 +29,65 @@
|
|||
|
||||
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. The pointer is null if [addr] itself is
|
||||
not covered, in which case *size is also set to 0. */
|
||||
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 [.address] 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, returns
|
||||
a dummy value of address -1. You should check the range beforehand! */
|
||||
|
||||
/* 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);
|
||||
/* 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;
|
||||
/* 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<MemoryRegion,std::string>;
|
||||
std::vector<Binding> bindings;
|
||||
/* Also the MPU to be set */
|
||||
std::string mpu;
|
||||
char const *translate_dynamic(uint32_t addr, int *size) override;
|
||||
};
|
||||
|
||||
/* A composite space where regions can be bound dynamically */
|
||||
class VirtualSpace: public AbstractMemory
|
||||
{
|
||||
public:
|
||||
/* Create an empty space with no regions */
|
||||
VirtualSpace();
|
||||
/* 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;
|
||||
|
||||
/* MPU used by this target, or an empty string if unspecified */
|
||||
std::string mpu;
|
||||
/* List of bindings (most recent first) */
|
||||
std::vector<Binding> bindings;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Cursor position, used by the interactive shell */
|
||||
uint32_t cursor;
|
||||
/* Symbol table */
|
||||
SymbolTable symbols;
|
||||
|
||||
/* Symbol table */
|
||||
SymbolTable symbols;
|
||||
/* Bind a memory region from a buffer. The region can either be
|
||||
standard (see <fxos/memory.h>) or custom.
|
||||
|
||||
/* 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.
|
||||
|
||||
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);
|
||||
|
||||
An error is raised if the buffer is smaller than the region being
|
||||
bound. */
|
||||
void bind_region(MemoryRegion const ®ion, Buffer const &buffer);
|
||||
/* Implementation of AbstractMemory primitives */
|
||||
|
||||
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;
|
||||
char const *translate_dynamic(uint32_t addr, int *size) 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;
|
||||
/* OS analysis results */
|
||||
std::unique_ptr<OS> m_os;
|
||||
};
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
||||
#endif /* LIBFXOS_VSPACE_H */
|
||||
#endif /* FXOS_VSPACE_H */
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
// 1100101 |_ mov #0, r4 __ //
|
||||
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
|
||||
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
|
||||
// |_ base# + offset |_| /_\_\___/__/ //
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
#include <fxos/AbstractMemory.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace FxOS {
|
||||
|
||||
bool AbstractMemory::covers(uint32_t addr, int size)
|
||||
{
|
||||
return (this->translate(addr, size) != nullptr);
|
||||
}
|
||||
|
||||
bool AbstractMemory::covers(MemoryRegion const ®ion)
|
||||
{
|
||||
return this->covers(region.start, region.size());
|
||||
}
|
||||
|
||||
char const *AbstractMemory::translate(uint32_t addr, int size)
|
||||
{
|
||||
int actual_size;
|
||||
char const *ptr = this->translate_dynamic(addr, &actual_size);
|
||||
return (ptr && actual_size >= size) ? ptr : nullptr;
|
||||
}
|
||||
|
||||
Addressable<int8_t> AbstractMemory::read_i8(uint32_t addr)
|
||||
{
|
||||
int8_t *i8 = (int8_t *)this->translate(addr, 1);
|
||||
if(!i8)
|
||||
return Addressable((int8_t)-1);
|
||||
return Addressable(addr, *i8);
|
||||
}
|
||||
|
||||
Addressable<uint8_t> AbstractMemory::read_u8(uint32_t addr)
|
||||
{
|
||||
uint8_t *u8 = (uint8_t *)this->translate(addr, 1);
|
||||
if(!u8)
|
||||
return Addressable((uint8_t)-1);
|
||||
return Addressable(addr, *u8);
|
||||
}
|
||||
|
||||
Addressable<int16_t> AbstractMemory::read_i16(uint32_t addr)
|
||||
{
|
||||
uint8_t *i16 = (uint8_t *)this->translate(addr, 2);
|
||||
if(!i16)
|
||||
return Addressable((int16_t)-1);
|
||||
int16_t v = (i16[0] << 8) | i16[1];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<uint16_t> AbstractMemory::read_u16(uint32_t addr)
|
||||
{
|
||||
uint8_t *u16 = (uint8_t *)this->translate(addr, 2);
|
||||
if(!u16)
|
||||
return Addressable((uint16_t)-1);
|
||||
uint16_t v = (u16[0] << 8) | u16[1];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<int32_t> AbstractMemory::read_i32(uint32_t addr)
|
||||
{
|
||||
uint8_t *i32 = (uint8_t *)this->translate(addr, 4);
|
||||
if(!i32)
|
||||
return Addressable((int32_t)-1);
|
||||
int32_t v = (i32[0] << 24) | (i32[1] << 16) | (i32[2] << 8) | i32[3];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<uint32_t> AbstractMemory::read_u32(uint32_t addr)
|
||||
{
|
||||
uint8_t *u32 = (uint8_t *)this->translate(addr, 4);
|
||||
if(!u32)
|
||||
return Addressable((uint32_t)-1);
|
||||
uint32_t v = (u32[0] << 24) | (u32[1] << 16) | (u32[2] << 8) | u32[3];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<std::string> AbstractMemory::read_str(uint32_t addr, size_t len)
|
||||
{
|
||||
char const *str = this->translate(addr, len);
|
||||
if(!str)
|
||||
return Addressable(std::string());
|
||||
return Addressable(addr, std::string(str, len));
|
||||
}
|
||||
|
||||
uint32_t AbstractMemory::search(uint32_t start, uint32_t end,
|
||||
void const *pattern, int size)
|
||||
{
|
||||
void const *data = translate(start, end-start);
|
||||
if(!data)
|
||||
return end;
|
||||
|
||||
void const *occurrence = memmem(data, end - start, pattern, size);
|
||||
if(!occurrence)
|
||||
return end;
|
||||
|
||||
return start + ((char *)occurrence - (char *)data);
|
||||
}
|
||||
|
||||
} /* namespace FxOS */
|
|
@ -181,8 +181,8 @@ void OS::parse_footer()
|
|||
// Checksum
|
||||
//---
|
||||
|
||||
static uint32_t accumulate_range(VirtualSpace const &m_space, uint32_t start,
|
||||
uint32_t end)
|
||||
static uint32_t accumulate_range(VirtualSpace &m_space,
|
||||
uint32_t start, uint32_t end)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
|
||||
|
|
214
lib/vspace.cpp
214
lib/vspace.cpp
|
@ -4,123 +4,25 @@
|
|||
|
||||
namespace FxOS {
|
||||
|
||||
//---
|
||||
// Simulated memory access primitives
|
||||
//---
|
||||
|
||||
bool AbstractMemory::covers(MemoryRegion const ®ion) const noexcept
|
||||
{
|
||||
return covers(region.start, region.size());
|
||||
}
|
||||
|
||||
Addressable<int8_t> AbstractMemory::read_i8(uint32_t addr) const
|
||||
{
|
||||
int8_t *i8 = (int8_t *)translate(addr, 1);
|
||||
if(!i8)
|
||||
return Addressable((int8_t)-1);
|
||||
return Addressable(addr, *i8);
|
||||
}
|
||||
|
||||
Addressable<uint8_t> AbstractMemory::read_u8(uint32_t addr) const
|
||||
{
|
||||
uint8_t *u8 = (uint8_t *)translate(addr, 1);
|
||||
if(!u8)
|
||||
return Addressable((uint8_t)-1);
|
||||
return Addressable(addr, *u8);
|
||||
}
|
||||
|
||||
Addressable<int16_t> AbstractMemory::read_i16(uint32_t addr) const
|
||||
{
|
||||
uint8_t *i16 = (uint8_t *)translate(addr, 2);
|
||||
if(!i16)
|
||||
return Addressable((int16_t)-1);
|
||||
int16_t v = (i16[0] << 8) | i16[1];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<uint16_t> AbstractMemory::read_u16(uint32_t addr) const
|
||||
{
|
||||
uint8_t *u16 = (uint8_t *)translate(addr, 2);
|
||||
if(!u16)
|
||||
return Addressable((uint16_t)-1);
|
||||
uint16_t v = (u16[0] << 8) | u16[1];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<int32_t> AbstractMemory::read_i32(uint32_t addr) const
|
||||
{
|
||||
uint8_t *i32 = (uint8_t *)translate(addr, 4);
|
||||
if(!i32)
|
||||
return Addressable((int32_t)-1);
|
||||
int32_t v = (i32[0] << 24) | (i32[1] << 16) | (i32[2] << 8) | i32[3];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<uint32_t> AbstractMemory::read_u32(uint32_t addr) const
|
||||
{
|
||||
uint8_t *u32 = (uint8_t *)translate(addr, 4);
|
||||
if(!u32)
|
||||
return Addressable((uint32_t)-1);
|
||||
uint32_t v = (u32[0] << 24) | (u32[1] << 16) | (u32[2] << 8) | u32[3];
|
||||
return Addressable(addr, v);
|
||||
}
|
||||
|
||||
Addressable<std::string> AbstractMemory::read_str(uint32_t addr, size_t len)
|
||||
const
|
||||
{
|
||||
char const *str = translate(addr, len);
|
||||
if(!str)
|
||||
return Addressable(std::string());
|
||||
return Addressable(addr, std::string(str, len));
|
||||
}
|
||||
|
||||
//---
|
||||
// Bindings of data buffers into memory regions
|
||||
//---
|
||||
|
||||
Binding::Binding(MemoryRegion source_region, Buffer source_buffer):
|
||||
region(source_region), buffer(source_buffer)
|
||||
region {source_region}, buffer {source_buffer}
|
||||
{
|
||||
/* Extend the buffer if it's not at least as large as the region */
|
||||
if(buffer.size < region.size()) {
|
||||
buffer = Buffer(buffer, region.size());
|
||||
}
|
||||
/* Extend the buffer if it's not at least as large as the region */
|
||||
if(buffer.size < region.size())
|
||||
buffer = Buffer(buffer, region.size());
|
||||
}
|
||||
|
||||
bool Binding::covers(uint32_t addr, int size) const noexcept
|
||||
char const *Binding::translate_dynamic(uint32_t addr, int *size)
|
||||
{
|
||||
return size >= 0 && addr >= region.start && addr + size <= region.end;
|
||||
}
|
||||
|
||||
bool Binding::covers(MemoryRegion const &r) const noexcept
|
||||
{
|
||||
return covers(r.start, r.size());
|
||||
}
|
||||
|
||||
char const *Binding::translate(uint32_t addr, int size) const
|
||||
{
|
||||
if(!covers(addr, size)) return nullptr;
|
||||
return buffer.data.get() + (addr - region.start);
|
||||
}
|
||||
|
||||
char const *Binding::translate_dynamic(uint32_t addr, int *size) const
|
||||
{
|
||||
if(!covers(addr, 1)) return nullptr;
|
||||
*size = region.end - addr;
|
||||
return buffer.data.get() + (addr - region.start);
|
||||
}
|
||||
|
||||
uint32_t Binding::search(uint32_t start, uint32_t end, void const *pattern,
|
||||
int size) const
|
||||
{
|
||||
void const *data = translate(start, end-start);
|
||||
if(!data)
|
||||
return end;
|
||||
void const *occurrence = memmem(data, end - start, pattern, size);
|
||||
|
||||
if(!occurrence)
|
||||
return end;
|
||||
return start + ((char *)occurrence - (char *)data);
|
||||
if(addr >= region.start && addr < region.end) {
|
||||
*size = region.end - addr;
|
||||
return buffer.data.get() + (addr - region.start);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -128,96 +30,34 @@ uint32_t Binding::search(uint32_t start, uint32_t end, void const *pattern,
|
|||
//---
|
||||
|
||||
VirtualSpace::VirtualSpace():
|
||||
m_bindings {}, m_buffers {}, m_os {nullptr}
|
||||
mpu {}, bindings {}, m_os {nullptr}
|
||||
{
|
||||
}
|
||||
|
||||
VirtualSpace::VirtualSpace(Target const &target,
|
||||
std::vector<std::string> const &folders):
|
||||
VirtualSpace()
|
||||
{
|
||||
for(auto binding: target.bindings)
|
||||
{
|
||||
MemoryRegion region = binding.first;
|
||||
ssize_t size = (region.size() > 0 ? region.size() : -1);
|
||||
|
||||
auto b = m_buffers.emplace(m_buffers.end(),
|
||||
binding.second, folders, size);
|
||||
bind_region(region, *b);
|
||||
}
|
||||
|
||||
this->mpu = target.mpu;
|
||||
}
|
||||
|
||||
OS *VirtualSpace::os_analysis(bool force)
|
||||
{
|
||||
if(!m_os || force) {
|
||||
m_os = std::make_unique<OS>(*this);
|
||||
/* We don't keep an OS analysis result that failed */
|
||||
if(m_os->type == OS::UNKNOWN)
|
||||
m_os = nullptr;
|
||||
}
|
||||
return m_os.get();
|
||||
if(!m_os || force) {
|
||||
m_os = std::make_unique<OS>(*this);
|
||||
/* We don't keep an OS analysis result that failed */
|
||||
if(m_os->type == OS::UNKNOWN)
|
||||
m_os = nullptr;
|
||||
}
|
||||
return m_os.get();
|
||||
}
|
||||
|
||||
void VirtualSpace::bind_region(MemoryRegion const ®ion,Buffer const &buffer)
|
||||
void VirtualSpace::bind_region(MemoryRegion const ®ion, Buffer const &buf)
|
||||
{
|
||||
Binding b(region, buffer);
|
||||
m_bindings.push_back(b);
|
||||
this->bindings.emplace(this->bindings.begin(), region, buf);
|
||||
}
|
||||
|
||||
bool VirtualSpace::covers(uint32_t addr, int size) const noexcept
|
||||
char const *VirtualSpace::translate_dynamic(uint32_t addr, int *size)
|
||||
{
|
||||
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
|
||||
{
|
||||
if(it->covers(addr, size)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VirtualSpace::covers(MemoryRegion const ®ion) const noexcept
|
||||
{
|
||||
return covers(region.start, region.size());
|
||||
}
|
||||
|
||||
char const *VirtualSpace::translate(uint32_t addr, int size) const
|
||||
{
|
||||
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
|
||||
{
|
||||
char const *ptr = it->translate(addr, size);
|
||||
if(ptr) return ptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char const *VirtualSpace::translate_dynamic(uint32_t addr, int *size) const
|
||||
{
|
||||
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
|
||||
{
|
||||
char const *ptr = it->translate_dynamic(addr, size);
|
||||
if(ptr) return ptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t VirtualSpace::search(uint32_t start, uint32_t end,
|
||||
void const *pattern, int size) const
|
||||
{
|
||||
uint32_t occurrence;
|
||||
if(end < start || !covers(start, end - start))
|
||||
return end;
|
||||
|
||||
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
|
||||
{
|
||||
if(it->covers(start, end - start))
|
||||
{
|
||||
occurrence = it->search(start, end, pattern, size);
|
||||
if(occurrence != end) return occurrence;
|
||||
}
|
||||
}
|
||||
|
||||
return end;
|
||||
for(auto &b: this->bindings) {
|
||||
char const *ptr = b.translate_dynamic(addr, size);
|
||||
if(ptr)
|
||||
return ptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} /* namespace FxOS */
|
||||
|
|
26
shell/a.cpp
26
shell/a.cpp
|
@ -113,11 +113,11 @@ void _afh(Session &session, char const *reference, char const *pattern,
|
|||
if(distance < 0) distance = 32;
|
||||
if(align <= 0) align = 1;
|
||||
|
||||
VirtualSpace const &v = *session.current_space;
|
||||
VirtualSpace &v = *session.current_space;
|
||||
|
||||
/* If no region is specified, explore the regions for all bindings */
|
||||
if(regions.size() == 0) {
|
||||
for(auto &b: v.bindings())
|
||||
for(auto &b: v.bindings)
|
||||
regions.push_back(b.region);
|
||||
}
|
||||
|
||||
|
@ -129,8 +129,7 @@ void _afh(Session &session, char const *reference, char const *pattern,
|
|||
std::vector<std::pair<uint32_t,int>> pending;
|
||||
|
||||
for(auto const &r: regions) {
|
||||
uint32_t region_size = r.end - r.start;
|
||||
char const *data = v.translate(r.start, region_size);
|
||||
char const *data = v.translate(r.start, r.size());
|
||||
if(!data) throw CommandError("region 0x{:08x} .. 0x{:08x} is not "
|
||||
"fully bound", r.start, r.end);
|
||||
|
||||
|
@ -139,7 +138,7 @@ void _afh(Session &session, char const *reference, char const *pattern,
|
|||
while((r.start + i) % align != 0) i++;
|
||||
|
||||
/* Search patterns for (size) bytes inside (data) */
|
||||
for(; i <= (int)region_size - (int)size; i += align) {
|
||||
for(; i <= (int)r.size() - (int)size; i += align) {
|
||||
if(!matches(data + i, reference, pattern, size)) continue;
|
||||
|
||||
uint32_t start = r.start + i;
|
||||
|
@ -150,7 +149,7 @@ void _afh(Session &session, char const *reference, char const *pattern,
|
|||
if(p.first + p.second + distance < start) {
|
||||
Range r;
|
||||
r.start = pending[0].first - distance;
|
||||
r.end = p.first + p.second + distance;
|
||||
r.end = p.first + p.second + distance - 1;
|
||||
|
||||
if(output_started) fmt::print("...\n");
|
||||
_h_hexdump(session, r, pending);
|
||||
|
@ -166,14 +165,15 @@ void _afh(Session &session, char const *reference, char const *pattern,
|
|||
if(match_count >= 128) break;
|
||||
}
|
||||
if(match_count >= 128) break;
|
||||
}
|
||||
|
||||
/* Print the last pending elements */
|
||||
if(pending.size()) {
|
||||
auto const &p = pending[pending.size() - 1];
|
||||
Range r = { pending[0].first-distance, p.first+p.second+distance };
|
||||
if(output_started) fmt::print("...\n");
|
||||
_h_hexdump(session, r, pending);
|
||||
/* Print the last pending elements */
|
||||
if(pending.size()) {
|
||||
auto const &p = pending[pending.size() - 1];
|
||||
Range r = { pending[0].first-distance, p.first+p.second+distance };
|
||||
if(output_started) fmt::print("...\n");
|
||||
_h_hexdump(session, r, pending);
|
||||
}
|
||||
pending.clear();
|
||||
}
|
||||
|
||||
if(match_count == 0)
|
||||
|
|
|
@ -33,13 +33,13 @@ static void show_vspace(std::string name, VirtualSpace &s, Session &session)
|
|||
if(is_current) fmt::print("* ");
|
||||
fmt::print(theme(11), "{}\n", name);
|
||||
|
||||
if(s.bindings().size() == 0) {
|
||||
if(s.bindings.size() == 0) {
|
||||
fmt::print(" (no bindings)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fmt::print(" Region Start End File\n");
|
||||
for(auto &b: s.bindings()) {
|
||||
for(auto &b: s.bindings) {
|
||||
MemoryRegion const *ref = MemoryRegion::region_for(b.region);
|
||||
fmt::print(" {:<7s} 0x{:08x} .. 0x{:08x}", (ref ? ref->name : ""),
|
||||
b.region.start, b.region.end);
|
||||
|
@ -168,7 +168,7 @@ void _vm(Session &session, std::string file, std::vector<MemoryRegion> regions)
|
|||
Buffer contents(path);
|
||||
|
||||
/* If no files are loaded yet, set the PC to the first loaded region */
|
||||
if(!session.current_space->bindings().size())
|
||||
if(!session.current_space->bindings.size())
|
||||
session.pc = regions[0].start;
|
||||
|
||||
for(auto &r: regions)
|
||||
|
|
Loading…
Reference in New Issue