From 24df7c65c2fc94a1b8dbd506896b635565058680 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Fri, 4 Apr 2025 13:13:09 +0200 Subject: [PATCH] Support accurate instruction counts --- src/emulator/cpu_interface.hpp | 2 +- src/emulator/typed_emulator.hpp | 5 ----- src/icicle-emulator/icicle_x64_emulator.cpp | 15 +++---------- src/icicle/src/icicle.rs | 9 +++++--- src/icicle/src/lib.rs | 4 ++-- src/unicorn-emulator/unicorn_x64_emulator.cpp | 13 ++++-------- src/windows-emulator-test/emulation_test.cpp | 6 +++--- .../emulation_test_utils.hpp | 2 +- .../serialization_test.cpp | 2 +- src/windows-emulator/windows_emulator.cpp | 21 ++----------------- src/windows-emulator/windows_emulator.hpp | 2 +- .../win_x64_gdb_stub_handler.hpp | 2 +- src/windows-gdb-stub/x64_gdb_stub_handler.hpp | 4 ++-- 13 files changed, 27 insertions(+), 60 deletions(-) diff --git a/src/emulator/cpu_interface.hpp b/src/emulator/cpu_interface.hpp index 6db2fc05..155682aa 100644 --- a/src/emulator/cpu_interface.hpp +++ b/src/emulator/cpu_interface.hpp @@ -9,7 +9,7 @@ struct cpu_interface { virtual ~cpu_interface() = default; - virtual void start(uint64_t start, uint64_t end = 0, std::chrono::nanoseconds timeout = {}, size_t count = 0) = 0; + virtual void start(size_t count = 0) = 0; virtual void stop() = 0; virtual size_t read_raw_register(int reg, void* value, size_t size) = 0; diff --git a/src/emulator/typed_emulator.hpp b/src/emulator/typed_emulator.hpp index 63516cba..1a67b038 100644 --- a/src/emulator/typed_emulator.hpp +++ b/src/emulator/typed_emulator.hpp @@ -15,11 +15,6 @@ class typed_emulator : public emulator static constexpr registers stack_pointer = StackPointer; static constexpr registers instruction_pointer = InstructionPointer; - void start_from_ip(const std::chrono::nanoseconds timeout = {}, const size_t count = 0) - { - this->start(this->read_instruction_pointer(), 0, timeout, count); - } - size_t write_register(registers reg, const void* value, const size_t size) { return this->write_raw_register(static_cast(reg), value, size); diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index a06b804c..31b62ce6 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -31,7 +31,7 @@ extern "C" void icicle_remove_syscall_hook(icicle_emulator*, uint32_t id); size_t icicle_read_register(icicle_emulator*, int reg, void* data, size_t length); size_t icicle_write_register(icicle_emulator*, int reg, const void* data, size_t length); - void icicle_start(icicle_emulator*); + void icicle_start(icicle_emulator*, size_t count); void icicle_stop(icicle_emulator*); void icicle_destroy_emulator(icicle_emulator*); } @@ -115,18 +115,9 @@ namespace icicle } } - void start(const uint64_t start, const uint64_t end, std::chrono::nanoseconds timeout, - const size_t count) override + void start(const size_t count) override { - if (timeout.count() < 0) - { - timeout = {}; - } - - (void)start; - (void)end; - (void)count; - icicle_start(this->emu_); + icicle_start(this->emu_, count); } void stop() override diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index dd604da2..292c4fd3 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -197,8 +197,11 @@ impl IcicleEmulator { return &mut self.vm.cpu.mem; } - pub fn start(&mut self) { - self.vm.icount_limit = u64::MAX; + pub fn start(&mut self, count: u64) { + self.vm.icount_limit = match count { + 0 => u64::MAX, + _ => self.vm.cpu.icount + count, + }; loop { let reason = self.vm.run(); @@ -255,7 +258,7 @@ impl IcicleEmulator { } pub fn stop(&mut self) { - self.vm.icount_limit = self.vm.cpu.icount; + self.vm.icount_limit = 0; } pub fn add_violation_hook(&mut self, callback: Box bool>) -> u32 { diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index 1b510a81..0e6eab75 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -20,10 +20,10 @@ pub fn icicle_create_emulator() -> *mut c_void { } #[unsafe(no_mangle)] -pub fn icicle_start(ptr: *mut c_void) { +pub fn icicle_start(ptr: *mut c_void, count: usize) { unsafe { let emulator = &mut *(ptr as *mut IcicleEmulator); - emulator.start(); + emulator.start(count as u64); } } diff --git a/src/unicorn-emulator/unicorn_x64_emulator.cpp b/src/unicorn-emulator/unicorn_x64_emulator.cpp index 7e785d18..f26dddda 100644 --- a/src/unicorn-emulator/unicorn_x64_emulator.cpp +++ b/src/unicorn-emulator/unicorn_x64_emulator.cpp @@ -269,17 +269,12 @@ namespace unicorn uc_close(this->uc_); } - void start(const uint64_t start, const uint64_t end, std::chrono::nanoseconds timeout, - const size_t count) override + void start(const size_t count) override { - if (timeout.count() < 0) - { - timeout = {}; - } - this->has_violation_ = false; - const auto timeoutYs = std::chrono::duration_cast(timeout); - const auto res = uc_emu_start(*this, start, end, static_cast(timeoutYs.count()), count); + const auto start = this->read_instruction_pointer(); + constexpr auto end = std::numeric_limits::max(); + const auto res = uc_emu_start(*this, start, end, 0, count); if (res == UC_ERR_OK) { return; diff --git a/src/windows-emulator-test/emulation_test.cpp b/src/windows-emulator-test/emulation_test.cpp index f5833843..dc600f92 100644 --- a/src/windows-emulator-test/emulation_test.cpp +++ b/src/windows-emulator-test/emulation_test.cpp @@ -15,7 +15,7 @@ namespace test constexpr auto count = 200000; auto emu = create_sample_emulator(); - emu.start({}, count); + emu.start(count); ASSERT_EQ(emu.get_executed_instructions(), count); } @@ -34,12 +34,12 @@ namespace test constexpr auto offset = 1; const auto instructionsToExecute = executedInstructions - offset; - new_emu.start({}, instructionsToExecute); + new_emu.start(instructionsToExecute); ASSERT_EQ(new_emu.get_executed_instructions(), instructionsToExecute); ASSERT_NOT_TERMINATED(new_emu); - new_emu.start({}, offset); + new_emu.start(offset); ASSERT_TERMINATED_SUCCESSFULLY(new_emu); ASSERT_EQ(new_emu.get_executed_instructions(), executedInstructions); diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index 69b4babc..5437aec1 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -141,7 +141,7 @@ namespace test const auto get_state_for_count = [&](const size_t count) { reset_emulator(); - emu.start({}, count); + emu.start(count); utils::buffer_serializer state{}; emu.serialize(state); diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index b82de8d3..1aadaabc 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -77,7 +77,7 @@ namespace test TEST(SerializationTest, DeserializedEmulatorBehavesLikeSource) { auto emu = create_sample_emulator(); - emu.start({}, 100); + emu.start(100); utils::buffer_serializer serializer{}; emu.serialize(serializer); diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 8a08ae67..cccbb3fb 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -514,15 +514,10 @@ void windows_emulator::setup_hooks() [&](const uint64_t address, const size_t, const uint64_t) { this->on_instruction_execution(address); }); } -void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) +void windows_emulator::start(size_t count) { const auto use_count = count > 0; - const auto use_timeout = timeout != std::chrono::nanoseconds{}; - - const auto start_time = std::chrono::high_resolution_clock::now(); const auto start_instructions = this->executed_instructions_; - - const auto target_time = start_time + timeout; const auto target_instructions = start_instructions + count; while (true) @@ -532,25 +527,13 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) this->perform_thread_switch(); } - this->emu().start_from_ip(timeout, count); + this->emu().start(count); if (!this->switch_thread_ && !this->emu().has_violation()) { break; } - if (use_timeout) - { - const auto now = std::chrono::high_resolution_clock::now(); - - if (now >= target_time) - { - break; - } - - timeout = target_time - now; - } - if (use_count) { const auto current_instructions = this->executed_instructions_; diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 7da1b18b..53c17f5c 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -130,7 +130,7 @@ class windows_emulator return this->executed_instructions_; } - void start(std::chrono::nanoseconds timeout = {}, size_t count = 0); + void start(size_t count = 0); void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); diff --git a/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp b/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp index b3ec03a4..1755e09a 100644 --- a/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp +++ b/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp @@ -37,7 +37,7 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler { try { - this->win_emu_->start({}, 1); + this->win_emu_->start(1); } catch (const std::exception& e) { diff --git a/src/windows-gdb-stub/x64_gdb_stub_handler.hpp b/src/windows-gdb-stub/x64_gdb_stub_handler.hpp index 64dea478..6fedb346 100644 --- a/src/windows-gdb-stub/x64_gdb_stub_handler.hpp +++ b/src/windows-gdb-stub/x64_gdb_stub_handler.hpp @@ -64,7 +64,7 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler { try { - this->emu_->start_from_ip(); + this->emu_->start(); } catch (const std::exception& e) { @@ -78,7 +78,7 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler { try { - this->emu_->start_from_ip({}, 1); + this->emu_->start(1); } catch (const std::exception& e) {