Merge icicle progress (#178)

This commit is contained in:
Maurice Heumann
2025-04-04 13:34:26 +02:00
committed by GitHub
13 changed files with 322 additions and 118 deletions

View File

@@ -9,13 +9,13 @@ 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;
virtual size_t write_raw_register(int reg, const void* value, size_t size) = 0;
virtual std::vector<std::byte> save_registers() = 0;
virtual std::vector<std::byte> save_registers() const = 0;
virtual void restore_registers(const std::vector<std::byte>& register_data) = 0;
// TODO: Remove this

View File

@@ -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);

View File

@@ -7,11 +7,14 @@ using icicle_emulator = struct icicle_emulator_;
extern "C"
{
using raw_func = void(void*);
using ptr_func = void(void*, uint64_t);
using violation_func = int32_t(void*, uint64_t address, uint8_t operation, int32_t unmapped);
using data_accessor_func = void(void* user, const void* data, size_t length);
using icicle_mmio_read_func = void(void* user, uint64_t address, size_t length, void* data);
using icicle_mmio_write_func = void(void* user, uint64_t address, size_t length, const void* data);
using data_accessor_func = void(void* user, const void* data, size_t length);
icicle_emulator* icicle_create_emulator();
int32_t icicle_protect_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions);
int32_t icicle_map_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions);
@@ -22,11 +25,14 @@ extern "C"
int32_t icicle_write_memory(icicle_emulator*, uint64_t address, const void* data, size_t length);
int32_t icicle_save_registers(icicle_emulator*, data_accessor_func* accessor, void* accessor_data);
int32_t icicle_restore_registers(icicle_emulator*, const void* data, size_t length);
uint32_t icicle_add_syscall_hook(icicle_emulator*, void (*callback)(void*), void* data);
uint32_t icicle_add_syscall_hook(icicle_emulator*, raw_func* callback, void* data);
uint32_t icicle_add_execution_hook(icicle_emulator*, ptr_func* callback, void* data);
uint32_t icicle_add_violation_hook(icicle_emulator*, violation_func* callback, void* data);
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*);
}
@@ -41,6 +47,51 @@ namespace icicle
throw std::runtime_error(std::string(error));
}
}
emulator_hook* wrap_hook(const uint32_t id)
{
return reinterpret_cast<emulator_hook*>(static_cast<size_t>(id));
}
template <typename T>
struct function_object : utils::object
{
std::function<T> func{};
function_object(std::function<T> f = {})
: func(std::move(f))
{
}
template <typename... Args>
auto operator()(Args&&... args) const
{
return this->func.operator()(std::forward<Args>(args)...);
}
~function_object() override = default;
};
template <typename T>
std::unique_ptr<function_object<T>> make_function_object(std::function<T> func)
{
return std::make_unique<function_object<T>>(std::move(func));
}
template <typename T>
std::unique_ptr<utils::object> wrap_shared(std::shared_ptr<T> shared_ptr)
{
struct shard_wrapper : utils::object
{
std::shared_ptr<T> ptr{};
~shard_wrapper() override = default;
};
auto wrapper = std::make_unique<shard_wrapper>();
wrapper->ptr = std::move(shared_ptr);
return wrapper;
}
}
class icicle_x64_emulator : public x64_emulator
@@ -64,22 +115,14 @@ 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
{
icicle_stop(this->emu_);
}
void load_gdt(const pointer_type address, const uint32_t limit) override
@@ -142,28 +185,30 @@ namespace icicle
auto* ptr = wrapper.get();
this->storage_.push_back(std::move(wrapper));
auto* read_wrapper = +[](void* user, const uint64_t address, const size_t length, void* data) {
auto* read_wrapper = +[](void* user, const uint64_t addr, const size_t length, void* data) {
constexpr auto limit = sizeof(uint64_t);
const auto* w = static_cast<mmio_wrapper*>(user);
// TODO: Change interface to get rid of loop
for (size_t offset = 0; offset < length; offset += limit)
{
const auto max_read = std::min(limit, length - offset);
const auto value = w->read_cb(address + offset - w->base, max_read);
const auto value = w->read_cb(addr + offset - w->base, max_read);
memcpy(static_cast<uint8_t*>(data) + offset, &value, max_read);
}
};
auto* write_wrapper = +[](void* user, const uint64_t address, const size_t length, const void* data) {
auto* write_wrapper = +[](void* user, const uint64_t addr, const size_t length, const void* data) {
constexpr auto limit = sizeof(uint64_t);
const auto* w = static_cast<mmio_wrapper*>(user);
// TODO: Change interface to get rid of loop
for (size_t offset = 0; offset < length; offset += limit)
{
uint64_t value{};
const auto max_read = std::min(limit, length - offset);
memcpy(&value, static_cast<const uint8_t*>(data) + offset, max_read);
w->write_cb(address + offset - w->base, max_read, value);
w->write_cb(addr + offset - w->base, max_read, value);
}
};
@@ -209,50 +254,69 @@ namespace icicle
{
if (static_cast<x64_hookable_instructions>(instruction_type) != x64_hookable_instructions::syscall)
{
// TODO
return nullptr;
}
auto callback_store = std::make_unique<std::function<void()>>([c = std::move(callback)] {
(void)c(); //
});
auto obj = make_function_object(std::move(callback));
auto* ptr = obj.get();
const auto invoker = +[](void* cb) {
(*static_cast<std::function<void()>*>(cb))(); //
const auto& func = *static_cast<decltype(ptr)>(cb);
(void)func(); //
};
const auto id = icicle_add_syscall_hook(this->emu_, invoker, callback_store.get());
this->syscall_hooks_[id] = std::move(callback_store);
const auto id = icicle_add_syscall_hook(this->emu_, invoker, ptr);
this->hooks_[id] = std::move(obj);
return reinterpret_cast<emulator_hook*>(static_cast<size_t>(id));
return wrap_hook(id);
}
emulator_hook* hook_basic_block(basic_block_hook_callback callback) override
{
// TODO
(void)callback;
throw std::runtime_error("Not implemented");
}
emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override
{
// TODO
(void)callback;
throw std::runtime_error("Not implemented");
}
emulator_hook* hook_interrupt(interrupt_hook_callback callback) override
{
// TODO
(void)callback;
return nullptr;
// throw std::runtime_error("Not implemented");
}
emulator_hook* hook_memory_violation(uint64_t address, size_t size,
emulator_hook* hook_memory_violation(const uint64_t address, const size_t size,
memory_violation_hook_callback callback) override
{
(void)address;
(void)size;
(void)callback;
return nullptr;
// throw std::runtime_error("Not implemented");
auto obj = make_function_object(std::move(callback));
auto* ptr = obj.get();
auto* wrapper =
+[](void* user, const uint64_t address, const uint8_t operation, const int32_t unmapped) -> int32_t {
const auto violation_type = unmapped //
? memory_violation_type::unmapped
: memory_violation_type::protection;
const auto& func = *static_cast<decltype(ptr)>(user);
const auto res = func(address, 1, static_cast<memory_operation>(operation), violation_type);
return res == memory_violation_continuation::resume ? 1 : 0;
};
const auto id = icicle_add_violation_hook(this->emu_, wrapper, ptr);
this->hooks_[id] = std::move(obj);
return wrap_hook(id);
}
emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
@@ -263,41 +327,65 @@ namespace icicle
return nullptr;
}
(void)address;
(void)size;
(void)callback;
const auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
if ((filter & memory_permission::exec) == memory_permission::exec)
{
if (address != 0 || size != std::numeric_limits<size_t>::max())
{
throw std::runtime_error("Not supported!");
}
auto* ptr = shared_callback.get();
auto wrapper = wrap_shared(shared_callback);
auto* func = +[](void* user, const uint64_t ptr) {
(*static_cast<complex_memory_hook_callback*>(user))(ptr, 0, 0, memory_permission::exec);
};
const auto id = icicle_add_execution_hook(this->emu_, func, ptr);
this->hooks_[id] = std::move(wrapper);
return wrap_hook(id);
}
return nullptr;
// throw std::runtime_error("Not implemented");
}
void delete_hook(emulator_hook* hook) override
{
const auto id = static_cast<uint32_t>(reinterpret_cast<size_t>(hook));
const auto entry = this->syscall_hooks_.find(id);
if (entry == this->syscall_hooks_.end())
const auto entry = this->hooks_.find(id);
if (entry == this->hooks_.end())
{
return;
}
icicle_remove_syscall_hook(this->emu_, id);
this->syscall_hooks_.erase(entry);
this->hooks_.erase(entry);
}
void serialize_state(utils::buffer_serializer& buffer, const bool is_snapshot) const override
{
(void)buffer;
(void)is_snapshot;
throw std::runtime_error("Not implemented");
if (is_snapshot)
{
throw std::runtime_error("Not implemented");
}
buffer.write_vector(this->save_registers());
}
void deserialize_state(utils::buffer_deserializer& buffer, const bool is_snapshot) override
{
(void)buffer;
(void)is_snapshot;
throw std::runtime_error("Not implemented");
if (is_snapshot)
{
throw std::runtime_error("Not implemented");
}
const auto data = buffer.read_vector<std::byte>();
this->restore_registers(data);
}
std::vector<std::byte> save_registers() override
std::vector<std::byte> save_registers() const override
{
std::vector<std::byte> data{};
auto* accessor = +[](void* user, const void* data, const size_t length) {
@@ -323,8 +411,7 @@ namespace icicle
private:
std::list<std::unique_ptr<utils::object>> storage_{};
using syscall_hook_storage = std::unique_ptr<std::function<void()>>;
std::unordered_map<uint32_t, syscall_hook_storage> syscall_hooks_{};
std::unordered_map<uint32_t, std::unique_ptr<utils::object>> hooks_{};
icicle_emulator* emu_{};
};

View File

@@ -1,5 +1,6 @@
use icicle_cpu::ValueSource;
use std::collections::HashMap;
use icicle_cpu::ExceptionCode;
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use crate::registers;
@@ -16,11 +17,11 @@ fn create_x64_vm() -> icicle_vm::Vm {
return icicle_vm::build(&cpu_config).unwrap();
}
fn map_permissions(foreign_permissions: u8) -> u8 {
const FOREIGN_READ: u8 = 1 << 0;
const FOREIGN_WRITE: u8 = 1 << 1;
const FOREIGN_EXEC: u8 = 1 << 2;
const FOREIGN_READ: u8 = 1 << 0;
const FOREIGN_WRITE: u8 = 1 << 1;
const FOREIGN_EXEC: u8 = 1 << 2;
fn map_permissions(foreign_permissions: u8) -> u8 {
let mut permissions: u8 = 0;
if (foreign_permissions & FOREIGN_READ) != 0 {
@@ -46,6 +47,7 @@ enum HookType {
Read,
Write,
Execute,
Violation,
Unknown,
}
@@ -96,10 +98,45 @@ impl<Func: ?Sized> HookContainer<Func> {
}
}
struct InstructionHookInjector {
hook: pcode::HookId,
}
impl icicle_vm::CodeInjector for InstructionHookInjector {
fn inject(
&mut self,
_cpu: &mut icicle_vm::cpu::Cpu,
group: &icicle_vm::cpu::BlockGroup,
code: &mut icicle_vm::BlockTable,
) {
for id in group.range() {
let block = &mut code.blocks[id];
let mut tmp_block = pcode::Block::new();
tmp_block.next_tmp = block.pcode.next_tmp;
for stmt in block.pcode.instructions.drain(..) {
tmp_block.push(stmt);
if let pcode::Op::InstructionMarker = stmt.op {
tmp_block.push(pcode::Op::Hook(self.hook));
code.modified.insert(id);
}
}
std::mem::swap(
&mut tmp_block.instructions,
&mut block.pcode.instructions,
);
}
}
}
pub struct IcicleEmulator {
vm: icicle_vm::Vm,
reg: registers::X64RegisterNodes,
syscall_hooks: HookContainer<dyn Fn()>,
violation_hooks: HookContainer<dyn Fn(u64, u8, bool) -> bool>,
execution_hooks: Rc<RefCell<HookContainer<dyn Fn(u64)>>>,
}
pub struct MmioHandler {
@@ -133,11 +170,26 @@ impl icicle_cpu::mem::IoMemory for MmioHandler {
impl IcicleEmulator {
pub fn new() -> Self {
let virtual_machine = create_x64_vm();
let mut virtual_machine = create_x64_vm();
let exec_hooks: Rc<RefCell<HookContainer<dyn Fn(u64)>>> = Rc::new(RefCell::new(HookContainer::new()));
let exec_hooks_clone = Rc::clone(&exec_hooks);
let hook = icicle_cpu::InstHook::new(move |_: &mut icicle_cpu::Cpu, addr: u64| {
for (_key, func) in exec_hooks_clone.borrow().get_hooks() {
func(addr);
}
});
let hook = virtual_machine.cpu.add_hook(hook);
virtual_machine.add_injector(InstructionHookInjector { hook });
Self {
reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch),
vm: virtual_machine,
syscall_hooks: HookContainer::new(),
violation_hooks: HookContainer::new(),
execution_hooks: exec_hooks,
}
}
@@ -145,29 +197,80 @@ impl IcicleEmulator {
return &mut self.vm.cpu.mem;
}
pub fn start(&mut self) {
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();
let invoke_syscall = match reason {
icicle_vm::VmExit::UnhandledException((code, _)) => {
code == icicle_cpu::ExceptionCode::Syscall
}
_ => false,
match reason {
icicle_vm::VmExit::InstructionLimit => break,
icicle_vm::VmExit::UnhandledException((code, value)) => {
let continue_execution = self.handle_exception(code, value);
if !continue_execution {
break
}
},
_ => break,
};
if !invoke_syscall {
break;
}
for (_key, func) in self.syscall_hooks.get_hooks() {
func();
}
self.vm.cpu.write_pc(self.vm.cpu.read_pc() + 2);
}
}
fn handle_exception(&mut self, code: ExceptionCode, value: u64) -> bool {
let continue_execution = match code {
ExceptionCode::Syscall => self.handle_syscall(),
ExceptionCode::ReadPerm => self.handle_violation(value, FOREIGN_READ, false),
ExceptionCode::WritePerm => self.handle_violation(value, FOREIGN_WRITE, false),
ExceptionCode::ReadUnmapped => self.handle_violation(value, FOREIGN_READ, true),
ExceptionCode::WriteUnmapped => self.handle_violation(value, FOREIGN_WRITE, true),
ExceptionCode::ExecViolation => self.handle_violation(value, FOREIGN_EXEC, true),
_ => false
};
return continue_execution;
}
fn handle_violation(&mut self, address: u64, permission: u8, unmapped: bool) -> bool {
let hooks = &self.violation_hooks.get_hooks();
if hooks.is_empty() {
return false;
}
let mut continue_execution = true;
for (_key, func) in self.violation_hooks.get_hooks() {
continue_execution &= func(address, permission, unmapped );
}
return continue_execution;
}
fn handle_syscall(&mut self) -> bool{
for (_key, func) in self.syscall_hooks.get_hooks() {
func();
}
self.vm.cpu.write_pc(self.vm.cpu.read_pc() + 2);
return true;
}
pub fn stop(&mut self) {
self.vm.icount_limit = 0;
}
pub fn add_violation_hook(&mut self, callback: Box<dyn Fn(u64, u8, bool) -> bool>) -> u32 {
let hook_id = self.violation_hooks.add_hook(callback);
return qualify_hook_id(hook_id, HookType::Violation);
}
pub fn add_execution_hook(&mut self, callback: Box<dyn Fn(u64)>) -> u32 {
let hook_id = self.execution_hooks.borrow_mut().add_hook(callback);
return qualify_hook_id(hook_id, HookType::Execute);
}
pub fn add_syscall_hook(&mut self, callback: Box<dyn Fn()>) -> u32 {
let hook_id = self.syscall_hooks.add_hook(callback);
return qualify_hook_id(hook_id, HookType::Syscall);
@@ -178,6 +281,8 @@ impl IcicleEmulator {
match hook_type {
HookType::Syscall => self.syscall_hooks.remove_hook(hook_id),
HookType::Violation => self.violation_hooks.remove_hook(hook_id),
HookType::Execute => self.execution_hooks.borrow_mut().remove_hook(hook_id),
_ => {}
}
}

View File

@@ -20,17 +20,27 @@ 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);
}
}
#[unsafe(no_mangle)]
pub fn icicle_stop(ptr: *mut c_void) {
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
emulator.stop();
}
}
type RawFunction = extern "C" fn(*mut c_void);
type PtrFunction = extern "C" fn(*mut c_void, u64);
type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize);
type MmioReadFunction = extern "C" fn(*mut c_void, u64, usize, *mut c_void);
type MmioWriteFunction = extern "C" fn(*mut c_void, u64, usize, *const c_void);
type ViolationFunction = extern "C" fn(*mut c_void, u64, u8, i32) -> i32;
#[unsafe(no_mangle)]
pub fn icicle_map_mmio(
@@ -107,7 +117,11 @@ pub fn icicle_save_registers(ptr: *mut c_void, accessor: DataFunction, accessor_
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
let registers = emulator.save_registers();
accessor(accessor_data, registers.as_ptr() as *const c_void, registers.len());
accessor(
accessor_data,
registers.as_ptr() as *const c_void,
registers.len(),
);
}
}
@@ -131,10 +145,35 @@ pub fn icicle_read_memory(ptr: *mut c_void, address: u64, data: *mut c_void, siz
}
#[unsafe(no_mangle)]
pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: RawFunction, data: *mut c_void) {
pub fn icicle_add_violation_hook(ptr: *mut c_void, callback: ViolationFunction, data: *mut c_void) -> u32 {
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
emulator.add_syscall_hook(Box::new(move || callback(data)));
return emulator.add_violation_hook(Box::new(
move |address: u64, permission: u8, unmapped: bool| {
let result = callback(data, address, permission, to_cbool(unmapped));
if result == 0 {
return false;
}
return true;
},
));
}
}
#[unsafe(no_mangle)]
pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: RawFunction, data: *mut c_void) -> u32 {
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
return emulator.add_syscall_hook(Box::new(move || callback(data)));
}
}
#[unsafe(no_mangle)]
pub fn icicle_add_execution_hook(ptr: *mut c_void, callback: PtrFunction, data: *mut c_void) -> u32 {
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
return emulator.add_execution_hook(Box::new(move |ptr: u64| callback(data, ptr)));
}
}

View File

@@ -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;
@@ -647,7 +642,7 @@ namespace unicorn
serializer.deserialize(buffer);
}
std::vector<std::byte> save_registers() override
std::vector<std::byte> save_registers() const override
{
utils::buffer_serializer buffer{};
const uc_context_serializer serializer(this->uc_, false);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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_;

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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)
{