Skip to main content

libemei/
page_manage.rs

1#[cfg(unix)]
2use std::ffi::c_void;
3#[cfg(windows)]
4use winapi::ctypes::c_void;
5
6// use crate::insts::x86_64::inst_dump_buf::InstBuffer;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
9pub struct PageSize(pub usize);
10
11impl From<usize> for PageSize {
12    fn from(i: usize) -> Self {
13        Self(i)
14    }
15}
16
17impl PageSize {
18    #[cfg(unix)]
19    #[inline]
20    pub fn from_system() -> Self {
21        use nix::unistd::{sysconf, SysconfVar};
22
23        let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
24        Self(page_size)
25    }
26
27    #[cfg(windows)]
28    #[inline]
29    pub fn from_system() -> Self {
30        use std::alloc::{alloc, dealloc, Layout};
31        use winapi::um::sysinfoapi;
32
33        let size = std::mem::size_of::<sysinfoapi::SYSTEM_INFO>();
34        let layout = Layout::from_size_align(size, 8).unwrap();
35        let sysinfo = unsafe { alloc(layout) } as *mut sysinfoapi::SYSTEM_INFO;
36
37        let page_size = unsafe {
38            sysinfoapi::GetSystemInfo(sysinfo);
39            (*sysinfo).dwPageSize as usize
40        };
41
42        unsafe {
43            dealloc(sysinfo as *mut u8, layout);
44        }
45        Self(page_size)
46    }
47}
48
49#[derive(Debug, Clone, Eq, PartialEq)]
50pub struct PageHandle {
51    pub ptr: *mut u8,
52    pub len: usize,
53    pub cap: usize,
54}
55
56impl PageHandle {
57    #[inline]
58    pub fn from(page_size: PageSize, src: &[u8]) -> Self {
59        let r = Self::new(src.len(), page_size);
60        unsafe {
61            std::ptr::copy(src.as_ptr(), r.ptr, r.len);
62        }
63        r.make_page_executable();
64        r
65    }
66
67    #[inline]
68    pub fn store(&self, src: &[u8]) {
69        if src.len() > self.len {
70            panic!("store length invilid");
71        }
72        unsafe {
73            std::ptr::copy(src.as_ptr(), self.ptr, self.len);
74        }
75    }
76
77    #[inline]
78    pub fn get_ptr(&self) -> *const u8 {
79        self.ptr
80    }
81}
82
83#[cfg(unix)]
84impl PageHandle {
85    #[inline]
86    pub fn new(size: usize, page_size: PageSize) -> Self {
87        use nix::sys::mman::{mmap, MapFlags, ProtFlags};
88        unsafe {
89            let page_size = page_size.0;
90            let size_mod = size % page_size;
91            let alloc_size = if size_mod == 0 {
92                size
93            } else {
94                size + page_size - size_mod
95            };
96            let ptr = mmap(
97                std::ptr::null_mut(),
98                alloc_size,
99                ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
100                MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
101                -1,
102                0,
103            )
104            .unwrap();
105            if ptr.is_null() {
106                panic!("VirtualAlloc failed");
107            }
108            PageHandle {
109                ptr: ptr as *mut u8,
110                len: size,
111                cap: alloc_size,
112            }
113        }
114    }
115
116    #[inline]
117    pub fn make_page_executable(&self) {
118        use nix::sys::mman::{mprotect, ProtFlags};
119        unsafe {
120            mprotect(
121                self.ptr as *mut c_void,
122                self.cap,
123                ProtFlags::PROT_READ | ProtFlags::PROT_EXEC,
124            )
125            .unwrap();
126        }
127    }
128}
129
130#[cfg(windows)]
131impl PageHandle {
132    #[inline]
133    pub fn new(size: usize, page_size: PageSize) -> Self {
134        use winapi::um::{memoryapi, winnt};
135        unsafe {
136            let page_size = page_size.0;
137            let size_mod = size % page_size;
138            let alloc_size = if size_mod == 0 {
139                size
140            } else {
141                size + page_size - size_mod
142            };
143            let ptr = memoryapi::VirtualAlloc(
144                std::ptr::null_mut(),
145                alloc_size,
146                winnt::MEM_COMMIT,
147                winnt::PAGE_READWRITE,
148            );
149            if ptr.is_null() {
150                panic!("VirtualAlloc failed");
151            }
152            PageHandle {
153                ptr: ptr as *mut u8,
154                len: size,
155                cap: alloc_size,
156            }
157        }
158    }
159
160    #[inline]
161    pub fn make_page_executable(&self) {
162        use winapi::um::{memoryapi, winnt};
163        unsafe {
164            let mut flag = winnt::PAGE_READWRITE;
165            let r = memoryapi::VirtualProtect(
166                self.ptr as *mut c_void,
167                self.cap,
168                winnt::PAGE_EXECUTE_READ,
169                &mut flag,
170            );
171            if r == 0 {
172                panic!("VirtualProtect failed");
173            }
174        }
175    }
176}
177
178#[cfg(unix)]
179impl Drop for PageHandle {
180    #[inline]
181    fn drop(&mut self) {
182        use nix::sys::mman::munmap;
183        unsafe {
184            munmap(self.ptr as *mut c_void, self.cap).unwrap();
185        }
186    }
187}
188
189#[cfg(windows)]
190impl Drop for PageHandle {
191    #[inline]
192    fn drop(&mut self) {
193        use winapi::um::{memoryapi, winnt};
194        unsafe {
195            memoryapi::VirtualFree(self.ptr as *mut c_void, 0, winnt::MEM_RELEASE);
196        }
197    }
198}