#include #include #include #include namespace FxOS { //--- // Simulated memory access primitives //--- Addressable AbstractMemory::read_i8(uint32_t addr) const { int8_t *i8 = (int8_t *)translate(addr, 1); return Addressable(addr, *i8); } Addressable AbstractMemory::read_u8(uint32_t addr) const { uint8_t *u8 = (uint8_t *)translate(addr, 1); return Addressable(addr, *u8); } Addressable AbstractMemory::read_i16(uint32_t addr) const { uint8_t *i16 = (uint8_t *)translate(addr, 2); int16_t v = (i16[0] << 8) | i16[1]; return Addressable(addr, v); } Addressable AbstractMemory::read_u16(uint32_t addr) const { uint8_t *u16 = (uint8_t *)translate(addr, 2); uint16_t v = (u16[0] << 8) | u16[1]; return Addressable(addr, v); } Addressable 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 Addressable(addr, v); } Addressable 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 Addressable(addr, v); } Addressable AbstractMemory::read_str(uint32_t addr, size_t len) const { char const *str = translate(addr, len); return Addressable(addr, std::string(str, len)); } //--- // Bindings of data buffers into memory regions //--- Binding::Binding(MemoryRegion source_region, Buffer const &buffer): region(source_region), data(buffer.data), size(region.size()) { if(buffer.size < region.size()) { throw std::runtime_error("Buffer too small to create binding"); } } bool Binding::covers(uint32_t addr, int size) const noexcept { return addr >= region.start && addr + size <= region.end; } char const *Binding::translate(uint32_t addr, int size) const { if(!covers(addr, size)) { throw std::out_of_range("Out of binding range"); } return (char *)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_bindings {}, m_buffers {} { } Target::Target(TargetDescription const &descr, std::vector folders): Target() { for(auto binding: descr.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); } } void Target::bind_region(MemoryRegion const ®ion, Buffer const &buffer) { Binding b(region, buffer); 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; } char 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 AddrError(addr, size, "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 AddrError(start, end-start, "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 */