From d3a2cada88d881833de260ba7c97f825060d6f82 Mon Sep 17 00:00:00 2001 From: templexxx Date: Sat, 26 Nov 2022 18:32:55 +0800 Subject: [PATCH 1/3] munmap using u64 as debug log info & remove "TODO should handle fd" we just need anonymous fd (-1) to allocate memory, that could satisfy most cases --- omo/src/os/linux/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/omo/src/os/linux/mod.rs b/omo/src/os/linux/mod.rs index 7f4dbee..049fbf9 100644 --- a/omo/src/os/linux/mod.rs +++ b/omo/src/os/linux/mod.rs @@ -1,4 +1,3 @@ -use log::info; use std::{ cell::RefCell, collections::HashMap, env, mem, os::unix::ffi::OsStrExt, rc::Rc, str::FromStr, }; @@ -718,7 +717,7 @@ impl Inner { mmap_base + mmap_size ); } - // TODO: should handle fd? + if fd != -1 { log::warn!("[mmap2] fd {} not handled", fd); } @@ -749,7 +748,7 @@ impl Inner { addr: u64, length: u64, ) -> Result { - log::debug!("[munmap] addr: {:#x}, length: {:#x}", addr, length); + log::debug!("[munmap] addr: {}, length: {}", addr, length); let length = align_up(length as u32, core.pagesize() as u32); Memory::mem_unmap(core, addr, length as usize)?; Ok(0) From 5eaa4f9377e3799d3e0a5ace032b98dce25be1e7 Mon Sep 17 00:00:00 2001 From: templexxx Date: Sun, 27 Nov 2022 15:42:44 +0800 Subject: [PATCH 2/3] using trace log to trace step avoiding too many logs --- omo/src/emulator.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/omo/src/emulator.rs b/omo/src/emulator.rs index 7ad1d7a..2db5be4 100644 --- a/omo/src/emulator.rs +++ b/omo/src/emulator.rs @@ -1,5 +1,12 @@ //use crate::arch::Core; +use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; + +use log::{info, trace}; +use num_traits::Zero; +use serde::{Deserialize, Serialize}; +use unicorn_engine::unicorn_const::{HookType, MemType, Mode}; + use crate::{ arch::{ArchInfo, ArchT}, config::OmoConfig, @@ -9,11 +16,6 @@ use crate::{ os::Runner, registers::{RegisterState, Registers}, }; -use log::{info, trace}; -use num_traits::Zero; -use serde::{Deserialize, Serialize}; -use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; -use unicorn_engine::unicorn_const::{HookType, MemType, Mode}; pub struct Emulator<'a, A, Os> { config: OmoConfig, @@ -70,7 +72,7 @@ impl<'a, A: ArchT, O: Runner> Emulator<'a, A, O> { machine.add_code_hook(0, u32::MAX as u64, { |uc, addr, size| { - info!( + trace!( "step {}, {} {}, pc {}", uc.get_data().state.steps, addr, @@ -239,6 +241,7 @@ pub struct StateChange { pub step: u64, pub access: Vec, } + #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct MemAccess { /// read or write From 3539e9cda839f2ddb8ca04b9f3ed70b18920db61 Mon Sep 17 00:00:00 2001 From: templexxx Date: Sun, 27 Nov 2022 15:43:40 +0800 Subject: [PATCH 3/3] add mmap manager to reuse unmapped memory --- omo/src/memory.rs | 137 +++++++++++++++++++++++++++++++++++++--- omo/src/os/linux/mod.rs | 9 +-- 2 files changed, 133 insertions(+), 13 deletions(-) diff --git a/omo/src/memory.rs b/omo/src/memory.rs index 2f8cd83..1b4f247 100644 --- a/omo/src/memory.rs +++ b/omo/src/memory.rs @@ -1,14 +1,22 @@ -use anyhow::Result; - -use crate::arch::ArchInfo; +use std::borrow::BorrowMut; -use crate::{engine::Machine, utils::Packer, PAGE_SIZE}; +use anyhow::Result; +use log::info; use unicorn_engine::{ unicorn_const::{uc_error, MemRegion, Permission}, Unicorn, }; +use crate::{ + arch::ArchInfo, + engine::Machine, + errors::{from_raw_syscall_ret, EmulatorError}, + utils::Packer, + PAGE_SIZE, +}; + pub type PointerSizeT = u8; + #[derive(Debug)] struct MapInfo { info: MemRegion, @@ -36,7 +44,14 @@ pub trait Memory { } fn mem_map(&mut self, region: MemRegion, info: Option) -> Result<(), uc_error>; fn mem_unmap(&mut self, addr: u64, size: usize) -> Result<(), uc_error>; - fn is_mapped(&self, addr: u64, size: usize) -> Result; + // Query whether the memory range starting at `addr` and is of length of `size` bytes + // is fully mapped. + // + // Returns: True if the specified memory range is taken fully, False otherwise + fn is_mapped(&self, addr: u64, size: usize) -> bool; + // Choose mmap address by size. + // Start searching with mmap base address in config. + fn next_mmap_address(&self, base_address: u64, size: usize) -> Result; fn mprotect(&mut self, addr: u64, size: usize, perm: Permission) -> Result<(), uc_error>; fn read(&self, addr: u64, size: usize) -> Result, uc_error>; fn read_ptr(&self, address: u64, pointersize: Option) -> Result; @@ -75,16 +90,120 @@ impl<'a, A> Memory for Unicorn<'a, Machine> { MemRegion { begin, end, perms }, info.unwrap_or_else(|| "[mapped]".to_string()), ); + log::debug!("mmapped: {:?}", self.get_data().memories.map_info); Ok(()) } fn mem_unmap(&mut self, addr: u64, size: usize) -> Result<(), uc_error> { - // TODO: manage map_info + let begin = addr; + let end = addr + size as u64; + let mut wait_rm: Vec = Vec::new(); + let mut wait_add: Vec = Vec::new(); + + let mut unmap_begin = begin; + + for mut i in &self.get_data_mut().memories.map_info { + if unmap_begin < i.info.begin { + unmap_begin = i.info.begin // illegal range -> illegal range. + } + if unmap_begin >= end { + break; // all marked. + } + if unmap_begin >= i.info.end { + continue; // no overlap in this range, try next. + } + if unmap_begin == i.info.begin { + wait_rm.push(MemRegion { + begin: i.info.begin, + end: i.info.end, + perms: i.info.perms, + }); + if end < i.info.end { + wait_add.push(MapInfo { + info: MemRegion { + begin: end, + end: i.info.end, + perms: i.info.perms, + }, + label: i.label.clone(), + }); + }; + } else { + // unmap_begin > i.info.begin && unmap_begin < i.info.end + wait_rm.push(MemRegion { + begin: i.info.begin, + end: i.info.end, + perms: i.info.perms, + }); + wait_add.push(MapInfo { + info: MemRegion { + begin: i.info.begin, + end: unmap_begin, + perms: i.info.perms, + }, + label: i.label.clone(), + }); + if end < i.info.end { + wait_add.push(MapInfo { + info: MemRegion { + begin: end, + end: i.info.end, + perms: i.info.perms, + }, + label: i.label.clone(), + }); + } + } + } + + for ri in wait_rm { + self.get_data_mut() + .memories + .map_info + .retain(|i| !(i.info.begin == ri.begin && i.info.end == ri.end)) + } + for ai in wait_add { + self.get_data_mut().memories.map_info.push(ai) + } + self.get_data_mut() + .memories + .map_info + .sort_by_key(|info| info.info.begin); + Unicorn::mem_unmap(self, addr, size) } - fn is_mapped(&self, _addr: u64, _size: usize) -> Result { - // FIXME: impl it. - Ok(false) + fn is_mapped(&self, addr: u64, size: usize) -> bool { + let mut begin = addr; + let mut end = addr + size as u64; + for i in &self.get_data().memories.map_info { + if begin < i.info.begin { + break; + } + if end <= i.info.end { + return true; + } + begin = i.info.end + } + false } + + fn next_mmap_address(&self, base_address: u64, size: usize) -> Result { + let mut addr = base_address; + let size = size as u64; + for i in &self.get_data().memories.map_info { + if i.info.begin < base_address { + continue; + } + if addr + size <= i.info.begin { + break; + } + addr = i.info.end + } + if addr + size > (1 << 32) - 1 { + return Err(from_raw_syscall_ret(-12)); // ENOMEM, Cannot allocate memory + } + Ok(addr) + } + fn mprotect(&mut self, addr: u64, size: usize, perm: Permission) -> Result<(), uc_error> { // TODO: manage map_info Unicorn::mem_protect(self, addr, size, perm) diff --git a/omo/src/os/linux/mod.rs b/omo/src/os/linux/mod.rs index 049fbf9..3d1842f 100644 --- a/omo/src/os/linux/mod.rs +++ b/omo/src/os/linux/mod.rs @@ -2,6 +2,7 @@ use std::{ cell::RefCell, collections::HashMap, env, mem, os::unix::ffi::OsStrExt, rc::Rc, str::FromStr, }; +use log::info; use unicorn_engine::{ unicorn_const::{uc_error, Arch, MemRegion, Permission}, RegisterARM, RegisterARM64, RegisterMIPS, RegisterRISCV, RegisterX86, @@ -535,6 +536,7 @@ impl Inner { }, Some("[brk]".to_string()), )?; + log::debug!("brk mmaped, begin: {}, end: {}", cur_brk_addr, new_brk_addr) } else if inp < cur_brk_addr { Memory::mem_unmap(core, new_brk_addr, (cur_brk_addr - new_brk_addr) as usize)?; } @@ -639,7 +641,7 @@ impl Inner { fd: u64, pgoffset: u64, // TODO no fd supports yet _ver: u8, - ) -> Result { + ) -> Result { let fd = fd as i32; log::debug!( @@ -673,7 +675,7 @@ impl Inner { let mut need_map = true; if mmap_base != 0 { // already mapped. - if Memory::is_mapped(core, mmap_base as u64, mmap_size as usize)? { + if Memory::is_mapped(core, mmap_base, mmap_size as usize) { // if map fixed, we just protect mem if flags & MAP_FIXED != 0 { log::debug!("mmap2 - MAP_FIXED, mapping not needed"); @@ -688,8 +690,7 @@ impl Inner { } if need_map { if mmap_base == 0 { - mmap_base = self.mmap_address; - self.mmap_address = mmap_base + mmap_size; + mmap_base = Memory::next_mmap_address(core, self.mmap_address, mmap_size as usize)?; } log::debug!(