HookId trait and types in libafl_qemu (#1796)

* libafl_qemu fix remove_hook

* libafl_qemu specialize hooks into separated types

* libafl_qemu generalize HookState to allow any HookId implementation

* fmt: external C qemu hook functions

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
This commit is contained in:
Rubens Brandão 2024-02-01 06:55:55 -03:00 committed by GitHub
parent 13dd1cc4ec
commit c96d103b37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 186 additions and 123 deletions

View File

@ -832,8 +832,45 @@ impl CPU {
} }
} }
#[derive(Clone, Copy, PartialEq, Debug)] pub trait HookId {
pub struct HookId(pub(crate) usize); fn remove(&self, invalidate_block: bool) -> bool;
}
macro_rules! create_hook_id {
($name:ident, $sys:ident, true) => {
paste::paste! {
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct [<$name HookId>](pub(crate) usize);
impl HookId for [<$name HookId>] {
fn remove(&self, invalidate_block: bool) -> bool {
unsafe { libafl_qemu_sys::$sys(self.0, invalidate_block.into()) != 0 }
}
}
}
};
($name:ident, $sys:ident, false) => {
paste::paste! {
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct [<$name HookId>](pub(crate) usize);
impl HookId for [<$name HookId>] {
fn remove(&self, _invalidate_block: bool) -> bool {
unsafe { libafl_qemu_sys::$sys(self.0) != 0 }
}
}
}
};
}
create_hook_id!(Instruction, libafl_qemu_remove_hook, true);
create_hook_id!(Backdoor, libafl_qemu_remove_backdoor_hook, true);
create_hook_id!(Edge, libafl_qemu_remove_edge_hook, true);
create_hook_id!(Block, libafl_qemu_remove_block_hook, true);
create_hook_id!(Read, libafl_qemu_remove_read_hook, true);
create_hook_id!(Write, libafl_qemu_remove_write_hook, true);
create_hook_id!(Cmp, libafl_qemu_remove_cmp_hook, true);
create_hook_id!(PreSyscall, libafl_qemu_remove_pre_syscall_hook, false);
create_hook_id!(PostSyscall, libafl_qemu_remove_post_syscall_hook, false);
create_hook_id!(NewThread, libafl_qemu_remove_new_thread_hook, false);
use std::pin::Pin; use std::pin::Pin;
@ -1347,7 +1384,7 @@ impl Emulator {
addr: GuestAddr, addr: GuestAddr,
callback: extern "C" fn(T, GuestAddr), callback: extern "C" fn(T, GuestAddr),
invalidate_block: bool, invalidate_block: bool,
) -> HookId { ) -> InstructionHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback); let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback);
@ -1357,13 +1394,13 @@ impl Emulator {
data, data,
i32::from(invalidate_block), i32::from(invalidate_block),
); );
HookId(num) InstructionHookId(num)
} }
} }
#[must_use] #[must_use]
pub fn remove_hook(&self, id: HookId, invalidate_block: bool) -> bool { pub fn remove_hook(&self, id: impl HookId, invalidate_block: bool) -> bool {
unsafe { libafl_qemu_sys::libafl_qemu_remove_hook(id.0, i32::from(invalidate_block)) != 0 } id.remove(invalidate_block)
} }
#[must_use] #[must_use]
@ -1378,14 +1415,14 @@ impl Emulator {
data: T, data: T,
gen: Option<extern "C" fn(T, GuestAddr, GuestAddr) -> u64>, gen: Option<extern "C" fn(T, GuestAddr, GuestAddr) -> u64>,
exec: Option<extern "C" fn(T, u64)>, exec: Option<extern "C" fn(T, u64)>,
) -> HookId { ) -> EdgeHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let gen: Option<extern "C" fn(u64, GuestAddr, GuestAddr) -> u64> = let gen: Option<extern "C" fn(u64, GuestAddr, GuestAddr) -> u64> =
core::mem::transmute(gen); core::mem::transmute(gen);
let exec: Option<extern "C" fn(u64, u64)> = core::mem::transmute(exec); let exec: Option<extern "C" fn(u64, u64)> = core::mem::transmute(exec);
let num = libafl_qemu_sys::libafl_add_edge_hook(gen, exec, data); let num = libafl_qemu_sys::libafl_add_edge_hook(gen, exec, data);
HookId(num) EdgeHookId(num)
} }
} }
@ -1395,7 +1432,7 @@ impl Emulator {
gen: Option<extern "C" fn(T, GuestAddr) -> u64>, gen: Option<extern "C" fn(T, GuestAddr) -> u64>,
post_gen: Option<extern "C" fn(T, GuestAddr, GuestUsize)>, post_gen: Option<extern "C" fn(T, GuestAddr, GuestUsize)>,
exec: Option<extern "C" fn(T, u64)>, exec: Option<extern "C" fn(T, u64)>,
) -> HookId { ) -> BlockHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let gen: Option<extern "C" fn(u64, GuestAddr) -> u64> = core::mem::transmute(gen); let gen: Option<extern "C" fn(u64, GuestAddr) -> u64> = core::mem::transmute(gen);
@ -1403,7 +1440,7 @@ impl Emulator {
core::mem::transmute(post_gen); core::mem::transmute(post_gen);
let exec: Option<extern "C" fn(u64, u64)> = core::mem::transmute(exec); let exec: Option<extern "C" fn(u64, u64)> = core::mem::transmute(exec);
let num = libafl_qemu_sys::libafl_add_block_hook(gen, post_gen, exec, data); let num = libafl_qemu_sys::libafl_add_block_hook(gen, post_gen, exec, data);
HookId(num) BlockHookId(num)
} }
} }
@ -1416,7 +1453,7 @@ impl Emulator {
exec4: Option<extern "C" fn(T, u64, GuestAddr)>, exec4: Option<extern "C" fn(T, u64, GuestAddr)>,
exec8: Option<extern "C" fn(T, u64, GuestAddr)>, exec8: Option<extern "C" fn(T, u64, GuestAddr)>,
exec_n: Option<extern "C" fn(T, u64, GuestAddr, usize)>, exec_n: Option<extern "C" fn(T, u64, GuestAddr, usize)>,
) -> HookId { ) -> ReadHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let gen: Option<extern "C" fn(u64, GuestAddr, libafl_qemu_sys::MemOpIdx) -> u64> = let gen: Option<extern "C" fn(u64, GuestAddr, libafl_qemu_sys::MemOpIdx) -> u64> =
@ -1430,7 +1467,7 @@ impl Emulator {
let num = libafl_qemu_sys::libafl_add_read_hook( let num = libafl_qemu_sys::libafl_add_read_hook(
gen, exec1, exec2, exec4, exec8, exec_n, data, gen, exec1, exec2, exec4, exec8, exec_n, data,
); );
HookId(num) ReadHookId(num)
} }
} }
@ -1444,7 +1481,7 @@ impl Emulator {
exec4: Option<extern "C" fn(T, u64, GuestAddr)>, exec4: Option<extern "C" fn(T, u64, GuestAddr)>,
exec8: Option<extern "C" fn(T, u64, GuestAddr)>, exec8: Option<extern "C" fn(T, u64, GuestAddr)>,
exec_n: Option<extern "C" fn(T, u64, GuestAddr, usize)>, exec_n: Option<extern "C" fn(T, u64, GuestAddr, usize)>,
) -> HookId { ) -> WriteHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let gen: Option<extern "C" fn(u64, GuestAddr, libafl_qemu_sys::MemOpIdx) -> u64> = let gen: Option<extern "C" fn(u64, GuestAddr, libafl_qemu_sys::MemOpIdx) -> u64> =
@ -1458,7 +1495,7 @@ impl Emulator {
let num = libafl_qemu_sys::libafl_add_write_hook( let num = libafl_qemu_sys::libafl_add_write_hook(
gen, exec1, exec2, exec4, exec8, exec_n, data, gen, exec1, exec2, exec4, exec8, exec_n, data,
); );
HookId(num) WriteHookId(num)
} }
} }
@ -1470,7 +1507,7 @@ impl Emulator {
exec2: Option<extern "C" fn(T, u64, u16, u16)>, exec2: Option<extern "C" fn(T, u64, u16, u16)>,
exec4: Option<extern "C" fn(T, u64, u32, u32)>, exec4: Option<extern "C" fn(T, u64, u32, u32)>,
exec8: Option<extern "C" fn(T, u64, u64, u64)>, exec8: Option<extern "C" fn(T, u64, u64, u64)>,
) -> HookId { ) -> CmpHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let gen: Option<extern "C" fn(u64, GuestAddr, usize) -> u64> = let gen: Option<extern "C" fn(u64, GuestAddr, usize) -> u64> =
@ -1480,7 +1517,7 @@ impl Emulator {
let exec4: Option<extern "C" fn(u64, u64, u32, u32)> = core::mem::transmute(exec4); let exec4: Option<extern "C" fn(u64, u64, u32, u32)> = core::mem::transmute(exec4);
let exec8: Option<extern "C" fn(u64, u64, u64, u64)> = core::mem::transmute(exec8); let exec8: Option<extern "C" fn(u64, u64, u64, u64)> = core::mem::transmute(exec8);
let num = libafl_qemu_sys::libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data); let num = libafl_qemu_sys::libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data);
HookId(num) CmpHookId(num)
} }
} }
@ -1488,12 +1525,12 @@ impl Emulator {
&self, &self,
data: T, data: T,
callback: extern "C" fn(T, GuestAddr), callback: extern "C" fn(T, GuestAddr),
) -> HookId { ) -> BackdoorHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback); let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback);
let num = libafl_qemu_sys::libafl_add_backdoor_hook(Some(callback), data); let num = libafl_qemu_sys::libafl_add_backdoor_hook(Some(callback), data);
HookId(num) BackdoorHookId(num)
} }
} }
@ -1514,7 +1551,7 @@ impl Emulator {
GuestAddr, GuestAddr,
GuestAddr, GuestAddr,
) -> SyscallHookResult, ) -> SyscallHookResult,
) -> HookId { ) -> PreSyscallHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let callback: extern "C" fn( let callback: extern "C" fn(
@ -1530,7 +1567,7 @@ impl Emulator {
GuestAddr, GuestAddr,
) -> libafl_qemu_sys::syshook_ret = core::mem::transmute(callback); ) -> libafl_qemu_sys::syshook_ret = core::mem::transmute(callback);
let num = libafl_qemu_sys::libafl_add_pre_syscall_hook(Some(callback), data); let num = libafl_qemu_sys::libafl_add_pre_syscall_hook(Some(callback), data);
HookId(num) PreSyscallHookId(num)
} }
} }
@ -1552,7 +1589,7 @@ impl Emulator {
GuestAddr, GuestAddr,
GuestAddr, GuestAddr,
) -> GuestAddr, ) -> GuestAddr,
) -> HookId { ) -> PostSyscallHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let callback: extern "C" fn( let callback: extern "C" fn(
@ -1569,7 +1606,7 @@ impl Emulator {
GuestAddr, GuestAddr,
) -> GuestAddr = core::mem::transmute(callback); ) -> GuestAddr = core::mem::transmute(callback);
let num = libafl_qemu_sys::libafl_add_post_syscall_hook(Some(callback), data); let num = libafl_qemu_sys::libafl_add_post_syscall_hook(Some(callback), data);
HookId(num) PostSyscallHookId(num)
} }
} }
@ -1578,12 +1615,12 @@ impl Emulator {
&self, &self,
data: T, data: T,
callback: extern "C" fn(T, tid: u32) -> bool, callback: extern "C" fn(T, tid: u32) -> bool,
) -> HookId { ) -> NewThreadHookId {
unsafe { unsafe {
let data: u64 = data.into().0; let data: u64 = data.into().0;
let callback: extern "C" fn(u64, u32) -> bool = core::mem::transmute(callback); let callback: extern "C" fn(u64, u32) -> bool = core::mem::transmute(callback);
let num = libafl_qemu_sys::libafl_add_new_thread_hook(Some(callback), data); let num = libafl_qemu_sys::libafl_add_new_thread_hook(Some(callback), data);
HookId(num) NewThreadHookId(num)
} }
} }

