From f1aee3c3761ebcc564338048730a07b647b12963 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 23 Nov 2023 18:57:15 +0100 Subject: [PATCH] Refactor QEMU hooks (#1690) * Rewrite QEMU Asan * fake sys * New hooks * edge cov helper * opaque raw hook * new hooks * EMulator::get * new asan * fix fuzzers * fix types * fix * fix * fix * merge fix * fix --- fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs | 2 +- fuzzers/fuzzbench_qemu/src/fuzzer.rs | 10 +- fuzzers/qemu_cmin/src/fuzzer.rs | 5 +- fuzzers/qemu_coverage/src/fuzzer.rs | 2 +- fuzzers/qemu_launcher/src/client.rs | 14 +- fuzzers/qemu_launcher/src/instance.rs | 2 +- fuzzers/qemu_systemmode/src/fuzzer.rs | 2 +- libafl_qemu/Cargo.toml | 1 + libafl_qemu/libafl_qemu_build/Cargo.toml | 1 + libafl_qemu/libafl_qemu_build/src/bindings.rs | 9 +- libafl_qemu/libafl_qemu_build/src/build.rs | 2 +- libafl_qemu/libafl_qemu_build/src/lib.rs | 8 + .../src/x86_64_stub_bindings.rs | 1758 ++++++++++++++ libafl_qemu/src/asan.rs | 284 ++- libafl_qemu/src/calls.rs | 100 +- libafl_qemu/src/cmplog.rs | 56 +- libafl_qemu/src/drcov.rs | 16 +- libafl_qemu/src/edges.rs | 67 +- libafl_qemu/src/emu.rs | 526 ++-- libafl_qemu/src/executor.rs | 16 +- libafl_qemu/src/helper.rs | 16 +- libafl_qemu/src/hooks.rs | 2161 +++++++---------- libafl_qemu/src/snapshot.rs | 100 +- libafl_sugar/src/qemu.rs | 8 +- 24 files changed, 3385 insertions(+), 1781 deletions(-) diff --git a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs index 9f3b940f39..0970d5a544 100644 --- a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs @@ -329,7 +329,7 @@ fn fuzz( }; let mut hooks = QemuHooks::new( - &emu, + emu.clone(), tuple_list!( QemuEdgeCoverageChildHelper::default(), QemuCmpLogChildHelper::default(), diff --git a/fuzzers/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_qemu/src/fuzzer.rs index ce0a304186..cc16a9d29a 100644 --- a/fuzzers/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_qemu/src/fuzzer.rs @@ -45,15 +45,15 @@ use libafl_bolts::{ AsSlice, }; use libafl_qemu::{ + // asan::{init_with_asan, QemuAsanHelper}, cmplog::{CmpLogObserver, QemuCmpLogHelper}, - //asan::{init_with_asan, QemuAsanHelper}, edges::edges_map_mut_slice, edges::QemuEdgeCoverageHelper, edges::MAX_EDGES_NUM, elf::EasyElf, - emu::Emulator, filter_qemu_args, hooks::QemuHooks, + Emulator, GuestReg, //snapshot::QemuSnapshotHelper, MmapPerms, @@ -173,7 +173,7 @@ fn fuzz( let args: Vec = env::args().collect(); let env: Vec<(String, String)> = env::vars().collect(); let emu = Emulator::new(&args, &env).unwrap(); - //let emu = init_with_asan(&mut args, &mut env); + // let (emu, asan) = init_with_asan(&mut args, &mut env).unwrap(); let mut elf_buffer = Vec::new(); let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer)?; @@ -342,11 +342,11 @@ fn fuzz( }; let mut hooks = QemuHooks::new( - &emu, + emu.clone(), tuple_list!( QemuEdgeCoverageHelper::default(), QemuCmpLogHelper::default(), - //QemuAsanHelper::default(), + // QemuAsanHelper::default(asan), //QemuSnapshotHelper::new() ), ); diff --git a/fuzzers/qemu_cmin/src/fuzzer.rs b/fuzzers/qemu_cmin/src/fuzzer.rs index 11ad859d7d..e2a69ad254 100644 --- a/fuzzers/qemu_cmin/src/fuzzer.rs +++ b/fuzzers/qemu_cmin/src/fuzzer.rs @@ -215,7 +215,10 @@ pub fn fuzz() -> Result<(), Error> { ExitKind::Ok }; - let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageChildHelper::default(),)); + let mut hooks = QemuHooks::new( + emu.clone(), + tuple_list!(QemuEdgeCoverageChildHelper::default(),), + ); let mut executor = QemuForkExecutor::new( &mut hooks, diff --git a/fuzzers/qemu_coverage/src/fuzzer.rs b/fuzzers/qemu_coverage/src/fuzzer.rs index d6df3637d8..90087497e6 100644 --- a/fuzzers/qemu_coverage/src/fuzzer.rs +++ b/fuzzers/qemu_coverage/src/fuzzer.rs @@ -236,7 +236,7 @@ pub fn fuzz() { coverage.set_file_name(format!("{coverage_name}-{core:03}.{coverage_extension}")); let mut hooks = QemuHooks::new( - &emu, + emu.clone(), tuple_list!(QemuDrCovHelper::new( QemuInstrumentationFilter::None, rangemap, diff --git a/fuzzers/qemu_launcher/src/client.rs b/fuzzers/qemu_launcher/src/client.rs index 953c1178ec..b8f73ade55 100644 --- a/fuzzers/qemu_launcher/src/client.rs +++ b/fuzzers/qemu_launcher/src/client.rs @@ -103,11 +103,12 @@ impl<'a> Client<'a> { let mut env = self.env()?; log::debug!("ENV: {:#?}", env); - let emu = { + let (emu, mut asan) = { if self.options.is_asan_core(core_id) { - init_with_asan(&mut args, &mut env)? + let (emu, asan) = init_with_asan(&mut args, &mut env)?; + (emu, Some(asan)) } else { - Emulator::new(&args, &env)? + (Emulator::new(&args, &env)?, None) } }; @@ -136,11 +137,14 @@ impl<'a> Client<'a> { let helpers = tuple_list!( edge_coverage_helper, QemuCmpLogHelper::default(), - QemuAsanHelper::default(), + QemuAsanHelper::default(asan.take().unwrap()), ); instance.build().run(helpers, state) } else if is_asan { - let helpers = tuple_list!(edge_coverage_helper, QemuAsanHelper::default(),); + let helpers = tuple_list!( + edge_coverage_helper, + QemuAsanHelper::default(asan.take().unwrap()), + ); instance.build().run(helpers, state) } else if is_cmplog { let helpers = tuple_list!(edge_coverage_helper, QemuCmpLogHelper::default(),); diff --git a/fuzzers/qemu_launcher/src/instance.rs b/fuzzers/qemu_launcher/src/instance.rs index ad1c6d0419..70b44098d0 100644 --- a/fuzzers/qemu_launcher/src/instance.rs +++ b/fuzzers/qemu_launcher/src/instance.rs @@ -59,7 +59,7 @@ impl<'a> Instance<'a> { where QT: QemuHelperTuple, { - let mut hooks = QemuHooks::new(self.emu, helpers); + let mut hooks = QemuHooks::new(self.emu.clone(), helpers); // Create an observation channel using the coverage map let edges_observer = unsafe { diff --git a/fuzzers/qemu_systemmode/src/fuzzer.rs b/fuzzers/qemu_systemmode/src/fuzzer.rs index c0e79e0703..5229eba8f7 100644 --- a/fuzzers/qemu_systemmode/src/fuzzer.rs +++ b/fuzzers/qemu_systemmode/src/fuzzer.rs @@ -192,7 +192,7 @@ pub fn fuzz() { // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageHelper::default())); + let mut hooks = QemuHooks::new(emu.clone(), tuple_list!(QemuEdgeCoverageHelper::default())); // Create a QEMU in-process executor let mut executor = QemuExecutor::new( diff --git a/libafl_qemu/Cargo.toml b/libafl_qemu/Cargo.toml index 4e2a16fdd6..be844296c9 100644 --- a/libafl_qemu/Cargo.toml +++ b/libafl_qemu/Cargo.toml @@ -65,6 +65,7 @@ rangemap = "1.3" log = "0.4.20" addr2line = "0.21" typed-arena = "2.0" +paste = "1" enum-map = "2.7" pyo3 = { version = "0.18", optional = true } diff --git a/libafl_qemu/libafl_qemu_build/Cargo.toml b/libafl_qemu/libafl_qemu_build/Cargo.toml index 8d434be990..4ab683ae31 100644 --- a/libafl_qemu/libafl_qemu_build/Cargo.toml +++ b/libafl_qemu/libafl_qemu_build/Cargo.toml @@ -32,3 +32,4 @@ json = "0.12" shell-words = "1.1" pkg-config = "0.3.26" cc = "1.0" +regex = "1" diff --git a/libafl_qemu/libafl_qemu_build/src/bindings.rs b/libafl_qemu/libafl_qemu_build/src/bindings.rs index 6d5347295d..fd9128f2a8 100644 --- a/libafl_qemu/libafl_qemu_build/src/bindings.rs +++ b/libafl_qemu/libafl_qemu_build/src/bindings.rs @@ -77,6 +77,7 @@ const WRAPPER_HEADER: &str = r#" #include "qemu/plugin-memory.h" #include "libafl_extras/exit.h" +#include "libafl_extras/hook.h" "#; @@ -114,6 +115,7 @@ pub fn generate( .allowlist_type("libafl_exit_reason_kind") .allowlist_type("libafl_exit_reason_sync_backdoor") .allowlist_type("libafl_exit_reason_breakpoint") + .allowlist_type("Syx.*") .allowlist_function("qemu_user_init") .allowlist_function("target_mmap") .allowlist_function("target_mprotect") @@ -128,12 +130,9 @@ pub fn generate( .allowlist_function("qemu_plugin_hwaddr_phys_addr") .allowlist_function("qemu_plugin_get_hwaddr") .allowlist_function("qemu_target_page_size") - .allowlist_function("syx_snapshot_init") - .allowlist_function("syx_snapshot_new") - .allowlist_function("syx_snapshot_root_restore") - .allowlist_function("syx_snapshot_dirty_list_add") + .allowlist_function("syx_.*") .allowlist_function("device_list_all") - .allowlist_function("libafl_get_exit_reason") + .allowlist_function("libafl_.*") .blocklist_function("main_loop_wait") // bindgen issue #1313 .parse_callbacks(Box::new(bindgen::CargoCallbacks)); diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index b02333c926..4cfcc86fa3 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -8,7 +8,7 @@ use which::which; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -const QEMU_REVISION: &str = "8db5524416b52c999459f1fe3373846bdcb23ac1"; +const QEMU_REVISION: &str = "6a63c7f7924d3db1dfff99e7b6cf460e8fb35785"; fn build_dep_check(tools: &[&str]) { for tool in tools { diff --git a/libafl_qemu/libafl_qemu_build/src/lib.rs b/libafl_qemu/libafl_qemu_build/src/lib.rs index 5f19cb3997..a6fedff623 100644 --- a/libafl_qemu/libafl_qemu_build/src/lib.rs +++ b/libafl_qemu/libafl_qemu_build/src/lib.rs @@ -5,6 +5,7 @@ use std::{ process::Command, }; +use regex::Regex; use which::which; mod bindings; @@ -28,6 +29,13 @@ pub fn build_with_bindings( .expect("Failed to generate the bindings"); bind.write_to_file(bindings_file) .expect("Faield to write to the bindings file"); + + // """Fix""" the bindings here + let contents = + fs::read_to_string(bindings_file).expect("Should have been able to read the file"); + let re = Regex::new("(Option<\\s*)unsafe( extern \"C\" fn\\(data: u64)").unwrap(); + let replaced = re.replace_all(&contents, "$1$2"); + fs::write(bindings_file, replaced.as_bytes()).expect("Unable to write file"); } // For bindgen, the llvm version must be >= of the rust llvm version diff --git a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs index 7f86c0117c..91c9cef288 100644 --- a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs @@ -11633,6 +11633,382 @@ impl ::std::ops::BitAndAssign for MemOp { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct MemOp(pub ::std::os::raw::c_uint); pub type MemOpIdx = u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RBNode { + pub rb_parent_color: usize, + pub rb_right: *mut RBNode, + pub rb_left: *mut RBNode, +} +#[test] +fn bindgen_test_layout_RBNode() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 24usize, + concat!("Size of: ", stringify!(RBNode)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(RBNode)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb_parent_color) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(RBNode), + "::", + stringify!(rb_parent_color) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb_right) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(RBNode), + "::", + stringify!(rb_right) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb_left) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(RBNode), + "::", + stringify!(rb_left) + ) + ); +} +impl Default for RBNode { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IntervalTreeNode { + pub rb: RBNode, + pub start: u64, + pub last: u64, + pub subtree_last: u64, +} +#[test] +fn bindgen_test_layout_IntervalTreeNode() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 48usize, + concat!("Size of: ", stringify!(IntervalTreeNode)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(IntervalTreeNode)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(IntervalTreeNode), + "::", + stringify!(rb) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).start) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(IntervalTreeNode), + "::", + stringify!(start) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).last) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(IntervalTreeNode), + "::", + stringify!(last) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).subtree_last) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(IntervalTreeNode), + "::", + stringify!(subtree_last) + ) + ); +} +impl Default for IntervalTreeNode { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct tb_tc { + pub ptr: *const ::std::os::raw::c_void, + pub size: usize, +} +#[test] +fn bindgen_test_layout_tb_tc() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(tb_tc)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(tb_tc)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).ptr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(tb_tc), + "::", + stringify!(ptr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(tb_tc), + "::", + stringify!(size) + ) + ); +} +impl Default for tb_tc { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TranslationBlock { + pub pc: vaddr, + pub cs_base: u64, + pub flags: u32, + pub cflags: u32, + pub size: u16, + pub icount: u16, + pub tc: tb_tc, + pub itree: IntervalTreeNode, + pub jmp_lock: QemuSpin, + pub jmp_reset_offset: [u16; 2usize], + pub jmp_insn_offset: [u16; 2usize], + pub jmp_target_addr: [usize; 2usize], + pub jmp_list_head: usize, + pub jmp_list_next: [usize; 2usize], + pub jmp_dest: [usize; 2usize], +} +#[test] +fn bindgen_test_layout_TranslationBlock() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 168usize, + concat!("Size of: ", stringify!(TranslationBlock)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TranslationBlock)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pc) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(pc) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).cs_base) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(cs_base) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).cflags) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(cflags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(size) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).icount) as usize - ptr as usize }, + 26usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(icount) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).tc) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(tc) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).itree) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(itree) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_lock) as usize - ptr as usize }, + 96usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_lock) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_reset_offset) as usize - ptr as usize }, + 100usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_reset_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_insn_offset) as usize - ptr as usize }, + 104usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_insn_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_target_addr) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_target_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_list_head) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_list_head) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_list_next) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_list_next) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).jmp_dest) as usize - ptr as usize }, + 152usize, + concat!( + "Offset of field: ", + stringify!(TranslationBlock), + "::", + stringify!(jmp_dest) + ) + ); +} +impl Default for TranslationBlock { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} extern "C" { pub fn target_mprotect( start: abi_ulong, @@ -11653,6 +12029,258 @@ extern "C" { extern "C" { pub fn target_munmap(start: abi_ulong, len: abi_ulong) -> ::std::os::raw::c_int; } +extern "C" { + pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong); +} +extern "C" { + pub fn libafl_qemu_set_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_remove_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; +} +pub const libafl_exit_reason_kind_BREAKPOINT: libafl_exit_reason_kind = libafl_exit_reason_kind(0); +pub const libafl_exit_reason_kind_SYNC_BACKDOOR: libafl_exit_reason_kind = + libafl_exit_reason_kind(1); +impl ::std::ops::BitOr for libafl_exit_reason_kind { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + libafl_exit_reason_kind(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for libafl_exit_reason_kind { + #[inline] + fn bitor_assign(&mut self, rhs: libafl_exit_reason_kind) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for libafl_exit_reason_kind { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + libafl_exit_reason_kind(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for libafl_exit_reason_kind { + #[inline] + fn bitand_assign(&mut self, rhs: libafl_exit_reason_kind) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct libafl_exit_reason_kind(pub ::std::os::raw::c_uint); +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct libafl_exit_reason_breakpoint { + pub addr: target_ulong, +} +#[test] +fn bindgen_test_layout_libafl_exit_reason_breakpoint() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(libafl_exit_reason_breakpoint)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(libafl_exit_reason_breakpoint)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason_breakpoint), + "::", + stringify!(addr) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct libafl_exit_reason_sync_backdoor {} +#[test] +fn bindgen_test_layout_libafl_exit_reason_sync_backdoor() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(libafl_exit_reason_sync_backdoor)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(libafl_exit_reason_sync_backdoor) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct libafl_exit_reason { + pub kind: libafl_exit_reason_kind, + pub cpu: *mut CPUState, + pub next_pc: vaddr, + pub data: libafl_exit_reason__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union libafl_exit_reason__bindgen_ty_1 { + pub breakpoint: libafl_exit_reason_breakpoint, + pub backdoor: libafl_exit_reason_sync_backdoor, +} +#[test] +fn bindgen_test_layout_libafl_exit_reason__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(libafl_exit_reason__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!( + "Alignment of ", + stringify!(libafl_exit_reason__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).breakpoint) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason__bindgen_ty_1), + "::", + stringify!(breakpoint) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).backdoor) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason__bindgen_ty_1), + "::", + stringify!(backdoor) + ) + ); +} +impl Default for libafl_exit_reason__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for libafl_exit_reason__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "libafl_exit_reason__bindgen_ty_1 {{ union }}") + } +} +#[test] +fn bindgen_test_layout_libafl_exit_reason() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(libafl_exit_reason)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(libafl_exit_reason)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).kind) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason), + "::", + stringify!(kind) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).cpu) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason), + "::", + stringify!(cpu) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).next_pc) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason), + "::", + stringify!(next_pc) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(libafl_exit_reason), + "::", + stringify!(data) + ) + ); +} +impl Default for libafl_exit_reason { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for libafl_exit_reason { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "libafl_exit_reason {{ kind: {:?}, cpu: {:?}, data: {:?} }}", + self.kind, self.cpu, self.data + ) + } +} +extern "C" { + pub fn libafl_last_exit_cpu() -> *mut CPUState; +} +extern "C" { + pub fn libafl_exit_signal_vm_start(); +} +extern "C" { + pub fn libafl_exit_asap() -> bool; +} +extern "C" { + pub fn libafl_sync_exit_cpu(); +} +extern "C" { + pub fn libafl_exit_request_sync_backdoor(cpu: *mut CPUState, pc: target_ulong); +} +extern "C" { + pub fn libafl_exit_request_breakpoint(cpu: *mut CPUState, pc: target_ulong); +} +extern "C" { + pub fn libafl_get_exit_reason() -> *mut libafl_exit_reason; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct AccelCPUClass { @@ -11772,6 +12400,815 @@ extern "C" { #[doc = " qemu_plugin_hwaddr_phys_addr() - query physical address for memory operation\n @haddr: address handle from qemu_plugin_get_hwaddr()\n\n Returns the physical address associated with the memory operation\n\n Note that the returned physical address may not be unique if you are dealing\n with multiple address spaces."] pub fn qemu_plugin_hwaddr_phys_addr(haddr: *const qemu_plugin_hwaddr) -> u64; } +pub const TCGReg_TCG_REG_EAX: TCGReg = TCGReg(0); +pub const TCGReg_TCG_REG_ECX: TCGReg = TCGReg(1); +pub const TCGReg_TCG_REG_EDX: TCGReg = TCGReg(2); +pub const TCGReg_TCG_REG_EBX: TCGReg = TCGReg(3); +pub const TCGReg_TCG_REG_ESP: TCGReg = TCGReg(4); +pub const TCGReg_TCG_REG_EBP: TCGReg = TCGReg(5); +pub const TCGReg_TCG_REG_ESI: TCGReg = TCGReg(6); +pub const TCGReg_TCG_REG_EDI: TCGReg = TCGReg(7); +pub const TCGReg_TCG_REG_R8: TCGReg = TCGReg(8); +pub const TCGReg_TCG_REG_R9: TCGReg = TCGReg(9); +pub const TCGReg_TCG_REG_R10: TCGReg = TCGReg(10); +pub const TCGReg_TCG_REG_R11: TCGReg = TCGReg(11); +pub const TCGReg_TCG_REG_R12: TCGReg = TCGReg(12); +pub const TCGReg_TCG_REG_R13: TCGReg = TCGReg(13); +pub const TCGReg_TCG_REG_R14: TCGReg = TCGReg(14); +pub const TCGReg_TCG_REG_R15: TCGReg = TCGReg(15); +pub const TCGReg_TCG_REG_XMM0: TCGReg = TCGReg(16); +pub const TCGReg_TCG_REG_XMM1: TCGReg = TCGReg(17); +pub const TCGReg_TCG_REG_XMM2: TCGReg = TCGReg(18); +pub const TCGReg_TCG_REG_XMM3: TCGReg = TCGReg(19); +pub const TCGReg_TCG_REG_XMM4: TCGReg = TCGReg(20); +pub const TCGReg_TCG_REG_XMM5: TCGReg = TCGReg(21); +pub const TCGReg_TCG_REG_XMM6: TCGReg = TCGReg(22); +pub const TCGReg_TCG_REG_XMM7: TCGReg = TCGReg(23); +pub const TCGReg_TCG_REG_XMM8: TCGReg = TCGReg(24); +pub const TCGReg_TCG_REG_XMM9: TCGReg = TCGReg(25); +pub const TCGReg_TCG_REG_XMM10: TCGReg = TCGReg(26); +pub const TCGReg_TCG_REG_XMM11: TCGReg = TCGReg(27); +pub const TCGReg_TCG_REG_XMM12: TCGReg = TCGReg(28); +pub const TCGReg_TCG_REG_XMM13: TCGReg = TCGReg(29); +pub const TCGReg_TCG_REG_XMM14: TCGReg = TCGReg(30); +pub const TCGReg_TCG_REG_XMM15: TCGReg = TCGReg(31); +pub const TCGReg_TCG_REG_RAX: TCGReg = TCGReg(0); +pub const TCGReg_TCG_REG_RCX: TCGReg = TCGReg(1); +pub const TCGReg_TCG_REG_RDX: TCGReg = TCGReg(2); +pub const TCGReg_TCG_REG_RBX: TCGReg = TCGReg(3); +pub const TCGReg_TCG_REG_RSP: TCGReg = TCGReg(4); +pub const TCGReg_TCG_REG_RBP: TCGReg = TCGReg(5); +pub const TCGReg_TCG_REG_RSI: TCGReg = TCGReg(6); +pub const TCGReg_TCG_REG_RDI: TCGReg = TCGReg(7); +pub const TCGReg_TCG_AREG0: TCGReg = TCGReg(5); +pub const TCGReg_TCG_REG_CALL_STACK: TCGReg = TCGReg(4); +impl ::std::ops::BitOr for TCGReg { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + TCGReg(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for TCGReg { + #[inline] + fn bitor_assign(&mut self, rhs: TCGReg) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for TCGReg { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + TCGReg(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for TCGReg { + #[inline] + fn bitand_assign(&mut self, rhs: TCGReg) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TCGReg(pub ::std::os::raw::c_uint); +pub const TCGType_TCG_TYPE_I32: TCGType = TCGType(0); +pub const TCGType_TCG_TYPE_I64: TCGType = TCGType(1); +pub const TCGType_TCG_TYPE_I128: TCGType = TCGType(2); +pub const TCGType_TCG_TYPE_V64: TCGType = TCGType(3); +pub const TCGType_TCG_TYPE_V128: TCGType = TCGType(4); +pub const TCGType_TCG_TYPE_V256: TCGType = TCGType(5); +pub const TCGType_TCG_TYPE_REG: TCGType = TCGType(1); +pub const TCGType_TCG_TYPE_PTR: TCGType = TCGType(1); +impl ::std::ops::BitOr for TCGType { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + TCGType(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for TCGType { + #[inline] + fn bitor_assign(&mut self, rhs: TCGType) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for TCGType { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + TCGType(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for TCGType { + #[inline] + fn bitand_assign(&mut self, rhs: TCGType) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TCGType(pub ::std::os::raw::c_uint); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TCGv_i64_d { + _unused: [u8; 0], +} +pub type TCGv_i64 = *mut TCGv_i64_d; +pub const TCGTempVal_TEMP_VAL_DEAD: TCGTempVal = TCGTempVal(0); +pub const TCGTempVal_TEMP_VAL_REG: TCGTempVal = TCGTempVal(1); +pub const TCGTempVal_TEMP_VAL_MEM: TCGTempVal = TCGTempVal(2); +pub const TCGTempVal_TEMP_VAL_CONST: TCGTempVal = TCGTempVal(3); +impl ::std::ops::BitOr for TCGTempVal { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + TCGTempVal(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for TCGTempVal { + #[inline] + fn bitor_assign(&mut self, rhs: TCGTempVal) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for TCGTempVal { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + TCGTempVal(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for TCGTempVal { + #[inline] + fn bitand_assign(&mut self, rhs: TCGTempVal) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TCGTempVal(pub ::std::os::raw::c_uint); +pub const TCGTempKind_TEMP_EBB: TCGTempKind = TCGTempKind(0); +pub const TCGTempKind_TEMP_TB: TCGTempKind = TCGTempKind(1); +pub const TCGTempKind_TEMP_GLOBAL: TCGTempKind = TCGTempKind(2); +pub const TCGTempKind_TEMP_FIXED: TCGTempKind = TCGTempKind(3); +pub const TCGTempKind_TEMP_CONST: TCGTempKind = TCGTempKind(4); +impl ::std::ops::BitOr for TCGTempKind { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + TCGTempKind(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for TCGTempKind { + #[inline] + fn bitor_assign(&mut self, rhs: TCGTempKind) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for TCGTempKind { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + TCGTempKind(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for TCGTempKind { + #[inline] + fn bitand_assign(&mut self, rhs: TCGTempKind) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TCGTempKind(pub ::std::os::raw::c_uint); +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TCGTemp { + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 6usize]>, + pub val: i64, + pub mem_base: *mut TCGTemp, + pub mem_offset: isize, + pub name: *const ::std::os::raw::c_char, + pub state: usize, + pub state_ptr: *mut ::std::os::raw::c_void, +} +#[test] +fn bindgen_test_layout_TCGTemp() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 56usize, + concat!("Size of: ", stringify!(TCGTemp)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TCGTemp)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(TCGTemp), + "::", + stringify!(val) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mem_base) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(TCGTemp), + "::", + stringify!(mem_base) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mem_offset) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(TCGTemp), + "::", + stringify!(mem_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(TCGTemp), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).state) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(TCGTemp), + "::", + stringify!(state) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).state_ptr) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(TCGTemp), + "::", + stringify!(state_ptr) + ) + ); +} +impl Default for TCGTemp { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl TCGTemp { + #[inline] + pub fn reg(&self) -> TCGReg { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 8u8) as u32) } + } + #[inline] + pub fn set_reg(&mut self, val: TCGReg) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 8u8, val as u64) + } + } + #[inline] + pub fn val_type(&self) -> TCGTempVal { + unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 8u8) as u32) } + } + #[inline] + pub fn set_val_type(&mut self, val: TCGTempVal) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(8usize, 8u8, val as u64) + } + } + #[inline] + pub fn base_type(&self) -> TCGType { + unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 8u8) as u32) } + } + #[inline] + pub fn set_base_type(&mut self, val: TCGType) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(16usize, 8u8, val as u64) + } + } + #[inline] + pub fn type_(&self) -> TCGType { + unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 8u8) as u32) } + } + #[inline] + pub fn set_type(&mut self, val: TCGType) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(24usize, 8u8, val as u64) + } + } + #[inline] + pub fn kind(&self) -> TCGTempKind { + unsafe { ::std::mem::transmute(self._bitfield_1.get(32usize, 3u8) as u32) } + } + #[inline] + pub fn set_kind(&mut self, val: TCGTempKind) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(32usize, 3u8, val as u64) + } + } + #[inline] + pub fn indirect_reg(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(35usize, 1u8) as u32) } + } + #[inline] + pub fn set_indirect_reg(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(35usize, 1u8, val as u64) + } + } + #[inline] + pub fn indirect_base(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(36usize, 1u8) as u32) } + } + #[inline] + pub fn set_indirect_base(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(36usize, 1u8, val as u64) + } + } + #[inline] + pub fn mem_coherent(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(37usize, 1u8) as u32) } + } + #[inline] + pub fn set_mem_coherent(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(37usize, 1u8, val as u64) + } + } + #[inline] + pub fn mem_allocated(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(38usize, 1u8) as u32) } + } + #[inline] + pub fn set_mem_allocated(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(38usize, 1u8, val as u64) + } + } + #[inline] + pub fn temp_allocated(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(39usize, 1u8) as u32) } + } + #[inline] + pub fn set_temp_allocated(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(39usize, 1u8, val as u64) + } + } + #[inline] + pub fn temp_subindex(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(40usize, 1u8) as u32) } + } + #[inline] + pub fn set_temp_subindex(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(40usize, 1u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + reg: TCGReg, + val_type: TCGTempVal, + base_type: TCGType, + type_: TCGType, + kind: TCGTempKind, + indirect_reg: ::std::os::raw::c_uint, + indirect_base: ::std::os::raw::c_uint, + mem_coherent: ::std::os::raw::c_uint, + mem_allocated: ::std::os::raw::c_uint, + temp_allocated: ::std::os::raw::c_uint, + temp_subindex: ::std::os::raw::c_uint, + ) -> __BindgenBitfieldUnit<[u8; 6usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 6usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 8u8, { + let reg: u32 = unsafe { ::std::mem::transmute(reg) }; + reg as u64 + }); + __bindgen_bitfield_unit.set(8usize, 8u8, { + let val_type: u32 = unsafe { ::std::mem::transmute(val_type) }; + val_type as u64 + }); + __bindgen_bitfield_unit.set(16usize, 8u8, { + let base_type: u32 = unsafe { ::std::mem::transmute(base_type) }; + base_type as u64 + }); + __bindgen_bitfield_unit.set(24usize, 8u8, { + let type_: u32 = unsafe { ::std::mem::transmute(type_) }; + type_ as u64 + }); + __bindgen_bitfield_unit.set(32usize, 3u8, { + let kind: u32 = unsafe { ::std::mem::transmute(kind) }; + kind as u64 + }); + __bindgen_bitfield_unit.set(35usize, 1u8, { + let indirect_reg: u32 = unsafe { ::std::mem::transmute(indirect_reg) }; + indirect_reg as u64 + }); + __bindgen_bitfield_unit.set(36usize, 1u8, { + let indirect_base: u32 = unsafe { ::std::mem::transmute(indirect_base) }; + indirect_base as u64 + }); + __bindgen_bitfield_unit.set(37usize, 1u8, { + let mem_coherent: u32 = unsafe { ::std::mem::transmute(mem_coherent) }; + mem_coherent as u64 + }); + __bindgen_bitfield_unit.set(38usize, 1u8, { + let mem_allocated: u32 = unsafe { ::std::mem::transmute(mem_allocated) }; + mem_allocated as u64 + }); + __bindgen_bitfield_unit.set(39usize, 1u8, { + let temp_allocated: u32 = unsafe { ::std::mem::transmute(temp_allocated) }; + temp_allocated as u64 + }); + __bindgen_bitfield_unit.set(40usize, 1u8, { + let temp_subindex: u32 = unsafe { ::std::mem::transmute(temp_subindex) }; + temp_subindex as u64 + }); + __bindgen_bitfield_unit + } +} +pub const TCGCallReturnKind_TCG_CALL_RET_NORMAL: TCGCallReturnKind = TCGCallReturnKind(0); +pub const TCGCallReturnKind_TCG_CALL_RET_BY_REF: TCGCallReturnKind = TCGCallReturnKind(1); +pub const TCGCallReturnKind_TCG_CALL_RET_BY_VEC: TCGCallReturnKind = TCGCallReturnKind(2); +impl ::std::ops::BitOr for TCGCallReturnKind { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + TCGCallReturnKind(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for TCGCallReturnKind { + #[inline] + fn bitor_assign(&mut self, rhs: TCGCallReturnKind) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for TCGCallReturnKind { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + TCGCallReturnKind(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for TCGCallReturnKind { + #[inline] + fn bitand_assign(&mut self, rhs: TCGCallReturnKind) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TCGCallReturnKind(pub ::std::os::raw::c_uint); +pub const TCGCallArgumentKind_TCG_CALL_ARG_NORMAL: TCGCallArgumentKind = TCGCallArgumentKind(0); +pub const TCGCallArgumentKind_TCG_CALL_ARG_EVEN: TCGCallArgumentKind = TCGCallArgumentKind(1); +pub const TCGCallArgumentKind_TCG_CALL_ARG_EXTEND: TCGCallArgumentKind = TCGCallArgumentKind(2); +pub const TCGCallArgumentKind_TCG_CALL_ARG_EXTEND_U: TCGCallArgumentKind = TCGCallArgumentKind(3); +pub const TCGCallArgumentKind_TCG_CALL_ARG_EXTEND_S: TCGCallArgumentKind = TCGCallArgumentKind(4); +pub const TCGCallArgumentKind_TCG_CALL_ARG_BY_REF: TCGCallArgumentKind = TCGCallArgumentKind(5); +pub const TCGCallArgumentKind_TCG_CALL_ARG_BY_REF_N: TCGCallArgumentKind = TCGCallArgumentKind(6); +impl ::std::ops::BitOr for TCGCallArgumentKind { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + TCGCallArgumentKind(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for TCGCallArgumentKind { + #[inline] + fn bitor_assign(&mut self, rhs: TCGCallArgumentKind) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for TCGCallArgumentKind { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + TCGCallArgumentKind(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for TCGCallArgumentKind { + #[inline] + fn bitand_assign(&mut self, rhs: TCGCallArgumentKind) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TCGCallArgumentKind(pub ::std::os::raw::c_uint); +#[repr(C)] +#[repr(align(4))] +#[derive(Debug, Copy, Clone)] +pub struct TCGCallArgumentLoc { + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, +} +#[test] +fn bindgen_test_layout_TCGCallArgumentLoc() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(TCGCallArgumentLoc)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(TCGCallArgumentLoc)) + ); +} +impl Default for TCGCallArgumentLoc { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl TCGCallArgumentLoc { + #[inline] + pub fn kind(&self) -> TCGCallArgumentKind { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 8u8) as u32) } + } + #[inline] + pub fn set_kind(&mut self, val: TCGCallArgumentKind) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 8u8, val as u64) + } + } + #[inline] + pub fn arg_slot(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 8u8) as u32) } + } + #[inline] + pub fn set_arg_slot(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(8usize, 8u8, val as u64) + } + } + #[inline] + pub fn ref_slot(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 8u8) as u32) } + } + #[inline] + pub fn set_ref_slot(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(16usize, 8u8, val as u64) + } + } + #[inline] + pub fn arg_idx(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 4u8) as u32) } + } + #[inline] + pub fn set_arg_idx(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(24usize, 4u8, val as u64) + } + } + #[inline] + pub fn tmp_subindex(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(28usize, 2u8) as u32) } + } + #[inline] + pub fn set_tmp_subindex(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(28usize, 2u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + kind: TCGCallArgumentKind, + arg_slot: ::std::os::raw::c_uint, + ref_slot: ::std::os::raw::c_uint, + arg_idx: ::std::os::raw::c_uint, + tmp_subindex: ::std::os::raw::c_uint, + ) -> __BindgenBitfieldUnit<[u8; 4usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 8u8, { + let kind: u32 = unsafe { ::std::mem::transmute(kind) }; + kind as u64 + }); + __bindgen_bitfield_unit.set(8usize, 8u8, { + let arg_slot: u32 = unsafe { ::std::mem::transmute(arg_slot) }; + arg_slot as u64 + }); + __bindgen_bitfield_unit.set(16usize, 8u8, { + let ref_slot: u32 = unsafe { ::std::mem::transmute(ref_slot) }; + ref_slot as u64 + }); + __bindgen_bitfield_unit.set(24usize, 4u8, { + let arg_idx: u32 = unsafe { ::std::mem::transmute(arg_idx) }; + arg_idx as u64 + }); + __bindgen_bitfield_unit.set(28usize, 2u8, { + let tmp_subindex: u32 = unsafe { ::std::mem::transmute(tmp_subindex) }; + tmp_subindex as u64 + }); + __bindgen_bitfield_unit + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TCGHelperInfo { + pub func: *mut ::std::os::raw::c_void, + pub name: *const ::std::os::raw::c_char, + pub init: usize, + pub _bitfield_align_1: [u32; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, + pub in_: [TCGCallArgumentLoc; 14usize], +} +#[test] +fn bindgen_test_layout_TCGHelperInfo() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 88usize, + concat!("Size of: ", stringify!(TCGHelperInfo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TCGHelperInfo)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).func) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(TCGHelperInfo), + "::", + stringify!(func) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(TCGHelperInfo), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).init) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(TCGHelperInfo), + "::", + stringify!(init) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).in_) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(TCGHelperInfo), + "::", + stringify!(in_) + ) + ); +} +impl Default for TCGHelperInfo { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl TCGHelperInfo { + #[inline] + pub fn typemask(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 32u8) as u32) } + } + #[inline] + pub fn set_typemask(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 32u8, val as u64) + } + } + #[inline] + pub fn flags(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(32usize, 8u8) as u32) } + } + #[inline] + pub fn set_flags(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(32usize, 8u8, val as u64) + } + } + #[inline] + pub fn nr_in(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(40usize, 8u8) as u32) } + } + #[inline] + pub fn set_nr_in(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(40usize, 8u8, val as u64) + } + } + #[inline] + pub fn nr_out(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(48usize, 8u8) as u32) } + } + #[inline] + pub fn set_nr_out(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(48usize, 8u8, val as u64) + } + } + #[inline] + pub fn out_kind(&self) -> TCGCallReturnKind { + unsafe { ::std::mem::transmute(self._bitfield_1.get(56usize, 8u8) as u32) } + } + #[inline] + pub fn set_out_kind(&mut self, val: TCGCallReturnKind) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(56usize, 8u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + typemask: ::std::os::raw::c_uint, + flags: ::std::os::raw::c_uint, + nr_in: ::std::os::raw::c_uint, + nr_out: ::std::os::raw::c_uint, + out_kind: TCGCallReturnKind, + ) -> __BindgenBitfieldUnit<[u8; 8usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 8usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 32u8, { + let typemask: u32 = unsafe { ::std::mem::transmute(typemask) }; + typemask as u64 + }); + __bindgen_bitfield_unit.set(32usize, 8u8, { + let flags: u32 = unsafe { ::std::mem::transmute(flags) }; + flags as u64 + }); + __bindgen_bitfield_unit.set(40usize, 8u8, { + let nr_in: u32 = unsafe { ::std::mem::transmute(nr_in) }; + nr_in as u64 + }); + __bindgen_bitfield_unit.set(48usize, 8u8, { + let nr_out: u32 = unsafe { ::std::mem::transmute(nr_out) }; + nr_out as u64 + }); + __bindgen_bitfield_unit.set(56usize, 8u8, { + let out_kind: u32 = unsafe { ::std::mem::transmute(out_kind) }; + out_kind as u64 + }); + __bindgen_bitfield_unit + } +} +pub type TCGv = TCGv_i64; #[doc = " struct qemu_plugin_hwaddr - opaque hw address handle"] #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -11855,6 +13292,327 @@ extern "C" { data: *mut qemu_plugin_hwaddr, ) -> bool; } +extern "C" { + pub fn libafl_gen_edge( + cpu: *mut CPUState, + src_block: target_ulong, + dst_block: target_ulong, + exit_n: ::std::os::raw::c_int, + cs_base: target_ulong, + flags: u32, + cflags: ::std::os::raw::c_int, + ) -> *mut TranslationBlock; +} +extern "C" { + pub fn libafl_gen_cmp(pc: target_ulong, op0: TCGv, op1: TCGv, ot: MemOp); +} +extern "C" { + pub fn libafl_gen_backdoor(pc: target_ulong); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct libafl_hook { + pub addr: target_ulong, + pub data: u64, + pub num: usize, + pub helper_info: TCGHelperInfo, + pub next: *mut libafl_hook, +} +#[test] +fn bindgen_test_layout_libafl_hook() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 120usize, + concat!("Size of: ", stringify!(libafl_hook)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(libafl_hook)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(libafl_hook), + "::", + stringify!(addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(libafl_hook), + "::", + stringify!(data) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).num) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(libafl_hook), + "::", + stringify!(num) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).helper_info) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(libafl_hook), + "::", + stringify!(helper_info) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).next) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(libafl_hook), + "::", + stringify!(next) + ) + ); +} +impl Default for libafl_hook { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +extern "C" { + pub fn libafl_qemu_set_hook( + pc: target_ulong, + callback: ::std::option::Option, + data: u64, + invalidate: ::std::os::raw::c_int, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_hooks_at( + addr: target_ulong, + invalidate: ::std::os::raw::c_int, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_search_hook(addr: target_ulong) -> *mut libafl_hook; +} +extern "C" { + pub fn libafl_add_backdoor_hook( + exec: ::std::option::Option, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_backdoor_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_add_edge_hook( + gen: ::std::option::Option< + extern "C" fn(data: u64, src: target_ulong, dst: target_ulong) -> u64, + >, + exec: ::std::option::Option, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_edge_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_add_block_hook( + gen: ::std::option::Option u64>, + post_gen: ::std::option::Option< + extern "C" fn(data: u64, pc: target_ulong, block_length: target_ulong), + >, + exec: ::std::option::Option, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_block_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_add_read_hook( + gen: ::std::option::Option u64>, + exec1: ::std::option::Option, + exec2: ::std::option::Option, + exec4: ::std::option::Option, + exec8: ::std::option::Option, + execN: ::std::option::Option< + extern "C" fn(data: u64, id: u64, addr: target_ulong, size: usize), + >, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_add_write_hook( + gen: ::std::option::Option u64>, + exec1: ::std::option::Option, + exec2: ::std::option::Option, + exec4: ::std::option::Option, + exec8: ::std::option::Option, + execN: ::std::option::Option< + extern "C" fn(data: u64, id: u64, addr: target_ulong, size: usize), + >, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_read_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_remove_write_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_gen_read(addr: *mut TCGTemp, oi: MemOpIdx); +} +extern "C" { + pub fn libafl_gen_write(addr: *mut TCGTemp, oi: MemOpIdx); +} +extern "C" { + pub fn libafl_add_cmp_hook( + gen: ::std::option::Option u64>, + exec1: ::std::option::Option, + exec2: ::std::option::Option, + exec4: ::std::option::Option, + exec8: ::std::option::Option, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_cmp_hook( + num: usize, + invalidate: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct syshook_ret { + pub retval: target_ulong, + pub skip_syscall: bool, +} +#[test] +fn bindgen_test_layout_syshook_ret() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(syshook_ret)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(syshook_ret)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).retval) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(syshook_ret), + "::", + stringify!(retval) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).skip_syscall) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(syshook_ret), + "::", + stringify!(skip_syscall) + ) + ); +} +extern "C" { + pub fn libafl_add_pre_syscall_hook( + callback: ::std::option::Option< + unsafe extern "C" fn( + data: u64, + sys_num: ::std::os::raw::c_int, + arg0: target_ulong, + arg1: target_ulong, + arg2: target_ulong, + arg3: target_ulong, + arg4: target_ulong, + arg5: target_ulong, + arg6: target_ulong, + arg7: target_ulong, + ) -> syshook_ret, + >, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_add_post_syscall_hook( + callback: ::std::option::Option< + unsafe extern "C" fn( + data: u64, + ret: target_ulong, + sys_num: ::std::os::raw::c_int, + arg0: target_ulong, + arg1: target_ulong, + arg2: target_ulong, + arg3: target_ulong, + arg4: target_ulong, + arg5: target_ulong, + arg6: target_ulong, + arg7: target_ulong, + ) -> target_ulong, + >, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_pre_syscall_hook(num: usize) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_remove_post_syscall_hook(num: usize) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_add_new_thread_hook( + callback: ::std::option::Option bool>, + data: u64, + ) -> usize; +} +extern "C" { + pub fn libafl_qemu_remove_new_thread_hook(num: usize) -> ::std::os::raw::c_int; +} #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct kvm_dirty_gfn { diff --git a/libafl_qemu/src/asan.rs b/libafl_qemu/src/asan.rs index 458fa74034..07cd3f4c5c 100644 --- a/libafl_qemu/src/asan.rs +++ b/libafl_qemu/src/asan.rs @@ -22,7 +22,7 @@ use crate::{ calls::FullBacktraceCollector, emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult}, helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, - hooks::QemuHooks, + hooks::{Hook, QemuHooks}, GuestAddr, Regs, }; @@ -61,6 +61,14 @@ pub enum QasanAction { SwapState, } +impl TryFrom for QasanAction { + type Error = num_enum::TryFromPrimitiveError; + + fn try_from(value: u32) -> Result { + QasanAction::try_from(value as u64) + } +} + #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, PartialEq)] #[repr(i8)] pub enum PoisonKind { @@ -143,7 +151,7 @@ impl AllocTreeItem { self.allocated = false; } } - +use std::pin::Pin; pub struct AsanGiovese { pub alloc_tree: Mutex>, pub saved_tree: IntervalTree, @@ -163,7 +171,7 @@ impl core::fmt::Debug for AsanGiovese { } impl AsanGiovese { - pub unsafe fn map_shadow() { + unsafe fn map_shadow() { assert!( libc::mmap( HIGH_SHADOW_ADDR, @@ -196,6 +204,80 @@ impl AsanGiovese { ); } + #[must_use] + fn new(emu: &Emulator) -> Pin> { + let res = Self { + alloc_tree: Mutex::new(IntervalTree::new()), + saved_tree: IntervalTree::new(), + error_callback: None, + dirty_shadow: Mutex::new(HashSet::default()), + saved_shadow: HashMap::default(), + snapshot_shadow: true, // By default, track the dirty shadow pages + }; + let mut boxed = Box::pin(res); + emu.add_pre_syscall_hook(boxed.as_mut(), Self::fake_syscall); + boxed + } + + extern "C" fn fake_syscall( + mut self: Pin<&mut Self>, + sys_num: i32, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + _a4: GuestAddr, + _a5: GuestAddr, + _a6: GuestAddr, + _a7: GuestAddr, + ) -> SyscallHookResult { + if sys_num == QASAN_FAKESYS_NR { + let mut r = 0; + let emulator = Emulator::get().unwrap(); + match QasanAction::try_from(a0).expect("Invalid QASan action number") { + QasanAction::Poison => { + self.poison( + &emulator, + a1, + a2 as usize, + PoisonKind::try_from(a3 as i8).unwrap().into(), + ); + } + QasanAction::UserPoison => { + self.poison(&emulator, a1, a2 as usize, PoisonKind::User.into()); + } + QasanAction::UnPoison => { + Self::unpoison(&emulator, a1, a2 as usize); + } + QasanAction::IsPoison => { + if Self::is_invalid_access(&emulator, a1, a2 as usize) { + r = 1; + } + } + QasanAction::Alloc => { + let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap(); + self.allocation(pc, a1, a2); + } + QasanAction::Dealloc => { + let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap(); + self.deallocation(&emulator, pc, a1); + } + _ => (), + } + SyscallHookResult::new(Some(r)) + } else { + SyscallHookResult::new(None) + } + } + + fn set_error_callback(&mut self, error_callback: AsanErrorCallback) { + self.error_callback = Some(error_callback); + } + + fn set_snapshot_shadow(&mut self, snapshot_shadow: bool) { + self.snapshot_shadow = snapshot_shadow; + } + #[inline] #[must_use] pub fn is_invalid_access_1(emu: &Emulator, addr: GuestAddr) -> bool { @@ -357,7 +439,7 @@ impl AsanGiovese { } #[inline] - fn unpoison_page(emu: &Emulator, page: GuestAddr) { + pub fn unpoison_page(emu: &Emulator, page: GuestAddr) { unsafe { let h = emu.g2h::<*const c_void>(page) as isize; let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET); @@ -375,30 +457,6 @@ impl AsanGiovese { } } - #[must_use] - pub fn new(snapshot_shadow: bool) -> Self { - Self { - alloc_tree: Mutex::new(IntervalTree::new()), - saved_tree: IntervalTree::new(), - error_callback: None, - dirty_shadow: Mutex::new(HashSet::default()), - saved_shadow: HashMap::default(), - snapshot_shadow, - } - } - - #[must_use] - pub fn with_error_callback(snapshot_shadow: bool, error_callback: AsanErrorCallback) -> Self { - Self { - alloc_tree: Mutex::new(IntervalTree::new()), - saved_tree: IntervalTree::new(), - error_callback: Some(error_callback), - dirty_shadow: Mutex::new(HashSet::default()), - saved_shadow: HashMap::default(), - snapshot_shadow, - } - } - pub fn report_or_crash(&mut self, emu: &Emulator, pc: GuestAddr, error: AsanError) { if let Some(mut cb) = self.error_callback.take() { (cb)(self, emu, pc, error); @@ -529,6 +587,15 @@ impl AsanGiovese { } } + pub fn allocation(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) { + self.alloc_remove(start, end); + self.alloc_insert(pc, start, end); + } + + pub fn deallocation(&mut self, emulator: &Emulator, pc: GuestAddr, addr: GuestAddr) { + self.alloc_free(emulator, pc, addr); + } + pub fn snapshot(&mut self, emu: &Emulator) { if self.snapshot_shadow { let set = self.dirty_shadow.lock().unwrap(); @@ -599,7 +666,7 @@ static mut ASAN_INITED: bool = false; pub fn init_with_asan( args: &mut Vec, env: &mut [(String, String)], -) -> Result { +) -> Result<(Emulator, Pin>), EmuError> { let current = env::current_exe().unwrap(); let asan_lib = fs::canonicalize(current) .unwrap() @@ -644,7 +711,11 @@ pub fn init_with_asan( AsanGiovese::map_shadow(); ASAN_INITED = true; } - Emulator::new(args, env) + + let emu = Emulator::new(args, env)?; + let rt = AsanGiovese::new(&emu); + + Ok((emu, rt)) } pub enum QemuAsanOptions { @@ -661,13 +732,26 @@ pub struct QemuAsanHelper { enabled: bool, detect_leaks: bool, empty: bool, - rt: AsanGiovese, + rt: Pin>, filter: QemuInstrumentationFilter, } impl QemuAsanHelper { #[must_use] - pub fn new(filter: QemuInstrumentationFilter, options: QemuAsanOptions) -> Self { + pub fn default(rt: Pin>) -> Self { + Self::new( + rt, + QemuInstrumentationFilter::None, + QemuAsanOptions::Snapshot, + ) + } + + #[must_use] + pub fn new( + mut rt: Pin>, + filter: QemuInstrumentationFilter, + options: QemuAsanOptions, + ) -> Self { assert!(unsafe { ASAN_INITED }, "The ASan runtime is not initialized, use init_with_asan(...) instead of just Emulator::new(...)"); let (snapshot, detect_leaks) = match options { QemuAsanOptions::None => (false, false), @@ -675,17 +759,19 @@ impl QemuAsanHelper { QemuAsanOptions::DetectLeaks => (false, true), QemuAsanOptions::SnapshotDetectLeaks => (true, true), }; + rt.set_snapshot_shadow(snapshot); Self { enabled: true, detect_leaks, empty: true, - rt: AsanGiovese::new(snapshot), + rt, filter, } } #[must_use] pub fn with_error_callback( + mut rt: Pin>, filter: QemuInstrumentationFilter, error_callback: AsanErrorCallback, options: QemuAsanOptions, @@ -697,18 +783,24 @@ impl QemuAsanHelper { QemuAsanOptions::DetectLeaks => (false, true), QemuAsanOptions::SnapshotDetectLeaks => (true, true), }; + rt.set_snapshot_shadow(snapshot); + rt.set_error_callback(error_callback); Self { enabled: true, detect_leaks, empty: true, - rt: AsanGiovese::with_error_callback(snapshot, error_callback), + rt, filter, } } #[must_use] - pub fn with_asan_report(filter: QemuInstrumentationFilter, options: QemuAsanOptions) -> Self { - Self::with_error_callback(filter, Box::new(asan_report), options) + pub fn with_asan_report( + rt: Pin>, + filter: QemuInstrumentationFilter, + options: QemuAsanOptions, + ) -> Self { + Self::with_error_callback(rt, filter, Box::new(asan_report), options) } #[must_use] @@ -726,12 +818,11 @@ impl QemuAsanHelper { } pub fn alloc(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) { - self.rt.alloc_remove(start, end); - self.rt.alloc_insert(pc, start, end); + self.rt.allocation(pc, start, end); } pub fn dealloc(&mut self, emulator: &Emulator, pc: GuestAddr, addr: GuestAddr) { - self.rt.alloc_free(emulator, pc, addr); + self.rt.deallocation(emulator, pc, addr); } #[allow(clippy::unused_self)] @@ -830,12 +921,6 @@ impl QemuAsanHelper { } } -impl Default for QemuAsanHelper { - fn default() -> Self { - Self::new(QemuInstrumentationFilter::None, QemuAsanOptions::Snapshot) - } -} - impl HasInstrumentationFilter for QemuAsanHelper { fn filter(&self) -> &QemuInstrumentationFilter { &self.filter @@ -852,37 +937,37 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { - hooks.syscalls(qasan_fake_syscall::); + hooks.syscalls(Hook::Function(qasan_fake_syscall::)); if self.rt.error_callback.is_some() { - hooks.crash(oncrash_asan::); + hooks.crash_function(oncrash_asan::); } } - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { hooks.reads( - Some(gen_readwrite_asan::), - Some(trace_read1_asan::), - Some(trace_read2_asan::), - Some(trace_read4_asan::), - Some(trace_read8_asan::), - Some(trace_read_n_asan::), + Hook::Function(gen_readwrite_asan::), + Hook::Function(trace_read1_asan::), + Hook::Function(trace_read2_asan::), + Hook::Function(trace_read4_asan::), + Hook::Function(trace_read8_asan::), + Hook::Function(trace_read_n_asan::), ); hooks.writes( - Some(gen_readwrite_asan::), - Some(trace_write1_asan::), - Some(trace_write2_asan::), - Some(trace_write4_asan::), - Some(trace_write8_asan::), - Some(trace_write_n_asan::), + Hook::Function(gen_readwrite_asan::), + Hook::Function(trace_write1_asan::), + Hook::Function(trace_write2_asan::), + Hook::Function(trace_write4_asan::), + Hook::Function(trace_write8_asan::), + Hook::Function(trace_write_n_asan::), ); } @@ -908,7 +993,7 @@ where } } -pub fn oncrash_asan(hooks: &mut QemuHooks<'_, QT, S>, target_sig: i32) +pub fn oncrash_asan(hooks: &mut QemuHooks, target_sig: i32) where S: UsesInput, QT: QemuHelperTuple, @@ -920,7 +1005,7 @@ where } pub fn gen_readwrite_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, _info: MemAccessInfo, @@ -938,7 +1023,7 @@ where } pub fn trace_read1_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -952,7 +1037,7 @@ pub fn trace_read1_asan( } pub fn trace_read2_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -966,7 +1051,7 @@ pub fn trace_read2_asan( } pub fn trace_read4_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -980,7 +1065,7 @@ pub fn trace_read4_asan( } pub fn trace_read8_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -994,7 +1079,7 @@ pub fn trace_read8_asan( } pub fn trace_read_n_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -1009,7 +1094,7 @@ pub fn trace_read_n_asan( } pub fn trace_write1_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -1023,7 +1108,7 @@ pub fn trace_write1_asan( } pub fn trace_write2_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -1037,7 +1122,7 @@ pub fn trace_write2_asan( } pub fn trace_write4_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -1051,7 +1136,7 @@ pub fn trace_write4_asan( } pub fn trace_write8_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -1065,7 +1150,7 @@ pub fn trace_write8_asan( } pub fn trace_write_n_asan( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64, addr: GuestAddr, @@ -1081,17 +1166,17 @@ pub fn trace_write_n_asan( #[allow(clippy::too_many_arguments)] pub fn qasan_fake_syscall( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, sys_num: i32, - a0: u64, - a1: u64, - a2: u64, - a3: u64, - _a4: u64, - _a5: u64, - _a6: u64, - _a7: u64, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + _a3: GuestAddr, + _a4: GuestAddr, + _a5: GuestAddr, + _a6: GuestAddr, + _a7: GuestAddr, ) -> SyscallHookResult where S: UsesInput, @@ -1100,42 +1185,14 @@ where if sys_num == QASAN_FAKESYS_NR { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); - let mut r = 0; match QasanAction::try_from(a0).expect("Invalid QASan action number") { QasanAction::CheckLoad => { let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap(); - h.read_n(&emulator, pc, a1 as GuestAddr, a2 as usize); + h.read_n(&emulator, pc, a1, a2 as usize); } QasanAction::CheckStore => { let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap(); - h.write_n(&emulator, pc, a1 as GuestAddr, a2 as usize); - } - QasanAction::Poison => { - h.poison( - &emulator, - a1 as GuestAddr, - a2 as usize, - PoisonKind::try_from(a3 as i8).unwrap(), - ); - } - QasanAction::UserPoison => { - h.poison(&emulator, a1 as GuestAddr, a2 as usize, PoisonKind::User); - } - QasanAction::UnPoison => { - h.unpoison(&emulator, a1 as GuestAddr, a2 as usize); - } - QasanAction::IsPoison => { - if h.is_poisoned(&emulator, a1 as GuestAddr, a2 as usize) { - r = 1; - } - } - QasanAction::Alloc => { - let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap(); - h.alloc(pc, a1 as GuestAddr, a2 as GuestAddr); - } - QasanAction::Dealloc => { - let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap(); - h.dealloc(&emulator, pc, a1 as GuestAddr); + h.write_n(&emulator, pc, a1, a2 as usize); } QasanAction::Enable => { h.set_enabled(true); @@ -1146,8 +1203,9 @@ where QasanAction::SwapState => { h.set_enabled(!h.enabled()); } + _ => (), } - SyscallHookResult::new(Some(r)) + SyscallHookResult::new(Some(0)) } else { SyscallHookResult::new(None) } diff --git a/libafl_qemu/src/calls.rs b/libafl_qemu/src/calls.rs index 19172f9336..ec8ea05465 100644 --- a/libafl_qemu/src/calls.rs +++ b/libafl_qemu/src/calls.rs @@ -13,14 +13,14 @@ use crate::{ capstone, emu::{ArchExtras, Emulator}, helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, - hooks::QemuHooks, + hooks::{Hook, QemuHooks}, GuestAddr, }; pub trait CallTraceCollector: 'static + Debug { fn on_call( &mut self, - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, state: Option<&mut S>, pc: GuestAddr, call_len: usize, @@ -30,7 +30,7 @@ pub trait CallTraceCollector: 'static + Debug { fn on_ret( &mut self, - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, state: Option<&mut S>, pc: GuestAddr, ret_addr: GuestAddr, @@ -61,7 +61,7 @@ pub trait CallTraceCollector: 'static + Debug { pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug { fn on_call_all( &mut self, - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, call_len: usize, @@ -71,7 +71,7 @@ pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug { fn on_ret_all( &mut self, - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, _pc: GuestAddr, ret_addr: GuestAddr, @@ -97,7 +97,7 @@ pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug { impl CallTraceCollectorTuple for () { fn on_call_all( &mut self, - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, _pc: GuestAddr, _call_len: usize, @@ -109,7 +109,7 @@ impl CallTraceCollectorTuple for () { fn on_ret_all( &mut self, - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, _pc: GuestAddr, _ret_addr: GuestAddr, @@ -145,7 +145,7 @@ where { fn on_call_all( &mut self, - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, mut state: Option<&mut S>, pc: GuestAddr, call_len: usize, @@ -167,7 +167,7 @@ where fn on_ret_all( &mut self, - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, mut state: Option<&mut S>, pc: GuestAddr, ret_addr: GuestAddr, @@ -238,7 +238,7 @@ where self.filter.allowed(addr) } - fn on_ret(hooks: &mut QemuHooks<'_, QT, S>, state: Option<&mut S>, pc: GuestAddr) + fn on_ret(hooks: &mut QemuHooks, state: Option<&mut S>, pc: GuestAddr) where S: UsesInput, QT: QemuHelperTuple, @@ -267,7 +267,7 @@ where } fn gen_blocks_calls( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, ) -> Option @@ -319,40 +319,38 @@ where capstone::InsnGroupType::CS_GRP_CALL => { let call_len = insn.bytes().len(); // TODO do not use a closure, find a more efficient way to pass call_len - let call_cb = move |hooks: &mut QemuHooks<'_, QT, S>, - state: Option<&mut S>, - pc| { - // eprintln!("CALL @ 0x{:#x}", pc + call_len); - let mut collectors = if let Some(h) = - hooks.helpers_mut().match_first_type_mut::() - { - h.collectors.take() - } else { - return; - }; - if collectors.is_none() { - return; // TODO fix this, it can be None on races ret - } - collectors - .as_mut() - .unwrap() - .on_call_all(hooks, state, pc, call_len); - hooks - .helpers_mut() - .match_first_type_mut::() - .unwrap() - .collectors = collectors; - }; - unsafe { - hooks.instruction_closure( - insn.address() as GuestAddr, - Box::new(call_cb), - false, - ); - } + let call_cb = Box::new( + move |hooks: &mut QemuHooks, state: Option<&mut S>, pc| { + // eprintln!("CALL @ 0x{:#x}", pc + call_len); + let mut collectors = if let Some(h) = + hooks.helpers_mut().match_first_type_mut::() + { + h.collectors.take() + } else { + return; + }; + if collectors.is_none() { + return; // TODO fix this, it can be None on races ret + } + collectors + .as_mut() + .unwrap() + .on_call_all(hooks, state, pc, call_len); + hooks + .helpers_mut() + .match_first_type_mut::() + .unwrap() + .collectors = collectors; + }, + ); + hooks.instruction_closure(insn.address() as GuestAddr, call_cb, false); } capstone::InsnGroupType::CS_GRP_RET => { - hooks.instruction(insn.address() as GuestAddr, Self::on_ret, false); + hooks.instruction_function( + insn.address() as GuestAddr, + Self::on_ret, + false, + ); break 'disasm; } capstone::InsnGroupType::CS_GRP_INVALID @@ -400,11 +398,15 @@ where S: UsesInput, T: CallTraceCollectorTuple, { - fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { - hooks.blocks(Some(Self::gen_blocks_calls::), None, None); + hooks.blocks( + Hook::Function(Self::gen_blocks_calls::), + Hook::Empty, + Hook::Empty, + ); } fn pre_exec(&mut self, emulator: &Emulator, input: &S::Input) { @@ -468,7 +470,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector { #[allow(clippy::unnecessary_cast)] fn on_call( &mut self, - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, call_len: usize, @@ -482,7 +484,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector { #[allow(clippy::unnecessary_cast)] fn on_ret( &mut self, - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, _pc: GuestAddr, ret_addr: GuestAddr, @@ -557,7 +559,7 @@ impl CallTraceCollector for FullBacktraceCollector { #[allow(clippy::unnecessary_cast)] fn on_call( &mut self, - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, call_len: usize, @@ -574,7 +576,7 @@ impl CallTraceCollector for FullBacktraceCollector { #[allow(clippy::unnecessary_cast)] fn on_ret( &mut self, - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, _pc: GuestAddr, ret_addr: GuestAddr, diff --git a/libafl_qemu/src/cmplog.rs b/libafl_qemu/src/cmplog.rs index 4eae220540..53de83b554 100644 --- a/libafl_qemu/src/cmplog.rs +++ b/libafl_qemu/src/cmplog.rs @@ -20,7 +20,7 @@ use crate::{ helper::{ hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter, }, - hooks::QemuHooks, + hooks::{Hook, QemuHooks}, GuestAddr, }; @@ -83,16 +83,16 @@ impl QemuHelper for QemuCmpLogHelper where S: UsesInput + HasMetadata, { - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { - hooks.cmps_raw( - Some(gen_unique_cmp_ids::), - Some(trace_cmp1_cmplog), - Some(trace_cmp2_cmplog), - Some(trace_cmp4_cmplog), - Some(trace_cmp8_cmplog), + hooks.cmps( + Hook::Function(gen_unique_cmp_ids::), + Hook::Raw(trace_cmp1_cmplog), + Hook::Raw(trace_cmp2_cmplog), + Hook::Raw(trace_cmp4_cmplog), + Hook::Raw(trace_cmp8_cmplog), ); } } @@ -127,22 +127,22 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { - hooks.cmps_raw( - Some(gen_hashed_cmp_ids::), - Some(trace_cmp1_cmplog), - Some(trace_cmp2_cmplog), - Some(trace_cmp4_cmplog), - Some(trace_cmp8_cmplog), + hooks.cmps( + Hook::Function(gen_hashed_cmp_ids::), + Hook::Raw(trace_cmp1_cmplog), + Hook::Raw(trace_cmp2_cmplog), + Hook::Raw(trace_cmp4_cmplog), + Hook::Raw(trace_cmp8_cmplog), ); } } pub fn gen_unique_cmp_ids( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, state: Option<&mut S>, pc: GuestAddr, _size: usize, @@ -174,7 +174,7 @@ where } pub fn gen_hashed_cmp_ids( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, _size: usize, @@ -192,25 +192,25 @@ where Some(hash_me(pc.into()) & (CMPLOG_MAP_W as u64 - 1)) } -pub extern "C" fn trace_cmp1_cmplog(id: u64, v0: u8, v1: u8, _data: u64) { +pub extern "C" fn trace_cmp1_cmplog(_: *const (), id: u64, v0: u8, v1: u8) { unsafe { __libafl_targets_cmplog_instructions(id as usize, 1, u64::from(v0), u64::from(v1)); } } -pub extern "C" fn trace_cmp2_cmplog(id: u64, v0: u16, v1: u16, _data: u64) { +pub extern "C" fn trace_cmp2_cmplog(_: *const (), id: u64, v0: u16, v1: u16) { unsafe { __libafl_targets_cmplog_instructions(id as usize, 2, u64::from(v0), u64::from(v1)); } } -pub extern "C" fn trace_cmp4_cmplog(id: u64, v0: u32, v1: u32, _data: u64) { +pub extern "C" fn trace_cmp4_cmplog(_: *const (), id: u64, v0: u32, v1: u32) { unsafe { __libafl_targets_cmplog_instructions(id as usize, 4, u64::from(v0), u64::from(v1)); } } -pub extern "C" fn trace_cmp8_cmplog(id: u64, v0: u64, v1: u64, _data: u64) { +pub extern "C" fn trace_cmp8_cmplog(_: *const (), id: u64, v0: u64, v1: u64) { unsafe { __libafl_targets_cmplog_instructions(id as usize, 8, v0, v1); } @@ -238,7 +238,7 @@ impl QemuCmpLogRoutinesHelper { self.filter.allowed(addr) } - extern "C" fn on_call(_pc: GuestAddr, k: u64) { + extern "C" fn on_call(k: u64, _pc: GuestAddr) { unsafe { if CMPLOG_ENABLED == 0 { return; @@ -266,7 +266,7 @@ impl QemuCmpLogRoutinesHelper { } fn gen_blocks_calls( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, ) -> Option @@ -317,7 +317,7 @@ impl QemuCmpLogRoutinesHelper { match u32::from(detail.0) { capstone::InsnGroupType::CS_GRP_CALL => { let k = (hash_me(pc.into())) & (CMPLOG_MAP_W as u64 - 1); - emu.set_hook(insn.address() as GuestAddr, Self::on_call, k, false); + emu.set_hook(k, insn.address() as GuestAddr, Self::on_call, false); } capstone::InsnGroupType::CS_GRP_RET | capstone::InsnGroupType::CS_GRP_INVALID @@ -363,10 +363,14 @@ impl QemuHelper for QemuCmpLogRoutinesHelper where S: UsesInput, { - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { - hooks.blocks(Some(Self::gen_blocks_calls::), None, None); + hooks.blocks( + Hook::Function(Self::gen_blocks_calls::), + Hook::Empty, + Hook::Empty, + ); } } diff --git a/libafl_qemu/src/drcov.rs b/libafl_qemu/src/drcov.rs index 72c0733682..3cd2b51532 100644 --- a/libafl_qemu/src/drcov.rs +++ b/libafl_qemu/src/drcov.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::{ emu::{GuestAddr, GuestUsize}, helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, - hooks::QemuHooks, + hooks::{Hook, QemuHooks}, Emulator, }; @@ -89,14 +89,14 @@ impl QemuHelper for QemuDrCovHelper where S: UsesInput + HasMetadata, { - fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { hooks.blocks( - Some(gen_unique_block_ids::), - Some(gen_block_lengths::), - Some(exec_trace_block::), + Hook::Function(gen_unique_block_ids::), + Hook::Function(gen_block_lengths::), + Hook::Function(exec_trace_block::), ); } @@ -192,7 +192,7 @@ where } pub fn gen_unique_block_ids( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, state: Option<&mut S>, pc: GuestAddr, ) -> Option @@ -247,7 +247,7 @@ where } pub fn gen_block_lengths( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, block_length: GuestUsize, @@ -271,7 +271,7 @@ pub fn gen_block_lengths( .insert(pc, block_length); } -pub fn exec_trace_block(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, id: u64) +pub fn exec_trace_block(hooks: &mut QemuHooks, _state: Option<&mut S>, id: u64) where S: HasMetadata, S: UsesInput, diff --git a/libafl_qemu/src/edges.rs b/libafl_qemu/src/edges.rs index c9737dbb6b..3eddde39fd 100644 --- a/libafl_qemu/src/edges.rs +++ b/libafl_qemu/src/edges.rs @@ -13,7 +13,7 @@ use crate::{ helper::{ hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter, }, - hooks::QemuHooks, + hooks::{Hook, QemuHooks}, }; #[cfg_attr( @@ -87,17 +87,20 @@ impl QemuHelper for QemuEdgeCoverageHelper where S: UsesInput + HasMetadata, { - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { if self.use_hitcounts { - hooks.edges_raw( - Some(gen_unique_edge_ids::), - Some(trace_edge_hitcount), + hooks.edges( + Hook::Function(gen_unique_edge_ids::), + Hook::Raw(trace_edge_hitcount), ); } else { - hooks.edges_raw(Some(gen_unique_edge_ids::), Some(trace_edge_single)); + hooks.edges( + Hook::Function(gen_unique_edge_ids::), + Hook::Raw(trace_edge_single), + ); } } } @@ -156,19 +159,19 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { if self.use_hitcounts { - hooks.edges_raw( - Some(gen_hashed_edge_ids::), - Some(trace_edge_hitcount_ptr), + hooks.edges( + Hook::Function(gen_hashed_edge_ids::), + Hook::Raw(trace_edge_hitcount_ptr), ); } else { - hooks.edges_raw( - Some(gen_hashed_edge_ids::), - Some(trace_edge_single_ptr), + hooks.edges( + Hook::Function(gen_hashed_edge_ids::), + Hook::Raw(trace_edge_single_ptr), ); } } @@ -226,21 +229,21 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { if self.use_hitcounts { - hooks.blocks_raw( - Some(gen_hashed_block_ids::), - None, - Some(trace_block_transition_hitcount), + hooks.blocks( + Hook::Function(gen_hashed_block_ids::), + Hook::Empty, + Hook::Raw(trace_block_transition_hitcount), ); } else { - hooks.blocks_raw( - Some(gen_hashed_block_ids::), - None, - Some(trace_block_transition_single), + hooks.blocks( + Hook::Function(gen_hashed_block_ids::), + Hook::Empty, + Hook::Raw(trace_block_transition_single), ); } } @@ -249,7 +252,7 @@ where thread_local!(static PREV_LOC : UnsafeCell = UnsafeCell::new(0)); pub fn gen_unique_edge_ids( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, state: Option<&mut S>, src: GuestAddr, dest: GuestAddr, @@ -296,20 +299,20 @@ where } } -pub extern "C" fn trace_edge_hitcount(id: u64, _data: u64) { +pub extern "C" fn trace_edge_hitcount(_: *const (), id: u64) { unsafe { EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1); } } -pub extern "C" fn trace_edge_single(id: u64, _data: u64) { +pub extern "C" fn trace_edge_single(_: *const (), id: u64) { unsafe { EDGES_MAP[id as usize] = 1; } } pub fn gen_hashed_edge_ids( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, src: GuestAddr, dest: GuestAddr, @@ -331,14 +334,14 @@ where Some((hash_me(src as u64) ^ hash_me(dest as u64)) & (unsafe { EDGES_MAP_PTR_NUM } as u64 - 1)) } -pub extern "C" fn trace_edge_hitcount_ptr(id: u64, _data: u64) { +pub extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) { unsafe { let ptr = EDGES_MAP_PTR.add(id as usize); *ptr = (*ptr).wrapping_add(1); } } -pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) { +pub extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) { unsafe { let ptr = EDGES_MAP_PTR.add(id as usize); *ptr = 1; @@ -347,7 +350,7 @@ pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) { /* pub fn gen_addr_block_ids( - _hooks: &mut QemuHooks<'_, QT, S>, + _hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, ) -> Option @@ -362,7 +365,7 @@ where */ pub fn gen_hashed_block_ids( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, pc: GuestAddr, ) -> Option @@ -383,7 +386,7 @@ where Some(hash_me(pc as u64)) } -pub extern "C" fn trace_block_transition_hitcount(id: u64, _data: u64) { +pub extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) { unsafe { PREV_LOC.with(|prev_loc| { let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1); @@ -394,7 +397,7 @@ pub extern "C" fn trace_block_transition_hitcount(id: u64, _data: u64) { } } -pub extern "C" fn trace_block_transition_single(id: u64, _data: u64) { +pub extern "C" fn trace_block_transition_single(_: *const (), id: u64) { unsafe { PREV_LOC.with(|prev_loc| { let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1); diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 97fabe4b01..9dd71b7b16 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -14,11 +14,7 @@ use std::{ ffi::{CStr, CString}, ptr::null_mut, }; -use std::{ - slice::from_raw_parts, - str::from_utf8_unchecked, - sync::{Mutex, OnceLock}, -}; +use std::{slice::from_raw_parts, str::from_utf8_unchecked}; #[cfg(emulation_mode = "usermode")] use libc::c_int; @@ -224,11 +220,12 @@ pub enum VerifyAccess { Write = libc::PROT_READ | libc::PROT_WRITE, } +// syshook_ret #[repr(C)] #[cfg_attr(feature = "python", pyclass)] #[cfg_attr(feature = "python", derive(FromPyObject))] pub struct SyscallHookResult { - pub retval: u64, + pub retval: GuestAddr, pub skip_syscall: bool, } @@ -237,7 +234,7 @@ pub struct SyscallHookResult { impl SyscallHookResult { #[new] #[must_use] - pub fn new(value: Option) -> Self { + pub fn new(value: Option) -> Self { value.map_or( Self { retval: 0, @@ -254,7 +251,7 @@ impl SyscallHookResult { #[cfg(not(feature = "python"))] impl SyscallHookResult { #[must_use] - pub fn new(value: Option) -> Self { + pub fn new(value: Option) -> Self { value.map_or( Self { retval: 0, @@ -340,13 +337,6 @@ extern "C" { static guest_base: usize; static mut mmap_next_start: GuestAddr; - static mut libafl_on_thread_hook: unsafe extern "C" fn(u32); - - static mut libafl_pre_syscall_hook: - unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult; - static mut libafl_post_syscall_hook: - unsafe extern "C" fn(u64, i32, u64, u64, u64, u64, u64, u64, u64, u64) -> u64; - static mut libafl_dump_core_hook: unsafe extern "C" fn(i32); static mut libafl_force_dfl: i32; } @@ -370,6 +360,7 @@ extern "C" fn qemu_cleanup_atexit() { } } +// TODO rely completely on libafl_qemu_sys extern "C" { //static libafl_page_size: GuestUsize; fn libafl_page_from_addr(addr: GuestAddr) -> GuestAddr; @@ -395,87 +386,10 @@ extern "C" { fn libafl_flush_jit(); fn libafl_qemu_trigger_breakpoint(cpu: CPUStatePtr); - fn libafl_qemu_set_hook( - addr: GuestAddr, - callback: extern "C" fn(GuestAddr, u64), - data: u64, - invalidate_block: i32, - ) -> usize; - // fn libafl_qemu_remove_hook(num: usize, invalidate_block: i32) -> i32; - fn libafl_qemu_remove_hooks_at(addr: GuestAddr, invalidate_block: i32) -> usize; - fn strlen(s: *const u8) -> usize; - // void libafl_add_edge_hook(uint64_t (*gen)(target_ulong src, target_ulong dst), void (*exec)(uint64_t id)); - fn libafl_add_edge_hook( - gen: Option u64>, - exec: Option, - data: u64, - ); - - // void libafl_add_block_hook(uint64_t (*gen)(target_ulong pc), void (*exec)(uint64_t id)); - fn libafl_add_block_hook( - gen: Option u64>, - post_gen: Option, - exec: Option, - data: u64, - ); - - // void libafl_add_read_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data), - // void (*exec1)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec2)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec4)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec8)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec_n)(uint64_t id, target_ulong addr, size_t size, uint64_t data), - // uint64_t data); - fn libafl_add_read_hook( - gen: Option u64>, - exec1: Option, - exec2: Option, - exec4: Option, - exec8: Option, - exec_n: Option, - data: u64, - ); - - // void libafl_add_write_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data), - // void (*exec1)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec2)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec4)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec8)(uint64_t id, target_ulong addr, uint64_t data), - // void (*exec_n)(uint64_t id, target_ulong addr, size_t size, uint64_t data), - // uint64_t data); - fn libafl_add_write_hook( - gen: Option u64>, - exec1: Option, - exec2: Option, - exec4: Option, - exec8: Option, - exec_n: Option, - data: u64, - ); - - // void libafl_add_cmp_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data), - // void (*exec1)(uint64_t id, uint8_t v0, uint8_t v1, uint64_t data), - // void (*exec2)(uint64_t id, uint16_t v0, uint16_t v1, uint64_t data), - // void (*exec4)(uint64_t id, uint32_t v0, uint32_t v1, uint64_t data), - // void (*exec8)(uint64_t id, uint64_t v0, uint64_t v1, uint64_t data), - // uint64_t data); - fn libafl_add_cmp_hook( - gen: Option u64>, - exec1: Option, - exec2: Option, - exec4: Option, - exec8: Option, - data: u64, - ); - - // void libafl_add_backdoor_hook(void (*exec)(uint64_t id, uint64_t data), - // uint64_t data) - fn libafl_add_backdoor_hook(exec: extern "C" fn(GuestAddr, u64), data: u64); - fn libafl_qemu_add_gdb_cmd( - callback: extern "C" fn(*const u8, usize, *const ()) -> i32, + callback: extern "C" fn(*const (), *const u8, usize) -> i32, data: *const (), ); fn libafl_qemu_gdb_reply(buf: *const u8, len: usize); @@ -550,7 +464,7 @@ pub(crate) struct FatPtr(pub *const c_void, pub *const c_void); static mut GDB_COMMANDS: Vec = vec![]; -extern "C" fn gdb_cmd(buf: *const u8, len: usize, data: *const ()) -> i32 { +extern "C" fn gdb_cmd(data: *const (), buf: *const u8, len: usize) -> i32 { unsafe { let closure = &mut *(data as *mut Box FnMut(&Emulator, &'r str) -> bool>); let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); @@ -845,11 +759,72 @@ impl CPU { } } -static EMULATOR_IS_INITIALIZED: OnceLock> = OnceLock::new(); +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct HookId(pub(crate) usize); -#[derive(Clone, Debug)] -pub struct Emulator { - _private: (), +use std::pin::Pin; + +#[derive(Debug)] +pub struct HookData(u64); + +impl From> for HookData { + fn from(value: Pin<&mut T>) -> Self { + unsafe { HookData(core::mem::transmute(value)) } + } +} + +impl From> for HookData { + fn from(value: Pin<&T>) -> Self { + unsafe { HookData(core::mem::transmute(value)) } + } +} + +impl From<&'static mut T> for HookData { + fn from(value: &'static mut T) -> Self { + unsafe { HookData(core::mem::transmute(value)) } + } +} + +impl From<&'static T> for HookData { + fn from(value: &'static T) -> Self { + unsafe { HookData(core::mem::transmute(value)) } + } +} + +impl From<*mut T> for HookData { + fn from(value: *mut T) -> Self { + unsafe { HookData(core::mem::transmute(value)) } + } +} + +impl From<*const T> for HookData { + fn from(value: *const T) -> Self { + unsafe { HookData(core::mem::transmute(value)) } + } +} + +impl From for HookData { + fn from(value: u64) -> Self { + HookData(value) + } +} + +impl From for HookData { + fn from(value: u32) -> Self { + HookData(value as u64) + } +} + +impl From for HookData { + fn from(value: u16) -> Self { + HookData(value as u64) + } +} + +impl From for HookData { + fn from(value: u8) -> Self { + HookData(value as u64) + } } #[derive(Debug)] @@ -940,19 +915,17 @@ impl From for libafl::Error { } } +static mut EMULATOR_IS_INITIALIZED: bool = false; + +#[derive(Clone, Debug)] +pub struct Emulator { + _private: (), +} + #[allow(clippy::unused_self)] impl Emulator { #[allow(clippy::must_use_candidate, clippy::similar_names)] pub fn new(args: &[String], env: &[(String, String)]) -> Result { - let mut is_initialized = EMULATOR_IS_INITIALIZED - .get_or_init(|| Mutex::new(false)) - .lock() - .unwrap(); - - if *is_initialized { - return Err(EmuError::MultipleInstances); - } - if args.is_empty() { return Err(EmuError::EmptyArgs); } @@ -961,6 +934,14 @@ impl Emulator { if i32::try_from(argc).is_err() { return Err(EmuError::TooManyArgs(argc)); } + + unsafe { + if EMULATOR_IS_INITIALIZED { + return Err(EmuError::MultipleInstances); + } + EMULATOR_IS_INITIALIZED = true; + } + #[allow(clippy::cast_possible_wrap)] let argc = argc as i32; @@ -985,11 +966,21 @@ impl Emulator { libc::atexit(qemu_cleanup_atexit); libafl_qemu_sys::syx_snapshot_init(); } - *is_initialized = true; } Ok(Emulator { _private: () }) } + #[must_use] + pub fn get() -> Option { + unsafe { + if EMULATOR_IS_INITIALIZED { + Some(Self::new_empty()) + } else { + None + } + } + } + #[must_use] pub(crate) fn new_empty() -> Emulator { Emulator { _private: () } @@ -1141,22 +1132,6 @@ impl Emulator { libafl_force_dfl = 1; } } - - pub fn set_hook( - &self, - addr: GuestAddr, - callback: extern "C" fn(GuestAddr, u64), - data: u64, - invalidate_block: bool, - ) -> usize { - unsafe { libafl_qemu_set_hook(addr.into(), callback, data, i32::from(invalidate_block)) } - } - - #[must_use] - pub fn remove_hook(&self, addr: GuestAddr, invalidate_block: bool) -> usize { - unsafe { libafl_qemu_remove_hooks_at(addr.into(), i32::from(invalidate_block)) } - } - /// This function will run the emulator until the next breakpoint, or until finish. /// # Safety /// @@ -1282,72 +1257,250 @@ impl Emulator { } } - pub fn add_edge_hooks( + // TODO set T lifetime to be like Emulator + pub fn set_hook>( &self, - gen: Option u64>, - exec: Option, - data: u64, - ) { - unsafe { libafl_add_edge_hook(gen, exec, data) } + data: T, + addr: GuestAddr, + callback: extern "C" fn(T, GuestAddr), + invalidate_block: bool, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback); + let num = libafl_qemu_sys::libafl_qemu_set_hook( + addr.into(), + Some(callback), + data, + i32::from(invalidate_block), + ); + HookId(num) + } } - pub fn add_block_hooks( - &self, - gen: Option u64>, - post_gen: Option, - exec: Option, - data: u64, - ) { - unsafe { libafl_add_block_hook(gen, post_gen, exec, data) } + #[must_use] + pub fn remove_hook(&self, id: HookId, invalidate_block: bool) -> bool { + unsafe { libafl_qemu_sys::libafl_qemu_remove_hook(id.0, i32::from(invalidate_block)) != 0 } } - pub fn add_read_hooks( + #[must_use] + pub fn remove_hooks_at(&self, addr: GuestAddr, invalidate_block: bool) -> usize { + unsafe { + libafl_qemu_sys::libafl_qemu_remove_hooks_at(addr.into(), i32::from(invalidate_block)) + } + } + + pub fn add_edge_hooks>( &self, - gen: Option u64>, - exec1: Option, - exec2: Option, - exec4: Option, - exec8: Option, - exec_n: Option, - data: u64, - ) { - unsafe { libafl_add_read_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) } + data: T, + gen: Option u64>, + exec: Option, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let gen: Option u64> = + core::mem::transmute(gen); + let exec: Option = core::mem::transmute(exec); + let num = libafl_qemu_sys::libafl_add_edge_hook(gen, exec, data); + HookId(num) + } + } + + pub fn add_block_hooks>( + &self, + data: T, + gen: Option u64>, + post_gen: Option, + exec: Option, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let gen: Option u64> = core::mem::transmute(gen); + let post_gen: Option = + core::mem::transmute(post_gen); + let exec: Option = core::mem::transmute(exec); + let num = libafl_qemu_sys::libafl_add_block_hook(gen, post_gen, exec, data); + HookId(num) + } + } + + pub fn add_read_hooks>( + &self, + data: T, + gen: Option u64>, + exec1: Option, + exec2: Option, + exec4: Option, + exec8: Option, + exec_n: Option, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let gen: Option u64> = + core::mem::transmute(gen); + let exec1: Option = core::mem::transmute(exec1); + let exec2: Option = core::mem::transmute(exec2); + let exec4: Option = core::mem::transmute(exec4); + let exec8: Option = core::mem::transmute(exec8); + let exec_n: Option = + core::mem::transmute(exec_n); + let num = libafl_qemu_sys::libafl_add_read_hook( + gen, exec1, exec2, exec4, exec8, exec_n, data, + ); + HookId(num) + } } // TODO add MemOp info - pub fn add_write_hooks( + pub fn add_write_hooks>( &self, - gen: Option u64>, - exec1: Option, - exec2: Option, - exec4: Option, - exec8: Option, - exec_n: Option, - data: u64, - ) { - unsafe { libafl_add_write_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) } + data: T, + gen: Option u64>, + exec1: Option, + exec2: Option, + exec4: Option, + exec8: Option, + exec_n: Option, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let gen: Option u64> = + core::mem::transmute(gen); + let exec1: Option = core::mem::transmute(exec1); + let exec2: Option = core::mem::transmute(exec2); + let exec4: Option = core::mem::transmute(exec4); + let exec8: Option = core::mem::transmute(exec8); + let exec_n: Option = + core::mem::transmute(exec_n); + let num = libafl_qemu_sys::libafl_add_write_hook( + gen, exec1, exec2, exec4, exec8, exec_n, data, + ); + HookId(num) + } } - pub fn add_cmp_hooks( + pub fn add_cmp_hooks>( &self, - gen: Option u64>, - exec1: Option, - exec2: Option, - exec4: Option, - exec8: Option, - data: u64, - ) { - unsafe { libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data) } + data: T, + gen: Option u64>, + exec1: Option, + exec2: Option, + exec4: Option, + exec8: Option, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let gen: Option u64> = + core::mem::transmute(gen); + let exec1: Option = core::mem::transmute(exec1); + let exec2: Option = core::mem::transmute(exec2); + let exec4: Option = core::mem::transmute(exec4); + let exec8: Option = core::mem::transmute(exec8); + let num = libafl_qemu_sys::libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data); + HookId(num) + } } - pub fn add_backdoor_hook(&self, exec: extern "C" fn(GuestAddr, u64), data: u64) { - unsafe { libafl_add_backdoor_hook(exec, data) }; + pub fn add_backdoor_hook>( + &self, + data: T, + callback: extern "C" fn(T, GuestAddr), + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback); + let num = libafl_qemu_sys::libafl_add_backdoor_hook(Some(callback), data); + HookId(num) + } } #[cfg(emulation_mode = "usermode")] - pub fn set_on_thread_hook(&self, hook: extern "C" fn(tid: u32)) { + #[allow(clippy::type_complexity)] + pub fn add_pre_syscall_hook>( + &self, + data: T, + callback: extern "C" fn( + T, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> SyscallHookResult, + ) -> HookId { unsafe { - libafl_on_thread_hook = hook; + let data: u64 = data.into().0; + let callback: extern "C" fn( + u64, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> libafl_qemu_sys::syshook_ret = core::mem::transmute(callback); + let num = libafl_qemu_sys::libafl_add_pre_syscall_hook(Some(callback), data); + HookId(num) + } + } + + #[cfg(emulation_mode = "usermode")] + #[allow(clippy::type_complexity)] + pub fn add_post_syscall_hook>( + &self, + data: T, + callback: extern "C" fn( + T, + GuestAddr, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> GuestAddr, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + let callback: extern "C" fn( + u64, + GuestAddr, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> GuestAddr = core::mem::transmute(callback); + let num = libafl_qemu_sys::libafl_add_post_syscall_hook(Some(callback), data); + HookId(num) + } + } + + #[cfg(emulation_mode = "usermode")] + pub fn add_new_thread_hook>( + &self, + data: T, + callback: extern "C" fn(T, tid: u32) -> bool, + ) -> HookId { + unsafe { + let data: u64 = data.into().0; + 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); + HookId(num) } } @@ -1420,26 +1573,6 @@ impl Emulator { } } - #[cfg(emulation_mode = "usermode")] - pub fn set_pre_syscall_hook( - &self, - hook: extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult, - ) { - unsafe { - libafl_pre_syscall_hook = hook; - } - } - - #[cfg(emulation_mode = "usermode")] - pub fn set_post_syscall_hook( - &self, - hook: extern "C" fn(u64, i32, u64, u64, u64, u64, u64, u64, u64, u64) -> u64, - ) { - unsafe { - libafl_post_syscall_hook = hook; - } - } - #[allow(clippy::type_complexity)] pub fn add_gdb_cmd(&self, callback: Box bool>) { unsafe { @@ -1519,6 +1652,7 @@ pub mod pybind { static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![]; extern "C" fn py_syscall_hook_wrapper( + data: u64, sys_num: i32, a0: u64, a1: u64, @@ -1554,7 +1688,7 @@ pub mod pybind { ) } - extern "C" fn py_generic_hook_wrapper(_pc: GuestAddr, idx: u64) { + extern "C" fn py_generic_hook_wrapper(idx: u64, _pc: GuestAddr) { let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 }; Python::with_gil(|py| { obj.call0(py).expect("Error in the hook"); @@ -1678,7 +1812,7 @@ pub mod pybind { unsafe { PY_SYSCALL_HOOK = Some(hook); } - self.emu.set_pre_syscall_hook(py_syscall_hook_wrapper); + self.emu.add_pre_syscall_hook(0u64, py_syscall_hook_wrapper); } fn set_hook(&self, addr: GuestAddr, hook: PyObject) { @@ -1686,15 +1820,15 @@ pub mod pybind { let idx = PY_GENERIC_HOOKS.len(); PY_GENERIC_HOOKS.push((addr, hook)); self.emu - .set_hook(addr, py_generic_hook_wrapper, idx as u64, true); + .set_hook(idx as u64, addr, py_generic_hook_wrapper, true); } } - fn remove_hook(&self, addr: GuestAddr) -> usize { + fn remove_hooks_at(&self, addr: GuestAddr) -> usize { unsafe { PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr); } - self.emu.remove_hook(addr, true) + self.emu.remove_hooks_at(addr, true) } } } diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 84af6c3c70..225807f5ea 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -37,7 +37,7 @@ where QT: QemuHelperTuple, { inner: InProcessExecutor<'a, H, OT, S>, - hooks: &'a mut QemuHooks<'a, QT, S>, + hooks: &'a mut QemuHooks, first_exec: bool, } @@ -138,7 +138,7 @@ where QT: QemuHelperTuple, { pub fn new( - hooks: &'a mut QemuHooks<'a, QT, S>, + hooks: &'a mut QemuHooks, harness_fn: &'a mut H, observers: OT, fuzzer: &mut Z, @@ -186,11 +186,11 @@ where &mut self.inner } - pub fn hooks(&self) -> &QemuHooks<'a, QT, S> { + pub fn hooks(&self) -> &QemuHooks { self.hooks } - pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> { + pub fn hooks_mut(&mut self) -> &mut QemuHooks { self.hooks } @@ -280,7 +280,7 @@ where SP: ShMemProvider, { first_exec: bool, - hooks: &'a mut QemuHooks<'a, QT, S>, + hooks: &'a mut QemuHooks, inner: InProcessForkExecutor<'a, H, OT, S, SP>, } @@ -311,7 +311,7 @@ where SP: ShMemProvider, { pub fn new( - hooks: &'a mut QemuHooks<'a, QT, S>, + hooks: &'a mut QemuHooks, harness_fn: &'a mut H, observers: OT, fuzzer: &mut Z, @@ -349,11 +349,11 @@ where &mut self.inner } - pub fn hooks(&self) -> &QemuHooks<'a, QT, S> { + pub fn hooks(&self) -> &QemuHooks { self.hooks } - pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> { + pub fn hooks_mut(&mut self) -> &mut QemuHooks { self.hooks } diff --git a/libafl_qemu/src/helper.rs b/libafl_qemu/src/helper.rs index 88e35c20cc..707d408cf4 100644 --- a/libafl_qemu/src/helper.rs +++ b/libafl_qemu/src/helper.rs @@ -16,13 +16,13 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = true; - fn init_hooks(&self, _hooks: &QemuHooks<'_, QT, S>) + fn init_hooks(&self, _hooks: &QemuHooks) where QT: QemuHelperTuple, { } - fn first_exec(&self, _hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, _hooks: &QemuHooks) where QT: QemuHelperTuple, { @@ -48,11 +48,11 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool; - fn init_hooks_all(&self, hooks: &QemuHooks<'_, QT, S>) + fn init_hooks_all(&self, hooks: &QemuHooks) where QT: QemuHelperTuple; - fn first_exec_all(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec_all(&self, hooks: &QemuHooks) where QT: QemuHelperTuple; @@ -74,13 +74,13 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn init_hooks_all(&self, _hooks: &QemuHooks<'_, QT, S>) + fn init_hooks_all(&self, _hooks: &QemuHooks) where QT: QemuHelperTuple, { } - fn first_exec_all(&self, _hooks: &QemuHooks<'_, QT, S>) + fn first_exec_all(&self, _hooks: &QemuHooks) where QT: QemuHelperTuple, { @@ -108,7 +108,7 @@ where { const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS; - fn init_hooks_all(&self, hooks: &QemuHooks<'_, QT, S>) + fn init_hooks_all(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { @@ -116,7 +116,7 @@ where self.1.init_hooks_all(hooks); } - fn first_exec_all(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec_all(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { diff --git a/libafl_qemu/src/hooks.rs b/libafl_qemu/src/hooks.rs index cc8901270e..cb2427f0e5 100644 --- a/libafl_qemu/src/hooks.rs +++ b/libafl_qemu/src/hooks.rs @@ -17,11 +17,12 @@ use libafl::{ pub use crate::emu::SyscallHookResult; use crate::{ - emu::{Emulator, FatPtr, MemAccessInfo, SKIP_EXEC_HOOK}, + emu::{Emulator, FatPtr, HookId, MemAccessInfo, SKIP_EXEC_HOOK}, helper::QemuHelperTuple, GuestAddr, GuestUsize, }; +/* // all kinds of hooks #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub(crate) enum Hook { @@ -31,664 +32,287 @@ pub(crate) enum Hook { Once(FatPtr), Empty, } - -/* -// function signature for Read or Write hook functions with known length (1, 2, 4, 8) -type FixedLenHookFn = fn(&Emulator, &mut QT, Option<&mut S>, u64, GuestAddr); -type FixedLenHookCl = Box, u64, GuestAddr)>; - -// function signature for Read or Write hook functions with runtime length n -type DynamicLenHookFn = fn(&Emulator, &mut QT, Option<&mut S>, u64, GuestAddr, usize); -type DynamicLenHookCl = - Box, u64, GuestAddr, usize)>; */ +// all kinds of hooks +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub(crate) enum HookRepr { + Function(*const c_void), + Closure(FatPtr), + Empty, +} + +pub struct HookState { + id: HookId, + gen: HookRepr, + post_gen: HookRepr, + execs: [HookRepr; N], +} + +pub enum Hook { + Function(F), + Closure(C), + Raw(R), + Empty, +} + +impl Hook { + pub fn is_empty(&self) -> bool { + match self { + Hook::Empty => true, + _ => false, + } + } +} + +macro_rules! get_raw_hook { + ($h:expr, $replacement:expr, $fntype:ty) => { + match $h { + Hook::Function(_) | Hook::Closure(_) => Some($replacement as $fntype), + Hook::Raw(r) => { + let v: $fntype = transmute(r); + Some(v) + } + Hook::Empty => None, + } + }; +} + +macro_rules! hook_to_repr { + ($h:expr) => { + match $h { + Hook::Function(f) => HookRepr::Function(transmute(f)), + Hook::Closure(c) => HookRepr::Closure(transmute(c)), + Hook::Raw(_) => HookRepr::Empty, // managed by emu + Hook::Empty => HookRepr::Empty, + } + }; +} + static mut QEMU_HOOKS_PTR: *const c_void = ptr::null(); -unsafe fn get_qemu_hooks<'a, QT, S>() -> &'a mut QemuHooks<'a, QT, S> +unsafe fn get_qemu_hooks<'a, QT, S>() -> &'a mut QemuHooks where S: UsesInput, QT: QemuHelperTuple, { - (QEMU_HOOKS_PTR as *mut QemuHooks<'a, QT, S>) + (QEMU_HOOKS_PTR as *mut QemuHooks) .as_mut() .expect("A high-level hook is installed but QemuHooks is not initialized") } -static mut GENERIC_HOOKS: Vec = vec![]; +macro_rules! create_wrapper { + ($name:ident, ($($param:ident : $param_type:ty),*)) => { + paste::paste! { + extern "C" fn [](hook: &mut c_void, $($param: $param_type),*) + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + let func: fn(&mut QemuHooks, Option<&mut S>, $($param_type),*) = transmute(hook as *mut c_void); + func(hooks, inprocess_get_state::(), $($param),*); + } + } -extern "C" fn generic_hook_wrapper(pc: GuestAddr, index: u64) -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let hook = &mut GENERIC_HOOKS[index as usize]; - match hook { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) = - transmute(*ptr); - func(hooks, inprocess_get_state::(), pc); + extern "C" fn [](hook: &mut FatPtr, $($param: $param_type),*) + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + let func: &mut Box, Option<&mut S>, $($param_type),*)> = transmute(hook); + func(hooks, inprocess_get_state::(), $($param),*); + } } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr), - > = transmute(ptr); - func(hooks, inprocess_get_state::(), pc); - } - _ => (), } - } -} + }; + ($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty) => { + paste::paste! { + extern "C" fn [](hook: &mut c_void, $($param: $param_type),*) -> $ret_type + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + let func: fn(&mut QemuHooks, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(hook as *mut c_void); + func(hooks, inprocess_get_state::(), $($param),*) + } + } -static mut EDGE_HOOKS: Vec<(Hook, Hook)> = vec![]; - -extern "C" fn gen_edge_hook_wrapper(src: GuestAddr, dst: GuestAddr, index: u64) -> u64 -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (gen, _) = &mut EDGE_HOOKS[index as usize]; - match gen { - Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - GuestAddr, - ) -> Option = transmute(*ptr); - func(hooks, inprocess_get_state::(), src, dst).map_or(SKIP_EXEC_HOOK, |id| id) - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - GuestAddr, - ) -> Option, - > = transmute(ptr); - func(hooks, inprocess_get_state::(), src, dst).map_or(SKIP_EXEC_HOOK, |id| id) - } - _ => 0, - } - } -} - -extern "C" fn exec_edge_hook_wrapper(id: u64, index: u64) -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (_, exec) = &mut EDGE_HOOKS[index as usize]; - match exec { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64) = transmute(*ptr); - func(hooks, inprocess_get_state::(), id); - } - Hook::Closure(ptr) => { - let func: &mut Box, Option<&mut S>, u64)> = - transmute(ptr); - func(hooks, inprocess_get_state::(), id); - } - _ => (), - } - } -} - -static mut BLOCK_HOOKS: Vec<(Hook, Hook, Hook)> = vec![]; - -extern "C" fn gen_block_hook_wrapper(pc: GuestAddr, index: u64) -> u64 -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (gen, _, _) = &mut BLOCK_HOOKS[index as usize]; - match gen { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) -> Option = - transmute(*ptr); - func(hooks, inprocess_get_state::(), pc).map_or(SKIP_EXEC_HOOK, |id| id) - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) -> Option, - > = transmute(ptr); - func(hooks, inprocess_get_state::(), pc).map_or(SKIP_EXEC_HOOK, |id| id) - } - _ => 0, - } - } -} - -extern "C" fn gen_post_block_hook_wrapper( - pc: GuestAddr, - block_length: GuestUsize, - index: u64, -) where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (_, post_gen, _) = &mut BLOCK_HOOKS[index as usize]; - match post_gen { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, GuestUsize) = - transmute(*ptr); - func(hooks, inprocess_get_state::(), pc, block_length); - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, GuestUsize), - > = transmute(ptr); - func(hooks, inprocess_get_state::(), pc, block_length); - } - _ => (), - } - } -} - -extern "C" fn exec_block_hook_wrapper(id: u64, index: u64) -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (_, _, exec) = &mut BLOCK_HOOKS[index as usize]; - match exec { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64) = transmute(*ptr); - func(hooks, inprocess_get_state::(), id); - } - Hook::Closure(ptr) => { - let func: &mut Box, Option<&mut S>, u64)> = - transmute(ptr); - func(hooks, inprocess_get_state::(), id); - } - _ => (), - } - } -} - -static mut READ_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![]; -static mut WRITE_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![]; - -extern "C" fn gen_read_hook_wrapper(pc: GuestAddr, info: MemAccessInfo, index: u64) -> u64 -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (gen, _, _, _, _, _) = &mut READ_HOOKS[index as usize]; - match gen { - Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - MemAccessInfo, - ) -> Option = transmute(*ptr); - func(hooks, inprocess_get_state::(), pc, info).map_or(SKIP_EXEC_HOOK, |id| id) - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - MemAccessInfo, - ) -> Option, - > = transmute(ptr); - func(hooks, inprocess_get_state::(), pc, info).map_or(SKIP_EXEC_HOOK, |id| id) - } - _ => 0, - } - } -} - -extern "C" fn gen_write_hook_wrapper(pc: GuestAddr, info: MemAccessInfo, index: u64) -> u64 -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (gen, _, _, _, _, _) = &mut WRITE_HOOKS[index as usize]; - match gen { - Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - MemAccessInfo, - ) -> Option = transmute(*ptr); - func(hooks, inprocess_get_state::(), pc, info).map_or(SKIP_EXEC_HOOK, |id| id) - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - MemAccessInfo, - ) -> Option, - > = transmute(ptr); - func(hooks, inprocess_get_state::(), pc, info).map_or(SKIP_EXEC_HOOK, |id| id) - } - _ => 0, - } - } -} - -macro_rules! define_rw_exec_hook { - ($name:ident, $field:tt, $global:ident) => { - extern "C" fn $name(id: u64, addr: GuestAddr, index: u64) - where - S: UsesInput, - QT: QemuHelperTuple, - { - unsafe { - let hooks = get_qemu_hooks::(); - let exec = &mut $global[index as usize].$field; - match exec { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr) = - transmute(*ptr); - func(hooks, inprocess_get_state::(), id, addr); - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr), - > = transmute(ptr); - func(hooks, inprocess_get_state::(), id, addr); - } - _ => (), + extern "C" fn [](hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + let func: &mut Box, Option<&mut S>, $($param_type),*) -> $ret_type> = transmute(hook); + func(hooks, inprocess_get_state::(), $($param),*) } } } }; } -macro_rules! define_rw_exec_hook_n { - ($name:ident, $field:tt, $global:ident) => { - extern "C" fn $name(id: u64, addr: GuestAddr, size: usize, index: u64) - where - S: UsesInput, - QT: QemuHelperTuple, - { - unsafe { - let hooks = get_qemu_hooks::(); - let exec = &mut $global[index as usize].$field; - match exec { - Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - u64, - GuestAddr, - usize, - ) = transmute(*ptr); - func(hooks, inprocess_get_state::(), id, addr, size); +macro_rules! create_gen_wrapper { + ($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal) => { + paste::paste! { + extern "C" fn [<$name _gen_hook_wrapper>](hook: &mut HookState<{ $execs }>, $($param: $param_type),*) -> $ret_type + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + match &mut hook.gen { + HookRepr::Function(ptr) => { + let func: fn(&mut QemuHooks, Option<&mut S>, $($param_type),*) -> Option<$ret_type> = + transmute(*ptr); + func(hooks, inprocess_get_state::(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id) + } + HookRepr::Closure(ptr) => { + let func: &mut Box< + dyn FnMut(&mut QemuHooks, Option<&mut S>, $($param_type),*) -> Option<$ret_type>, + > = transmute(ptr); + func(hooks, inprocess_get_state::(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id) + } + _ => 0, } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - u64, - GuestAddr, - usize, - ), - > = transmute(ptr); - func(hooks, inprocess_get_state::(), id, addr, size); - } - _ => (), } } } - }; -} - -define_rw_exec_hook!(exec_read1_hook_wrapper, 1, READ_HOOKS); -define_rw_exec_hook!(exec_read2_hook_wrapper, 2, READ_HOOKS); -define_rw_exec_hook!(exec_read4_hook_wrapper, 3, READ_HOOKS); -define_rw_exec_hook!(exec_read8_hook_wrapper, 4, READ_HOOKS); -define_rw_exec_hook_n!(exec_read_n_hook_wrapper, 5, READ_HOOKS); - -define_rw_exec_hook!(exec_write1_hook_wrapper, 1, WRITE_HOOKS); -define_rw_exec_hook!(exec_write2_hook_wrapper, 2, WRITE_HOOKS); -define_rw_exec_hook!(exec_write4_hook_wrapper, 3, WRITE_HOOKS); -define_rw_exec_hook!(exec_write8_hook_wrapper, 4, WRITE_HOOKS); -define_rw_exec_hook_n!(exec_write_n_hook_wrapper, 5, WRITE_HOOKS); - -static mut CMP_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook)> = vec![]; - -extern "C" fn gen_cmp_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let (gen, _, _, _, _) = &mut CMP_HOOKS[index as usize]; - match gen { - Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - usize, - ) -> Option = transmute(*ptr); - func(hooks, inprocess_get_state::(), pc, size).map_or(SKIP_EXEC_HOOK, |id| id) - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - GuestAddr, - usize, - ) -> Option, - > = transmute(ptr); - func(hooks, inprocess_get_state::(), pc, size).map_or(SKIP_EXEC_HOOK, |id| id) - } - _ => 0, - } - } -} - -macro_rules! define_cmp_exec_hook { - ($name:ident, $field:tt, $itype:ty) => { - extern "C" fn $name(id: u64, v0: $itype, v1: $itype, index: u64) - where - S: UsesInput, - QT: QemuHelperTuple, - { - unsafe { - let hooks = get_qemu_hooks::(); - let exec = &mut CMP_HOOKS[index as usize].$field; - match exec { - Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - u64, - $itype, - $itype, - ) = transmute(*ptr); - func(hooks, inprocess_get_state::(), id, v0, v1); - } - Hook::Closure(ptr) => { - let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - u64, - $itype, - $itype, - ), - > = transmute(ptr); - func(hooks, inprocess_get_state::(), id, v0, v1); - } - _ => (), - } - } - } - }; -} - -define_cmp_exec_hook!(exec_cmp1_hook_wrapper, 1, u8); -define_cmp_exec_hook!(exec_cmp2_hook_wrapper, 2, u16); -define_cmp_exec_hook!(exec_cmp4_hook_wrapper, 3, u32); -define_cmp_exec_hook!(exec_cmp8_hook_wrapper, 4, u64); - -#[cfg(emulation_mode = "usermode")] -static mut ON_THREAD_HOOKS: Vec = vec![]; -#[cfg(emulation_mode = "usermode")] -extern "C" fn on_thread_hooks_wrapper(tid: u32) -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - for hook in &mut ON_THREAD_HOOKS { - let hooks = get_qemu_hooks::(); - match hook { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u32) = transmute(*ptr); - func(hooks, inprocess_get_state::(), tid); - } - Hook::Closure(ptr) => { - let mut func: Box, Option<&mut S>, u32)> = - transmute(*ptr); - func(hooks, inprocess_get_state::(), tid); - - // Forget the closure so that drop is not called on captured variables. - core::mem::forget(func); - } - Hook::Once(ptr) => { - let func: Box, Option<&mut S>, u32)> = - transmute(*ptr); - func(hooks, inprocess_get_state::(), tid); - *hook = Hook::Empty; - } - Hook::Empty => (), - } - } } } -#[cfg(emulation_mode = "usermode")] -static mut SYSCALL_HOOKS: Vec = vec![]; -#[cfg(emulation_mode = "usermode")] -extern "C" fn syscall_hooks_wrapper( - sys_num: i32, - a0: u64, - a1: u64, - a2: u64, - a3: u64, - a4: u64, - a5: u64, - a6: u64, - a7: u64, -) -> SyscallHookResult -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let mut res = SyscallHookResult::new(None); - for hook in &SYSCALL_HOOKS { - match hook { - Hook::Function(ptr) => { - #[allow(clippy::type_complexity)] - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> SyscallHookResult = transmute(*ptr); - let r = func( - hooks, - inprocess_get_state::(), - sys_num, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - ); - if r.skip_syscall { - res.skip_syscall = true; - res.retval = r.retval; +macro_rules! create_post_gen_wrapper { + ($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal) => { + paste::paste! { + extern "C" fn [<$name _post_gen_hook_wrapper>](hook: &mut HookState<{ $execs }>, $($param: $param_type),*) + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + match &mut hook.post_gen { + HookRepr::Function(ptr) => { + let func: fn(&mut QemuHooks, Option<&mut S>, $($param_type),*) = + transmute(*ptr); + func(hooks, inprocess_get_state::(), $($param),*); + } + HookRepr::Closure(ptr) => { + let func: &mut Box< + dyn FnMut(&mut QemuHooks, Option<&mut S>, $($param_type),*), + > = transmute(ptr); + func(hooks, inprocess_get_state::(), $($param),*); + } + _ => (), } } - Hook::Closure(ptr) => { - #[allow(clippy::type_complexity)] - let mut func: Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> SyscallHookResult, - > = transmute(*ptr); - let r = func( - hooks, - inprocess_get_state::(), - sys_num, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - ); - - // Forget the closure so that drop is not called on captured variables. - core::mem::forget(func); - - if r.skip_syscall { - res.skip_syscall = true; - res.retval = r.retval; - } - } - _ => (), } } - res } } -#[cfg(emulation_mode = "usermode")] -static mut SYSCALL_POST_HOOKS: Vec = vec![]; -#[cfg(emulation_mode = "usermode")] -extern "C" fn syscall_after_hooks_wrapper( - result: u64, - sys_num: i32, - a0: u64, - a1: u64, - a2: u64, - a3: u64, - a4: u64, - a5: u64, - a6: u64, - a7: u64, -) -> u64 -where - S: UsesInput, - QT: QemuHelperTuple, -{ - unsafe { - let hooks = get_qemu_hooks::(); - let mut res = result; - for hook in &SYSCALL_POST_HOOKS { - match hook { - Hook::Function(ptr) => { - #[allow(clippy::type_complexity)] - let func: fn( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - u64, - i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> u64 = transmute(*ptr); - res = func( - hooks, - inprocess_get_state::(), - res, - sys_num, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - ); +macro_rules! create_exec_wrapper { + ($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal) => { + paste::paste! { + extern "C" fn [<$name _ $execidx _exec_hook_wrapper>](hook: &mut HookState<{ $execs }>, $($param: $param_type),*) + where + S: UsesInput, + QT: QemuHelperTuple, + { + unsafe { + let hooks = get_qemu_hooks::(); + match &mut hook.execs[$execidx] { + HookRepr::Function(ptr) => { + let func: fn(&mut QemuHooks, Option<&mut S>, $($param_type),*) = transmute(*ptr); + func(hooks, inprocess_get_state::(), $($param),*); + } + HookRepr::Closure(ptr) => { + let func: &mut Box, Option<&mut S>, $($param_type),*)> = + transmute(ptr); + func(hooks, inprocess_get_state::(), $($param),*); + } + _ => (), + } } - Hook::Closure(ptr) => { - #[allow(clippy::type_complexity)] - let mut func: Box< - dyn FnMut( - &mut QemuHooks<'_, QT, S>, - Option<&mut S>, - u64, - i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> u64, - > = transmute(*ptr); - res = func( - hooks, - inprocess_get_state::(), - res, - sys_num, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - ); - - // Forget the closure so that drop is not called on captured variables. - core::mem::forget(func); - } - _ => (), } } - res } } +static mut GENERIC_HOOKS: Vec<(HookId, FatPtr)> = vec![]; +create_wrapper!(generic, (pc: GuestAddr)); +static mut BACKDOOR_HOOKS: Vec<(HookId, FatPtr)> = vec![]; +create_wrapper!(backdoor, (pc: GuestAddr)); + #[cfg(emulation_mode = "usermode")] -static mut CRASH_HOOKS: Vec = vec![]; +static mut PRE_SYSCALL_HOOKS: Vec<(HookId, FatPtr)> = vec![]; +#[cfg(emulation_mode = "usermode")] +create_wrapper!(pre_syscall, (sys_num: i32, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + a4: GuestAddr, + a5: GuestAddr, + a6: GuestAddr, + a7: GuestAddr), SyscallHookResult); +#[cfg(emulation_mode = "usermode")] +static mut POST_SYSCALL_HOOKS: Vec<(HookId, FatPtr)> = vec![]; +#[cfg(emulation_mode = "usermode")] +create_wrapper!(post_syscall, (res: GuestAddr, sys_num: i32, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + a4: GuestAddr, + a5: GuestAddr, + a6: GuestAddr, + a7: GuestAddr), GuestAddr); +#[cfg(emulation_mode = "usermode")] +static mut NEW_THREAD_HOOKS: Vec<(HookId, FatPtr)> = vec![]; +#[cfg(emulation_mode = "usermode")] +create_wrapper!(new_thread, (tid: u32), bool); + +static mut EDGE_HOOKS: Vec> = vec![]; +create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1); +create_exec_wrapper!(edge, (id: u64), 0, 1); + +static mut BLOCK_HOOKS: Vec> = vec![]; +create_gen_wrapper!(block, (addr: GuestAddr), u64, 1); +create_post_gen_wrapper!(block, (addr: GuestAddr, len: GuestUsize), 1); +create_exec_wrapper!(block, (id: u64), 0, 1); + +static mut READ_HOOKS: Vec> = vec![]; +create_gen_wrapper!(read, (pc: GuestAddr, info: MemAccessInfo), u64, 5); +create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 0, 5); +create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 1, 5); +create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 2, 5); +create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 3, 5); +create_exec_wrapper!(read, (id: u64, addr: GuestAddr, size: usize), 4, 5); + +static mut WRITE_HOOKS: Vec> = vec![]; +create_gen_wrapper!(write, (pc: GuestAddr, info: MemAccessInfo), u64, 5); +create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 0, 5); +create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 1, 5); +create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 2, 5); +create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 3, 5); +create_exec_wrapper!(write, (id: u64, addr: GuestAddr, size: usize), 4, 5); + +static mut CMP_HOOKS: Vec> = vec![]; +create_gen_wrapper!(cmp, (pc: GuestAddr, size: usize), u64, 4); +create_exec_wrapper!(cmp, (id: u64, v0: u8, v1: u8), 0, 4); +create_exec_wrapper!(cmp, (id: u64, v0: u16, v1: u16), 1, 4); +create_exec_wrapper!(cmp, (id: u64, v0: u32, v1: u32), 2, 4); +create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4); + +#[cfg(emulation_mode = "usermode")] +static mut CRASH_HOOKS: Vec = vec![]; #[cfg(emulation_mode = "usermode")] extern "C" fn crash_hook_wrapper(target_sig: i32) @@ -700,12 +324,12 @@ where let hooks = get_qemu_hooks::(); for hook in &mut CRASH_HOOKS { match hook { - Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, QT, S>, i32) = transmute(*ptr); + HookRepr::Function(ptr) => { + let func: fn(&mut QemuHooks, i32) = transmute(*ptr); func(hooks, target_sig); } - Hook::Closure(ptr) => { - let func: &mut Box, i32)> = transmute(ptr); + HookRepr::Closure(ptr) => { + let func: &mut Box, i32)> = transmute(ptr); func(hooks, target_sig); } _ => (), @@ -715,18 +339,19 @@ where } static mut HOOKS_IS_INITIALIZED: bool = false; +static mut FIRST_EXEC: bool = true; -pub struct QemuHooks<'a, QT, S> +pub struct QemuHooks where QT: QemuHelperTuple, S: UsesInput, { helpers: QT, - emulator: &'a Emulator, + emulator: Emulator, phantom: PhantomData, } -impl<'a, QT, S> Debug for QemuHooks<'a, QT, S> +impl Debug for QemuHooks where S: UsesInput, QT: QemuHelperTuple + Debug, @@ -739,14 +364,12 @@ where } } -static mut FIRST_EXEC: bool = true; - -impl<'a, I, QT> QemuHooks<'a, QT, NopState> +impl QemuHooks> where QT: QemuHelperTuple>, NopState: UsesInput, { - pub fn reproducer(emulator: &'a Emulator, helpers: QT) -> Box { + pub fn reproducer(emulator: Emulator, helpers: QT) -> Box { Self::new(emulator, helpers) } @@ -760,23 +383,23 @@ where FIRST_EXEC = false; } } - self.helpers.pre_exec_all(self.emulator, input); + self.helpers.pre_exec_all(&self.emulator, input); let mut exit_kind = harness(input); self.helpers - .post_exec_all(self.emulator, input, &mut (), &mut exit_kind); + .post_exec_all(&self.emulator, input, &mut (), &mut exit_kind); exit_kind } } -impl<'a, QT, S> QemuHooks<'a, QT, S> +impl QemuHooks where QT: QemuHelperTuple, S: UsesInput, { - pub fn new(emulator: &'a Emulator, helpers: QT) -> Box { + pub fn new(emulator: Emulator, helpers: QT) -> Box { unsafe { assert!( !HOOKS_IS_INITIALIZED, @@ -815,7 +438,7 @@ where } pub fn emulator(&self) -> &Emulator { - self.emulator + &self.emulator } pub fn helpers(&self) -> &QT { @@ -829,673 +452,555 @@ where pub fn instruction( &self, addr: GuestAddr, - hook: fn(&mut Self, Option<&mut S>, GuestAddr), + hook: Hook< + fn(&mut Self, Option<&mut S>, GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, + extern "C" fn(*const (), pc: GuestAddr), + >, invalidate_block: bool, - ) { + ) -> HookId { unsafe { - let index = GENERIC_HOOKS.len(); - self.emulator.set_hook( - addr, - generic_hook_wrapper::, - index as u64, - invalidate_block, - ); - GENERIC_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + match hook { + Hook::Function(f) => self.instruction_function(addr, f, invalidate_block), + Hook::Closure(c) => self.instruction_closure(addr, c, invalidate_block), + Hook::Raw(r) => { + let z: *const () = transmute(0u64); + self.emulator.set_hook(z, addr, r, invalidate_block) + } + Hook::Empty => HookId(0), // TODO error type + } } } - pub unsafe fn instruction_closure( + pub fn instruction_function( &self, addr: GuestAddr, - hook: Box, GuestAddr)>, + hook: fn(&mut Self, Option<&mut S>, GuestAddr), invalidate_block: bool, - ) { - let index = GENERIC_HOOKS.len(); - self.emulator.set_hook( - addr, - generic_hook_wrapper::, - index as u64, - invalidate_block, - ); - GENERIC_HOOKS.push(Hook::Closure(transmute(hook))); + ) -> HookId { + unsafe { + self.emulator.set_hook( + transmute(hook), + addr, + func_generic_hook_wrapper::, + invalidate_block, + ) + } + } + + pub fn instruction_closure( + &self, + addr: GuestAddr, + hook: Box FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, + invalidate_block: bool, + ) -> HookId { + unsafe { + let fat: FatPtr = transmute(hook); + GENERIC_HOOKS.push((HookId(0), fat)); + let id = self.emulator.set_hook( + &mut GENERIC_HOOKS.last_mut().unwrap().1, + addr, + closure_generic_hook_wrapper::, + invalidate_block, + ); + GENERIC_HOOKS.last_mut().unwrap().0 = id; + id + } } pub fn edges( &self, - generation_hook: Option< + generation_hook: Hook< fn(&mut Self, Option<&mut S>, src: GuestAddr, dest: GuestAddr) -> Option, + Box< + dyn for<'a> FnMut( + &'a mut Self, + Option<&'a mut S>, + GuestAddr, + GuestAddr, + ) -> Option, + >, + extern "C" fn(*const (), src: GuestAddr, dest: GuestAddr) -> u64, >, - execution_hook: Option, id: u64)>, - ) { + execution_hook: Hook< + fn(&mut Self, Option<&mut S>, id: u64), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64)>, + extern "C" fn(*const (), id: u64), + >, + ) -> HookId { unsafe { - let index = EDGE_HOOKS.len(); - self.emulator.add_edge_hooks( - generation_hook - .as_ref() - .map(|_| gen_edge_hook_wrapper:: as _), - execution_hook - .as_ref() - .map(|_| exec_edge_hook_wrapper:: as _), - index as u64, + let gen = get_raw_hook!( + generation_hook, + edge_gen_hook_wrapper::, + extern "C" fn(&mut HookState<1>, src: GuestAddr, dest: GuestAddr) -> u64 ); - EDGE_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - )); - } - } - - pub unsafe fn edges_closures( - &self, - generation_hook: Option< - Box, GuestAddr, GuestAddr) -> Option>, - >, - execution_hook: Option, u64)>>, - ) { - let index = EDGE_HOOKS.len(); - self.emulator.add_edge_hooks( - generation_hook - .as_ref() - .map(|_| gen_edge_hook_wrapper:: as _), - execution_hook - .as_ref() - .map(|_| exec_edge_hook_wrapper:: as _), - index as u64, - ); - EDGE_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - )); - } - - pub fn edges_raw( - &self, - generation_hook: Option< - fn(&mut Self, Option<&mut S>, src: GuestAddr, dest: GuestAddr) -> Option, - >, - execution_hook: Option, - ) { - unsafe { - let index = EDGE_HOOKS.len(); - self.emulator.add_edge_hooks( - generation_hook - .as_ref() - .map(|_| gen_edge_hook_wrapper:: as _), + let exec = get_raw_hook!( execution_hook, - index as u64, + edge_0_exec_hook_wrapper::, + extern "C" fn(&mut HookState<1>, id: u64) ); - EDGE_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - Hook::Empty, - )); + EDGE_HOOKS.push(HookState { + id: HookId(0), + gen: hook_to_repr!(generation_hook), + post_gen: HookRepr::Empty, + execs: [hook_to_repr!(execution_hook)], + }); + let id = self + .emulator + .add_edge_hooks(EDGE_HOOKS.last_mut().unwrap(), gen, exec); + EDGE_HOOKS.last_mut().unwrap().id = id; + id } } pub fn blocks( &self, - generation_hook: Option, pc: GuestAddr) -> Option>, - post_generation_hook: Option< - fn(&mut Self, Option<&mut S>, pc: GuestAddr, block_length: GuestUsize), + generation_hook: Hook< + fn(&mut Self, Option<&mut S>, pc: GuestAddr) -> Option, + Box FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr) -> Option>, + extern "C" fn(*const (), pc: GuestAddr) -> u64, >, - execution_hook: Option, id: u64)>, - ) { + post_generation_hook: Hook< + fn(&mut Self, Option<&mut S>, pc: GuestAddr, block_length: GuestUsize), + Box FnMut(&'a mut Self, Option<&mut S>, GuestAddr, GuestUsize)>, + extern "C" fn(*const (), pc: GuestAddr, block_length: GuestUsize), + >, + execution_hook: Hook< + fn(&mut Self, Option<&mut S>, id: u64), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64)>, + extern "C" fn(*const (), id: u64), + >, + ) -> HookId { unsafe { - let index = BLOCK_HOOKS.len(); - self.emulator.add_block_hooks( - generation_hook - .as_ref() - .map(|_| gen_block_hook_wrapper:: as _), - post_generation_hook - .as_ref() - .map(|_| gen_post_block_hook_wrapper:: as _), - execution_hook - .as_ref() - .map(|_| exec_block_hook_wrapper:: as _), - index as u64, + let gen = get_raw_hook!( + generation_hook, + block_gen_hook_wrapper::, + extern "C" fn(&mut HookState<1>, pc: GuestAddr) -> u64 ); - BLOCK_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - post_generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - )); - } - } - - pub unsafe fn blocks_closures( - &self, - generation_hook: Option< - Box, GuestAddr) -> Option>, - >, - post_generation_hook: Option< - Box, GuestAddr, GuestUsize)>, - >, - execution_hook: Option, u64)>>, - ) { - let index = BLOCK_HOOKS.len(); - self.emulator.add_block_hooks( - generation_hook - .as_ref() - .map(|_| gen_block_hook_wrapper:: as _), - post_generation_hook - .as_ref() - .map(|_| gen_post_block_hook_wrapper:: as _), - execution_hook - .as_ref() - .map(|_| exec_block_hook_wrapper:: as _), - index as u64, - ); - BLOCK_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - post_generation_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - )); - } - - pub fn blocks_raw( - &self, - generation_hook: Option, pc: GuestAddr) -> Option>, - post_generation_hook: Option< - fn(&mut Self, Option<&mut S>, pc: GuestAddr, block_length: GuestUsize), - >, - execution_hook: Option, - ) { - unsafe { - let index = BLOCK_HOOKS.len(); - self.emulator.add_block_hooks( - generation_hook - .as_ref() - .map(|_| gen_block_hook_wrapper:: as _), - post_generation_hook - .as_ref() - .map(|_| gen_post_block_hook_wrapper:: as _), + let postgen = get_raw_hook!( + post_generation_hook, + block_post_gen_hook_wrapper::, + extern "C" fn(&mut HookState<1>, pc: GuestAddr, block_length: GuestUsize) + ); + let exec = get_raw_hook!( execution_hook, - index as u64, + block_0_exec_hook_wrapper::, + extern "C" fn(&mut HookState<1>, id: u64) ); - BLOCK_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - post_generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - Hook::Empty, - )); + BLOCK_HOOKS.push(HookState { + id: HookId(0), + gen: hook_to_repr!(generation_hook), + post_gen: hook_to_repr!(post_generation_hook), + execs: [hook_to_repr!(execution_hook)], + }); + let id = + self.emulator + .add_block_hooks(BLOCK_HOOKS.last_mut().unwrap(), gen, postgen, exec); + BLOCK_HOOKS.last_mut().unwrap().id = id; + id } } pub fn reads( &self, - generation_hook: Option< + generation_hook: Hook< fn(&mut Self, Option<&mut S>, pc: GuestAddr, info: MemAccessInfo) -> Option, - >, - execution_hook1: Option, id: u64, addr: GuestAddr)>, - execution_hook2: Option, id: u64, addr: GuestAddr)>, - execution_hook4: Option, id: u64, addr: GuestAddr)>, - execution_hook8: Option, id: u64, addr: GuestAddr)>, - execution_hook_n: Option< - fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), - >, - ) { - unsafe { - let index = READ_HOOKS.len(); - self.emulator.add_read_hooks( - generation_hook - .as_ref() - .map(|_| gen_read_hook_wrapper:: as _), - execution_hook1 - .as_ref() - .map(|_| exec_read1_hook_wrapper:: as _), - execution_hook2 - .as_ref() - .map(|_| exec_read2_hook_wrapper:: as _), - execution_hook4 - .as_ref() - .map(|_| exec_read4_hook_wrapper:: as _), - execution_hook8 - .as_ref() - .map(|_| exec_read8_hook_wrapper:: as _), - execution_hook_n - .as_ref() - .map(|_| exec_read_n_hook_wrapper:: as _), - index as u64, - ); - READ_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook1.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook2.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook4.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook8.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook_n.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - )); - } - } - - pub unsafe fn reads_closures( - &self, - generation_hook: Option< Box< - dyn FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr, MemAccessInfo) -> Option, + dyn for<'a> FnMut( + &'a mut Self, + Option<&'a mut S>, + GuestAddr, + MemAccessInfo, + ) -> Option, >, + extern "C" fn(*const (), pc: GuestAddr, info: MemAccessInfo) -> u64, >, - execution_hook1: Option, u64, GuestAddr)>>, - execution_hook2: Option, u64, GuestAddr)>>, - execution_hook4: Option, u64, GuestAddr)>>, - execution_hook8: Option, u64, GuestAddr)>>, - execution_hook_n: Option< - Box, u64, GuestAddr, usize)>, + execution_hook_1: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), >, - ) { - let index = READ_HOOKS.len(); - self.emulator.add_read_hooks( - generation_hook - .as_ref() - .map(|_| gen_read_hook_wrapper:: as _), - execution_hook1 - .as_ref() - .map(|_| exec_read1_hook_wrapper:: as _), - execution_hook2 - .as_ref() - .map(|_| exec_read2_hook_wrapper:: as _), - execution_hook4 - .as_ref() - .map(|_| exec_read4_hook_wrapper:: as _), - execution_hook8 - .as_ref() - .map(|_| exec_read8_hook_wrapper:: as _), - execution_hook_n - .as_ref() - .map(|_| exec_read_n_hook_wrapper:: as _), - index as u64, - ); - READ_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook1.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook2.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook4.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook8.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook_n.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - )); - } - - pub fn reads_raw( - &self, - generation_hook: Option< - fn(&mut Self, Option<&mut S>, pc: GuestAddr, info: MemAccessInfo) -> Option, + execution_hook_2: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), >, - execution_hook1: Option, - execution_hook2: Option, - execution_hook4: Option, - execution_hook8: Option, - execution_hook_n: Option, - ) { + execution_hook_4: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), + >, + execution_hook_8: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), + >, + execution_hook_n: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr, usize)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize), + >, + ) -> HookId { unsafe { - let index = READ_HOOKS.len(); - self.emulator.add_read_hooks( - generation_hook - .as_ref() - .map(|_| gen_read_hook_wrapper:: as _), - execution_hook1, - execution_hook2, - execution_hook4, - execution_hook8, - execution_hook_n, - index as u64, + let gen = get_raw_hook!( + generation_hook, + read_gen_hook_wrapper::, + extern "C" fn(&mut HookState<5>, pc: GuestAddr, info: MemAccessInfo) -> u64 ); - READ_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - Hook::Empty, - Hook::Empty, - Hook::Empty, - Hook::Empty, - Hook::Empty, - )); + let exec1 = get_raw_hook!( + execution_hook_1, + read_0_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let exec2 = get_raw_hook!( + execution_hook_2, + read_1_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let exec4 = get_raw_hook!( + execution_hook_4, + read_2_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let exec8 = get_raw_hook!( + execution_hook_8, + read_3_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let execn = get_raw_hook!( + execution_hook_n, + read_4_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr, size: usize) + ); + READ_HOOKS.push(HookState { + id: HookId(0), + gen: hook_to_repr!(generation_hook), + post_gen: HookRepr::Empty, + execs: [ + hook_to_repr!(execution_hook_1), + hook_to_repr!(execution_hook_2), + hook_to_repr!(execution_hook_4), + hook_to_repr!(execution_hook_8), + hook_to_repr!(execution_hook_n), + ], + }); + let id = self.emulator.add_read_hooks( + READ_HOOKS.last_mut().unwrap(), + gen, + exec1, + exec2, + exec4, + exec8, + execn, + ); + READ_HOOKS.last_mut().unwrap().id = id; + id } } pub fn writes( &self, - generation_hook: Option< + generation_hook: Hook< fn(&mut Self, Option<&mut S>, pc: GuestAddr, info: MemAccessInfo) -> Option, - >, - execution_hook1: Option, id: u64, addr: GuestAddr)>, - execution_hook2: Option, id: u64, addr: GuestAddr)>, - execution_hook4: Option, id: u64, addr: GuestAddr)>, - execution_hook8: Option, id: u64, addr: GuestAddr)>, - execution_hook_n: Option< - fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), - >, - ) { - unsafe { - let index = WRITE_HOOKS.len(); - self.emulator.add_write_hooks( - generation_hook - .as_ref() - .map(|_| gen_write_hook_wrapper:: as _), - execution_hook1 - .as_ref() - .map(|_| exec_write1_hook_wrapper:: as _), - execution_hook2 - .as_ref() - .map(|_| exec_write2_hook_wrapper:: as _), - execution_hook4 - .as_ref() - .map(|_| exec_write4_hook_wrapper:: as _), - execution_hook8 - .as_ref() - .map(|_| exec_write8_hook_wrapper:: as _), - execution_hook_n - .as_ref() - .map(|_| exec_write_n_hook_wrapper:: as _), - index as u64, - ); - WRITE_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook1.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook2.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook4.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook8.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook_n.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - )); - } - } - - pub unsafe fn writes_closures( - &self, - generation_hook: Option< Box< - dyn FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr, MemAccessInfo) -> Option, + dyn for<'a> FnMut( + &'a mut Self, + Option<&'a mut S>, + GuestAddr, + MemAccessInfo, + ) -> Option, >, + extern "C" fn(*const (), pc: GuestAddr, info: MemAccessInfo) -> u64, >, - execution_hook1: Option, u64, GuestAddr)>>, - execution_hook2: Option, u64, GuestAddr)>>, - execution_hook4: Option, u64, GuestAddr)>>, - execution_hook8: Option, u64, GuestAddr)>>, - execution_hook_n: Option< - Box, u64, GuestAddr, usize)>, + execution_hook_1: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), >, - ) { - let index = WRITE_HOOKS.len(); - self.emulator.add_write_hooks( - generation_hook - .as_ref() - .map(|_| gen_write_hook_wrapper:: as _), - execution_hook1 - .as_ref() - .map(|_| exec_write1_hook_wrapper:: as _), - execution_hook2 - .as_ref() - .map(|_| exec_write2_hook_wrapper:: as _), - execution_hook4 - .as_ref() - .map(|_| exec_write4_hook_wrapper:: as _), - execution_hook8 - .as_ref() - .map(|_| exec_write8_hook_wrapper:: as _), - execution_hook_n - .as_ref() - .map(|_| exec_write_n_hook_wrapper:: as _), - index as u64, - ); - WRITE_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook1.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook2.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook4.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook8.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook_n.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - )); - } - - pub fn writes_raw( - &self, - generation_hook: Option< - fn(&mut Self, Option<&mut S>, pc: GuestAddr, info: MemAccessInfo) -> Option, + execution_hook_2: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), >, - execution_hook1: Option, - execution_hook2: Option, - execution_hook4: Option, - execution_hook8: Option, - execution_hook_n: Option, - ) { + execution_hook_4: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), + >, + execution_hook_8: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr), + >, + execution_hook_n: Hook< + fn(&mut Self, Option<&mut S>, id: u64, addr: GuestAddr, size: usize), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, GuestAddr, usize)>, + extern "C" fn(*const (), id: u64, addr: GuestAddr, size: usize), + >, + ) -> HookId { unsafe { - let index = WRITE_HOOKS.len(); - self.emulator.add_write_hooks( - generation_hook - .as_ref() - .map(|_| gen_write_hook_wrapper:: as _), - execution_hook1, - execution_hook2, - execution_hook4, - execution_hook8, - execution_hook_n, - index as u64, + let gen = get_raw_hook!( + generation_hook, + write_gen_hook_wrapper::, + extern "C" fn(&mut HookState<5>, pc: GuestAddr, info: MemAccessInfo) -> u64 ); - WRITE_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - Hook::Empty, - Hook::Empty, - Hook::Empty, - Hook::Empty, - Hook::Empty, - )); + let exec1 = get_raw_hook!( + execution_hook_1, + write_0_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let exec2 = get_raw_hook!( + execution_hook_2, + write_1_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let exec4 = get_raw_hook!( + execution_hook_4, + write_2_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let exec8 = get_raw_hook!( + execution_hook_8, + write_3_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr) + ); + let execn = get_raw_hook!( + execution_hook_n, + write_4_exec_hook_wrapper::, + extern "C" fn(&mut HookState<5>, id: u64, addr: GuestAddr, size: usize) + ); + WRITE_HOOKS.push(HookState { + id: HookId(0), + gen: hook_to_repr!(generation_hook), + post_gen: HookRepr::Empty, + execs: [ + hook_to_repr!(execution_hook_1), + hook_to_repr!(execution_hook_2), + hook_to_repr!(execution_hook_4), + hook_to_repr!(execution_hook_8), + hook_to_repr!(execution_hook_n), + ], + }); + let id = self.emulator.add_write_hooks( + WRITE_HOOKS.last_mut().unwrap(), + gen, + exec1, + exec2, + exec4, + exec8, + execn, + ); + WRITE_HOOKS.last_mut().unwrap().id = id; + id } } pub fn cmps( &self, - generation_hook: Option< + generation_hook: Hook< fn(&mut Self, Option<&mut S>, pc: GuestAddr, size: usize) -> Option, + Box< + dyn for<'a> FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr, usize) -> Option, + >, + extern "C" fn(*const (), pc: GuestAddr, size: usize) -> u64, >, - execution_hook1: Option, id: u64, v0: u8, v1: u8)>, - execution_hook2: Option, id: u64, v0: u16, v1: u16)>, - execution_hook4: Option, id: u64, v0: u32, v1: u32)>, - execution_hook8: Option, id: u64, v0: u64, v1: u64)>, - ) { + execution_hook_1: Hook< + fn(&mut Self, Option<&mut S>, id: u64, v0: u8, v1: u8), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, u8, u8)>, + extern "C" fn(*const (), id: u64, v0: u8, v1: u8), + >, + execution_hook_2: Hook< + fn(&mut Self, Option<&mut S>, id: u64, v0: u16, v1: u16), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, u16, u16)>, + extern "C" fn(*const (), id: u64, v0: u16, v1: u16), + >, + execution_hook_4: Hook< + fn(&mut Self, Option<&mut S>, id: u64, v0: u32, v1: u32), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, u32, u32)>, + extern "C" fn(*const (), id: u64, v0: u32, v1: u32), + >, + execution_hook_8: Hook< + fn(&mut Self, Option<&mut S>, id: u64, v0: u64, v1: u64), + Box FnMut(&'a mut Self, Option<&'a mut S>, u64, u64, u64)>, + extern "C" fn(*const (), id: u64, v0: u64, v1: u64), + >, + ) -> HookId { unsafe { - let index = CMP_HOOKS.len(); - self.emulator.add_cmp_hooks( - generation_hook - .as_ref() - .map(|_| gen_cmp_hook_wrapper:: as _), - execution_hook1 - .as_ref() - .map(|_| exec_cmp1_hook_wrapper:: as _), - execution_hook2 - .as_ref() - .map(|_| exec_cmp2_hook_wrapper:: as _), - execution_hook4 - .as_ref() - .map(|_| exec_cmp4_hook_wrapper:: as _), - execution_hook8 - .as_ref() - .map(|_| exec_cmp8_hook_wrapper:: as _), - index as u64, + let gen = get_raw_hook!( + generation_hook, + cmp_gen_hook_wrapper::, + extern "C" fn(&mut HookState<4>, pc: GuestAddr, size: usize) -> u64 ); - CMP_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook1.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook2.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook4.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - execution_hook8.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - )); - } - } - - pub unsafe fn cmps_closures( - &self, - generation_hook: Option< - Box, GuestAddr, usize) -> Option>, - >, - execution_hook1: Option, u64, u8, u8)>>, - execution_hook2: Option, u64, u16, u16)>>, - execution_hook4: Option, u64, u32, u32)>>, - execution_hook8: Option, u64, u64, u64)>>, - ) { - let index = CMP_HOOKS.len(); - self.emulator.add_cmp_hooks( - generation_hook - .as_ref() - .map(|_| gen_cmp_hook_wrapper:: as _), - execution_hook1 - .as_ref() - .map(|_| exec_cmp1_hook_wrapper:: as _), - execution_hook2 - .as_ref() - .map(|_| exec_cmp2_hook_wrapper:: as _), - execution_hook4 - .as_ref() - .map(|_| exec_cmp4_hook_wrapper:: as _), - execution_hook8 - .as_ref() - .map(|_| exec_cmp8_hook_wrapper:: as _), - index as u64, - ); - CMP_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook1.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook2.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook4.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - execution_hook8.map_or(Hook::Empty, |hook| Hook::Closure(transmute(hook))), - )); - } - - pub fn cmps_raw( - &self, - generation_hook: Option< - fn(&mut Self, Option<&mut S>, pc: GuestAddr, size: usize) -> Option, - >, - execution_hook1: Option, - execution_hook2: Option, - execution_hook4: Option, - execution_hook8: Option, - ) { - unsafe { - let index = CMP_HOOKS.len(); - self.emulator.add_cmp_hooks( - generation_hook - .as_ref() - .map(|_| gen_cmp_hook_wrapper:: as _), - execution_hook1, - execution_hook2, - execution_hook4, - execution_hook8, - index as u64, + let exec1 = get_raw_hook!( + execution_hook_1, + cmp_0_exec_hook_wrapper::, + extern "C" fn(&mut HookState<4>, id: u64, v0: u8, v1: u8) ); - CMP_HOOKS.push(( - generation_hook.map_or(Hook::Empty, |hook| { - Hook::Function(hook as *const libc::c_void) - }), - Hook::Empty, - Hook::Empty, - Hook::Empty, - Hook::Empty, - )); + let exec2 = get_raw_hook!( + execution_hook_2, + cmp_1_exec_hook_wrapper::, + extern "C" fn(&mut HookState<4>, id: u64, v0: u16, v1: u16) + ); + let exec4 = get_raw_hook!( + execution_hook_4, + cmp_2_exec_hook_wrapper::, + extern "C" fn(&mut HookState<4>, id: u64, v0: u32, v1: u32) + ); + let exec8 = get_raw_hook!( + execution_hook_8, + cmp_3_exec_hook_wrapper::, + extern "C" fn(&mut HookState<4>, id: u64, v0: u64, v1: u64) + ); + CMP_HOOKS.push(HookState { + id: HookId(0), + gen: hook_to_repr!(generation_hook), + post_gen: HookRepr::Empty, + execs: [ + hook_to_repr!(execution_hook_1), + hook_to_repr!(execution_hook_2), + hook_to_repr!(execution_hook_4), + hook_to_repr!(execution_hook_8), + ], + }); + let id = self.emulator.add_cmp_hooks( + CMP_HOOKS.last_mut().unwrap(), + gen, + exec1, + exec2, + exec4, + exec8, + ); + CMP_HOOKS.last_mut().unwrap().id = id; + id } } - #[cfg(emulation_mode = "usermode")] - pub fn thread_creation(&self, hook: fn(&mut Self, Option<&mut S>, tid: u32)) { - unsafe { - ON_THREAD_HOOKS.push(Hook::Function(hook as *const libc::c_void)); - } - self.emulator - .set_on_thread_hook(on_thread_hooks_wrapper::); - } - - #[cfg(emulation_mode = "usermode")] - pub fn thread_creation_closure( + pub fn backdoor( &self, - hook: Box, u32) + 'a>, - ) { + hook: Hook< + fn(&mut Self, Option<&mut S>, GuestAddr), + Box FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, + extern "C" fn(*const (), pc: GuestAddr), + >, + ) -> HookId { unsafe { - ON_THREAD_HOOKS.push(Hook::Closure(transmute(hook))); + match hook { + Hook::Function(f) => self.backdoor_function(f), + Hook::Closure(c) => self.backdoor_closure(c), + Hook::Raw(r) => { + let z: *const () = transmute(0u64); + self.emulator.add_backdoor_hook(z, r) + } + Hook::Empty => HookId(0), // TODO error type + } } - self.emulator - .set_on_thread_hook(on_thread_hooks_wrapper::); } - #[cfg(emulation_mode = "usermode")] - pub fn thread_creation_once(&self, hook: Box, u32) + 'a>) { + pub fn backdoor_function(&self, hook: fn(&mut Self, Option<&mut S>, pc: GuestAddr)) -> HookId { unsafe { - ON_THREAD_HOOKS.push(Hook::Once(transmute(hook))); + self.emulator + .add_backdoor_hook(transmute(hook), func_backdoor_hook_wrapper::) + } + } + + pub fn backdoor_closure( + &self, + hook: Box FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, + ) -> HookId { + unsafe { + let fat: FatPtr = transmute(hook); + BACKDOOR_HOOKS.push((HookId(0), fat)); + let id = self.emulator.add_backdoor_hook( + &mut BACKDOOR_HOOKS.last_mut().unwrap().1, + closure_backdoor_hook_wrapper::, + ); + BACKDOOR_HOOKS.last_mut().unwrap().0 = id; + id } - self.emulator - .set_on_thread_hook(on_thread_hooks_wrapper::); } #[cfg(emulation_mode = "usermode")] #[allow(clippy::type_complexity)] pub fn syscalls( + &self, + hook: Hook< + fn( + &mut Self, + Option<&mut S>, + sys_num: i32, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + a4: GuestAddr, + a5: GuestAddr, + a6: GuestAddr, + a7: GuestAddr, + ) -> SyscallHookResult, + Box< + dyn for<'a> FnMut( + &'a mut Self, + Option<&'a mut S>, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> SyscallHookResult, + >, + extern "C" fn( + *const (), + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> SyscallHookResult, + >, + ) -> HookId { + unsafe { + match hook { + Hook::Function(f) => self.syscalls_function(f), + Hook::Closure(c) => self.syscalls_closure(c), + Hook::Raw(r) => { + let z: *const () = transmute(0u64); + self.emulator.add_pre_syscall_hook(z, r) + } + Hook::Empty => HookId(0), // TODO error type + } + } + } + + #[cfg(emulation_mode = "usermode")] + #[allow(clippy::type_complexity)] + pub fn syscalls_function( &self, hook: fn( &mut Self, Option<&mut S>, sys_num: i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + a4: GuestAddr, + a5: GuestAddr, + a6: GuestAddr, + a7: GuestAddr, ) -> SyscallHookResult, - ) { + ) -> HookId { unsafe { - SYSCALL_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + self.emulator + .add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::) } - self.emulator - .set_pre_syscall_hook(syscall_hooks_wrapper::); } #[cfg(emulation_mode = "usermode")] @@ -1503,52 +1008,119 @@ where pub fn syscalls_closure( &self, hook: Box< - dyn FnMut( - &mut Self, - Option<&mut S>, + dyn for<'a> FnMut( + &'a mut Self, + Option<&'a mut S>, i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, ) -> SyscallHookResult, >, - ) { + ) -> HookId { unsafe { - SYSCALL_HOOKS.push(Hook::Closure(transmute(hook))); + let fat: FatPtr = transmute(hook); + PRE_SYSCALL_HOOKS.push((HookId(0), fat)); + let id = self.emulator.add_pre_syscall_hook( + &mut PRE_SYSCALL_HOOKS.last_mut().unwrap().1, + closure_pre_syscall_hook_wrapper::, + ); + PRE_SYSCALL_HOOKS.last_mut().unwrap().0 = id; + id } - self.emulator - .set_pre_syscall_hook(syscall_hooks_wrapper::); } #[cfg(emulation_mode = "usermode")] #[allow(clippy::type_complexity)] pub fn after_syscalls( + &self, + hook: Hook< + fn( + &mut Self, + Option<&mut S>, + res: GuestAddr, + sys_num: i32, + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + a4: GuestAddr, + a5: GuestAddr, + a6: GuestAddr, + a7: GuestAddr, + ) -> GuestAddr, + Box< + dyn for<'a> FnMut( + &'a mut Self, + Option<&mut S>, + GuestAddr, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> GuestAddr, + >, + extern "C" fn( + *const (), + GuestAddr, + i32, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> GuestAddr, + >, + ) -> HookId { + unsafe { + match hook { + Hook::Function(f) => self.after_syscalls_function(f), + Hook::Closure(c) => self.after_syscalls_closure(c), + Hook::Raw(r) => { + let z: *const () = transmute(0u64); + self.emulator.add_post_syscall_hook(z, r) + } + Hook::Empty => HookId(0), // TODO error type + } + } + } + + #[cfg(emulation_mode = "usermode")] + #[allow(clippy::type_complexity)] + pub fn after_syscalls_function( &self, hook: fn( &mut Self, Option<&mut S>, - result: u64, + res: GuestAddr, sys_num: i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> u64, - ) { + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + a4: GuestAddr, + a5: GuestAddr, + a6: GuestAddr, + a7: GuestAddr, + ) -> GuestAddr, + ) -> HookId { unsafe { - SYSCALL_POST_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + self.emulator + .add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::) } - self.emulator - .set_post_syscall_hook(syscall_after_hooks_wrapper::); } #[cfg(emulation_mode = "usermode")] @@ -1556,42 +1128,97 @@ where pub fn after_syscalls_closure( &self, hook: Box< - dyn FnMut( - &mut Self, + dyn for<'a> FnMut( + &'a mut Self, Option<&mut S>, - u64, + GuestAddr, i32, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> u64, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + GuestAddr, + ) -> GuestAddr, >, - ) { + ) -> HookId { unsafe { - SYSCALL_POST_HOOKS.push(Hook::Closure(transmute(hook))); + let fat: FatPtr = transmute(hook); + POST_SYSCALL_HOOKS.push((HookId(0), fat)); + let id = self.emulator.add_post_syscall_hook( + &mut POST_SYSCALL_HOOKS.last_mut().unwrap().1, + closure_post_syscall_hook_wrapper::, + ); + POST_SYSCALL_HOOKS.last_mut().unwrap().0 = id; + id + } + } + + #[cfg(emulation_mode = "usermode")] + pub fn thread_creation( + &self, + hook: Hook< + fn(&mut Self, Option<&mut S>, tid: u32) -> bool, + Box FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>, + extern "C" fn(*const (), tid: u32) -> bool, + >, + ) -> HookId { + unsafe { + match hook { + Hook::Function(f) => self.thread_creation_function(f), + Hook::Closure(c) => self.thread_creation_closure(c), + Hook::Raw(r) => { + let z: *const () = transmute(0u64); + self.emulator.add_new_thread_hook(z, r) + } + Hook::Empty => HookId(0), // TODO error type + } + } + } + + #[cfg(emulation_mode = "usermode")] + pub fn thread_creation_function( + &self, + hook: fn(&mut Self, Option<&mut S>, tid: u32) -> bool, + ) -> HookId { + unsafe { + self.emulator + .add_new_thread_hook(transmute(hook), func_new_thread_hook_wrapper::) + } + } + + #[cfg(emulation_mode = "usermode")] + pub fn thread_creation_closure( + &self, + hook: Box FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>, + ) -> HookId { + unsafe { + let fat: FatPtr = transmute(hook); + NEW_THREAD_HOOKS.push((HookId(0), fat)); + let id = self.emulator.add_new_thread_hook( + &mut NEW_THREAD_HOOKS.last_mut().unwrap().1, + closure_new_thread_hook_wrapper::, + ); + NEW_THREAD_HOOKS.last_mut().unwrap().0 = id; + id + } + } + + #[cfg(emulation_mode = "usermode")] + pub fn crash_function(&self, hook: fn(&mut Self, target_signal: i32)) { + unsafe { + self.emulator.set_crash_hook(crash_hook_wrapper::); + CRASH_HOOKS.push(HookRepr::Function(hook as *const libc::c_void)); } - self.emulator - .set_post_syscall_hook(syscall_after_hooks_wrapper::); } #[cfg(emulation_mode = "usermode")] pub fn crash_closure(&self, hook: Box) { unsafe { self.emulator.set_crash_hook(crash_hook_wrapper::); - CRASH_HOOKS.push(Hook::Closure(transmute(hook))); - } - } - - #[cfg(emulation_mode = "usermode")] - pub fn crash(&self, hook: fn(&mut Self, target_signal: i32)) { - unsafe { - self.emulator.set_crash_hook(crash_hook_wrapper::); - CRASH_HOOKS.push(Hook::Function(hook as *const libc::c_void)); + CRASH_HOOKS.push(HookRepr::Closure(transmute(hook))); } } } diff --git a/libafl_qemu/src/snapshot.rs b/libafl_qemu/src/snapshot.rs index 54a8ac4d4c..7767d6bccd 100644 --- a/libafl_qemu/src/snapshot.rs +++ b/libafl_qemu/src/snapshot.rs @@ -24,7 +24,7 @@ use crate::SYS_newfstatat; use crate::{ emu::{Emulator, MmapPerms, SyscallHookResult}, helper::{QemuHelper, QemuHelperTuple}, - hooks::QemuHooks, + hooks::{Hook, QemuHooks}, GuestAddr, SYS_fstat, SYS_fstatfs, SYS_futex, SYS_getrandom, SYS_mprotect, SYS_mremap, SYS_munmap, SYS_pread64, SYS_read, SYS_readlinkat, SYS_statfs, }; @@ -487,23 +487,23 @@ impl QemuHelper for QemuSnapshotHelper where S: UsesInput + HasMetadata, { - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn first_exec(&self, hooks: &QemuHooks) where QT: QemuHelperTuple, { hooks.writes( - None, - Some(trace_write1_snapshot::), - Some(trace_write2_snapshot::), - Some(trace_write4_snapshot::), - Some(trace_write8_snapshot::), - Some(trace_write_n_snapshot::), + Hook::Empty, + Hook::Function(trace_write1_snapshot::), + Hook::Function(trace_write2_snapshot::), + Hook::Function(trace_write4_snapshot::), + Hook::Function(trace_write8_snapshot::), + Hook::Function(trace_write_n_snapshot::), ); if !self.accurate_unmap { - hooks.syscalls(filter_mmap_snapshot::); + hooks.syscalls(Hook::Function(filter_mmap_snapshot::)); } - hooks.after_syscalls(trace_mmap_snapshot::); + hooks.after_syscalls(Hook::Function(trace_mmap_snapshot::)); } fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) { @@ -516,7 +516,7 @@ where } pub fn trace_write1_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, _id: u64, addr: GuestAddr, @@ -529,7 +529,7 @@ pub fn trace_write1_snapshot( } pub fn trace_write2_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, _id: u64, addr: GuestAddr, @@ -542,7 +542,7 @@ pub fn trace_write2_snapshot( } pub fn trace_write4_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, _id: u64, addr: GuestAddr, @@ -555,7 +555,7 @@ pub fn trace_write4_snapshot( } pub fn trace_write8_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, _id: u64, addr: GuestAddr, @@ -568,7 +568,7 @@ pub fn trace_write8_snapshot( } pub fn trace_write_n_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, _id: u64, addr: GuestAddr, @@ -584,17 +584,17 @@ pub fn trace_write_n_snapshot( #[allow(clippy::too_many_arguments)] #[allow(non_upper_case_globals)] pub fn filter_mmap_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, sys_num: i32, - a0: u64, - a1: u64, - _a2: u64, - _a3: u64, - _a4: u64, - _a5: u64, - _a6: u64, - _a7: u64, + a0: GuestAddr, + a1: GuestAddr, + _a2: GuestAddr, + _a3: GuestAddr, + _a4: GuestAddr, + _a5: GuestAddr, + _a6: GuestAddr, + _a7: GuestAddr, ) -> SyscallHookResult where S: UsesInput, @@ -612,19 +612,19 @@ where #[allow(clippy::too_many_arguments)] #[allow(non_upper_case_globals)] pub fn trace_mmap_snapshot( - hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks, _state: Option<&mut S>, - result: u64, + result: GuestAddr, sys_num: i32, - a0: u64, - a1: u64, - a2: u64, - a3: u64, - _a4: u64, - _a5: u64, - _a6: u64, - _a7: u64, -) -> u64 + a0: GuestAddr, + a1: GuestAddr, + a2: GuestAddr, + a3: GuestAddr, + _a4: GuestAddr, + _a5: GuestAddr, + _a6: GuestAddr, + _a7: GuestAddr, +) -> GuestAddr where S: UsesInput, QT: QemuHelperTuple, @@ -633,15 +633,15 @@ where match i64::from(sys_num) { SYS_read | SYS_pread64 => { let h = hooks.match_helper_mut::().unwrap(); - h.access(a1 as GuestAddr, a2 as usize); + h.access(a1, a2 as usize); } SYS_readlinkat => { let h = hooks.match_helper_mut::().unwrap(); - h.access(a2 as GuestAddr, a3 as usize); + h.access(a2, a3 as usize); } SYS_futex => { let h = hooks.match_helper_mut::().unwrap(); - h.access(a0 as GuestAddr, a3 as usize); + h.access(a0, a3 as usize); } #[cfg(not(any( cpu_target = "arm", @@ -652,27 +652,27 @@ where SYS_newfstatat => { if a2 != 0 { let h = hooks.match_helper_mut::().unwrap(); - h.access(a2 as GuestAddr, 4096); // stat is not greater than a page + h.access(a2, 4096); // stat is not greater than a page } } #[cfg(any(cpu_target = "arm", cpu_target = "mips", cpu_target = "i386"))] SYS_fstatat64 => { if a2 != 0 { let h = hooks.match_helper_mut::().unwrap(); - h.access(a2 as GuestAddr, 4096); // stat is not greater than a page + h.access(a2, 4096); // stat is not greater than a page } } SYS_statfs | SYS_fstatfs | SYS_fstat => { let h = hooks.match_helper_mut::().unwrap(); - h.access(a1 as GuestAddr, 4096); // stat is not greater than a page + h.access(a1, 4096); // stat is not greater than a page } SYS_getrandom => { let h = hooks.match_helper_mut::().unwrap(); - h.access(a0 as GuestAddr, a1 as usize); + h.access(a0, a1 as usize); } // mmap syscalls sys_const => { - if result as GuestAddr == GuestAddr::MAX + if result == GuestAddr::MAX /* -1 */ { return result; @@ -684,7 +684,7 @@ where if sys_const == SYS_mmap2 { if let Ok(prot) = MmapPerms::try_from(a2 as i32) { let h = hooks.match_helper_mut::().unwrap(); - h.add_mapped(result as GuestAddr, a1 as usize, Some(prot)); + h.add_mapped(result, a1 as usize, Some(prot)); } } @@ -692,24 +692,24 @@ where if sys_const == SYS_mmap { if let Ok(prot) = MmapPerms::try_from(a2 as i32) { let h = hooks.match_helper_mut::().unwrap(); - h.add_mapped(result as GuestAddr, a1 as usize, Some(prot)); + h.add_mapped(result, a1 as usize, Some(prot)); } } if sys_const == SYS_mremap { let h = hooks.match_helper_mut::().unwrap(); // TODO get the old permissions from the removed mapping - h.remove_mapped(a0 as GuestAddr, a1 as usize); - h.add_mapped(result as GuestAddr, a2 as usize, None); + h.remove_mapped(a0, a1 as usize); + h.add_mapped(result, a2 as usize, None); } else if sys_const == SYS_mprotect { if let Ok(prot) = MmapPerms::try_from(a2 as i32) { let h = hooks.match_helper_mut::().unwrap(); - h.add_mapped(a0 as GuestAddr, a1 as usize, Some(prot)); + h.add_mapped(a0, a1 as usize, Some(prot)); } } else if sys_const == SYS_munmap { let h = hooks.match_helper_mut::().unwrap(); - if !h.accurate_unmap && !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) { - h.remove_mapped(a0 as GuestAddr, a1 as usize); + if !h.accurate_unmap && !h.is_unmap_allowed(a0, a1 as usize) { + h.remove_mapped(a0, a1 as usize); } } } diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 93f28a2340..3a32e9a05b 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -214,7 +214,7 @@ where if self.use_cmplog.unwrap_or(false) { let mut hooks = QemuHooks::new( - emulator, + emulator.clone(), #[cfg(not(any(feature = "mips", feature = "hexagon")))] tuple_list!( QemuEdgeCoverageHelper::default(), @@ -325,8 +325,10 @@ where } } } else { - let mut hooks = - QemuHooks::new(emulator, tuple_list!(QemuEdgeCoverageHelper::default())); + let mut hooks = QemuHooks::new( + emulator.clone(), + tuple_list!(QemuEdgeCoverageHelper::default()), + ); let executor = QemuExecutor::new( &mut hooks,