summaryrefslogtreecommitdiff
path: root/view/sharedcache/core/VirtualMemory.cpp
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-03-10 11:05:40 -0400
committerMason Reed <mason@vector35.com>2025-04-02 05:36:54 -0400
commit25cc02431b61097b2adfc2fbc493b648b0300c3b (patch)
treea79d9c4f4f67234d3bf9bda413e8608f479a4cc8 /view/sharedcache/core/VirtualMemory.cpp
parentfa85bf28502286c4821427c5d0ed91a7ed46f8f6 (diff)
[SharedCache] Refactor Shared Cache
In absence of a better name, this commit refactors the shared cache code.
Diffstat (limited to 'view/sharedcache/core/VirtualMemory.cpp')
-rw-r--r--view/sharedcache/core/VirtualMemory.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/view/sharedcache/core/VirtualMemory.cpp b/view/sharedcache/core/VirtualMemory.cpp
new file mode 100644
index 00000000..b55ddefe
--- /dev/null
+++ b/view/sharedcache/core/VirtualMemory.cpp
@@ -0,0 +1,375 @@
+#include "VirtualMemory.h"
+
+// TODO: Add back the ability to do relocations on this stuff.
+// TODO: ^ the above is currently handled only by the consumers of the VirtualMemory
+// TODO: however we might still want to have this be done here as well for persistence.
+
+void VirtualMemory::MapRegion(WeakFileAccessor fileAccessor, AddressRange mappedRange, uint64_t fileOffset)
+{
+ // Create a new VirtualMemoryRegion object
+ VirtualMemoryRegion region {fileOffset, std::move(fileAccessor)};
+
+ // TODO: How to handle overlapping regions?
+ for (const auto& [existingRange, existingRegion] : m_regions)
+ {
+ if (existingRange.Overlaps(mappedRange))
+ {
+ // Handle overlapping regions, e.g., throw an exception or skip the mapping
+ BinaryNinja::LogError("Overlapping memory region %llx", existingRange.start);
+ }
+ }
+
+ // Insert the region into the map
+ m_regions.insert_or_assign(mappedRange, region);
+}
+
+std::optional<VirtualMemoryRegion> VirtualMemory::GetRegionAtAddress(uint64_t address, uint64_t& addressOffset)
+{
+ if (const auto& it = m_regions.find(address); it != m_regions.end())
+ {
+ // The VirtualMemoryRegion object returned contains the page, and more importantly, the file pointer (there can
+ // be multiple in newer caches) This is relevant for reading out the data in the rest of this file. The second
+ // item in the returned pair is the offset of `address` within the file.
+ const auto& range = it->first;
+ auto mapping = it->second;
+ addressOffset = mapping.fileOffset + (address - range.start);
+ return mapping;
+ }
+
+ return std::nullopt;
+}
+
+std::optional<VirtualMemoryRegion> VirtualMemory::GetRegionAtAddress(uint64_t address)
+{
+ uint64_t offset;
+ return GetRegionAtAddress(address, offset);
+}
+
+bool VirtualMemory::IsAddressMapped(uint64_t address)
+{
+ return m_regions.find(address) != m_regions.end();
+}
+
+void VirtualMemory::WritePointer(size_t address, size_t pointer)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ // Unique to the `VirtualMemory::WritePointer` we actually have an interface on the WeakFileAccessor to use.
+ // this is the mechanism for persisting our written pointers.
+ region->fileAccessor.WritePointer(offset, pointer);
+}
+
+std::string VirtualMemory::ReadCString(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadNullTermString(offset);
+}
+
+uint8_t VirtualMemory::ReadUInt8(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadUInt8(offset);
+}
+
+int8_t VirtualMemory::ReadInt8(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadInt8(offset);
+}
+
+uint16_t VirtualMemory::ReadUInt16(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadUInt16(offset);
+}
+
+int16_t VirtualMemory::ReadInt16(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadInt16(offset);
+}
+
+uint32_t VirtualMemory::ReadUInt32(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadUInt32(offset);
+}
+
+int32_t VirtualMemory::ReadInt32(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadInt32(offset);
+}
+
+uint64_t VirtualMemory::ReadUInt64(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadUInt64(offset);
+}
+
+int64_t VirtualMemory::ReadInt64(uint64_t address)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadInt64(offset);
+}
+
+BinaryNinja::DataBuffer VirtualMemory::ReadBuffer(uint64_t address, size_t length)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadBuffer(offset, length);
+}
+
+std::pair<const uint8_t*, const uint8_t*> VirtualMemory::ReadSpan(size_t address, size_t length)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ return region->fileAccessor.lock()->ReadSpan(offset, length);
+}
+
+void VirtualMemory::Read(void* dest, uint64_t address, size_t length)
+{
+ uint64_t offset;
+ auto region = GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ region->fileAccessor.lock()->Read(dest, offset, length);
+}
+
+VirtualMemoryReader::VirtualMemoryReader(std::shared_ptr<VirtualMemory> memory, uint64_t addressSize)
+{
+ m_memory = memory;
+ m_addressSize = addressSize;
+ m_cursor = 0;
+}
+
+std::string VirtualMemoryReader::ReadCString(uint64_t address, size_t maxLength)
+{
+ uint64_t offset;
+ auto region = m_memory->GetRegionAtAddress(address, offset);
+ if (!region.has_value())
+ throw UnmappedRegionException(address);
+ // TODO: Advance cursor?
+ return region->fileAccessor.lock()->ReadNullTermString(offset);
+}
+
+uint64_t VirtualMemoryReader::ReadULEB128(size_t cursorLimit)
+{
+ uint64_t result = 0;
+ int bit = 0;
+ uint64_t offset;
+ auto mapping = m_memory->GetRegionAtAddress(m_cursor, offset);
+ auto fileLimit = offset + (cursorLimit - m_cursor);
+ auto fa = mapping->fileAccessor.lock();
+ auto* fileBuff = (uint8_t*)fa->Data();
+ do
+ {
+ if (offset >= fileLimit)
+ return -1;
+ uint64_t slice = ((uint64_t*)&((fileBuff)[offset]))[0] & 0x7f;
+ if (bit > 63)
+ return -1;
+ else
+ {
+ result |= (slice << bit);
+ bit += 7;
+ }
+ } while (((uint64_t*)&(fileBuff[offset++]))[0] & 0x80);
+ // TODO: There has got to be a better way to prevent this...
+ fa->Data(); // prevent deallocation of the fileAccessor as we're operating on the raw data buffer
+ return result;
+}
+
+int64_t VirtualMemoryReader::ReadSLEB128(size_t cursorLimit)
+{
+ constexpr size_t BYTE_SIZE = 7; // Number of bits in each SLEB128 byte
+ constexpr size_t INT64_BITS = 64; // Total number of bits in an int64_t
+
+ int64_t value = 0;
+ size_t shift = 0;
+ uint64_t offset;
+
+ // Retrieve associated memory region and the file buffer
+ auto mapping = m_memory->GetRegionAtAddress(m_cursor, offset);
+ auto fileLimit = offset + (cursorLimit - m_cursor);
+ auto fileAccessor = mapping->fileAccessor.lock();
+ auto* fileBuffer = static_cast<uint8_t*>(fileAccessor->Data());
+
+ // Loop through the SLEB128 encoded bytes
+ while (offset < fileLimit)
+ {
+ uint8_t currentByte = fileBuffer[offset++];
+ value |= (static_cast<int64_t>(currentByte & 0x7F) << shift);
+ shift += BYTE_SIZE;
+
+ if ((currentByte & 0x80) == 0) // If MSB is not set, we're done
+ break;
+ }
+
+ // Properly sign-extend the value according to its size
+ value = (value << (INT64_BITS - shift)) >> (INT64_BITS - shift);
+
+ // TODO: There has got to be a better way to prevent this...
+ // Prevent deallocation of the fileAccessor
+ fileAccessor->Data();
+
+ return value;
+}
+
+uint64_t VirtualMemoryReader::ReadPointer()
+{
+ return ReadPointer(m_cursor);
+}
+
+uint64_t VirtualMemoryReader::ReadPointer(uint64_t address)
+{
+ if (m_addressSize == 8)
+ return ReadUInt64(address);
+ if (m_addressSize == 4)
+ return ReadUInt32(address);
+ // TODO: Throw here or assert.
+ return 0;
+}
+
+uint8_t VirtualMemoryReader::ReadUInt8()
+{
+ return ReadUInt8(m_cursor);
+}
+
+uint8_t VirtualMemoryReader::ReadUInt8(uint64_t address)
+{
+ m_cursor = address + 1;
+ return m_memory->ReadUInt8(address);
+}
+
+int8_t VirtualMemoryReader::ReadInt8()
+{
+ return ReadUInt8(m_cursor);
+}
+
+int8_t VirtualMemoryReader::ReadInt8(uint64_t address)
+{
+ m_cursor = address + 1;
+ return m_memory->ReadInt8(address);
+}
+
+uint16_t VirtualMemoryReader::ReadUInt16()
+{
+ return ReadUInt16(m_cursor);
+}
+
+uint16_t VirtualMemoryReader::ReadUInt16(uint64_t address)
+{
+ m_cursor = address + 2;
+ return m_memory->ReadUInt16(address);
+}
+
+int16_t VirtualMemoryReader::ReadInt16()
+{
+ return ReadInt16(m_cursor);
+}
+
+int16_t VirtualMemoryReader::ReadInt16(uint64_t address)
+{
+ m_cursor = address + 2;
+ return m_memory->ReadInt16(address);
+}
+
+uint32_t VirtualMemoryReader::ReadUInt32()
+{
+ return ReadUInt32(m_cursor);
+}
+
+uint32_t VirtualMemoryReader::ReadUInt32(uint64_t address)
+{
+ m_cursor = address + 4;
+ return m_memory->ReadUInt32(address);
+}
+
+int32_t VirtualMemoryReader::ReadInt32()
+{
+ return ReadInt32(m_cursor);
+}
+
+int32_t VirtualMemoryReader::ReadInt32(uint64_t address)
+{
+ m_cursor = address + 4;
+ return m_memory->ReadInt32(address);
+}
+
+uint64_t VirtualMemoryReader::ReadUInt64()
+{
+ return ReadUInt64(m_cursor);
+}
+
+uint64_t VirtualMemoryReader::ReadUInt64(uint64_t address)
+{
+ m_cursor = address + 8;
+ return m_memory->ReadUInt64(address);
+}
+
+int64_t VirtualMemoryReader::ReadInt64()
+{
+ return ReadInt64(m_cursor);
+}
+
+int64_t VirtualMemoryReader::ReadInt64(uint64_t address)
+{
+ m_cursor = address + 8;
+ return m_memory->ReadInt64(address);
+}
+
+BinaryNinja::DataBuffer VirtualMemoryReader::ReadBuffer(size_t length)
+{
+ return ReadBuffer(m_cursor, length);
+}
+
+BinaryNinja::DataBuffer VirtualMemoryReader::ReadBuffer(uint64_t address, size_t length)
+{
+ m_cursor = address + length;
+ return m_memory->ReadBuffer(address, length);
+}
+
+void VirtualMemoryReader::Read(void* dest, size_t length)
+{
+ Read(dest, m_cursor, length);
+}
+
+void VirtualMemoryReader::Read(void* dest, uint64_t address, size_t length)
+{
+ m_cursor = address + length;
+ m_memory->Read(dest, address, length);
+}