#include #include 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(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 ®ion, 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 */