Fix broken closure hooks in libafl_qemu (#1839)

* Fix broken crash hook

* fix hooks

* clippy

* pin
This commit is contained in:
Andrea Fioraldi 2024-02-07 15:03:27 +01:00 committed by GitHub
parent 9b82af4539
commit 41d24ca375
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 303 additions and 185 deletions

View File

@ -56,9 +56,11 @@ systemmode = ["libafl_qemu_sys/systemmode"]
## Automatically register all `#[derive(SerdeAny)]` types at startup. ## Automatically register all `#[derive(SerdeAny)]` types at startup.
serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"] serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"]
## Automatically register all `#[derive(SerdeAny)]` types at startup.
slirp = [ "systemmode", "libafl_qemu_sys/slirp" ] # build qemu with host libslirp (for user networking) slirp = [ "systemmode", "libafl_qemu_sys/slirp" ] # build qemu with host libslirp (for user networking)
# disabled atm, enabled when fixed with dynamic list
# shared = [ "libafl_qemu_sys/shared" ]
[dependencies] [dependencies]
libafl = { path = "../libafl", version = "0.11.2", default-features = false, features = ["std", "derive", "regex"] } libafl = { path = "../libafl", version = "0.11.2", default-features = false, features = ["std", "derive", "regex"] }
libafl_bolts = { path = "../libafl_bolts", version = "0.11.2", default-features = false, features = ["std", "derive"] } libafl_bolts = { path = "../libafl_bolts", version = "0.11.2", default-features = false, features = ["std", "derive"] }

View File

@ -95,6 +95,6 @@ pub fn build() {
.status() .status()
.expect("make failed") .expect("make failed")
.success()); .success());
println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display()); // println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display());
} }
} }

View File

