From 450e3c2a9c9c87d8b2b0879ce64776d14ae5f49b Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Tue, 18 Mar 2025 11:48:44 +0100 Subject: [PATCH] Use clock interfaces to precisely control time --- src/common/utils/time.cpp | 10 ++- src/common/utils/time.hpp | 59 ++++++++++++- src/samples/test-sample/test.cpp | 2 + .../serialization_test.cpp | 4 +- src/windows-emulator/devices/afd_endpoint.cpp | 5 +- src/windows-emulator/emulator_thread.cpp | 8 +- src/windows-emulator/emulator_thread.hpp | 6 +- src/windows-emulator/emulator_utils.hpp | 4 + src/windows-emulator/kusd_mmio.cpp | 52 +++--------- src/windows-emulator/kusd_mmio.hpp | 10 +-- src/windows-emulator/process_context.cpp | 6 +- src/windows-emulator/process_context.hpp | 7 +- src/windows-emulator/syscalls.cpp | 26 +++--- src/windows-emulator/windows_emulator.cpp | 83 +++++++++++++++++-- src/windows-emulator/windows_emulator.hpp | 29 +++++-- 15 files changed, 214 insertions(+), 97 deletions(-) diff --git a/src/common/utils/time.cpp b/src/common/utils/time.cpp index 18957e0d..c643c9da 100644 --- a/src/common/utils/time.cpp +++ b/src/common/utils/time.cpp @@ -3,7 +3,9 @@ namespace utils { - std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(const LARGE_INTEGER delay_interval) + std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(steady_clock& steady_time, + system_clock& system_time, + const LARGE_INTEGER delay_interval) { if (delay_interval.QuadPart <= 0) { @@ -13,7 +15,7 @@ namespace utils const auto relative_duration = std::chrono::microseconds(relative_ticks_in_ms) + std::chrono::nanoseconds(relative_fraction_ns); - return std::chrono::steady_clock::now() + relative_duration; + return steady_time.now() + relative_duration; } const auto delay_seconds_since_1601 = delay_interval.QuadPart / HUNDRED_NANOSECONDS_IN_ONE_SECOND; @@ -24,12 +26,12 @@ namespace utils const auto target_time = std::chrono::system_clock::from_time_t(delay_seconds_since_1970) + std::chrono::nanoseconds(delay_fraction_ns); - const auto now_system = std::chrono::system_clock::now(); + const auto now_system = system_time.now(); const auto duration_until_target = std::chrono::duration_cast(target_time - now_system); - return std::chrono::steady_clock::now() + duration_until_target; + return steady_time.now() + duration_until_target; } KSYSTEM_TIME convert_to_ksystem_time(const std::chrono::system_clock::time_point& tp) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index bf592f18..1b6ccea0 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -10,7 +10,62 @@ constexpr auto WINDOWS_EPOCH_DIFFERENCE = EPOCH_DIFFERENCE_1601_TO_1970_SECONDS namespace utils { - std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(const LARGE_INTEGER delay_interval); + template + struct clock + { + using base_clock = Clock; + using time_point = typename base_clock::time_point; + using duration = typename base_clock::duration; + + virtual ~clock() = default; + virtual time_point now() + { + return base_clock::now(); + } + }; + + template + class tick_clock : public clock + { + public: + tick_clock(const typename tick_clock::time_point start, const uint64_t frequency) + : frequency_(frequency), + start_(start) + { + if (this->frequency_ == 0) + { + throw std::invalid_argument("Frequency can not be 0"); + } + } + + typename tick_clock::time_point now() override + { + const auto passed_ticks = this->ticks(); + const auto passed_time = + tick_clock::duration(passed_ticks * tick_clock::duration::period::den / this->frequency_); + + return this->start_ + passed_time; + } + + virtual uint64_t ticks() = 0; + + uint64_t get_frequency() const + { + return this->frequency_; + } + + private: + uint64_t frequency_{1}; + typename tick_clock::time_point start_{}; + }; + + using system_clock = clock; + using steady_clock = clock; + + std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(steady_clock& steady_time, + system_clock& system_time, + LARGE_INTEGER delay_interval); + KSYSTEM_TIME convert_to_ksystem_time(const std::chrono::system_clock::time_point& tp); void convert_to_ksystem_time(volatile KSYSTEM_TIME* dest, const std::chrono::system_clock::time_point& tp); std::chrono::system_clock::time_point convert_from_ksystem_time(const KSYSTEM_TIME& time); @@ -18,5 +73,5 @@ namespace utils #ifndef OS_WINDOWS using __time64_t = int64_t; #endif - LARGE_INTEGER convert_unix_to_windows_time(const __time64_t unix_time); + LARGE_INTEGER convert_unix_to_windows_time(__time64_t unix_time); } diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 7c1d5b60..d4f27cb4 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -423,6 +423,8 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_native_exceptions, "Native Exceptions") RUN_TEST(test_tls, "TLS") + Sleep(1); + if (!reproducible) { RUN_TEST(test_socket, "Socket") diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 97060080..a14b7e89 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -49,7 +49,7 @@ namespace test utils::buffer_deserializer deserializer{serializer1.get_buffer()}; - windows_emulator new_emu{{.emulation_root = get_emulator_root()}}; + windows_emulator new_emu{{.emulation_root = get_emulator_root(), .use_relative_time = true}}; new_emu.deserialize(deserializer); utils::buffer_serializer serializer2{}; @@ -92,7 +92,7 @@ namespace test utils::buffer_deserializer deserializer{serializer.get_buffer()}; - windows_emulator new_emu{{.emulation_root = get_emulator_root()}}; + windows_emulator new_emu{{.emulation_root = get_emulator_root(), .use_relative_time = true}}; new_emu.log.disable_output(true); new_emu.deserialize(deserializer); diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index e3d38399..7b55f182 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -457,7 +457,7 @@ namespace const auto status = this->execute_ioctl(win_emu, *this->delayed_ioctl_); if (status == STATUS_PENDING) { - if (!this->timeout_ || this->timeout_ > std::chrono::steady_clock::now()) + if (!this->timeout_ || this->timeout_ > win_emu.steady_clock().now()) { return; } @@ -593,7 +593,8 @@ namespace std::optional timeout{}; if (info.Timeout.QuadPart != std::numeric_limits::max()) { - timeout = utils::convert_delay_interval_to_time_point(info.Timeout); + timeout = utils::convert_delay_interval_to_time_point(win_emu.steady_clock(), + win_emu.system_clock(), info.Timeout); } this->delay_ioctrl(c, timeout); diff --git a/src/windows-emulator/emulator_thread.cpp b/src/windows-emulator/emulator_thread.cpp index 8798520e..46596e40 100644 --- a/src/windows-emulator/emulator_thread.cpp +++ b/src/windows-emulator/emulator_thread.cpp @@ -148,7 +148,7 @@ bool emulator_thread::is_terminated() const return this->exit_status.has_value(); } -bool emulator_thread::is_thread_ready(process_context& process) +bool emulator_thread::is_thread_ready(process_context& process, utils::steady_clock& steady_clock) { if (this->is_terminated()) { @@ -162,7 +162,7 @@ bool emulator_thread::is_thread_ready(process_context& process) this->mark_as_ready(STATUS_ALERTED); return true; } - if (this->is_await_time_over()) + if (this->is_await_time_over(steady_clock)) { this->mark_as_ready(STATUS_TIMEOUT); return true; @@ -194,7 +194,7 @@ bool emulator_thread::is_thread_ready(process_context& process) return true; } - if (this->is_await_time_over()) + if (this->is_await_time_over(steady_clock)) { this->mark_as_ready(STATUS_TIMEOUT); return true; @@ -205,7 +205,7 @@ bool emulator_thread::is_thread_ready(process_context& process) if (this->await_time.has_value()) { - if (this->is_await_time_over()) + if (this->is_await_time_over(steady_clock)) { this->mark_as_ready(STATUS_SUCCESS); return true; diff --git a/src/windows-emulator/emulator_thread.hpp b/src/windows-emulator/emulator_thread.hpp index 2908b9a9..44ed6820 100644 --- a/src/windows-emulator/emulator_thread.hpp +++ b/src/windows-emulator/emulator_thread.hpp @@ -65,14 +65,14 @@ class emulator_thread : public ref_counted_object void mark_as_ready(NTSTATUS status); - bool is_await_time_over() const + bool is_await_time_over(utils::steady_clock& steady_clock) const { - return this->await_time.has_value() && this->await_time.value() < std::chrono::steady_clock::now(); + return this->await_time.has_value() && this->await_time.value() < steady_clock.now(); } bool is_terminated() const; - bool is_thread_ready(process_context& process); + bool is_thread_ready(process_context& process, utils::steady_clock& steady_clock); void save(x64_emulator& emu) { diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index 11d87d01..f130143f 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -6,6 +6,8 @@ #include "memory_utils.hpp" #include "address_utils.hpp" +#include + // TODO: Replace with pointer handling structure for future 32 bit support using emulator_pointer = uint64_t; @@ -47,6 +49,8 @@ using x64_emulator_wrapper = object_wrapper; using memory_manager_wrapper = object_wrapper; using module_manager_wrapper = object_wrapper; using process_context_wrapper = object_wrapper; +using system_clock_wrapper = object_wrapper; +using steady_clock_wrapper = object_wrapper; using windows_emulator_wrapper = object_wrapper; template diff --git a/src/windows-emulator/kusd_mmio.cpp b/src/windows-emulator/kusd_mmio.cpp index 256f02e4..63b98e23 100644 --- a/src/windows-emulator/kusd_mmio.cpp +++ b/src/windows-emulator/kusd_mmio.cpp @@ -10,7 +10,7 @@ constexpr auto KUSD_BUFFER_SIZE = page_align_up(KUSD_SIZE); namespace { - void setup_kusd(KUSER_SHARED_DATA64& kusd, const bool use_relative_time) + void setup_kusd(KUSER_SHARED_DATA64& kusd) { memset(reinterpret_cast(&kusd), 0, sizeof(kusd)); @@ -60,25 +60,17 @@ namespace kusd.TelemetryCoverageRound = 0x00000001; kusd.LangGenerationCount = 0x00000003; kusd.InterruptTimeBias = 0x00000015a5d56406; - kusd.QpcBias = 0x000000159530c4af; kusd.ActiveProcessorCount = 0x0000000c; kusd.ActiveGroupCount = 0x01; - kusd.QpcData.QpcData = 0x0083; - kusd.QpcData.QpcBypassEnabled = 0x83; kusd.TimeZoneBiasEffectiveStart.QuadPart = 0x01db276e654cb2ff; kusd.TimeZoneBiasEffectiveEnd.QuadPart = 0x01db280b8c3b2800; kusd.XState.EnabledFeatures = 0x000000000000001f; kusd.XState.EnabledVolatileFeatures = 0x000000000000000f; kusd.XState.Size = 0x000003c0; - - if (use_relative_time) - { - kusd.QpcFrequency = 1000; - } - else - { - kusd.QpcFrequency = std::chrono::steady_clock::period::den; - } + kusd.QpcData.QpcData = 0x0083; + kusd.QpcData.QpcBypassEnabled = 0x83; + kusd.QpcBias = 0x000000159530c4af; + kusd.QpcFrequency = utils::steady_clock::duration::period::den; constexpr std::u16string_view root_dir{u"C:\\WINDOWS"}; memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2); @@ -102,9 +94,9 @@ namespace utils } } -kusd_mmio::kusd_mmio(memory_manager& memory, process_context& process) +kusd_mmio::kusd_mmio(memory_manager& memory, utils::system_clock& clock) : memory_(&memory), - process_(&process) + system_clock_(&clock) { } @@ -114,32 +106,24 @@ kusd_mmio::~kusd_mmio() } kusd_mmio::kusd_mmio(utils::buffer_deserializer& buffer) - : kusd_mmio(buffer.read(), buffer.read()) + : kusd_mmio(buffer.read(), buffer.read()) { } -void kusd_mmio::setup(const bool use_relative_time) +void kusd_mmio::setup() { - this->use_relative_time_ = use_relative_time; - - setup_kusd(this->kusd_, use_relative_time); - this->start_time_ = utils::convert_from_ksystem_time(this->kusd_.SystemTime); - + setup_kusd(this->kusd_); this->register_mmio(); } void kusd_mmio::serialize(utils::buffer_serializer& buffer) const { - buffer.write(this->use_relative_time_); buffer.write(this->kusd_); - buffer.write(this->start_time_); } void kusd_mmio::deserialize(utils::buffer_deserializer& buffer) { - buffer.read(this->use_relative_time_); buffer.read(this->kusd_); - buffer.read(this->start_time_); this->deregister_mmio(); this->register_mmio(); @@ -178,21 +162,7 @@ uint64_t kusd_mmio::address() void kusd_mmio::update() { - auto time = this->start_time_; - - if (this->use_relative_time_) - { - const auto passed_time = this->process_->executed_instructions; - const auto clock_frequency = static_cast(this->kusd_.QpcFrequency); - - using duration = std::chrono::system_clock::duration; - time += duration(passed_time * duration::period::den / clock_frequency); - } - else - { - time = std::chrono::system_clock::now(); - } - + const auto time = this->system_clock_->now(); utils::convert_to_ksystem_time(&this->kusd_.SystemTime, time); } diff --git a/src/windows-emulator/kusd_mmio.hpp b/src/windows-emulator/kusd_mmio.hpp index b9d408a3..645f9471 100644 --- a/src/windows-emulator/kusd_mmio.hpp +++ b/src/windows-emulator/kusd_mmio.hpp @@ -5,13 +5,15 @@ #include "x64_emulator.hpp" +#include + struct process_context; class windows_emulator; class kusd_mmio { public: - kusd_mmio(memory_manager& memory, process_context& process); + kusd_mmio(memory_manager& memory, utils::system_clock& clock); ~kusd_mmio(); kusd_mmio(utils::buffer_deserializer& buffer); @@ -36,17 +38,15 @@ class kusd_mmio static uint64_t address(); - void setup(bool use_relative_time); + void setup(); private: memory_manager* memory_{}; - process_context* process_{}; + utils::system_clock* system_clock_{}; bool registered_{}; - bool use_relative_time_{}; KUSER_SHARED_DATA64 kusd_{}; - std::chrono::system_clock::time_point start_time_{}; uint64_t read(uint64_t addr, size_t size); diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 67bdec3c..bec7c813 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -28,12 +28,12 @@ namespace } void process_context::setup(x64_emulator& emu, memory_manager& memory, const application_settings& app_settings, - const emulator_settings& emu_settings, const mapped_module& executable, - const mapped_module& ntdll, const apiset::container& apiset_container) + const mapped_module& executable, const mapped_module& ntdll, + const apiset::container& apiset_container) { setup_gdt(emu, memory); - this->kusd.setup(emu_settings.use_relative_time); + this->kusd.setup(); this->base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE); auto& allocator = this->base_allocator; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index ba7c2f47..54879bbf 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -38,18 +38,17 @@ struct process_context utils::optional_function on_thread_terminated{}; }; - process_context(x64_emulator& emu, memory_manager& memory, callbacks& cb) + process_context(x64_emulator& emu, memory_manager& memory, utils::system_clock& clock, callbacks& cb) : callbacks_(&cb), base_allocator(emu), peb(emu), process_params(emu), - kusd(memory, *this) + kusd(memory, clock) { } void setup(x64_emulator& emu, memory_manager& memory, const application_settings& app_settings, - const emulator_settings& emu_settings, const mapped_module& executable, const mapped_module& ntdll, - const apiset::container& apiset_container); + const mapped_module& executable, const mapped_module& ntdll, const apiset::container& apiset_container); handle create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument, const uint64_t stack_size); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 8999236d..604c4fe8 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -27,21 +27,15 @@ namespace if (performance_counter) { performance_counter.access([&](LARGE_INTEGER& value) { - if (c.win_emu.time_is_relative()) - { - value.QuadPart = static_cast(c.proc.executed_instructions); - } - else - { - value.QuadPart = std::chrono::steady_clock::now().time_since_epoch().count(); - } + value.QuadPart = c.win_emu.steady_clock().now().time_since_epoch().count(); }); } if (performance_frequency) { - performance_frequency.access( - [&](LARGE_INTEGER& value) { value.QuadPart = c.proc.kusd.get().QpcFrequency; }); + performance_frequency.access([&](LARGE_INTEGER& value) { + value.QuadPart = c.proc.kusd.get().QpcFrequency; // + }); } return STATUS_SUCCESS; @@ -3639,7 +3633,8 @@ namespace if (timeout.value() && !t.await_time.has_value()) { - t.await_time = utils::convert_delay_interval_to_time_point(timeout.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), + c.win_emu.system_clock(), timeout.read()); } c.win_emu.yield_thread(); @@ -3666,7 +3661,8 @@ namespace if (timeout.value() && !t.await_time.has_value()) { - t.await_time = utils::convert_delay_interval_to_time_point(timeout.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), + c.win_emu.system_clock(), timeout.read()); } c.win_emu.yield_thread(); @@ -3703,7 +3699,8 @@ namespace } auto& t = c.win_emu.current_thread(); - t.await_time = utils::convert_delay_interval_to_time_point(delay_interval.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), c.win_emu.system_clock(), + delay_interval.read()); c.win_emu.yield_thread(); @@ -3745,7 +3742,8 @@ namespace if (timeout.value() && !t.await_time.has_value()) { - t.await_time = utils::convert_delay_interval_to_time_point(timeout.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), + c.win_emu.system_clock(), timeout.read()); } c.win_emu.yield_thread(); diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 708cc8bf..9d54a7e4 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -86,7 +86,7 @@ namespace auto& emu = win_emu.emu(); auto& context = win_emu.process; - const auto is_ready = thread.is_thread_ready(context); + const auto is_ready = thread.is_thread_ready(context, win_emu.steady_clock()); if (!is_ready && !force) { @@ -161,6 +161,48 @@ namespace return false; } + + template + struct instruction_tick_clock : utils::tick_clock + { + windows_emulator* win_emu_{}; + + instruction_tick_clock(windows_emulator& win_emu, const typename instruction_tick_clock::time_point start = {}) + : utils::tick_clock(start, 1000), + win_emu_(&win_emu) + { + } + + uint64_t ticks() override + { + if (!this->win_emu_->base_constructed_) // TODO: Remove that + { + throw std::runtime_error("Requesting ticks before construction!"); + } + + return this->win_emu_->process.executed_instructions; + } + }; + + std::unique_ptr get_steady_clock(windows_emulator& win_emu, const bool use_relative_time) + { + if (use_relative_time) + { + return std::make_unique>(win_emu); + } + + return std::make_unique(); + } + + std::unique_ptr get_system_clock(windows_emulator& win_emu, const bool use_relative_time) + { + if (use_relative_time) + { + return std::make_unique>(win_emu); + } + + return std::make_unique(); + } } std::unique_ptr create_default_x64_emulator() @@ -175,18 +217,22 @@ windows_emulator::windows_emulator(application_settings app_settings, const emul this->callbacks = std::move(callbacks); fixup_application_settings(app_settings); - this->setup_process(app_settings, settings); + this->setup_process(app_settings); } windows_emulator::windows_emulator(const emulator_settings& settings, std::unique_ptr emu) : emu_(std::move(emu)), + system_clock_(get_system_clock(*this, settings.use_relative_time)), + steady_clock_(get_steady_clock(*this, settings.use_relative_time)), emulation_root{settings.emulation_root.empty() ? settings.emulation_root : absolute(settings.emulation_root)}, file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), memory(*this->emu_), registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"), mod_manager(memory, file_sys, callbacks), - process(*this->emu_, memory, callbacks) + process(*this->emu_, memory, *this->system_clock_, callbacks) { + this->base_constructed_ = true; + #ifndef OS_WINDOWS if (this->emulation_root.empty()) { @@ -215,7 +261,7 @@ windows_emulator::windows_emulator(const emulator_settings& settings, std::uniqu windows_emulator::~windows_emulator() = default; -void windows_emulator::setup_process(const application_settings& app_settings, const emulator_settings& emu_settings) +void windows_emulator::setup_process(const application_settings& app_settings) { const auto& emu = this->emu(); auto& context = this->process; @@ -229,7 +275,7 @@ void windows_emulator::setup_process(const application_settings& app_settings, c const auto apiset_data = apiset::obtain(this->emulation_root); - this->process.setup(this->emu(), this->memory, app_settings, emu_settings, *executable, *ntdll, apiset_data); + this->process.setup(this->emu(), this->memory, app_settings, *executable, *ntdll, apiset_data); const auto ntdll_data = emu.read_memory(ntdll->image_base, ntdll->size_of_image); const auto win32u_data = emu.read_memory(win32u->image_base, win32u->size_of_image); @@ -251,8 +297,14 @@ void windows_emulator::perform_thread_switch() this->switch_thread_ = false; while (!switch_to_next_thread(*this)) { - // TODO: Optimize that - std::this_thread::sleep_for(1ms); + if (this->use_relative_time_) + { + this->process.executed_instructions += MAX_INSTRUCTIONS_PER_TIME_SLICE; + } + else + { + std::this_thread::sleep_for(1ms); + } } } @@ -450,7 +502,7 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) while (true) { - if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process)) + if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process, this->steady_clock())) { this->perform_thread_switch(); } @@ -517,9 +569,24 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) return windows_emulator_wrapper{*this}; // }); + buffer.register_factory([this] { + return system_clock_wrapper{this->system_clock()}; // + }); + + buffer.register_factory([this] { + return steady_clock_wrapper{this->steady_clock()}; // + }); + buffer.read(this->switch_thread_); + + const auto old_relative_time = this->use_relative_time_; buffer.read(this->use_relative_time_); + if (old_relative_time != this->use_relative_time_) + { + throw std::runtime_error("Can not deserialize emulator with different time dimensions"); + } + this->memory.unmap_all_memory(); this->emu().deserialize_state(buffer, false); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index b8b7b700..43015131 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -48,6 +48,8 @@ struct emulator_settings class windows_emulator { std::unique_ptr emu_{}; + std::unique_ptr system_clock_{}; + std::unique_ptr steady_clock_{}; public: std::filesystem::path emulation_root{}; @@ -83,6 +85,26 @@ class windows_emulator return *this->emu_; } + utils::system_clock& system_clock() + { + return *this->system_clock_; + } + + const utils::system_clock& system_clock() const + { + return *this->system_clock_; + } + + utils::steady_clock& steady_clock() + { + return *this->steady_clock_; + } + + const utils::steady_clock& steady_clock() const + { + return *this->steady_clock_; + } + emulator_thread& current_thread() const { if (!this->process.active_thread) @@ -149,10 +171,7 @@ class windows_emulator void perform_thread_switch(); bool activate_thread(uint32_t id); - bool time_is_relative() const - { - return this->use_relative_time_; - } + bool base_constructed_{false}; private: bool switch_thread_{false}; @@ -166,6 +185,6 @@ class windows_emulator // std::optional process_snapshot_{}; void setup_hooks(); - void setup_process(const application_settings& app_settings, const emulator_settings& emu_settings); + void setup_process(const application_settings& app_settings); void on_instruction_execution(uint64_t address); };