Finish context saving/restoration

This commit is contained in:
momo5502
2024-09-12 17:53:41 +02:00
parent d94a92df45
commit b1cbc5a7ad
11 changed files with 458 additions and 79 deletions

View File

@@ -84,17 +84,52 @@ static void serialize(utils::buffer_serializer& buffer, const memory_manager::re
static void deserialize(utils::buffer_deserializer& buffer, memory_manager::reserved_region& region)
{
region.length = static_cast<size_t>(buffer.read<uint64_t>());
region.committed_regions = buffer.read_map<uint64_t, memory_manager::committed_region>();
buffer.read_map(region.committed_regions);
}
void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer) const
{
buffer.write_map(this->reserved_regions_);
if (!this->use_in_place_serialization())
{
std::vector<uint8_t> data{};
for (const auto& reserved_region : this->reserved_regions_)
{
for (const auto& region : reserved_region.second.committed_regions)
{
data.resize(region.second.length);
this->read_memory(region.first, data.data(), region.second.length);
buffer.write(data.data(), region.second.length);
}
}
}
}
void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer)
{
this->reserved_regions_ = buffer.read_map<uint64_t, reserved_region>();
buffer.read_map(this->reserved_regions_);
if (!this->use_in_place_serialization())
{
std::vector<uint8_t> data{};
for (const auto& reserved_region : this->reserved_regions_)
{
for (const auto& region : reserved_region.second.committed_regions)
{
data.resize(region.second.length);
buffer.read(data.data(), region.second.length);
this->map_memory(region.first, region.second.length, region.second.pemissions);
this->write_memory(region.first, data.data(), region.second.length);
}
}
}
}
bool memory_manager::protect_memory(const uint64_t address, const size_t size, const memory_permission permissions,

View File

@@ -45,8 +45,8 @@ public:
this->write_memory(address, &value, sizeof(value));
}
virtual void read_memory(uint64_t address, void* data, size_t size) = 0;
virtual bool try_read_memory(uint64_t address, void* data, size_t size) = 0;
virtual void read_memory(uint64_t address, void* data, size_t size) const = 0;
virtual bool try_read_memory(uint64_t address, void* data, size_t size) const = 0;
virtual void write_memory(uint64_t address, const void* data, size_t size) = 0;
bool protect_memory(uint64_t address, size_t size, memory_permission permissions,
@@ -75,10 +75,22 @@ public:
return allocation_base;
}
bool use_in_place_serialization() const
{
return this->in_place_serialization_;
}
void set_in_place_serialization(const bool value)
{
this->in_place_serialization_ = value;
}
private:
using reserved_region_map = std::map<uint64_t, reserved_region>;
reserved_region_map reserved_regions_{};
bool in_place_serialization_{false};
reserved_region_map::iterator find_reserved_region(uint64_t address);
bool overlaps_reserved_region(uint64_t address, size_t size) const;

View File

