From baad36ccf20264f4ba031e96ba9a4aab2fceb8e9 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 7 Apr 2025 07:24:46 +0200 Subject: [PATCH] Support interrupt hooks --- src/icicle-emulator/icicle_x64_emulator.cpp | 21 +++++++++++++++------ src/icicle/src/icicle.rs | 20 +++++++++++++++++++- src/icicle/src/lib.rs | 11 +++++++++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index 77101bc5..8e6aa4b0 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -12,6 +12,7 @@ extern "C" using raw_func = void(void*); using ptr_func = void(void*, uint64_t); + using interrupt_func = void(void*, int32_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 memory_access_func = icicle_mmio_write_func; @@ -27,6 +28,7 @@ extern "C" 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*, raw_func* callback, void* data); + uint32_t icicle_add_interrupt_hook(icicle_emulator*, interrupt_func* callback, void* data); uint32_t icicle_add_execution_hook(icicle_emulator*, uint64_t address, ptr_func* callback, void* data); uint32_t icicle_add_generic_execution_hook(icicle_emulator*, ptr_func* callback, void* data); uint32_t icicle_add_violation_hook(icicle_emulator*, violation_func* callback, void* data); @@ -260,10 +262,17 @@ namespace icicle emulator_hook* hook_interrupt(interrupt_hook_callback callback) override { - // TODO - (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 int32_t code) { + const auto& func = *static_cast(user); + func(code); + }; + + const auto id = icicle_add_interrupt_hook(this->emu_, wrapper, ptr); + this->hooks_[id] = std::move(obj); + + return wrap_hook(id); } emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) override @@ -292,7 +301,7 @@ namespace icicle auto object = make_function_object(std::move(callback)); auto* ptr = object.get(); auto* wrapper = +[](void* user, const uint64_t addr) { - auto& func = *static_cast(user); + const auto& func = *static_cast(user); (func)(addr); }; @@ -307,7 +316,7 @@ namespace icicle auto object = make_function_object(std::move(callback)); auto* ptr = object.get(); auto* wrapper = +[](void* user, const uint64_t addr) { - auto& func = *static_cast(user); + const auto& func = *static_cast(user); (func)(addr); }; diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index ac0e4c9c..c601ce09 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -49,6 +49,7 @@ enum HookType { ExecuteGeneric, ExecuteSpecific, Violation, + Interrupt, Unknown, } @@ -216,6 +217,7 @@ pub struct IcicleEmulator { vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, + interrupt_hooks: HookContainer, violation_hooks: HookContainer bool>, execution_hooks: Rc>, stop: Rc>, @@ -287,6 +289,7 @@ impl IcicleEmulator { reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch), vm: virtual_machine, syscall_hooks: HookContainer::new(), + interrupt_hooks: HookContainer::new(), violation_hooks: HookContainer::new(), execution_hooks: exec_hooks, } @@ -326,6 +329,14 @@ impl IcicleEmulator { } } + fn handle_interrupt(&self, code: i32) -> bool { + for (_key, func) in self.interrupt_hooks.get_hooks() { + func(code); + } + + return true; + } + fn handle_exception(&mut self, code: ExceptionCode, value: u64) -> bool { let continue_execution = match code { ExceptionCode::Syscall => self.handle_syscall(), @@ -333,7 +344,8 @@ impl IcicleEmulator { 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), + ExceptionCode::InvalidInstruction => self.handle_interrupt(6), + ExceptionCode::DivisionException => self.handle_interrupt(0), _ => false, }; @@ -392,6 +404,11 @@ impl IcicleEmulator { return qualify_hook_id(hook_id, HookType::Syscall); } + pub fn add_interrupt_hook(&mut self, callback: Box) -> u32 { + let hook_id = self.interrupt_hooks.add_hook(callback); + return qualify_hook_id(hook_id, HookType::Interrupt); + } + pub fn add_read_hook( &mut self, start: u64, @@ -426,6 +443,7 @@ impl IcicleEmulator { match hook_type { HookType::Syscall => self.syscall_hooks.remove_hook(hook_id), HookType::Violation => self.violation_hooks.remove_hook(hook_id), + HookType::Interrupt => self.interrupt_hooks.remove_hook(hook_id), HookType::ExecuteGeneric => self.execution_hooks.borrow_mut().remove_generic_hook(hook_id), HookType::ExecuteSpecific => self.execution_hooks.borrow_mut().remove_specific_hook(hook_id), HookType::Read => {self.get_mem().remove_read_after_hook(hook_id);()}, diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index a494b806..19706c0f 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -41,6 +41,7 @@ type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize); type MmioReadFunction = extern "C" fn(*mut c_void, u64, *mut c_void, usize); type MmioWriteFunction = extern "C" fn(*mut c_void, u64, *const c_void, usize); type ViolationFunction = extern "C" fn(*mut c_void, u64, u8, i32) -> i32; +type InterruptFunction = extern "C" fn(*mut c_void, i32); type MemoryAccessFunction = MmioWriteFunction; #[unsafe(no_mangle)] @@ -165,6 +166,16 @@ pub fn icicle_read_memory(ptr: *mut c_void, address: u64, data: *mut c_void, siz } } +#[unsafe(no_mangle)] +pub fn icicle_add_interrupt_hook(ptr: *mut c_void, callback: InterruptFunction, data: *mut c_void) -> u32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + return emulator.add_interrupt_hook(Box::new( + move |code: i32| callback(data, code), + )); + } +} + #[unsafe(no_mangle)] pub fn icicle_add_violation_hook(ptr: *mut c_void, callback: ViolationFunction, data: *mut c_void) -> u32 { unsafe {