[libafl_qemu] GuestAddr type (#501)

Guest addresses now represented by correct sized integers.

Previously u64 was used to represent guest addresses. This is great for
64-bit targets, but clunky for other architectures. This introduces a
GuestAddr type alias that is defined based on the selected emulation
architecture.

Note: This changes only the user-facing Rust interface. Before
traversing the FFI boundary, all GuestAddrs are sized back to u64.

Another Note: Guest addresses _from_ the FFI boundary are completely
trusted. Values that are too large are truncated to fit into a GuestAddr
using the `as GuestAddr` cast. This may not be ideal, as errors could be
masked. If desired and the performance is ok, a non-breaking update
could change all `as` casts to `.try_into().unwrap()` so that critical
failures in FFI are always checked.
This commit is contained in:
Evan Richter 2022-01-28 02:42:23 -06:00 committed by GitHub
parent efb5e25411
commit 4e3e31df4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 206 additions and 150 deletions

View File

@ -6,7 +6,7 @@ use crate::{
emu::{Emulator, SyscallHookResult}, emu::{Emulator, SyscallHookResult},
executor::QemuExecutor, executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
Regs, GuestAddr, Regs,
}; };
// TODO at some point, merge parts with libafl_frida // TODO at some point, merge parts with libafl_frida
@ -231,16 +231,16 @@ impl QemuAsanHelper {
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
#[must_use] #[must_use]
pub fn is_poisoned(&self, emulator: &Emulator, addr: u64, size: usize) -> bool { pub fn is_poisoned(&self, emulator: &Emulator, addr: GuestAddr, size: usize) -> bool {
unsafe { asan_giovese_loadN(emulator.g2h(addr), size) != 0 } unsafe { asan_giovese_loadN(emulator.g2h(addr), size) != 0 }
} }
pub fn read_1(&mut self, emulator: &Emulator, addr: u64) { pub fn read_1(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_load1(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_load1(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
0, 0,
addr, addr.into(),
1, 1,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -250,12 +250,12 @@ impl QemuAsanHelper {
} }
} }
pub fn read_2(&mut self, emulator: &Emulator, addr: u64) { pub fn read_2(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_load2(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_load2(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
0, 0,
addr, addr.into(),
2, 2,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -265,12 +265,12 @@ impl QemuAsanHelper {
} }
} }
pub fn read_4(&mut self, emulator: &Emulator, addr: u64) { pub fn read_4(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_load4(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_load4(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
0, 0,
addr, addr.into(),
4, 4,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -280,12 +280,12 @@ impl QemuAsanHelper {
} }
} }
pub fn read_8(&mut self, emulator: &Emulator, addr: u64) { pub fn read_8(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_load8(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_load8(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
0, 0,
addr, addr.into(),
8, 8,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -295,12 +295,12 @@ impl QemuAsanHelper {
} }
} }
pub fn read_n(&mut self, emulator: &Emulator, addr: u64, size: usize) { pub fn read_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
unsafe { unsafe {
if self.enabled() && asan_giovese_loadN(emulator.g2h(addr), size) != 0 { if self.enabled() && asan_giovese_loadN(emulator.g2h(addr), size) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
0, 0,
addr, addr.into(),
size, size,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -310,12 +310,12 @@ impl QemuAsanHelper {
} }
} }
pub fn write_1(&mut self, emulator: &Emulator, addr: u64) { pub fn write_1(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_store1(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_store1(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
1, 1,
addr, addr.into(),
1, 1,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -325,12 +325,12 @@ impl QemuAsanHelper {
} }
} }
pub fn write_2(&mut self, emulator: &Emulator, addr: u64) { pub fn write_2(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_store2(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_store2(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
1, 1,
addr, addr.into(),
2, 2,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -340,12 +340,12 @@ impl QemuAsanHelper {
} }
} }
pub fn write_4(&mut self, emulator: &Emulator, addr: u64) { pub fn write_4(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_store4(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_store4(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
1, 1,
addr, addr.into(),
4, 4,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -355,12 +355,12 @@ impl QemuAsanHelper {
} }
} }
pub fn write_8(&mut self, emulator: &Emulator, addr: u64) { pub fn write_8(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe { unsafe {
if self.enabled() && asan_giovese_store8(emulator.g2h(addr)) != 0 { if self.enabled() && asan_giovese_store8(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
1, 1,
addr, addr.into(),
8, 8,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -370,12 +370,12 @@ impl QemuAsanHelper {
} }
} }
pub fn write_n(&mut self, emulator: &Emulator, addr: u64, size: usize) { pub fn write_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
unsafe { unsafe {
if self.enabled() && asan_giovese_storeN(emulator.g2h(addr), size) != 0 { if self.enabled() && asan_giovese_storeN(emulator.g2h(addr), size) != 0 {
asan_giovese_report_and_crash( asan_giovese_report_and_crash(
1, 1,
addr, addr.into(),
size, size,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX), emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0, 0,
@ -386,12 +386,18 @@ impl QemuAsanHelper {
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn poison(&mut self, emulator: &Emulator, addr: u64, size: usize, poison: PoisonKind) { pub fn poison(
&mut self,
emulator: &Emulator,
addr: GuestAddr,
size: usize,
poison: PoisonKind,
) {
unsafe { asan_giovese_poison_region(emulator.g2h(addr), size, poison.into()) }; unsafe { asan_giovese_poison_region(emulator.g2h(addr), size, poison.into()) };
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn unpoison(&mut self, emulator: &Emulator, addr: u64, size: usize) { pub fn unpoison(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
unsafe { asan_giovese_unpoison_region(emulator.g2h(addr), size) }; unsafe { asan_giovese_unpoison_region(emulator.g2h(addr), size) };
} }
@ -465,7 +471,7 @@ pub fn trace_read1_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -479,7 +485,7 @@ pub fn trace_read2_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -493,7 +499,7 @@ pub fn trace_read4_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -507,7 +513,7 @@ pub fn trace_read8_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -521,7 +527,7 @@ pub fn trace_read_n_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
size: usize, size: usize,
) where ) where
I: Input, I: Input,
@ -536,7 +542,7 @@ pub fn trace_write1_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -550,7 +556,7 @@ pub fn trace_write2_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -564,7 +570,7 @@ pub fn trace_write4_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -578,7 +584,7 @@ pub fn trace_write8_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -592,7 +598,7 @@ pub fn trace_write_n_asan<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
size: usize, size: usize,
) where ) where
I: Input, I: Input,
@ -626,27 +632,27 @@ where
let mut r = 0; let mut r = 0;
match QasanAction::try_from(a0).expect("Invalid QASan action number") { match QasanAction::try_from(a0).expect("Invalid QASan action number") {
QasanAction::CheckLoad => { QasanAction::CheckLoad => {
h.read_n(emulator, a1, a2 as usize); h.read_n(emulator, a1 as GuestAddr, a2 as usize);
} }
QasanAction::CheckStore => { QasanAction::CheckStore => {
h.write_n(emulator, a1, a2 as usize); h.write_n(emulator, a1 as GuestAddr, a2 as usize);
} }
QasanAction::Poison => { QasanAction::Poison => {
h.poison( h.poison(
emulator, emulator,
a1, a1 as GuestAddr,
a2 as usize, a2 as usize,
PoisonKind::try_from(a3 as u8).unwrap(), PoisonKind::try_from(a3 as u8).unwrap(),
); );
} }
QasanAction::UserPoison => { QasanAction::UserPoison => {
h.poison(emulator, a1, a2 as usize, PoisonKind::User); h.poison(emulator, a1 as GuestAddr, a2 as usize, PoisonKind::User);
} }
QasanAction::UnPoison => { QasanAction::UnPoison => {
h.unpoison(emulator, a1, a2 as usize); h.unpoison(emulator, a1 as GuestAddr, a2 as usize);
} }
QasanAction::IsPoison => { QasanAction::IsPoison => {
if h.is_poisoned(emulator, a1, a2 as usize) { if h.is_poisoned(emulator, a1 as GuestAddr, a2 as usize) {
r = 1; r = 1;
} }
} }

View File

@ -12,6 +12,16 @@ use num_traits::Num;
use std::{slice::from_raw_parts, str::from_utf8_unchecked}; use std::{slice::from_raw_parts, str::from_utf8_unchecked};
use strum_macros::EnumIter; use strum_macros::EnumIter;
#[cfg(not(any(feature = "x86_64", feature = "aarch64")))]
/// `GuestAddr` is u32 for 32-bit targets
pub type GuestAddr = u32;
#[cfg(any(feature = "x86_64", feature = "aarch64"))]
/// `GuestAddr` is u64 for 64-bit targets
pub type GuestAddr = u64;
pub type GuestUsize = GuestAddr;
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::{prelude::*, PyIterProtocol}; use pyo3::{prelude::*, PyIterProtocol};
@ -120,9 +130,9 @@ impl SyscallHookResult {
#[repr(C)] #[repr(C)]
#[cfg_attr(feature = "python", pyclass(unsendable))] #[cfg_attr(feature = "python", pyclass(unsendable))]
pub struct MapInfo { pub struct MapInfo {
start: u64, start: GuestAddr,
end: u64, end: GuestAddr,
offset: u64, offset: GuestAddr,
path: *const u8, path: *const u8,
flags: i32, flags: i32,
is_priv: i32, is_priv: i32,
@ -131,17 +141,17 @@ pub struct MapInfo {
#[cfg_attr(feature = "python", pymethods)] #[cfg_attr(feature = "python", pymethods)]
impl MapInfo { impl MapInfo {
#[must_use] #[must_use]
pub fn start(&self) -> u64 { pub fn start(&self) -> GuestAddr {
self.start self.start
} }
#[must_use] #[must_use]
pub fn end(&self) -> u64 { pub fn end(&self) -> GuestAddr {
self.end self.end
} }
#[must_use] #[must_use]
pub fn offset(&self) -> u64 { pub fn offset(&self) -> GuestAddr {
self.offset self.offset
} }
@ -349,7 +359,7 @@ impl Emulator {
/// This will write to a translated guest address (using `g2h`). /// This will write to a translated guest address (using `g2h`).
/// It just adds `guest_base` and writes to that location, without checking the bounds. /// It just adds `guest_base` and writes to that location, without checking the bounds.
/// This may only be safely used for valid guest addresses! /// This may only be safely used for valid guest addresses!
pub unsafe fn write_mem(&self, addr: u64, buf: &[u8]) { pub unsafe fn write_mem(&self, addr: GuestAddr, buf: &[u8]) {
let host_addr = self.g2h(addr); let host_addr = self.g2h(addr);
copy_nonoverlapping(buf.as_ptr(), host_addr, buf.len()); copy_nonoverlapping(buf.as_ptr(), host_addr, buf.len());
} }
@ -360,7 +370,7 @@ impl Emulator {
/// This will read from a translated guest address (using `g2h`). /// This will read from a translated guest address (using `g2h`).
/// It just adds `guest_base` and writes to that location, without checking the bounds. /// It just adds `guest_base` and writes to that location, without checking the bounds.
/// This may only be safely used for valid guest addresses! /// This may only be safely used for valid guest addresses!
pub unsafe fn read_mem(&self, addr: u64, buf: &mut [u8]) { pub unsafe fn read_mem(&self, addr: GuestAddr, buf: &mut [u8]) {
let host_addr = self.g2h(addr); let host_addr = self.g2h(addr);
copy_nonoverlapping(host_addr, buf.as_mut_ptr(), buf.len()); copy_nonoverlapping(host_addr, buf.as_mut_ptr(), buf.len());
} }
@ -399,27 +409,27 @@ impl Emulator {
} }
} }
pub fn set_breakpoint(&self, addr: u64) { pub fn set_breakpoint(&self, addr: GuestAddr) {
unsafe { unsafe {
libafl_qemu_set_breakpoint(addr); libafl_qemu_set_breakpoint(addr.into());
} }
} }
pub fn remove_breakpoint(&self, addr: u64) { pub fn remove_breakpoint(&self, addr: GuestAddr) {
unsafe { unsafe {
libafl_qemu_remove_breakpoint(addr); libafl_qemu_remove_breakpoint(addr.into());
} }
} }
pub fn set_hook(&self, addr: u64, callback: extern "C" fn(u64), val: u64) { pub fn set_hook(&self, addr: GuestAddr, callback: extern "C" fn(u64), val: u64) {
unsafe { unsafe {
libafl_qemu_set_hook(addr, callback, val); libafl_qemu_set_hook(addr.into(), callback, val);
} }
} }
pub fn remove_hook(&self, addr: u64) { pub fn remove_hook(&self, addr: GuestAddr) {
unsafe { unsafe {
libafl_qemu_remove_hook(addr); libafl_qemu_remove_hook(addr.into());
} }
} }
@ -433,13 +443,13 @@ impl Emulator {
} }
#[must_use] #[must_use]
pub fn g2h<T>(&self, addr: u64) -> *mut T { pub fn g2h<T>(&self, addr: GuestAddr) -> *mut T {
unsafe { transmute(addr + guest_base as u64) } unsafe { transmute(addr as usize + guest_base) }
} }
#[must_use] #[must_use]
pub fn h2g<T>(&self, addr: *const T) -> u64 { pub fn h2g<T>(&self, addr: *const T) -> GuestAddr {
unsafe { (addr as usize - guest_base) as u64 } unsafe { (addr as usize - guest_base) as GuestAddr }
} }
#[must_use] #[must_use]
@ -448,21 +458,27 @@ impl Emulator {
} }
#[must_use] #[must_use]
pub fn load_addr(&self) -> u64 { pub fn load_addr(&self) -> GuestAddr {
unsafe { libafl_load_addr() } unsafe { libafl_load_addr() as GuestAddr }
} }
#[must_use] #[must_use]
pub fn get_brk(&self) -> u64 { pub fn get_brk(&self) -> GuestAddr {
unsafe { libafl_get_brk() } unsafe { libafl_get_brk() as GuestAddr }
} }
pub fn set_brk(&self, brk: u64) { pub fn set_brk(&self, brk: GuestAddr) {
unsafe { libafl_set_brk(brk) }; unsafe { libafl_set_brk(brk.into()) };
} }
fn mmap(&self, addr: u64, size: usize, perms: MmapPerms, flags: c_int) -> Result<u64, ()> { fn mmap(
let res = unsafe { target_mmap(addr, size as u64, perms.into(), flags, -1, 0) }; &self,
addr: GuestAddr,
size: usize,
perms: MmapPerms,
flags: c_int,
) -> Result<u64, ()> {
let res = unsafe { target_mmap(addr.into(), size as u64, perms.into(), flags, -1, 0) };
if res == 0 { if res == 0 {
Err(()) Err(())
} else { } else {
@ -470,12 +486,23 @@ impl Emulator {
} }
} }
pub fn map_private(&self, addr: u64, size: usize, perms: MmapPerms) -> Result<u64, String> { pub fn map_private(
&self,
addr: GuestAddr,
size: usize,
perms: MmapPerms,
) -> Result<GuestAddr, String> {
self.mmap(addr, size, perms, libc::MAP_PRIVATE | libc::MAP_ANONYMOUS) self.mmap(addr, size, perms, libc::MAP_PRIVATE | libc::MAP_ANONYMOUS)
.map_err(|_| format!("Failed to map {}", addr)) .map_err(|_| format!("Failed to map {}", addr))
.map(|addr| addr as GuestAddr)
} }
pub fn map_fixed(&self, addr: u64, size: usize, perms: MmapPerms) -> Result<u64, String> { pub fn map_fixed(
&self,
addr: GuestAddr,
size: usize,
perms: MmapPerms,
) -> Result<GuestAddr, String> {
self.mmap( self.mmap(
addr, addr,
size, size,
@ -483,10 +510,11 @@ impl Emulator {
libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
) )
.map_err(|_| format!("Failed to map {}", addr)) .map_err(|_| format!("Failed to map {}", addr))
.map(|addr| addr as GuestAddr)
} }
pub fn mprotect(&self, addr: u64, size: usize, perms: MmapPerms) -> Result<(), String> { pub fn mprotect(&self, addr: GuestAddr, size: usize, perms: MmapPerms) -> Result<(), String> {
let res = unsafe { target_mprotect(addr, size as u64, perms.into()) }; let res = unsafe { target_mprotect(addr.into(), size as u64, perms.into()) };
if res == 0 { if res == 0 {
Ok(()) Ok(())
} else { } else {
@ -494,8 +522,8 @@ impl Emulator {
} }
} }
pub fn unmap(&self, addr: u64, size: usize) -> Result<(), String> { pub fn unmap(&self, addr: GuestAddr, size: usize) -> Result<(), String> {
if unsafe { target_munmap(addr, size as u64) } == 0 { if unsafe { target_munmap(addr.into(), size as u64) } == 0 {
Ok(()) Ok(())
} else { } else {
Err(format!("Failed to unmap {}", addr)) Err(format!("Failed to unmap {}", addr))
@ -652,14 +680,14 @@ impl Emulator {
#[cfg(feature = "python")] #[cfg(feature = "python")]
pub mod pybind { pub mod pybind {
use super::{MmapPerms, SyscallHookResult}; use super::{GuestAddr, GuestUsize, MmapPerms, SyscallHookResult};
use core::mem::transmute; use core::mem::transmute;
use pyo3::exceptions::PyValueError; use pyo3::exceptions::PyValueError;
use pyo3::{prelude::*, types::PyInt}; use pyo3::{prelude::*, types::PyInt};
use std::convert::TryFrom; use std::convert::TryFrom;
static mut PY_SYSCALL_HOOK: Option<PyObject> = None; static mut PY_SYSCALL_HOOK: Option<PyObject> = None;
static mut PY_GENERIC_HOOKS: Vec<(u64, PyObject)> = vec![]; static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![];
extern "C" fn py_syscall_hook_wrapper( extern "C" fn py_syscall_hook_wrapper(
sys_num: i32, sys_num: i32,
@ -719,13 +747,13 @@ pub mod pybind {
} }
} }
fn write_mem(&self, addr: u64, buf: &[u8]) { fn write_mem(&self, addr: GuestAddr, buf: &[u8]) {
unsafe { unsafe {
self.emu.write_mem(addr, buf); self.emu.write_mem(addr, buf);
} }
} }
fn read_mem(&self, addr: u64, size: usize) -> Vec<u8> { fn read_mem(&self, addr: GuestAddr, size: usize) -> Vec<u8> {
let mut buf = vec![0; size]; let mut buf = vec![0; size];
unsafe { unsafe {
self.emu.read_mem(addr, &mut buf); self.emu.read_mem(addr, &mut buf);
@ -737,19 +765,19 @@ pub mod pybind {
self.emu.num_regs() self.emu.num_regs()
} }
fn write_reg(&self, reg: i32, val: u64) -> PyResult<()> { fn write_reg(&self, reg: i32, val: GuestUsize) -> PyResult<()> {
self.emu.write_reg(reg, val).map_err(PyValueError::new_err) self.emu.write_reg(reg, val).map_err(PyValueError::new_err)
} }
fn read_reg(&self, reg: i32) -> PyResult<u64> { fn read_reg(&self, reg: i32) -> PyResult<GuestUsize> {
self.emu.read_reg(reg).map_err(PyValueError::new_err) self.emu.read_reg(reg).map_err(PyValueError::new_err)
} }
fn set_breakpoint(&self, addr: u64) { fn set_breakpoint(&self, addr: GuestAddr) {
self.emu.set_breakpoint(addr); self.emu.set_breakpoint(addr);
} }
fn remove_breakpoint(&self, addr: u64) { fn remove_breakpoint(&self, addr: GuestAddr) {
self.emu.remove_breakpoint(addr); self.emu.remove_breakpoint(addr);
} }
@ -759,11 +787,11 @@ pub mod pybind {
} }
} }
fn g2h(&self, addr: u64) -> u64 { fn g2h(&self, addr: GuestAddr) -> u64 {
self.emu.g2h::<*const u8>(addr) as u64 self.emu.g2h::<*const u8>(addr) as u64
} }
fn h2g(&self, addr: u64) -> u64 { fn h2g(&self, addr: u64) -> GuestAddr {
self.emu.h2g(unsafe { transmute::<_, *const u8>(addr) }) self.emu.h2g(unsafe { transmute::<_, *const u8>(addr) })
} }
@ -771,11 +799,11 @@ pub mod pybind {
self.emu.binary_path().to_owned() self.emu.binary_path().to_owned()
} }
fn load_addr(&self) -> u64 { fn load_addr(&self) -> GuestAddr {
self.emu.load_addr() self.emu.load_addr()
} }
fn map_private(&self, addr: u64, size: usize, perms: i32) -> PyResult<u64> { fn map_private(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> {
if let Ok(p) = MmapPerms::try_from(perms) { if let Ok(p) = MmapPerms::try_from(perms) {
self.emu self.emu
.map_private(addr, size, p) .map_private(addr, size, p)
@ -785,7 +813,7 @@ pub mod pybind {
} }
} }
fn map_fixed(&self, addr: u64, size: usize, perms: i32) -> PyResult<u64> { fn map_fixed(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> {
if let Ok(p) = MmapPerms::try_from(perms) { if let Ok(p) = MmapPerms::try_from(perms) {
self.emu self.emu
.map_fixed(addr, size, p) .map_fixed(addr, size, p)
@ -795,7 +823,7 @@ pub mod pybind {
} }
} }
fn mprotect(&self, addr: u64, size: usize, perms: i32) -> PyResult<()> { fn mprotect(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<()> {
if let Ok(p) = MmapPerms::try_from(perms) { if let Ok(p) = MmapPerms::try_from(perms) {
self.emu self.emu
.mprotect(addr, size, p) .mprotect(addr, size, p)
@ -805,7 +833,7 @@ pub mod pybind {
} }
} }
fn unmap(&self, addr: u64, size: usize) -> PyResult<()> { fn unmap(&self, addr: GuestAddr, size: usize) -> PyResult<()> {
self.emu.unmap(addr, size).map_err(PyValueError::new_err) self.emu.unmap(addr, size).map_err(PyValueError::new_err)
} }
@ -816,7 +844,7 @@ pub mod pybind {
self.emu.set_pre_syscall_hook(py_syscall_hook_wrapper); self.emu.set_pre_syscall_hook(py_syscall_hook_wrapper);
} }
fn set_hook(&self, addr: u64, hook: PyObject) { fn set_hook(&self, addr: GuestAddr, hook: PyObject) {
unsafe { unsafe {
let idx = PY_GENERIC_HOOKS.len(); let idx = PY_GENERIC_HOOKS.len();
PY_GENERIC_HOOKS.push((addr, hook)); PY_GENERIC_HOOKS.push((addr, hook));
@ -824,7 +852,7 @@ pub mod pybind {
} }
} }
fn remove_hook(&self, addr: u64) { fn remove_hook(&self, addr: GuestAddr) {
unsafe { unsafe {
PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr); PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr);
} }

View File

@ -23,6 +23,7 @@ pub use crate::emu::SyscallHookResult;
use crate::{ use crate::{
emu::{Emulator, SKIP_EXEC_HOOK}, emu::{Emulator, SKIP_EXEC_HOOK},
helper::QemuHelperTuple, helper::QemuHelperTuple,
GuestAddr,
}; };
static mut QEMU_HELPERS_PTR: *const c_void = ptr::null(); static mut QEMU_HELPERS_PTR: *const c_void = ptr::null();
@ -120,6 +121,12 @@ where
} }
} }
// function signature for Read or Write hook functions with known length (1, 2, 4, 8)
type FixedLenHook<QT, S> = fn(&Emulator, &mut QT, &mut S, u64, GuestAddr);
// function signature for Read or Write hook functions with runtime length n
type DynamicLenHook<QT, S> = fn(&Emulator, &mut QT, &mut S, u64, GuestAddr, usize);
static mut READ1_HOOKS: Vec<*const c_void> = vec![]; static mut READ1_HOOKS: Vec<*const c_void> = vec![];
extern "C" fn read1_hooks_wrapper<I, QT, S>(id: u64, addr: u64) extern "C" fn read1_hooks_wrapper<I, QT, S>(id: u64, addr: u64)
where where
@ -130,8 +137,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &READ1_HOOKS } { for hook in unsafe { &READ1_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -145,8 +152,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &READ2_HOOKS } { for hook in unsafe { &READ2_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -160,8 +167,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &READ4_HOOKS } { for hook in unsafe { &READ4_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -175,8 +182,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &READ8_HOOKS } { for hook in unsafe { &READ8_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -190,8 +197,15 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &READ_N_HOOKS } { for hook in unsafe { &READ_N_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64, usize) = unsafe { transmute(*hook) }; let func: DynamicLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr, size as usize); (func)(
&emulator,
helpers,
state,
id,
addr as GuestAddr,
size as usize,
);
} }
} }
@ -205,8 +219,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE1_HOOKS } { for hook in unsafe { &WRITE1_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -220,8 +234,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE2_HOOKS } { for hook in unsafe { &WRITE2_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -235,8 +249,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE4_HOOKS } { for hook in unsafe { &WRITE4_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -250,8 +264,8 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE8_HOOKS } { for hook in unsafe { &WRITE8_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) }; let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr); (func)(&emulator, helpers, state, id, addr as GuestAddr);
} }
} }
@ -265,8 +279,15 @@ where
let state = inprocess_get_state::<S>().unwrap(); let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty(); let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE_N_HOOKS } { for hook in unsafe { &WRITE_N_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64, usize) = unsafe { transmute(*hook) }; let func: DynamicLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr, size as usize); (func)(
&emulator,
helpers,
state,
id,
addr as GuestAddr,
size as usize,
);
} }
} }
@ -564,7 +585,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_read1_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_read1_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
READ1_HOOKS.push(hook as *const _); READ1_HOOKS.push(hook as *const _);
} }
@ -573,7 +594,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_read2_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_read2_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
READ2_HOOKS.push(hook as *const _); READ2_HOOKS.push(hook as *const _);
} }
@ -582,7 +603,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_read4_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_read4_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
READ4_HOOKS.push(hook as *const _); READ4_HOOKS.push(hook as *const _);
} }
@ -591,7 +612,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_read8_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_read8_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
READ8_HOOKS.push(hook as *const _); READ8_HOOKS.push(hook as *const _);
} }
@ -600,10 +621,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_read_n_execution( pub fn hook_read_n_execution(&self, hook: DynamicLenHook<QT, S>) {
&self,
hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64, size: usize),
) {
unsafe { unsafe {
READ_N_HOOKS.push(hook as *const _); READ_N_HOOKS.push(hook as *const _);
} }
@ -624,7 +642,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_write1_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_write1_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
WRITE1_HOOKS.push(hook as *const _); WRITE1_HOOKS.push(hook as *const _);
} }
@ -633,7 +651,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_write2_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_write2_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
WRITE2_HOOKS.push(hook as *const _); WRITE2_HOOKS.push(hook as *const _);
} }
@ -642,7 +660,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_write4_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_write4_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
WRITE4_HOOKS.push(hook as *const _); WRITE4_HOOKS.push(hook as *const _);
} }
@ -651,7 +669,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_write8_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) { pub fn hook_write8_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe { unsafe {
WRITE8_HOOKS.push(hook as *const _); WRITE8_HOOKS.push(hook as *const _);
} }
@ -660,10 +678,7 @@ where
} }
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn hook_write_n_execution( pub fn hook_write_n_execution(&self, hook: DynamicLenHook<QT, S>) {
&self,
hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64, size: usize),
) {
unsafe { unsafe {
WRITE_N_HOOKS.push(hook as *const _); WRITE_N_HOOKS.push(hook as *const _);
} }

View File

@ -1,3 +1,10 @@
// This lint triggers too often on the current GuestAddr type when emulating 64-bit targets because
// u64::from(GuestAddr) is a no-op, but the .into() call is needed when GuestAddr is u32.
#![cfg_attr(
any(feature = "x86_64", feature = "aarch64"),
allow(clippy::useless_conversion)
)]
use std::env; use std::env;
#[cfg(cpu_target = "aarch64")] #[cfg(cpu_target = "aarch64")]

View File

@ -5,14 +5,14 @@ use crate::{
emu::Emulator, emu::Emulator,
executor::QemuExecutor, executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple}, helper::{QemuHelper, QemuHelperTuple},
SYS_mmap, SYS_mremap, GuestAddr, SYS_mmap, SYS_mremap,
}; };
pub const SNAPSHOT_PAGE_SIZE: usize = 4096; pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
#[derive(Debug)] #[derive(Debug)]
pub struct SnapshotPageInfo { pub struct SnapshotPageInfo {
pub addr: u64, pub addr: GuestAddr,
pub dirty: bool, pub dirty: bool,
pub data: [u8; SNAPSHOT_PAGE_SIZE], pub data: [u8; SNAPSHOT_PAGE_SIZE],
} }
@ -20,12 +20,12 @@ pub struct SnapshotPageInfo {
#[derive(Debug)] #[derive(Debug)]
// TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html // TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html
pub struct QemuSnapshotHelper { pub struct QemuSnapshotHelper {
pub access_cache: [u64; 4], pub access_cache: [GuestAddr; 4],
pub access_cache_idx: usize, pub access_cache_idx: usize,
pub pages: HashMap<u64, SnapshotPageInfo>, pub pages: HashMap<GuestAddr, SnapshotPageInfo>,
pub dirty: Vec<u64>, pub dirty: Vec<GuestAddr>,
pub brk: u64, pub brk: GuestAddr,
pub new_maps: Vec<(u64, usize)>, pub new_maps: Vec<(GuestAddr, usize)>,
pub empty: bool, pub empty: bool,
} }
@ -33,7 +33,7 @@ impl QemuSnapshotHelper {
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
access_cache: [u64::MAX; 4], access_cache: [GuestAddr::MAX; 4],
access_cache_idx: 0, access_cache_idx: 0,
pages: HashMap::default(), pages: HashMap::default(),
dirty: vec![], dirty: vec![],
@ -60,13 +60,13 @@ impl QemuSnapshotHelper {
}; };
unsafe { emulator.read_mem(addr, &mut info.data) }; unsafe { emulator.read_mem(addr, &mut info.data) };
self.pages.insert(addr, info); self.pages.insert(addr, info);
addr += SNAPSHOT_PAGE_SIZE as u64; addr += SNAPSHOT_PAGE_SIZE as GuestAddr;
} }
} }
self.empty = false; self.empty = false;
} }
pub fn page_access(&mut self, page: u64) { pub fn page_access(&mut self, page: GuestAddr) {
if self.access_cache[0] == page if self.access_cache[0] == page
|| self.access_cache[1] == page || self.access_cache[1] == page
|| self.access_cache[2] == page || self.access_cache[2] == page
@ -85,18 +85,18 @@ impl QemuSnapshotHelper {
self.dirty.push(page); self.dirty.push(page);
} }
pub fn access(&mut self, addr: u64, size: usize) { pub fn access(&mut self, addr: GuestAddr, size: usize) {
debug_assert!(size > 0); debug_assert!(size > 0);
let page = addr & (SNAPSHOT_PAGE_SIZE as u64 - 1); let page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
self.page_access(page); self.page_access(page);
let second_page = (addr + size as u64 - 1) & (SNAPSHOT_PAGE_SIZE as u64 - 1); let second_page = (addr + size as GuestAddr - 1) & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
if page != second_page { if page != second_page {
self.page_access(second_page); self.page_access(second_page);
} }
} }
pub fn reset(&mut self, emulator: &Emulator) { pub fn reset(&mut self, emulator: &Emulator) {
self.access_cache = [u64::MAX; 4]; self.access_cache = [GuestAddr::MAX; 4];
self.access_cache_idx = 0; self.access_cache_idx = 0;
while let Some(page) = self.dirty.pop() { while let Some(page) = self.dirty.pop() {
if let Some(info) = self.pages.get_mut(&page) { if let Some(info) = self.pages.get_mut(&page) {
@ -108,7 +108,7 @@ impl QemuSnapshotHelper {
self.reset_maps(emulator); self.reset_maps(emulator);
} }
pub fn add_mapped(&mut self, start: u64, size: usize) { pub fn add_mapped(&mut self, start: GuestAddr, size: usize) {
self.new_maps.push((start, size)); self.new_maps.push((start, size));
} }
@ -160,7 +160,7 @@ pub fn trace_write1_snapshot<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -176,7 +176,7 @@ pub fn trace_write2_snapshot<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -192,7 +192,7 @@ pub fn trace_write4_snapshot<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -208,7 +208,7 @@ pub fn trace_write8_snapshot<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
) where ) where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
@ -224,7 +224,7 @@ pub fn trace_write_n_snapshot<I, QT, S>(
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, _state: &mut S,
_id: u64, _id: u64,
addr: u64, addr: GuestAddr,
size: usize, size: usize,
) where ) where
I: Input, I: Input,
@ -256,7 +256,7 @@ where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
if result == u64::MAX if result as GuestAddr == GuestAddr::MAX
/* -1 */ /* -1 */
{ {
return result; return result;
@ -265,12 +265,12 @@ where
let h = helpers let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>() .match_first_type_mut::<QemuSnapshotHelper>()
.unwrap(); .unwrap();
h.add_mapped(result, a1 as usize); h.add_mapped(result as GuestAddr, a1 as usize);
} else if i64::from(sys_num) == SYS_mremap { } else if i64::from(sys_num) == SYS_mremap {
let h = helpers let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>() .match_first_type_mut::<QemuSnapshotHelper>()
.unwrap(); .unwrap();
h.add_mapped(a0, a2 as usize); h.add_mapped(a0 as GuestAddr, a2 as usize);
} }
result result
} }