Support interrupt hooks

This commit is contained in:
Maurice Heumann
2025-04-07 07:24:46 +02:00
parent 1ed997445d
commit baad36ccf2
3 changed files with 45 additions and 7 deletions

View File

@@ -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<decltype(ptr)>(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<decltype(ptr)>(user);
const auto& func = *static_cast<decltype(ptr)>(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<decltype(ptr)>(user);
const auto& func = *static_cast<decltype(ptr)>(user);
(func)(addr);
};

View File

@@ -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<dyn Fn()>,
interrupt_hooks: HookContainer<dyn Fn(i32)>,
violation_hooks: HookContainer<dyn Fn(u64, u8, bool) -> bool>,
execution_hooks: Rc<RefCell<ExecutionHooks>>,
stop: Rc<RefCell<bool>>,
@@ -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<dyn Fn(i32)>) -> 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);()},

View File

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