@ -21,6 +21,7 @@ categories = [
all-features = true all-features = true
[features] [features]
shared = []
slirp = [] # build qemu with host libslirp (for user networking) slirp = [] # build qemu with host libslirp (for user networking)
clippy = [] # special feature for clippy, don't use in normal projects§ clippy = [] # special feature for clippy, don't use in normal projects§

View File

@ -10,6 +10,11 @@ const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
const QEMU_REVISION: &str = "75d15d54f4417a4766d2dcb493982d9df0e8eac4"; const QEMU_REVISION: &str = "75d15d54f4417a4766d2dcb493982d9df0e8eac4";
pub struct BuildResult {
pub qemu_path: PathBuf,
pub build_dir: PathBuf,
}
fn build_dep_check(tools: &[&str]) { fn build_dep_check(tools: &[&str]) {
for tool in tools { for tool in tools {
which(tool).unwrap_or_else(|_| panic!("Build tool {tool} not found")); which(tool).unwrap_or_else(|_| panic!("Build tool {tool} not found"));
@ -23,7 +28,7 @@ pub fn build(
is_big_endian: bool, is_big_endian: bool,
is_usermode: bool, is_usermode: bool,
jobs: Option<u32>, jobs: Option<u32>,
) -> (PathBuf, PathBuf) { ) -> BuildResult {
let mut cpu_target = cpu_target.to_string(); let mut cpu_target = cpu_target.to_string();
// qemu-system-arm supports both big and little endian configurations and so // qemu-system-arm supports both big and little endian configurations and so
// therefore the "be" feature should ignored in this configuration. Also // therefore the "be" feature should ignored in this configuration. Also
@ -120,13 +125,19 @@ pub fn build(
"softmmu".to_string() "softmmu".to_string()
}; };
let output_lib = if is_usermode { let (output_lib, output_lib_link) = if is_usermode {
build_dir.join(format!("libqemu-{cpu_target}.so")) (
build_dir.join(format!("libqemu-{cpu_target}.so")),
format!("qemu-{cpu_target}"),
)
} else { } else {
build_dir.join(format!("libqemu-system-{cpu_target}.so")) (
build_dir.join(format!("libqemu-system-{cpu_target}.so")),
format!("qemu-system-{cpu_target}"),
)
}; };
println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy()); // println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy());
if !output_lib.is_file() || (custom_qemu_dir.is_some() && !custom_qemu_no_build) { if !output_lib.is_file() || (custom_qemu_dir.is_some() && !custom_qemu_no_build) {
/*drop( /*drop(
@ -337,137 +348,145 @@ pub fn build(
} }
*/ */
let compile_commands_string = if cfg!(feature = "shared") {
&fs::read_to_string(build_dir.join("linkinfo.json")).expect("Failed to read linkinfo.json"); println!(
"cargo:rustc-link-search=native={}",
let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json"); build_dir.to_string_lossy()
let mut cmd = vec![];
for arg in linkinfo["cmd"].members() {
cmd.push(
arg.as_str()
.expect("linkinfo.json `cmd` values must be strings"),
); );
} println!("cargo:rustc-link-lib=dylib={output_lib_link}");
assert!(cpp_compiler
.to_command()
.current_dir(&build_dir)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(cmd)
.status()
.expect("Partial linked failure")
.success());
/* // Old manual linking, kept here for reference and debugging
if is_usermode {
Command::new("ld")
.current_dir(out_dir_path)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.status()
.expect("Partial linked failure");
} else { } else {
Command::new("ld") let compile_commands_string = &fs::read_to_string(build_dir.join("linkinfo.json"))
.current_dir(out_dir_path) .expect("Failed to read linkinfo.json");
let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json");
let mut cmd = vec![];
for arg in linkinfo["cmd"].members() {
cmd.push(
arg.as_str()
.expect("linkinfo.json `cmd` values must be strings"),
);
}
assert!(cpp_compiler
.to_command()
.current_dir(&build_dir)
.arg("-o") .arg("-o")
.arg("libqemu-partially-linked.o") .arg("libqemu-partially-linked.o")
.arg("-r") .arg("-r")
.args(objects) .args(cmd)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!(
"{}/subprojects/dtc/libfdt/libfdt.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user-glib.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvduse/libvduse.a",
build_dir.display()
))
.arg(format!("{}/libmigration.fa", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.status() .status()
.expect("Partial linked failure"); .expect("Partial linked failure")
}*/ .success());
Command::new("ar") /* // Old manual linking, kept here for reference and debugging
.current_dir(out_dir_path) if is_usermode {
.arg("crs") Command::new("ld")
.arg("libqemu-partially-linked.a") .current_dir(out_dir_path)
.arg(build_dir.join("libqemu-partially-linked.o")) .arg("-o")
.status() .arg("libqemu-partially-linked.o")
.expect("Ar creation"); .arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.status()
.expect("Partial linked failure");
} else {
Command::new("ld")
.current_dir(out_dir_path)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!(
"{}/subprojects/dtc/libfdt/libfdt.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user-glib.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvduse/libvduse.a",
build_dir.display()
))
.arg(format!("{}/libmigration.fa", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.status()
.expect("Partial linked failure");
}*/
println!("cargo:rustc-link-search=native={out_dir}"); Command::new("ar")
println!("cargo:rustc-link-lib=static=qemu-partially-linked"); .current_dir(out_dir_path)
.arg("crs")
.arg("libqemu-partially-linked.a")
.arg(build_dir.join("libqemu-partially-linked.o"))
.status()
.expect("Ar creation");
for arg in linkinfo["search"].members() { println!("cargo:rustc-link-search=native={out_dir}");
let val = arg println!("cargo:rustc-link-lib=static=qemu-partially-linked");
.as_str()
.expect("linkinfo.json `search` values must be strings");
println!("cargo:rustc-link-search={val}");
}
for arg in linkinfo["libs"].members() { for arg in linkinfo["search"].members() {
let val = arg let val = arg
.as_str() .as_str()
.expect("linkinfo.json `libs` values must be strings"); .expect("linkinfo.json `search` values must be strings");
println!("cargo:rustc-link-lib={val}"); println!("cargo:rustc-link-search={val}");
}
for arg in linkinfo["libs"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `libs` values must be strings");
println!("cargo:rustc-link-lib={val}");
}
} }
/* /*
@ -500,5 +519,8 @@ pub fn build(
} }
} }
(qemu_path, build_dir) BuildResult {
qemu_path,
build_dir,
}
} }

View File

@ -22,10 +22,16 @@ pub fn build_with_bindings(
jobs: Option<u32>, jobs: Option<u32>,
bindings_file: &Path, bindings_file: &Path,
) { ) {
let (qemu_dir, build_dir) = build::build(cpu_target, is_big_endian, is_usermode, jobs); let build_result = build::build(cpu_target, is_big_endian, is_usermode, jobs);
let clang_args = qemu_bindgen_clang_args(&qemu_dir, &build_dir, cpu_target, is_usermode);
let bind = bindings::generate(&build_dir, cpu_target, clang_args) let clang_args = qemu_bindgen_clang_args(
&build_result.qemu_path,
&build_result.build_dir,
cpu_target,
is_usermode,
);
let bind = bindings::generate(&build_result.build_dir, cpu_target, clang_args)
.expect("Failed to generate the bindings"); .expect("Failed to generate the bindings");
bind.write_to_file(bindings_file) bind.write_to_file(bindings_file)
.expect("Faield to write to the bindings file"); .expect("Faield to write to the bindings file");

View File

@ -31,6 +31,7 @@ usermode = []
systemmode = [] systemmode = []
slirp = [ "systemmode", "libafl_qemu_build/slirp" ] # build qemu with host libslirp (for user networking) slirp = [ "systemmode", "libafl_qemu_build/slirp" ] # build qemu with host libslirp (for user networking)
shared = [ "libafl_qemu_build/shared" ]
clippy = [ "libafl_qemu_build/clippy" ] # special feature for clippy, don't use in normal projects§ clippy = [ "libafl_qemu_build/clippy" ] # special feature for clippy, don't use in normal projects§

View File

@ -6,6 +6,7 @@ use core::{
fmt::{self, Debug, Formatter}, fmt::{self, Debug, Formatter},
marker::PhantomData, marker::PhantomData,
mem::transmute, mem::transmute,
pin::Pin,
ptr::{self, addr_of, addr_of_mut}, ptr::{self, addr_of, addr_of_mut},
}; };
@ -25,7 +26,7 @@ use crate::{
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum Hook { pub(crate) enum Hook {
Function(*const c_void), Function(*const c_void),
Closure(Box<FatPtr>), Closure(FatPtr),
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
Once(Box<FatPtr>), Once(Box<FatPtr>),
Empty, Empty,
@ -36,7 +37,7 @@ pub(crate) enum Hook {
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub(crate) enum HookRepr { pub(crate) enum HookRepr {
Function(*const c_void), Function(*const c_void),
Closure(Box<FatPtr>), Closure(FatPtr),
Empty, Empty,
} }
@ -77,7 +78,7 @@ macro_rules! hook_to_repr {
($h:expr) => { ($h:expr) => {
match $h { match $h {
Hook::Function(f) => HookRepr::Function(f as *const libc::c_void), Hook::Function(f) => HookRepr::Function(f as *const libc::c_void),
Hook::Closure(c) => HookRepr::Closure(Box::new(transmute(c))), Hook::Closure(c) => HookRepr::Closure(transmute(c)),
Hook::Raw(_) => HookRepr::Empty, // managed by emu Hook::Raw(_) => HookRepr::Empty, // managed by emu
Hook::Empty => HookRepr::Empty, Hook::Empty => HookRepr::Empty,
} }
@ -242,13 +243,13 @@ macro_rules! create_exec_wrapper {
} }
} }
static mut GENERIC_HOOKS: Vec<(InstructionHookId, Box<FatPtr>)> = vec![]; static mut GENERIC_HOOKS: Vec<Pin<Box<(InstructionHookId, FatPtr)>>> = vec![];
create_wrapper!(generic, (pc: GuestAddr)); create_wrapper!(generic, (pc: GuestAddr));
static mut BACKDOOR_HOOKS: Vec<(BackdoorHookId, Box<FatPtr>)> = vec![]; static mut BACKDOOR_HOOKS: Vec<Pin<Box<(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<(PreSyscallHookId, Box<FatPtr>)> = vec![]; static mut PRE_SYSCALL_HOOKS: Vec<Pin<Box<(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,
@ -260,7 +261,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<(PostSyscallHookId, Box<FatPtr>)> = vec![]; static mut POST_SYSCALL_HOOKS: Vec<Pin<Box<(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,
@ -272,20 +273,20 @@ 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<(NewThreadHookId, Box<FatPtr>)> = vec![]; static mut NEW_THREAD_HOOKS: Vec<Pin<Box<(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, EdgeHookId>> = vec![]; static mut EDGE_HOOKS: Vec<Pin<Box<HookState<1, EdgeHookId>>>> = vec![];
create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId); create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId);
create_exec_wrapper!(edge, (id: u64), 0, 1, EdgeHookId); create_exec_wrapper!(edge, (id: u64), 0, 1, EdgeHookId);
static mut BLOCK_HOOKS: Vec<HookState<1, BlockHookId>> = vec![]; static mut BLOCK_HOOKS: Vec<Pin<Box<HookState<1, BlockHookId>>>> = vec![];
create_gen_wrapper!(block, (addr: GuestAddr), u64, 1, BlockHookId); create_gen_wrapper!(block, (addr: GuestAddr), u64, 1, BlockHookId);
create_post_gen_wrapper!(block, (addr: GuestAddr, len: GuestUsize), 1, BlockHookId); create_post_gen_wrapper!(block, (addr: GuestAddr, len: GuestUsize), 1, BlockHookId);
create_exec_wrapper!(block, (id: u64), 0, 1, BlockHookId); create_exec_wrapper!(block, (id: u64), 0, 1, BlockHookId);
static mut READ_HOOKS: Vec<HookState<5, ReadHookId>> = vec![]; static mut READ_HOOKS: Vec<Pin<Box<HookState<5, ReadHookId>>>> = vec![];
create_gen_wrapper!(read, (pc: GuestAddr, info: MemAccessInfo), u64, 5, ReadHookId); create_gen_wrapper!(read, (pc: GuestAddr, info: MemAccessInfo), u64, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 0, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 0, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 1, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 1, 5, ReadHookId);
@ -293,7 +294,7 @@ create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 2, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 3, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 3, 5, ReadHookId);
create_exec_wrapper!(read, (id: u64, addr: GuestAddr, size: usize), 4, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr, size: usize), 4, 5, ReadHookId);
static mut WRITE_HOOKS: Vec<HookState<5, WriteHookId>> = vec![]; static mut WRITE_HOOKS: Vec<Pin<Box<HookState<5, WriteHookId>>>> = vec![];
create_gen_wrapper!(write, (pc: GuestAddr, info: MemAccessInfo), u64, 5, WriteHookId); create_gen_wrapper!(write, (pc: GuestAddr, info: MemAccessInfo), u64, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 0, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 0, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 1, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 1, 5, WriteHookId);
@ -301,7 +302,7 @@ create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 2, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 3, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 3, 5, WriteHookId);
create_exec_wrapper!(write, (id: u64, addr: GuestAddr, size: usize), 4, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr, size: usize), 4, 5, WriteHookId);
static mut CMP_HOOKS: Vec<HookState<4, CmpHookId>> = vec![]; static mut CMP_HOOKS: Vec<Pin<Box<HookState<4, CmpHookId>>>> = vec![];
create_gen_wrapper!(cmp, (pc: GuestAddr, size: usize), u64, 4, CmpHookId); create_gen_wrapper!(cmp, (pc: GuestAddr, size: usize), u64, 4, CmpHookId);
create_exec_wrapper!(cmp, (id: u64, v0: u8, v1: u8), 0, 4, CmpHookId); 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, CmpHookId); create_exec_wrapper!(cmp, (id: u64, v0: u16, v1: u16), 1, 4, CmpHookId);
@ -459,14 +460,25 @@ where
invalidate_block: bool, invalidate_block: bool,
) -> InstructionHookId { ) -> InstructionHookId {
unsafe { unsafe {
let mut fat: Box<FatPtr> = Box::new(transmute(hook)); let fat: FatPtr = transmute(hook);
GENERIC_HOOKS.push(Box::pin((InstructionHookId(0), fat)));
let id = self.emulator.set_hook( let id = self.emulator.set_hook(
transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime &mut GENERIC_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.1,
addr, addr,
closure_generic_hook_wrapper::<QT, S>, closure_generic_hook_wrapper::<QT, S>,
invalidate_block, invalidate_block,
); );
GENERIC_HOOKS.push((id, fat)); GENERIC_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.0 = id;
id id
} }
} }
@ -506,16 +518,23 @@ where
edge_0_exec_hook_wrapper::<QT, S>, edge_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1, EdgeHookId>, id: u64) extern "C" fn(&mut HookState<1, EdgeHookId>, id: u64)
); );
EDGE_HOOKS.push(HookState { EDGE_HOOKS.push(Box::pin(HookState {
id: EdgeHookId(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)],
}); }));
let id = self let id = self.emulator.add_edge_hooks(
.emulator EDGE_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(),
.add_edge_hooks(EDGE_HOOKS.last_mut().unwrap(), gen, exec); gen,
EDGE_HOOKS.last_mut().unwrap().id = id; exec,
);
EDGE_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.id = id;
id id
} }
} }
@ -558,16 +577,24 @@ where
block_0_exec_hook_wrapper::<QT, S>, block_0_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<1, BlockHookId>, id: u64) extern "C" fn(&mut HookState<1, BlockHookId>, id: u64)
); );
BLOCK_HOOKS.push(HookState { BLOCK_HOOKS.push(Box::pin(HookState {
id: BlockHookId(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)],
}); }));
let id = let id = self.emulator.add_block_hooks(
self.emulator BLOCK_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(),
.add_block_hooks(BLOCK_HOOKS.last_mut().unwrap(), gen, postgen, exec); gen,
BLOCK_HOOKS.last_mut().unwrap().id = id; postgen,
exec,
);
BLOCK_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.id = id;
id id
} }
} }
@ -648,7 +675,7 @@ where
read_4_exec_hook_wrapper::<QT, S>, read_4_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<5, ReadHookId>, 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(Box::pin(HookState {
id: ReadHookId(0), id: ReadHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
@ -659,9 +686,9 @@ where
hook_to_repr!(execution_hook_8), hook_to_repr!(execution_hook_8),
hook_to_repr!(execution_hook_n), hook_to_repr!(execution_hook_n),
], ],
}); }));
let id = self.emulator.add_read_hooks( let id = self.emulator.add_read_hooks(
READ_HOOKS.last_mut().unwrap(), READ_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(),
gen, gen,
exec1, exec1,
exec2, exec2,
@ -669,7 +696,12 @@ where
exec8, exec8,
execn, execn,
); );
READ_HOOKS.last_mut().unwrap().id = id; READ_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.id = id;
id id
} }
} }
@ -755,7 +787,7 @@ where
size: usize, size: usize,
) )
); );
WRITE_HOOKS.push(HookState { WRITE_HOOKS.push(Box::pin(HookState {
id: WriteHookId(0), id: WriteHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
@ -766,9 +798,9 @@ where
hook_to_repr!(execution_hook_8), hook_to_repr!(execution_hook_8),
hook_to_repr!(execution_hook_n), hook_to_repr!(execution_hook_n),
], ],
}); }));
let id = self.emulator.add_write_hooks( let id = self.emulator.add_write_hooks(
WRITE_HOOKS.last_mut().unwrap(), WRITE_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(),
gen, gen,
exec1, exec1,
exec2, exec2,
@ -776,7 +808,12 @@ where
exec8, exec8,
execn, execn,
); );
WRITE_HOOKS.last_mut().unwrap().id = id; WRITE_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.id = id;
id id
} }
} }
@ -837,7 +874,7 @@ where
cmp_3_exec_hook_wrapper::<QT, S>, cmp_3_exec_hook_wrapper::<QT, S>,
extern "C" fn(&mut HookState<4, CmpHookId>, 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(Box::pin(HookState {
id: CmpHookId(0), id: CmpHookId(0),
gen: hook_to_repr!(generation_hook), gen: hook_to_repr!(generation_hook),
post_gen: HookRepr::Empty, post_gen: HookRepr::Empty,
@ -847,16 +884,21 @@ where
hook_to_repr!(execution_hook_4), hook_to_repr!(execution_hook_4),
hook_to_repr!(execution_hook_8), hook_to_repr!(execution_hook_8),
], ],
}); }));
let id = self.emulator.add_cmp_hooks( let id = self.emulator.add_cmp_hooks(
CMP_HOOKS.last_mut().unwrap(), CMP_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(),
gen, gen,
exec1, exec1,
exec2, exec2,
exec4, exec4,
exec8, exec8,
); );
CMP_HOOKS.last_mut().unwrap().id = id; CMP_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.id = id;
id id
} }
} }
@ -895,12 +937,23 @@ where
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)>,
) -> BackdoorHookId { ) -> BackdoorHookId {
unsafe { unsafe {
let mut fat: Box<FatPtr> = Box::new(transmute(hook)); let fat: FatPtr = transmute(hook);
BACKDOOR_HOOKS.push(Box::pin((BackdoorHookId(0), fat)));
let id = self.emulator.add_backdoor_hook( let id = self.emulator.add_backdoor_hook(
transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime &mut BACKDOOR_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.1,
closure_backdoor_hook_wrapper::<QT, S>, closure_backdoor_hook_wrapper::<QT, S>,
); );
BACKDOOR_HOOKS.push((id, fat)); BACKDOOR_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.0 = id;
id id
} }
} }
@ -1008,12 +1061,23 @@ where
>, >,
) -> PreSyscallHookId { ) -> PreSyscallHookId {
unsafe { unsafe {
let mut fat: Box<FatPtr> = Box::new(transmute(hook)); let fat: FatPtr = transmute(hook);
PRE_SYSCALL_HOOKS.push(Box::pin((PreSyscallHookId(0), fat)));
let id = self.emulator.add_pre_syscall_hook( let id = self.emulator.add_pre_syscall_hook(
transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime &mut PRE_SYSCALL_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.1,
closure_pre_syscall_hook_wrapper::<QT, S>, closure_pre_syscall_hook_wrapper::<QT, S>,
); );
PRE_SYSCALL_HOOKS.push((id, fat)); PRE_SYSCALL_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.0 = id;
id id
} }
} }
@ -1126,12 +1190,23 @@ where
>, >,
) -> PostSyscallHookId { ) -> PostSyscallHookId {
unsafe { unsafe {
let mut fat: Box<FatPtr> = Box::new(transmute(hook)); let fat: FatPtr = transmute(hook);
POST_SYSCALL_HOOKS.push(Box::pin((PostSyscallHookId(0), fat)));
let id = self.emulator.add_post_syscall_hook( let id = self.emulator.add_post_syscall_hook(
transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime &mut POST_SYSCALL_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.1,
closure_post_syscall_hook_wrapper::<QT, S>, closure_post_syscall_hook_wrapper::<QT, S>,
); );
POST_SYSCALL_HOOKS.push((id, fat)); POST_SYSCALL_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.0 = id;
id id
} }
} }
@ -1173,12 +1248,23 @@ where
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>,
) -> NewThreadHookId { ) -> NewThreadHookId {
unsafe { unsafe {
let mut fat: Box<FatPtr> = Box::new(transmute(hook)); let fat: FatPtr = transmute(hook);
NEW_THREAD_HOOKS.push(Box::pin((NewThreadHookId(0), fat)));
let id = self.emulator.add_new_thread_hook( let id = self.emulator.add_new_thread_hook(
transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime &mut NEW_THREAD_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.1,
closure_new_thread_hook_wrapper::<QT, S>, closure_new_thread_hook_wrapper::<QT, S>,
); );
NEW_THREAD_HOOKS.push((id, fat)); NEW_THREAD_HOOKS
.last_mut()
.unwrap()
.as_mut()
.get_unchecked_mut()
.0 = id;
id id
} }
} }
@ -1195,7 +1281,7 @@ where
pub fn crash_closure(&self, hook: Box<dyn FnMut(&mut Self, i32)>) { pub fn crash_closure(&self, hook: Box<dyn FnMut(&mut Self, i32)>) {
unsafe { unsafe {
self.emulator.set_crash_hook(crash_hook_wrapper::<QT, S>); self.emulator.set_crash_hook(crash_hook_wrapper::<QT, S>);
CRASH_HOOKS.push(HookRepr::Closure(Box::new(transmute(hook)))); CRASH_HOOKS.push(HookRepr::Closure(transmute(hook)));
} }
} }
} }