@@ -2,6 +2,7 @@
#include <span>
#include <vector>
#include <string_view>
#include <stdexcept>
#include <cstring>
@@ -20,32 +21,52 @@ namespace utils
namespace detail
{
template <typename, typename = void>
struct has_serialize_function : std::false_type {};
struct has_serialize_function : std::false_type
{
};
template <typename T>
struct has_serialize_function<T, std::void_t<decltype(serialize(std::declval<buffer_serializer&>(), std::declval<const T&>()))>>
: std::true_type {};
struct has_serialize_function<T, std::void_t<decltype(serialize(std::declval<buffer_serializer&>(),
std::declval<const T&>()))>>
: std::true_type
{
};
template <typename, typename = void>
struct has_deserialize_function : std::false_type {};
struct has_deserialize_function : std::false_type
{
};
template <typename T>
struct has_deserialize_function<T, std::void_t<decltype(deserialize(std::declval<buffer_deserializer&>(), std::declval<T&>()))>>
: std::true_type {};
struct has_deserialize_function<T, std::void_t<decltype(deserialize(
std::declval<buffer_deserializer&>(), std::declval<T&>()))>>
: std::true_type
{
};
}
class buffer_deserializer
{
public:
template <typename T>
buffer_deserializer(const std::span<T>& buffer)
buffer_deserializer(const std::span<T> buffer)
: buffer_(reinterpret_cast<const std::byte*>(buffer.data()), buffer.size() * sizeof(T))
{
static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
}
template <typename T>
buffer_deserializer(const std::vector<T>& buffer)
: buffer_deserializer(std::span(buffer))
{
}
std::span<const std::byte> read_data(const size_t length)
{
#ifndef NDEBUG
const uint64_t real_old_size = this->offset_;
#endif
if (this->offset_ + length > this->buffer_.size())
{
throw std::runtime_error("Out of bounds read from byte buffer");
@@ -54,6 +75,23 @@ namespace utils
const std::span result(this->buffer_.data() + this->offset_, length);
this->offset_ += length;
#ifndef NDEBUG
uint64_t old_size{};
if (this->offset_ + sizeof(old_size) > this->buffer_.size())
{
throw std::runtime_error("Out of bounds read from byte buffer");
}
memcpy(&old_size, this->buffer_.data() + this->offset_, sizeof(old_size));
if (old_size != real_old_size)
{
throw std::runtime_error("Reading from serialized buffer mismatches written data!");
}
this->offset_ += sizeof(old_size);
#endif
return result;
}
@@ -64,10 +102,8 @@ namespace utils
}
template <typename T>
T read()
void read(T& object)
{
T object{};
if constexpr (std::is_base_of_v<serializable, T>)
{
object.deserialize(*this);
@@ -78,63 +114,98 @@ namespace utils
}
else if constexpr (std::is_trivially_copyable_v<T>)
{
this->read(&object, sizeof(object));
union
{
T* type_{};
void* void_;
} pointers;
pointers.type_ = &object;
this->read(pointers.void_, sizeof(object));
}
else
{
static_assert(std::false_type::value, "Key must be trivially copyable or implement serializable!");
std::abort();
}
}
template <typename T>
T read()
{
T object{};
this->read(object);
return object;
}
template <typename T>
void read_vector(std::vector<T>& result)
{
const auto size = this->read<uint64_t>();
result.clear();
result.reserve(size);
for (uint64_t i = 0; i < size; ++i)
{
result.emplace_back(this->read<T>());
}
}
template <typename T>
std::vector<T> read_vector()
{
static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
std::vector<T> result{};
const auto size = this->read<uint64_t>();
const auto totalSize = size * sizeof(T);
if (this->offset_ + totalSize > this->buffer_.size())
{
throw std::runtime_error("Out of bounds read from byte buffer");
}
result.resize(size);
this->read(result.data(), totalSize);
this->read_vector(result);
return result;
}
template <typename Key, typename Value>
std::map<Key, Value> read_map()
template <typename Map>
void read_map(Map& map)
{
using key_type = typename Map::key_type;
using value_type = typename Map::mapped_type;
map.clear();
const auto size = this->read<uint64_t>();
std::map<Key, Value> map{};
for (uint64_t i = 0; i < size; ++i)
{
auto key = this->read<Key>();
auto value = this->read<Value>();
auto key = this->read<key_type>();
auto value = this->read<value_type>();
map[std::move(key)] = std::move(value);
}
}
template <typename Map>
Map read_map()
{
Map map{};
this->read_map(map);
return map;
}
std::string read_string()
template <typename T = char>
void read_string(std::basic_string<T>& result)
{
std::string result{};
const auto size = this->read<uint64_t>();
const auto span = this->read_data(size);
result.resize(size);
memcpy(result.data(), span.data(), size);
result.clear();
result.reserve(size);
for (uint64_t i = 0; i < size; ++i)
{
result.push_back(this->read<T>());
}
}
template <typename T= char>
std::basic_string<T> read_string()
{
std::basic_string<T> result{};
this->read_string(result);
return result;
}
@@ -165,7 +236,17 @@ namespace utils
void write(const void* buffer, const size_t length)
{
this->buffer_.append(static_cast<const char*>(buffer), length);
#ifndef NDEBUG
const uint64_t old_size = this->buffer_.size();
#endif
const auto* byte_buffer = static_cast<const std::byte*>(buffer);
this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length);
#ifndef NDEBUG
const auto* security_buffer = reinterpret_cast<const std::byte*>(&old_size);
this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + sizeof(old_size));
#endif
}
void write(const buffer_serializer& object)
@@ -187,7 +268,15 @@ namespace utils
}
else if constexpr (std::is_trivially_copyable_v<T>)
{
this->write(&object, sizeof(object));
union
{
const T* type_{};
const void* void_;
} pointers;
pointers.type_ = &object;
this->write(pointers.void_, sizeof(object));
}
else
{
@@ -207,8 +296,26 @@ namespace utils
}
}
template <typename Key, typename Value>
void write_map(const std::map<Key, Value>& map)
template <typename T>
void write_vector(const std::vector<T> vec)
{
this->write_span(std::span(vec));
}
template <typename T>
void write_string(const std::basic_string_view<T> str)
{
this->write_span<const T>(str);
}
template <typename T>
void write_string(const std::basic_string<T>& str)
{
this->write_string(std::basic_string_view<T>(str));
}
template <typename Map>
void write_map(const Map& map)
{
this->write<uint64_t>(map.size());
@@ -219,17 +326,41 @@ namespace utils
}
}
const std::string& get_buffer() const
const std::vector<std::byte>& get_buffer() const
{
return this->buffer_;
}
std::string move_buffer()
std::vector<std::byte> move_buffer()
{
return std::move(this->buffer_);
}
private:
std::string buffer_{};
std::vector<std::byte> buffer_{};
};
template <>
inline void buffer_deserializer::read<std::string>(std::string& object)
{
object = this->read_string<char>();
}
template <>
inline void buffer_deserializer::read<std::wstring>(std::wstring& object)
{
object = this->read_string<wchar_t>();
}
template <>
inline void buffer_serializer::write<std::string>(const std::string& object)
{
this->write_string(object);
}
template <>
inline void buffer_serializer::write<std::wstring>(const std::wstring& object)
{
this->write_string(object);
}
}