fxos/lib/target.cpp

164 lines
3.3 KiB
C++

#include <fxos/target.h>
#include <cstring>
namespace FxOS {
//---
// Simulated memory primitives
//---
int32_t AbstractMemory::read_i8(uint32_t addr) const
{
int8_t *i8 = (int8_t *)translate(addr, 1);
return *i8;
}
uint32_t AbstractMemory::read_u8(uint32_t addr) const
{
uint8_t *u8 = (uint8_t *)translate(addr, 1);
return *u8;
}
int32_t AbstractMemory::read_i16(uint32_t addr) const
{
uint8_t *i16 = (uint8_t *)translate(addr, 2);
int16_t v = (i16[0] << 8) | i16[1];
return v;
}
uint32_t AbstractMemory::read_u16(uint32_t addr) const
{
uint8_t *u16 = (uint8_t *)translate(addr, 2);
uint16_t v = (u16[0] << 8) | u16[1];
return v;
}
int32_t AbstractMemory::read_i32(uint32_t addr) const
{
uint8_t *i32 = (uint8_t *)translate(addr, 4);
int32_t v = (i32[0] << 24) | (i32[1] << 16) | (i32[2] << 8) | i32[3];
return v;
}
uint32_t AbstractMemory::read_u32(uint32_t addr) const
{
uint8_t *u32 = (uint8_t *)translate(addr, 4);
uint32_t v = (u32[0] << 24) | (u32[1] << 16) | (u32[2] << 8) | u32[3];
return v;
}
//---
// Bindings of data buffers into memory regions
//---
Binding::Binding(MemoryRegion const &source_region, File &file):
region(source_region)
{
data = reinterpret_cast<uint8_t *>(file.data());
size = region.size();
if(file.size() < region.size())
{
region.end = region.start + file.size();
size = file.size();
}
}
bool Binding::covers(uint32_t addr, int size) const noexcept
{
return addr >= region.start && addr + size <= region.end;
}
void const *Binding::translate(uint32_t addr, int size) const
{
if(!covers(addr, size))
{
throw std::out_of_range("Out of binding range");
}
return (void *)(data + (addr - region.start));
}
uint32_t Binding::search(uint32_t start, uint32_t end, void const *pattern,
int size) const
{
if(end < start || !covers(start, end - start))
{
throw std::out_of_range("Out of binding range");
}
if(start + size > end) return end;
void const *data = translate(start);
void const *occurrence = memmem(data, end - start, pattern, size);
if(!occurrence) return end;
return start + ((char *)occurrence - (char *)data);
}
//---
// Composite memory targets
//---
Target::Target():
m_os(nullptr), m_bindings {}
{
}
void Target::bind_os(OS &os)
{
m_os = &os;
}
void Target::bind_region(MemoryRegion const &region, File &file)
{
Binding b(region, file);
m_bindings.push_back(b);
}
bool Target::covers(uint32_t addr, int size) const noexcept
{
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
{
if(it->covers(addr, size)) return true;
}
return false;
}
void const *Target::translate(uint32_t addr, int size) const
{
for(auto it = m_bindings.crbegin(); it != m_bindings.crend(); it++)
{
try
{
return it->translate(addr, size);
}
catch(std::out_of_range &e) {}
}
throw std::out_of_range("Out of target bindings");
}
uint32_t Target::search(uint32_t start, uint32_t end, void const *pattern,
int size) const
{
uint32_t occurrence;
if(end < start || !covers(start, end - start))
{
throw std::out_of_range("Out of target bindings");
}
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;
}
} /* namespace FxOS */