mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-20 04:03:57 +00:00
Support accurate instruction counts
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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<int>(reg), value, size);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<dyn Fn(u64, u8, bool) -> bool>) -> u32 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::chrono::microseconds>(timeout);
|
||||
const auto res = uc_emu_start(*this, start, end, static_cast<uint64_t>(timeoutYs.count()), count);
|
||||
const auto start = this->read_instruction_pointer();
|
||||
constexpr auto end = std::numeric_limits<uint64_t>::max();
|
||||
const auto res = uc_emu_start(*this, start, end, 0, count);
|
||||
if (res == UC_ERR_OK)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user