View File

@ -13,9 +13,11 @@ use libafl::{executors::hooks::inprocess::inprocess_get_state, inputs::UsesInput
pub use crate::emu::SyscallHookResult; pub use crate::emu::SyscallHookResult;
use crate::{ use crate::{
emu::{Emulator, FatPtr, HookId, MemAccessInfo, SKIP_EXEC_HOOK}, emu::{Emulator, FatPtr, MemAccessInfo, SKIP_EXEC_HOOK},
helper::QemuHelperTuple, helper::QemuHelperTuple,
GuestAddr, GuestUsize, BackdoorHookId, BlockHookId, CmpHookId, EdgeHookId, GuestAddr, GuestUsize, HookId,
InstructionHookId, NewThreadHookId, PostSyscallHookId, PreSyscallHookId, ReadHookId,
WriteHookId,
}; };
/* /*
@ -38,8 +40,8 @@ pub(crate) enum HookRepr {
Empty, Empty,
} }
pub struct HookState<const N: usize> { pub struct HookState<const N: usize, H: HookId> {
id: HookId, id: H,
gen: HookRepr, gen: HookRepr,
post_gen: HookRepr, post_gen: HookRepr,
execs: [HookRepr; N], execs: [HookRepr; N],
@ -153,9 +155,9 @@ macro_rules! create_wrapper {
} }
macro_rules! create_gen_wrapper { macro_rules! create_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal) => { ($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal, $hook_id:ident) => {
paste::paste! { paste::paste! {
extern "C" fn [<$name _gen_hook_wrapper>]<QT, S>(hook: &mut HookState<{ $execs }>, $($param: $param_type),*) -> $ret_type extern "C" fn [<$name _gen_hook_wrapper>]<QT, S>(hook: &mut HookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
where where
S: UsesInput, S: UsesInput,
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
@ -183,9 +185,9 @@ macro_rules! create_gen_wrapper {
} }
macro_rules! create_post_gen_wrapper { macro_rules! create_post_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal) => { ($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal, $hook_id:ident) => {
paste::paste! { paste::paste! {
extern "C" fn [<$name _post_gen_hook_wrapper>]<QT, S>(hook: &mut HookState<{ $execs }>, $($param: $param_type),*) extern "C" fn [<$name _post_gen_hook_wrapper>]<QT, S>(hook: &mut HookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where where
S: UsesInput, S: UsesInput,
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
@ -213,9 +215,9 @@ macro_rules! create_post_gen_wrapper {
} }
macro_rules! create_exec_wrapper { macro_rules! create_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal) => { ($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal, $hook_id:ident) => {
paste::paste! { paste::paste! {
extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<QT, S>(hook: &mut HookState<{ $execs }>, $($param: $param_type),*) extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<QT, S>(hook: &mut HookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where where
S: UsesInput, S: UsesInput,
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
@ -240,13 +242,13 @@ macro_rules! create_exec_wrapper {
} }
} }
static mut GENERIC_HOOKS: Vec<(HookId, FatPtr)> = vec![]; static mut GENERIC_HOOKS: Vec<(InstructionHookId, FatPtr)> = vec![];
create_wrapper!(generic, (pc: GuestAddr)); create_wrapper!(generic, (pc: GuestAddr));
static mut BACKDOOR_HOOKS: Vec<(HookId, FatPtr)> = vec![]; static mut BACKDOOR_HOOKS: Vec<(BackdoorHookId, FatPtr)> = vec![];
create_wrapper!(backdoor, (pc: GuestAddr)); create_wrapper!(backdoor, (pc: GuestAddr));
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
static mut PRE_SYSCALL_HOOKS: Vec<(HookId, FatPtr)> = vec![]; static mut PRE_SYSCALL_HOOKS: Vec<(PreSyscallHookId, FatPtr)> = vec![];
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
create_wrapper!(pre_syscall, (sys_num: i32, create_wrapper!(pre_syscall, (sys_num: i32,
a0: GuestAddr, a0: GuestAddr,
@ -258,7 +260,7 @@ create_wrapper!(pre_syscall, (sys_num: i32,
a6: GuestAddr, a6: GuestAddr,
a7: GuestAddr), SyscallHookResult); a7: GuestAddr), SyscallHookResult);
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
static mut POST_SYSCALL_HOOKS: Vec<(HookId, FatPtr)> = vec![]; static mut POST_SYSCALL_HOOKS: Vec<(PostSyscallHookId, FatPtr)> = vec![];
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
create_wrapper!(post_syscall, (res: GuestAddr, sys_num: i32, create_wrapper!(post_syscall, (res: GuestAddr, sys_num: i32,
a0: GuestAddr, a0: GuestAddr,
@ -270,41 +272,41 @@ create_wrapper!(post_syscall, (res: GuestAddr, sys_num: i32,
a6: GuestAddr, a6: GuestAddr,
a7: GuestAddr), GuestAddr); a7: GuestAddr), GuestAddr);
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
static mut NEW_THREAD_HOOKS: Vec<(HookId, FatPtr)> = vec![]; static mut NEW_THREAD_HOOKS: Vec<(NewThreadHookId, FatPtr)> = vec![];
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
create_wrapper!(new_thread, (tid: u32), bool); create_wrapper!(new_thread, (tid: u32), bool);
static mut EDGE_HOOKS: Vec<HookState<1>> = vec![]; static mut EDGE_HOOKS: Vec<HookState<1, EdgeHookId>> = vec![];
create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1); create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId);
create_exec_wrapper!(edge, (id: u64), 0, 1); create_exec_wrapper!(edge, (id: u64), 0, 1, EdgeHookId);
static mut BLOCK_HOOKS: Vec<HookState<1>> = vec![]; static mut BLOCK_HOOKS: Vec<HookState<1, BlockHookId>> = vec![];
create_gen_wrapper!(block, (addr: GuestAddr), u64, 1); create_gen_wrapper!(block, (addr: GuestAddr), u64, 1, BlockHookId);
create_post_gen_wrapper!(block, (addr: GuestAddr, len: GuestUsize), 1); create_post_gen_wrapper!(block, (addr: GuestAddr, len: GuestUsize), 1, BlockHookId);
create_exec_wrapper!(block, (id: u64), 0, 1); create_exec_wrapper!(block, (id: u64), 0, 1, BlockHookId);
static mut READ_HOOKS: Vec<HookState<5>> = vec![]; static mut READ_HOOKS: Vec<HookState<5, ReadHookId>> = vec![];
create_gen_wrapper!(read, (pc: GuestAddr, info: MemAccessInfo), u64, 5); create_gen_wrapper!(read, (pc: GuestAddr, info: MemAccessInfo), u64, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 0, 5); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 0, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 1, 5); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 1, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 2, 5); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 2, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 3, 5); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 3, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr, size: usize), 4, 5); create_exec_wrapper!(read, (id: u64, addr: GuestAddr, size: usize), 4, 5, ReadHookId);
static mut WRITE_HOOKS: Vec<HookState<5>> = vec![]; static mut WRITE_HOOKS: Vec<HookState<5, WriteHookId>> = vec![];
create_gen_wrapper!(write, (pc: GuestAddr, info: MemAccessInfo), u64, 5); create_gen_wrapper!(write, (pc: GuestAddr, info: MemAccessInfo), u64, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 0, 5); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 0, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 1, 5); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 1, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 2, 5); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 2, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 3, 5); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 3, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr, size: usize), 4, 5); create_exec_wrapper!(write, (id: u64, addr: GuestAddr, size: usize), 4, 5, WriteHookId);
static mut CMP_HOOKS: Vec<HookState<4>> = vec![]; static mut CMP_HOOKS: Vec<HookState<4, CmpHookId>> = vec![];
create_gen_wrapper!(cmp, (pc: GuestAddr, size: usize), u64, 4); create_gen_wrapper!(cmp, (pc: GuestAddr, size: usize), u64, 4, CmpHookId);
create_exec_wrapper!(cmp, (id: u64, v0: u8, v1: u8), 0, 4); create_exec_wrapper!(cmp, (id: u64, v0: u8, v1: u8), 0, 4, CmpHookId);
create_exec_wrapper!(cmp, (id: u64, v0: u16, v1: u16), 1, 4); create_exec_wrapper!(cmp, (id: u64, v0: u16, v1: u16), 1, 4, CmpHookId);
create_exec_wrapper!(cmp, (id: u64, v0: u32, v1: u32), 2, 4); create_exec_wrapper!(cmp, (id: u64, v0: u32, v1: u32), 2, 4, CmpHookId);
create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4); create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4, CmpHookId);
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
static mut CRASH_HOOKS: Vec<HookRepr> = vec![]; static mut CRASH_HOOKS: Vec<HookRepr> = vec![];
@ -422,7 +424,7 @@ where
extern "C" fn(*const (), pc: GuestAddr), extern "C" fn(*const (), pc: GuestAddr),
>, >,
invalidate_block: bool, invalidate_block: bool,
) -> HookId { ) -> InstructionHookId {
match hook { match hook {
Hook::Function(f) => self.instruction_function(addr, f, invalidate_block), Hook::Function(f) => self.instruction_function(addr, f, invalidate_block),
Hook::Closure(c) => self.instruction_closure(addr, c, invalidate_block), Hook::Closure(c) => self.instruction_closure(addr, c, invalidate_block),
@ -430,7 +432,7 @@ where
let z: *const () = ptr::null::<()>(); let z: *const () = ptr::null::<()>();
self.emulator.set_hook(z, addr, r, invalidate_block) self.emulator.set_hook(z, addr, r, invalidate_block)
} }
Hook::Empty => HookId(0), // TODO error type Hook::Empty => InstructionHookId(0), // TODO error type
} }
} }
@ -439,7 +441,7 @@ where
addr: GuestAddr, addr: GuestAddr,
hook: fn(&mut Self, Option<&mut S>, GuestAddr), hook: fn(&mut Self, Option<&mut S>, GuestAddr),
invalidate_block: bool, invalidate_block: bool,
) -> HookId { ) -> InstructionHookId {
unsafe { unsafe {
self.emulator.set_hook( self.emulator.set_hook(
transmute(hook), transmute(hook),
@ -455,10 +457,10 @@ where
addr: GuestAddr, addr: GuestAddr,
hook: Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, hook: Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>,
invalidate_block: bool, invalidate_block: bool,
) -> HookId { ) -> InstructionHookId {
unsafe { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
GENERIC_HOOKS.push((HookId(0), fat)); GENERIC_HOOKS.push((InstructionHookId(0), fat));
let id = self.emulator.set_hook( let id = self.emulator.set_hook(
&mut ((*addr_of_mut!(GENERIC_HOOKS)).last_mut().unwrap().1), &mut ((*addr_of_mut!(GENERIC_HOOKS)).last_mut().unwrap().1),
addr, addr,
@ -489,20 +491,24 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64)>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64)>,
extern "C" fn(*const (), id: u64), extern "C" fn(*const (), id: u64),
>, >,
) -> HookId { ) -> EdgeHookId {
unsafe { unsafe {
let gen = get_raw_hook!( let gen = get_raw_hook!(
generation_hook, generation_hook,
edge_gen_hook_wrapper::<QT, S>, edge_gen_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1>, src: GuestAddr, dest: GuestAddr) -> u64 extern "C" fn(
&mut HookState<1, EdgeHookId>,
src: GuestAddr,
dest: GuestAddr,
) -> u64
); );
let exec = get_raw_hook!( let exec = get_raw_hook!(
execution_hook, execution_hook,
edge_0_exec_hook_wrapper::<QT, S>, edge_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1>, id: u64) extern "C" fn(&mut HookState<1, EdgeHookId>, id: u64)
); );
EDGE_HOOKS.push(HookState { EDGE_HOOKS.push(HookState {
id: HookId(0), id: EdgeHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
execs: [hook_to_repr!(execution_hook)], execs: [hook_to_repr!(execution_hook)],
@ -532,25 +538,29 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64)>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64)>,
extern "C" fn(*const (), id: u64), extern "C" fn(*const (), id: u64),
>, >,
) -> HookId { ) -> BlockHookId {
unsafe { unsafe {
let gen = get_raw_hook!( let gen = get_raw_hook!(
generation_hook, generation_hook,
block_gen_hook_wrapper::<QT, S>, block_gen_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1>, pc: GuestAddr) -> u64 extern "C" fn(&mut HookState<1, BlockHookId>, pc: GuestAddr) -> u64
); );
let postgen = get_raw_hook!( let postgen = get_raw_hook!(
post_generation_hook, post_generation_hook,
block_post_gen_hook_wrapper::<QT, S>, block_post_gen_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1>, pc: GuestAddr, block_length: GuestUsize) extern "C" fn(
&mut HookState<1, BlockHookId>,
pc: GuestAddr,
block_length: GuestUsize,
)
); );
let exec = get_raw_hook!( let exec = get_raw_hook!(
execution_hook, execution_hook,
block_0_exec_hook_wrapper::<QT, S>, block_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1>, id: u64) extern "C" fn(&mut HookState<1, BlockHookId>, id: u64)
); );
BLOCK_HOOKS.push(HookState { BLOCK_HOOKS.push(HookState {
id: HookId(0), id: BlockHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: hook_to_repr!(post_generation_hook), post_gen: hook_to_repr!(post_generation_hook),
execs: [hook_to_repr!(execution_hook)], execs: [hook_to_repr!(execution_hook)],
@ -603,40 +613,44 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr, usize)>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr, usize)>,
extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize), extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize),
>, >,
) -> HookId { ) -> ReadHookId {
unsafe { unsafe {
let gen = get_raw_hook!( let gen = get_raw_hook!(
generation_hook, generation_hook,
read_gen_hook_wrapper::<QT, S>, read_gen_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, pc: GuestAddr, info: MemAccessInfo) -> u64 extern "C" fn(
&mut HookState<5, ReadHookId>,
pc: GuestAddr,
info: MemAccessInfo,
) -> u64
); );
let exec1 = get_raw_hook!( let exec1 = get_raw_hook!(
execution_hook_1, execution_hook_1,
read_0_exec_hook_wrapper::<QT, S>, read_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
); );
let exec2 = get_raw_hook!( let exec2 = get_raw_hook!(
execution_hook_2, execution_hook_2,
read_1_exec_hook_wrapper::<QT, S>, read_1_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
); );
let exec4 = get_raw_hook!( let exec4 = get_raw_hook!(
execution_hook_4, execution_hook_4,
read_2_exec_hook_wrapper::<QT, S>, read_2_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
); );
let exec8 = get_raw_hook!( let exec8 = get_raw_hook!(
execution_hook_8, execution_hook_8,
read_3_exec_hook_wrapper::<QT, S>, read_3_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr)
); );
let execn = get_raw_hook!( let execn = get_raw_hook!(
execution_hook_n, execution_hook_n,
read_4_exec_hook_wrapper::<QT, S>, read_4_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr, size: usize) extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr, size: usize)
); );
READ_HOOKS.push(HookState { READ_HOOKS.push(HookState {
id: HookId(0), id: ReadHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
execs: [ execs: [
@ -701,40 +715,49 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr, usize)>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr, usize)>,
extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize), extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize),
>, >,
) -> HookId { ) -> WriteHookId {
unsafe { unsafe {
let gen = get_raw_hook!( let gen = get_raw_hook!(
generation_hook, generation_hook,
write_gen_hook_wrapper::<QT, S>, write_gen_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, pc: GuestAddr, info: MemAccessInfo) -> u64 extern "C" fn(
&mut HookState<5, WriteHookId>,
pc: GuestAddr,
info: MemAccessInfo,
) -> u64
); );
let exec1 = get_raw_hook!( let exec1 = get_raw_hook!(
execution_hook_1, execution_hook_1,
write_0_exec_hook_wrapper::<QT, S>, write_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
); );
let exec2 = get_raw_hook!( let exec2 = get_raw_hook!(
execution_hook_2, execution_hook_2,
write_1_exec_hook_wrapper::<QT, S>, write_1_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
); );
let exec4 = get_raw_hook!( let exec4 = get_raw_hook!(
execution_hook_4, execution_hook_4,
write_2_exec_hook_wrapper::<QT, S>, write_2_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
); );
let exec8 = get_raw_hook!( let exec8 = get_raw_hook!(
execution_hook_8, execution_hook_8,
write_3_exec_hook_wrapper::<QT, S>, write_3_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) extern "C" fn(&mut HookState<5, WriteHookId>, id: u64, addr: GuestAddr)
); );
let execn = get_raw_hook!( let execn = get_raw_hook!(
execution_hook_n, execution_hook_n,
write_4_exec_hook_wrapper::<QT, S>, write_4_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr, size: usize) extern "C" fn(
&mut HookState<5, WriteHookId>,
id: u64,
addr: GuestAddr,
size: usize,
)
); );
WRITE_HOOKS.push(HookState { WRITE_HOOKS.push(HookState {
id: HookId(0), id: WriteHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
execs: [ execs: [
@ -788,35 +811,35 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64, u64, u64)>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u64, u64, u64)>,
extern "C" fn(*const (), id: u64, v0: u64, v1: u64), extern "C" fn(*const (), id: u64, v0: u64, v1: u64),
>, >,
) -> HookId { ) -> CmpHookId {
unsafe { unsafe {
let gen = get_raw_hook!( let gen = get_raw_hook!(
generation_hook, generation_hook,
cmp_gen_hook_wrapper::<QT, S>, cmp_gen_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<4>, pc: GuestAddr, size: usize) -> u64 extern "C" fn(&mut HookState<4, CmpHookId>, pc: GuestAddr, size: usize) -> u64
); );
let exec1 = get_raw_hook!( let exec1 = get_raw_hook!(
execution_hook_1, execution_hook_1,
cmp_0_exec_hook_wrapper::<QT, S>, cmp_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<4>, id: u64, v0: u8, v1: u8) extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u8, v1: u8)
); );
let exec2 = get_raw_hook!( let exec2 = get_raw_hook!(
execution_hook_2, execution_hook_2,
cmp_1_exec_hook_wrapper::<QT, S>, cmp_1_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<4>, id: u64, v0: u16, v1: u16) extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u16, v1: u16)
); );
let exec4 = get_raw_hook!( let exec4 = get_raw_hook!(
execution_hook_4, execution_hook_4,
cmp_2_exec_hook_wrapper::<QT, S>, cmp_2_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<4>, id: u64, v0: u32, v1: u32) extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u32, v1: u32)
); );
let exec8 = get_raw_hook!( let exec8 = get_raw_hook!(
execution_hook_8, execution_hook_8,
cmp_3_exec_hook_wrapper::<QT, S>, cmp_3_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<4>, id: u64, v0: u64, v1: u64) extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u64, v1: u64)
); );
CMP_HOOKS.push(HookState { CMP_HOOKS.push(HookState {
id: HookId(0), id: CmpHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
execs: [ execs: [
@ -846,7 +869,7 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>,
extern "C" fn(*const (), pc: GuestAddr), extern "C" fn(*const (), pc: GuestAddr),
>, >,
) -> HookId { ) -> BackdoorHookId {
match hook { match hook {
Hook::Function(f) => self.backdoor_function(f), Hook::Function(f) => self.backdoor_function(f),
Hook::Closure(c) => self.backdoor_closure(c), Hook::Closure(c) => self.backdoor_closure(c),
@ -854,11 +877,14 @@ where
let z: *const () = ptr::null::<()>(); let z: *const () = ptr::null::<()>();
self.emulator.add_backdoor_hook(z, r) self.emulator.add_backdoor_hook(z, r)
} }
Hook::Empty => HookId(0), // TODO error type Hook::Empty => BackdoorHookId(0), // TODO error type
} }
} }
pub fn backdoor_function(&self, hook: fn(&mut Self, Option<&mut S>, pc: GuestAddr)) -> HookId { pub fn backdoor_function(
&self,
hook: fn(&mut Self, Option<&mut S>, pc: GuestAddr),
) -> BackdoorHookId {
unsafe { unsafe {
self.emulator self.emulator
.add_backdoor_hook(transmute(hook), func_backdoor_hook_wrapper::<QT, S>) .add_backdoor_hook(transmute(hook), func_backdoor_hook_wrapper::<QT, S>)
@ -868,10 +894,10 @@ where
pub fn backdoor_closure( pub fn backdoor_closure(
&self, &self,
hook: Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, hook: Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>,
) -> HookId { ) -> BackdoorHookId {
unsafe { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
BACKDOOR_HOOKS.push((HookId(0), fat)); BACKDOOR_HOOKS.push((BackdoorHookId(0), fat));
let id = self.emulator.add_backdoor_hook( let id = self.emulator.add_backdoor_hook(
&mut ((*addr_of_mut!(BACKDOOR_HOOKS)).last_mut().unwrap().1), &mut ((*addr_of_mut!(BACKDOOR_HOOKS)).last_mut().unwrap().1),
closure_backdoor_hook_wrapper::<QT, S>, closure_backdoor_hook_wrapper::<QT, S>,
@ -927,7 +953,7 @@ where
GuestAddr, GuestAddr,
) -> SyscallHookResult, ) -> SyscallHookResult,
>, >,
) -> HookId { ) -> PreSyscallHookId {
match hook { match hook {
Hook::Function(f) => self.syscalls_function(f), Hook::Function(f) => self.syscalls_function(f),
Hook::Closure(c) => self.syscalls_closure(c), Hook::Closure(c) => self.syscalls_closure(c),
@ -935,7 +961,7 @@ where
let z: *const () = ptr::null::<()>(); let z: *const () = ptr::null::<()>();
self.emulator.add_pre_syscall_hook(z, r) self.emulator.add_pre_syscall_hook(z, r)
} }
Hook::Empty => HookId(0), // TODO error type Hook::Empty => PreSyscallHookId(0), // TODO error type
} }
} }
@ -956,7 +982,7 @@ where
a6: GuestAddr, a6: GuestAddr,
a7: GuestAddr, a7: GuestAddr,
) -> SyscallHookResult, ) -> SyscallHookResult,
) -> HookId { ) -> PreSyscallHookId {
unsafe { unsafe {
self.emulator self.emulator
.add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<QT, S>) .add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<QT, S>)
@ -982,10 +1008,10 @@ where
GuestAddr, GuestAddr,
) -> SyscallHookResult, ) -> SyscallHookResult,
>, >,
) -> HookId { ) -> PreSyscallHookId {
unsafe { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
PRE_SYSCALL_HOOKS.push((HookId(0), fat)); PRE_SYSCALL_HOOKS.push((PreSyscallHookId(0), fat));
let id = self.emulator.add_pre_syscall_hook( let id = self.emulator.add_pre_syscall_hook(
&mut ((*addr_of_mut!(PRE_SYSCALL_HOOKS)).last_mut().unwrap().1), &mut ((*addr_of_mut!(PRE_SYSCALL_HOOKS)).last_mut().unwrap().1),
closure_pre_syscall_hook_wrapper::<QT, S>, closure_pre_syscall_hook_wrapper::<QT, S>,
@ -1044,7 +1070,7 @@ where
GuestAddr, GuestAddr,
) -> GuestAddr, ) -> GuestAddr,
>, >,
) -> HookId { ) -> PostSyscallHookId {
match hook { match hook {
Hook::Function(f) => self.after_syscalls_function(f), Hook::Function(f) => self.after_syscalls_function(f),
Hook::Closure(c) => self.after_syscalls_closure(c), Hook::Closure(c) => self.after_syscalls_closure(c),
@ -1052,7 +1078,7 @@ where
let z: *const () = ptr::null::<()>(); let z: *const () = ptr::null::<()>();
self.emulator.add_post_syscall_hook(z, r) self.emulator.add_post_syscall_hook(z, r)
} }
Hook::Empty => HookId(0), // TODO error type Hook::Empty => PostSyscallHookId(0), // TODO error type
} }
} }
@ -1074,7 +1100,7 @@ where
a6: GuestAddr, a6: GuestAddr,
a7: GuestAddr, a7: GuestAddr,
) -> GuestAddr, ) -> GuestAddr,
) -> HookId { ) -> PostSyscallHookId {
unsafe { unsafe {
self.emulator self.emulator
.add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::<QT, S>) .add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::<QT, S>)
@ -1101,10 +1127,10 @@ where
GuestAddr, GuestAddr,
) -> GuestAddr, ) -> GuestAddr,
>, >,
) -> HookId { ) -> PostSyscallHookId {
unsafe { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
POST_SYSCALL_HOOKS.push((HookId(0), fat)); POST_SYSCALL_HOOKS.push((PostSyscallHookId(0), fat));
let id = self.emulator.add_post_syscall_hook( let id = self.emulator.add_post_syscall_hook(
&mut ((*addr_of_mut!(POST_SYSCALL_HOOKS)).last_mut().unwrap().1), &mut ((*addr_of_mut!(POST_SYSCALL_HOOKS)).last_mut().unwrap().1),
closure_post_syscall_hook_wrapper::<QT, S>, closure_post_syscall_hook_wrapper::<QT, S>,
@ -1122,7 +1148,7 @@ where
Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>, Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>,
extern "C" fn(*const (), tid: u32) -> bool, extern "C" fn(*const (), tid: u32) -> bool,
>, >,
) -> HookId { ) -> NewThreadHookId {
match hook { match hook {
Hook::Function(f) => self.thread_creation_function(f), Hook::Function(f) => self.thread_creation_function(f),
Hook::Closure(c) => self.thread_creation_closure(c), Hook::Closure(c) => self.thread_creation_closure(c),
@ -1130,7 +1156,7 @@ where
let z: *const () = ptr::null::<()>(); let z: *const () = ptr::null::<()>();
self.emulator.add_new_thread_hook(z, r) self.emulator.add_new_thread_hook(z, r)
} }
Hook::Empty => HookId(0), // TODO error type Hook::Empty => NewThreadHookId(0), // TODO error type
} }
} }
@ -1138,7 +1164,7 @@ where
pub fn thread_creation_function( pub fn thread_creation_function(
&self, &self,
hook: fn(&mut Self, Option<&mut S>, tid: u32) -> bool, hook: fn(&mut Self, Option<&mut S>, tid: u32) -> bool,
) -> HookId { ) -> NewThreadHookId {
unsafe { unsafe {
self.emulator self.emulator
.add_new_thread_hook(transmute(hook), func_new_thread_hook_wrapper::<QT, S>) .add_new_thread_hook(transmute(hook), func_new_thread_hook_wrapper::<QT, S>)
@ -1149,10 +1175,10 @@ where
pub fn thread_creation_closure( pub fn thread_creation_closure(
&self, &self,
hook: Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>, hook: Box<dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>,
) -> HookId { ) -> NewThreadHookId {
unsafe { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
NEW_THREAD_HOOKS.push((HookId(0), fat)); NEW_THREAD_HOOKS.push((NewThreadHookId(0), fat));
let id = self.emulator.add_new_thread_hook( let id = self.emulator.add_new_thread_hook(
&mut (*addr_of_mut!(NEW_THREAD_HOOKS)).last_mut().unwrap().1, &mut (*addr_of_mut!(NEW_THREAD_HOOKS)).last_mut().unwrap().1,
closure_new_thread_hook_wrapper::<QT, S>, closure_new_thread_hook_wrapper::<QT, S>,