1d4242001SAdam Bratschi-Kaye //! Memory management for executable code. 2d4242001SAdam Bratschi-Kaye 390ac295eSAlex Crichton use crate::Engine; 481a89169SAlex Crichton use crate::prelude::*; 5ee275a89SDan Gohman use crate::runtime::vm::MmapVec; 65eee6313SChris Fallin use alloc::sync::Arc; 781a89169SAlex Crichton use core::ops::Range; 8ee275a89SDan Gohman use object::SectionFlags; 990ac295eSAlex Crichton use object::endian::Endianness; 1090ac295eSAlex Crichton use object::read::{Object, ObjectSection, elf::ElfFile64}; 1190ac295eSAlex Crichton use wasmtime_environ::{Trap, lookup_trap_code, obj}; 122d25f862SChris Fallin use wasmtime_unwinder::ExceptionTable; 13d4242001SAdam Bratschi-Kaye 14d4242001SAdam Bratschi-Kaye /// Management of executable memory within a `MmapVec` 15d4242001SAdam Bratschi-Kaye /// 16d4242001SAdam Bratschi-Kaye /// This type consumes ownership of a region of memory and will manage the 17d4242001SAdam Bratschi-Kaye /// executable permissions of the contained JIT code as necessary. 18d4242001SAdam Bratschi-Kaye pub struct CodeMemory { 19ae3bf36fSSingleAccretion mmap: MmapVec, 204afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 214afa86b8SAlex Crichton unwind_registration: Option<crate::runtime::vm::UnwindRegistration>, 22ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 23ae3bf36fSSingleAccretion debug_registration: Option<crate::runtime::vm::GdbJitImageRegistration>, 24d4242001SAdam Bratschi-Kaye published: bool, 2517fbd3c6SChris Fallin registered: bool, 26d4242001SAdam Bratschi-Kaye enable_branch_protection: bool, 27d3132c9dSAlex Crichton needs_executable: bool, 28ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 29ae3bf36fSSingleAccretion has_native_debug_info: bool, 305eee6313SChris Fallin custom_code_memory: Option<Arc<dyn CustomCodeMemory>>, 31d4242001SAdam Bratschi-Kaye 32d4242001SAdam Bratschi-Kaye // Ranges within `self.mmap` of where the particular sections lie. 33d4242001SAdam Bratschi-Kaye text: Range<usize>, 34d4242001SAdam Bratschi-Kaye unwind: Range<usize>, 35d4242001SAdam Bratschi-Kaye trap_data: Range<usize>, 36d4242001SAdam Bratschi-Kaye wasm_data: Range<usize>, 37d4242001SAdam Bratschi-Kaye address_map_data: Range<usize>, 38452086fbSAlex Crichton stack_map_data: Range<usize>, 392d25f862SChris Fallin exception_data: Range<usize>, 4002155232SChris Fallin frame_tables_data: Range<usize>, 41d4242001SAdam Bratschi-Kaye func_name_data: Range<usize>, 42d4242001SAdam Bratschi-Kaye info_data: Range<usize>, 43ae3bf36fSSingleAccretion wasm_dwarf: Range<usize>, 44d4242001SAdam Bratschi-Kaye } 45d4242001SAdam Bratschi-Kaye 46d4242001SAdam Bratschi-Kaye impl Drop for CodeMemory { 47d4242001SAdam Bratschi-Kaye fn drop(&mut self) { 485eee6313SChris Fallin // If there is a custom code memory handler, restore the 495eee6313SChris Fallin // original (non-executable) state of the memory. 5017fbd3c6SChris Fallin // 5117fbd3c6SChris Fallin // We do this rather than invoking `unpublish()` because we 5217fbd3c6SChris Fallin // want to skip the mprotect() if we natively own the mmap and 5317fbd3c6SChris Fallin // are going to munmap soon anyway. 545eee6313SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 554e8dc9d0SPaul Osborne if self.published && self.needs_executable { 565eee6313SChris Fallin let text = self.text(); 575eee6313SChris Fallin mem.unpublish_executable(text.as_ptr(), text.len()) 585eee6313SChris Fallin .expect("Executable memory unpublish failed"); 595eee6313SChris Fallin } 604e8dc9d0SPaul Osborne } 615eee6313SChris Fallin 62ae3bf36fSSingleAccretion // Drop the registrations before `self.mmap` since they (implicitly) refer to it. 634afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 64ae3bf36fSSingleAccretion let _ = self.unwind_registration.take(); 65ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 66ae3bf36fSSingleAccretion let _ = self.debug_registration.take(); 67d4242001SAdam Bratschi-Kaye } 68d4242001SAdam Bratschi-Kaye } 69d4242001SAdam Bratschi-Kaye 70d4242001SAdam Bratschi-Kaye fn _assert() { 71d4242001SAdam Bratschi-Kaye fn _assert_send_sync<T: Send + Sync>() {} 72d4242001SAdam Bratschi-Kaye _assert_send_sync::<CodeMemory>(); 73d4242001SAdam Bratschi-Kaye } 74d4242001SAdam Bratschi-Kaye 755eee6313SChris Fallin /// Interface implemented by an embedder to provide custom 765eee6313SChris Fallin /// implementations of code-memory protection and execute permissions. 775eee6313SChris Fallin pub trait CustomCodeMemory: Send + Sync { 785eee6313SChris Fallin /// The minimal alignment granularity for an address region that 795eee6313SChris Fallin /// can be made executable. 805eee6313SChris Fallin /// 815eee6313SChris Fallin /// Wasmtime does not assume the system page size for this because 825eee6313SChris Fallin /// custom code-memory protection can be used when all other uses 835eee6313SChris Fallin /// of virtual memory are disabled. 845eee6313SChris Fallin fn required_alignment(&self) -> usize; 855eee6313SChris Fallin 865eee6313SChris Fallin /// Publish a region of memory as executable. 875eee6313SChris Fallin /// 885eee6313SChris Fallin /// This should update permissions from the default RW 895eee6313SChris Fallin /// (readable/writable but not executable) to RX 905eee6313SChris Fallin /// (readable/executable but not writable), enforcing W^X 915eee6313SChris Fallin /// discipline. 925eee6313SChris Fallin /// 935eee6313SChris Fallin /// If the platform requires any data/instruction coherence 945eee6313SChris Fallin /// action, that should be performed as part of this hook as well. 955eee6313SChris Fallin /// 965eee6313SChris Fallin /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 975eee6313SChris Fallin /// per `required_alignment()`. 9896e19700SNick Fitzgerald fn publish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>; 995eee6313SChris Fallin 1005eee6313SChris Fallin /// Unpublish a region of memory. 1015eee6313SChris Fallin /// 1025eee6313SChris Fallin /// This should perform the opposite effect of `make_executable`, 1035eee6313SChris Fallin /// switching a range of memory back from RX (readable/executable) 1045eee6313SChris Fallin /// to RW (readable/writable). It is guaranteed that no code is 1055eee6313SChris Fallin /// running anymore from this region. 1065eee6313SChris Fallin /// 1075eee6313SChris Fallin /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 1085eee6313SChris Fallin /// per `required_alignment()`. 10996e19700SNick Fitzgerald fn unpublish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>; 1105eee6313SChris Fallin } 1115eee6313SChris Fallin 112d4242001SAdam Bratschi-Kaye impl CodeMemory { 113d4242001SAdam Bratschi-Kaye /// Creates a new `CodeMemory` by taking ownership of the provided 114d4242001SAdam Bratschi-Kaye /// `MmapVec`. 115d4242001SAdam Bratschi-Kaye /// 116d4242001SAdam Bratschi-Kaye /// The returned `CodeMemory` manages the internal `MmapVec` and the 117d4242001SAdam Bratschi-Kaye /// `publish` method is used to actually make the memory executable. 1185eee6313SChris Fallin pub fn new(engine: &Engine, mmap: MmapVec) -> Result<Self> { 11957cd5a9eSAlex Crichton let obj = ElfFile64::<Endianness>::parse(&mmap[..]) 1209034e101SAlex Crichton .map_err(obj::ObjectCrateErrorWrapper) 121d4242001SAdam Bratschi-Kaye .with_context(|| "failed to parse internal compilation artifact")?; 122d4242001SAdam Bratschi-Kaye 123d4242001SAdam Bratschi-Kaye let mut text = 0..0; 124d4242001SAdam Bratschi-Kaye let mut unwind = 0..0; 125d4242001SAdam Bratschi-Kaye let mut enable_branch_protection = None; 126d3132c9dSAlex Crichton let mut needs_executable = true; 127ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 128ae3bf36fSSingleAccretion let mut has_native_debug_info = false; 129d4242001SAdam Bratschi-Kaye let mut trap_data = 0..0; 1302d25f862SChris Fallin let mut exception_data = 0..0; 13102155232SChris Fallin let mut frame_tables_data = 0..0; 132d4242001SAdam Bratschi-Kaye let mut wasm_data = 0..0; 133d4242001SAdam Bratschi-Kaye let mut address_map_data = 0..0; 134452086fbSAlex Crichton let mut stack_map_data = 0..0; 135d4242001SAdam Bratschi-Kaye let mut func_name_data = 0..0; 136d4242001SAdam Bratschi-Kaye let mut info_data = 0..0; 137ae3bf36fSSingleAccretion let mut wasm_dwarf = 0..0; 138d4242001SAdam Bratschi-Kaye for section in obj.sections() { 1399034e101SAlex Crichton let data = section.data().map_err(obj::ObjectCrateErrorWrapper)?; 1409034e101SAlex Crichton let name = section.name().map_err(obj::ObjectCrateErrorWrapper)?; 141d4242001SAdam Bratschi-Kaye let range = subslice_range(data, &mmap); 142d4242001SAdam Bratschi-Kaye 143d4242001SAdam Bratschi-Kaye // Double-check that sections are all aligned properly. 144d4242001SAdam Bratschi-Kaye if section.align() != 0 && data.len() != 0 { 145d4242001SAdam Bratschi-Kaye if (data.as_ptr() as u64 - mmap.as_ptr() as u64) % section.align() != 0 { 146d4242001SAdam Bratschi-Kaye bail!( 147d4242001SAdam Bratschi-Kaye "section `{}` isn't aligned to {:#x}", 148d4242001SAdam Bratschi-Kaye section.name().unwrap_or("ERROR"), 149d4242001SAdam Bratschi-Kaye section.align() 150d4242001SAdam Bratschi-Kaye ); 151d4242001SAdam Bratschi-Kaye } 152d4242001SAdam Bratschi-Kaye } 153d4242001SAdam Bratschi-Kaye 154d4242001SAdam Bratschi-Kaye match name { 155d4242001SAdam Bratschi-Kaye obj::ELF_WASM_BTI => match data.len() { 156d4242001SAdam Bratschi-Kaye 1 => enable_branch_protection = Some(data[0] != 0), 157d4242001SAdam Bratschi-Kaye _ => bail!("invalid `{name}` section"), 158d4242001SAdam Bratschi-Kaye }, 159d4242001SAdam Bratschi-Kaye ".text" => { 160d4242001SAdam Bratschi-Kaye text = range; 161d4242001SAdam Bratschi-Kaye 162d3132c9dSAlex Crichton if let SectionFlags::Elf { sh_flags } = section.flags() { 163d3132c9dSAlex Crichton if sh_flags & obj::SH_WASMTIME_NOT_EXECUTED != 0 { 164d3132c9dSAlex Crichton needs_executable = false; 165d3132c9dSAlex Crichton } 166d3132c9dSAlex Crichton } 167d3132c9dSAlex Crichton 168ee275a89SDan Gohman // Assert that Cranelift hasn't inserted any calls that need to be 169ee275a89SDan Gohman // relocated. We avoid using things like Cranelift's floor/ceil/etc. 170ee275a89SDan Gohman // operators in the Wasm-to-Cranelift translator specifically to 171ee275a89SDan Gohman // avoid having to do any relocations here. This also ensures that 172ee275a89SDan Gohman // all builtins use the same trampoline mechanism. 173ee275a89SDan Gohman assert!(section.relocations().next().is_none()); 174d4242001SAdam Bratschi-Kaye } 1754afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 1764afa86b8SAlex Crichton crate::runtime::vm::UnwindRegistration::SECTION_NAME => unwind = range, 177d4242001SAdam Bratschi-Kaye obj::ELF_WASM_DATA => wasm_data = range, 178d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_ADDRMAP => address_map_data = range, 179452086fbSAlex Crichton obj::ELF_WASMTIME_STACK_MAP => stack_map_data = range, 180d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_TRAPS => trap_data = range, 1812d25f862SChris Fallin obj::ELF_WASMTIME_EXCEPTIONS => exception_data = range, 18202155232SChris Fallin obj::ELF_WASMTIME_FRAMES => frame_tables_data = range, 183d4242001SAdam Bratschi-Kaye obj::ELF_NAME_DATA => func_name_data = range, 184d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_INFO => info_data = range, 185ae3bf36fSSingleAccretion obj::ELF_WASMTIME_DWARF => wasm_dwarf = range, 186ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 187ae3bf36fSSingleAccretion ".debug_info" => has_native_debug_info = true, 188d4242001SAdam Bratschi-Kaye 189d4242001SAdam Bratschi-Kaye _ => log::debug!("ignoring section {name}"), 190d4242001SAdam Bratschi-Kaye } 191d4242001SAdam Bratschi-Kaye } 1925eee6313SChris Fallin 1934afa86b8SAlex Crichton // require mutability even when this is turned off 1944afa86b8SAlex Crichton #[cfg(not(has_host_compiler_backend))] 1954afa86b8SAlex Crichton let _ = &mut unwind; 1964afa86b8SAlex Crichton 1972d25f862SChris Fallin // Ensure that the exception table is well-formed. This parser 1982d25f862SChris Fallin // construction is cheap: it reads the header and validates 1992d25f862SChris Fallin // ranges but nothing else. We do this only in debug-assertion 2002d25f862SChris Fallin // builds because we otherwise require for safety that the 2012d25f862SChris Fallin // compiled artifact is as-produced-by this version of 2022d25f862SChris Fallin // Wasmtime, and we should always produce a correct exception 2032d25f862SChris Fallin // table (i.e., we are not expecting untrusted data here). 2042d25f862SChris Fallin if cfg!(debug_assertions) { 2052d25f862SChris Fallin let _ = ExceptionTable::parse(&mmap[exception_data.clone()])?; 2062d25f862SChris Fallin } 2072d25f862SChris Fallin 208d4242001SAdam Bratschi-Kaye Ok(Self { 209ae3bf36fSSingleAccretion mmap, 2104afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 211ae3bf36fSSingleAccretion unwind_registration: None, 212ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 213ae3bf36fSSingleAccretion debug_registration: None, 214d4242001SAdam Bratschi-Kaye published: false, 21517fbd3c6SChris Fallin registered: false, 216d4242001SAdam Bratschi-Kaye enable_branch_protection: enable_branch_protection 217*ff33e949SNick Fitzgerald .ok_or_else(|| format_err!("missing `{}` section", obj::ELF_WASM_BTI))?, 218d3132c9dSAlex Crichton needs_executable, 219ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 220ae3bf36fSSingleAccretion has_native_debug_info, 2215eee6313SChris Fallin custom_code_memory: engine.custom_code_memory().cloned(), 222d4242001SAdam Bratschi-Kaye text, 223d4242001SAdam Bratschi-Kaye unwind, 224d4242001SAdam Bratschi-Kaye trap_data, 225d4242001SAdam Bratschi-Kaye address_map_data, 226452086fbSAlex Crichton stack_map_data, 2272d25f862SChris Fallin exception_data, 22802155232SChris Fallin frame_tables_data, 229d4242001SAdam Bratschi-Kaye func_name_data, 230ae3bf36fSSingleAccretion wasm_dwarf, 231d4242001SAdam Bratschi-Kaye info_data, 232d4242001SAdam Bratschi-Kaye wasm_data, 233d4242001SAdam Bratschi-Kaye }) 234d4242001SAdam Bratschi-Kaye } 235d4242001SAdam Bratschi-Kaye 236d4242001SAdam Bratschi-Kaye /// Returns a reference to the underlying `MmapVec` this memory owns. 237d4242001SAdam Bratschi-Kaye #[inline] 238d4242001SAdam Bratschi-Kaye pub fn mmap(&self) -> &MmapVec { 239d4242001SAdam Bratschi-Kaye &self.mmap 240d4242001SAdam Bratschi-Kaye } 241d4242001SAdam Bratschi-Kaye 242d4242001SAdam Bratschi-Kaye /// Returns the contents of the text section of the ELF executable this 243d4242001SAdam Bratschi-Kaye /// represents. 244d4242001SAdam Bratschi-Kaye #[inline] 245d4242001SAdam Bratschi-Kaye pub fn text(&self) -> &[u8] { 246d4242001SAdam Bratschi-Kaye &self.mmap[self.text.clone()] 247d4242001SAdam Bratschi-Kaye } 248d4242001SAdam Bratschi-Kaye 249d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_DWARF` section. 250d4242001SAdam Bratschi-Kaye #[inline] 251ae3bf36fSSingleAccretion pub fn wasm_dwarf(&self) -> &[u8] { 252ae3bf36fSSingleAccretion &self.mmap[self.wasm_dwarf.clone()] 253d4242001SAdam Bratschi-Kaye } 254d4242001SAdam Bratschi-Kaye 255d4242001SAdam Bratschi-Kaye /// Returns the data in the `ELF_NAME_DATA` section. 256d4242001SAdam Bratschi-Kaye #[inline] 257d4242001SAdam Bratschi-Kaye pub fn func_name_data(&self) -> &[u8] { 258d4242001SAdam Bratschi-Kaye &self.mmap[self.func_name_data.clone()] 259d4242001SAdam Bratschi-Kaye } 260d4242001SAdam Bratschi-Kaye 261d4242001SAdam Bratschi-Kaye /// Returns the concatenated list of all data associated with this wasm 262d4242001SAdam Bratschi-Kaye /// module. 263d4242001SAdam Bratschi-Kaye /// 264d4242001SAdam Bratschi-Kaye /// This is used for initialization of memories and all data ranges stored 265d4242001SAdam Bratschi-Kaye /// in a `Module` are relative to the slice returned here. 266d4242001SAdam Bratschi-Kaye #[inline] 267d4242001SAdam Bratschi-Kaye pub fn wasm_data(&self) -> &[u8] { 268d4242001SAdam Bratschi-Kaye &self.mmap[self.wasm_data.clone()] 269d4242001SAdam Bratschi-Kaye } 270d4242001SAdam Bratschi-Kaye 271d4242001SAdam Bratschi-Kaye /// Returns the encoded address map section used to pass to 272d4242001SAdam Bratschi-Kaye /// `wasmtime_environ::lookup_file_pos`. 273d4242001SAdam Bratschi-Kaye #[inline] 274d4242001SAdam Bratschi-Kaye pub fn address_map_data(&self) -> &[u8] { 275d4242001SAdam Bratschi-Kaye &self.mmap[self.address_map_data.clone()] 276d4242001SAdam Bratschi-Kaye } 277d4242001SAdam Bratschi-Kaye 278452086fbSAlex Crichton /// Returns the encoded stack map section used to pass to 279452086fbSAlex Crichton /// `wasmtime_environ::StackMap::lookup`. 280452086fbSAlex Crichton pub fn stack_map_data(&self) -> &[u8] { 281452086fbSAlex Crichton &self.mmap[self.stack_map_data.clone()] 282452086fbSAlex Crichton } 283452086fbSAlex Crichton 2842d25f862SChris Fallin /// Returns the encoded exception-tables section to pass to 2852d25f862SChris Fallin /// `wasmtime_unwinder::ExceptionTable::parse`. 2862d25f862SChris Fallin pub fn exception_tables(&self) -> &[u8] { 2872d25f862SChris Fallin &self.mmap[self.exception_data.clone()] 2882d25f862SChris Fallin } 2892d25f862SChris Fallin 29002155232SChris Fallin /// Returns the encoded frame-tables section to pass to 29102155232SChris Fallin /// `wasmtime_environ::FrameTable::parse`. 29202155232SChris Fallin pub fn frame_tables(&self) -> &[u8] { 29302155232SChris Fallin &self.mmap[self.frame_tables_data.clone()] 29402155232SChris Fallin } 29502155232SChris Fallin 296d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_INFO` section, or an empty 297d4242001SAdam Bratschi-Kaye /// slice if it wasn't found. 298d4242001SAdam Bratschi-Kaye #[inline] 299d4242001SAdam Bratschi-Kaye pub fn wasmtime_info(&self) -> &[u8] { 300d4242001SAdam Bratschi-Kaye &self.mmap[self.info_data.clone()] 301d4242001SAdam Bratschi-Kaye } 302d4242001SAdam Bratschi-Kaye 303d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_TRAPS` section, or an empty 304d4242001SAdam Bratschi-Kaye /// slice if it wasn't found. 305d4242001SAdam Bratschi-Kaye #[inline] 306d4242001SAdam Bratschi-Kaye pub fn trap_data(&self) -> &[u8] { 307d4242001SAdam Bratschi-Kaye &self.mmap[self.trap_data.clone()] 308d4242001SAdam Bratschi-Kaye } 309d4242001SAdam Bratschi-Kaye 310d4242001SAdam Bratschi-Kaye /// Publishes the internal ELF image to be ready for execution. 311d4242001SAdam Bratschi-Kaye /// 31217fbd3c6SChris Fallin /// This method can only be when the image is not published (its 31317fbd3c6SChris Fallin /// default state) and will panic if called when already 31417fbd3c6SChris Fallin /// published. This will parse the ELF image from the original 31517fbd3c6SChris Fallin /// `MmapVec` and do everything necessary to get it ready for 31617fbd3c6SChris Fallin /// execution, including: 317d4242001SAdam Bratschi-Kaye /// 318d4242001SAdam Bratschi-Kaye /// * Change page protections from read/write to read/execute. 319d4242001SAdam Bratschi-Kaye /// * Register unwinding information with the OS 320ae3bf36fSSingleAccretion /// * Register this image with the debugger if native DWARF is present 321d4242001SAdam Bratschi-Kaye /// 322d4242001SAdam Bratschi-Kaye /// After this function executes all JIT code should be ready to execute. 32317fbd3c6SChris Fallin /// 32417fbd3c6SChris Fallin /// The action may be reversed by calling [`unpublish`], as long 32517fbd3c6SChris Fallin /// as that method's safety requirements are upheld. 326d4242001SAdam Bratschi-Kaye pub fn publish(&mut self) -> Result<()> { 327d4242001SAdam Bratschi-Kaye assert!(!self.published); 328d4242001SAdam Bratschi-Kaye self.published = true; 329d4242001SAdam Bratschi-Kaye 330d4242001SAdam Bratschi-Kaye if self.text().is_empty() { 331d4242001SAdam Bratschi-Kaye return Ok(()); 332d4242001SAdam Bratschi-Kaye } 333d4242001SAdam Bratschi-Kaye 334d4242001SAdam Bratschi-Kaye // The unsafety here comes from a few things: 335d4242001SAdam Bratschi-Kaye // 336d4242001SAdam Bratschi-Kaye // * We're actually updating some page protections to executable memory. 337d4242001SAdam Bratschi-Kaye // 338d4242001SAdam Bratschi-Kaye // * We're registering unwinding information which relies on the 339d4242001SAdam Bratschi-Kaye // correctness of the information in the first place. This applies to 340d4242001SAdam Bratschi-Kaye // both the actual unwinding tables as well as the validity of the 341d4242001SAdam Bratschi-Kaye // pointers we pass in itself. 342d4242001SAdam Bratschi-Kaye unsafe { 343d4242001SAdam Bratschi-Kaye // Next freeze the contents of this image by making all of the 344d4242001SAdam Bratschi-Kaye // memory readonly. Nothing after this point should ever be modified 345d4242001SAdam Bratschi-Kaye // so commit everything. For a compiled-in-memory image this will 346d4242001SAdam Bratschi-Kaye // mean IPIs to evict writable mappings from other cores. For 347d4242001SAdam Bratschi-Kaye // loaded-from-disk images this shouldn't result in IPIs so long as 348d4242001SAdam Bratschi-Kaye // there weren't any relocations because nothing should have 349d4242001SAdam Bratschi-Kaye // otherwise written to the image at any point either. 350d3132c9dSAlex Crichton // 351d3132c9dSAlex Crichton // Note that if virtual memory is disabled this is skipped because 352d3132c9dSAlex Crichton // we aren't able to make it readonly, but this is just a 353d3132c9dSAlex Crichton // defense-in-depth measure and isn't required for correctness. 3547f9049b9SAlex Crichton #[cfg(has_virtual_memory)] 35599efc20bSPaul Osborne if self.mmap.supports_virtual_memory() { 356d4242001SAdam Bratschi-Kaye self.mmap.make_readonly(0..self.mmap.len())?; 35799efc20bSPaul Osborne } 358d4242001SAdam Bratschi-Kaye 359d3132c9dSAlex Crichton // Switch the executable portion from readonly to read/execute. 360d3132c9dSAlex Crichton if self.needs_executable { 3615eee6313SChris Fallin if !self.custom_publish()? { 36299efc20bSPaul Osborne if !self.mmap.supports_virtual_memory() { 36399efc20bSPaul Osborne bail!("this target requires virtual memory to be enabled"); 36499efc20bSPaul Osborne } 365dcfb6761SAlex Crichton #[cfg(has_virtual_memory)] 366d4242001SAdam Bratschi-Kaye self.mmap 367d4242001SAdam Bratschi-Kaye .make_executable(self.text.clone(), self.enable_branch_protection) 368d4242001SAdam Bratschi-Kaye .context("unable to make memory executable")?; 369d3132c9dSAlex Crichton } 3705eee6313SChris Fallin } 371d4242001SAdam Bratschi-Kaye 37217fbd3c6SChris Fallin if !self.registered { 373d4242001SAdam Bratschi-Kaye // With all our memory set up use the platform-specific 374d4242001SAdam Bratschi-Kaye // `UnwindRegistration` implementation to inform the general 375d4242001SAdam Bratschi-Kaye // runtime that there's unwinding information available for all 376d4242001SAdam Bratschi-Kaye // our just-published JIT functions. 377d4242001SAdam Bratschi-Kaye self.register_unwind_info()?; 378ae3bf36fSSingleAccretion 379ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 380ae3bf36fSSingleAccretion self.register_debug_image()?; 38117fbd3c6SChris Fallin self.registered = true; 38217fbd3c6SChris Fallin } 383d4242001SAdam Bratschi-Kaye } 384d4242001SAdam Bratschi-Kaye 385d4242001SAdam Bratschi-Kaye Ok(()) 386d4242001SAdam Bratschi-Kaye } 387d4242001SAdam Bratschi-Kaye 3885eee6313SChris Fallin fn custom_publish(&mut self) -> Result<bool> { 3895eee6313SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 3905eee6313SChris Fallin let text = self.text(); 3915eee6313SChris Fallin // The text section should be aligned to 3925eee6313SChris Fallin // `custom_code_memory.required_alignment()` due to a 3935eee6313SChris Fallin // combination of two invariants: 3945eee6313SChris Fallin // 3955eee6313SChris Fallin // - MmapVec aligns its start address, even in owned-Vec mode; and 3965eee6313SChris Fallin // - The text segment inside the ELF image will be aligned according 3975eee6313SChris Fallin // to the platform's requirements. 3985eee6313SChris Fallin let text_addr = text.as_ptr() as usize; 3995eee6313SChris Fallin assert_eq!(text_addr & (mem.required_alignment() - 1), 0); 4005eee6313SChris Fallin 4015eee6313SChris Fallin // The custom code memory handler will ensure the 4025eee6313SChris Fallin // memory is executable and also handle icache 4035eee6313SChris Fallin // coherence. 4045eee6313SChris Fallin mem.publish_executable(text.as_ptr(), text.len())?; 4055eee6313SChris Fallin Ok(true) 4065eee6313SChris Fallin } else { 4075eee6313SChris Fallin Ok(false) 4085eee6313SChris Fallin } 4095eee6313SChris Fallin } 4105eee6313SChris Fallin 41117fbd3c6SChris Fallin /// "Unpublish" code memory (transition it from executable to read/writable). 41217fbd3c6SChris Fallin /// 41317fbd3c6SChris Fallin /// This may be used to edit the code image, as long as the 41417fbd3c6SChris Fallin /// overall size of the memory remains the same. Note the hazards 41517fbd3c6SChris Fallin /// inherent in editing code that may have been executed: any 41617fbd3c6SChris Fallin /// stack frames with PC still active in this code must be 41717fbd3c6SChris Fallin /// suspended (e.g., called into a hostcall that is then invoking 41817fbd3c6SChris Fallin /// this method, or async-yielded) and any active PC values must 41917fbd3c6SChris Fallin /// point to valid instructions. Thus this is mostly useful for 42017fbd3c6SChris Fallin /// patching in-place at particular sites, such as by the use of 42117fbd3c6SChris Fallin /// Cranelift's `patchable_call` instruction. 42217fbd3c6SChris Fallin /// 42317fbd3c6SChris Fallin /// If this fails, then the memory remains executable. 42417fbd3c6SChris Fallin pub fn unpublish(&mut self) -> Result<()> { 42517fbd3c6SChris Fallin assert!(self.published); 42617fbd3c6SChris Fallin self.published = false; 42717fbd3c6SChris Fallin 42817fbd3c6SChris Fallin if self.text().is_empty() { 42917fbd3c6SChris Fallin return Ok(()); 43017fbd3c6SChris Fallin } 43117fbd3c6SChris Fallin 43217fbd3c6SChris Fallin if self.custom_unpublish()? { 43317fbd3c6SChris Fallin return Ok(()); 43417fbd3c6SChris Fallin } 43517fbd3c6SChris Fallin 43617fbd3c6SChris Fallin if !self.mmap.supports_virtual_memory() { 43717fbd3c6SChris Fallin bail!("this target requires virtual memory to be enabled"); 43817fbd3c6SChris Fallin } 43917fbd3c6SChris Fallin 44017fbd3c6SChris Fallin // SAFETY: we are guaranteed by our own safety conditions that 44117fbd3c6SChris Fallin // we have exclusive access to this code and can change its 44217fbd3c6SChris Fallin // permissions (removing the execute bit) without causing 44317fbd3c6SChris Fallin // problems. 44417fbd3c6SChris Fallin #[cfg(has_virtual_memory)] 44517fbd3c6SChris Fallin unsafe { 44617fbd3c6SChris Fallin self.mmap.make_readwrite(0..self.mmap.len())?; 44717fbd3c6SChris Fallin } 44817fbd3c6SChris Fallin 44917fbd3c6SChris Fallin // Note that we do *not* unregister: we expect unpublish 45017fbd3c6SChris Fallin // to be used for temporary edits, so we want the 45117fbd3c6SChris Fallin // registration to "stick" after the initial publish and 45217fbd3c6SChris Fallin // not toggle in subsequent unpublish/publish cycles. 45317fbd3c6SChris Fallin 45417fbd3c6SChris Fallin Ok(()) 45517fbd3c6SChris Fallin } 45617fbd3c6SChris Fallin 45717fbd3c6SChris Fallin fn custom_unpublish(&mut self) -> Result<bool> { 45817fbd3c6SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 45917fbd3c6SChris Fallin let text = self.text(); 46017fbd3c6SChris Fallin mem.unpublish_executable(text.as_ptr(), text.len())?; 46117fbd3c6SChris Fallin Ok(true) 46217fbd3c6SChris Fallin } else { 46317fbd3c6SChris Fallin Ok(false) 46417fbd3c6SChris Fallin } 46517fbd3c6SChris Fallin } 46617fbd3c6SChris Fallin 46717fbd3c6SChris Fallin /// Return a mutable borrow to the code, suitable for editing. 46817fbd3c6SChris Fallin /// 46917fbd3c6SChris Fallin /// Must not be published. 47017fbd3c6SChris Fallin /// 47117fbd3c6SChris Fallin /// # Panics 47217fbd3c6SChris Fallin /// 47317fbd3c6SChris Fallin /// This method panics if the code has been published (and not 47417fbd3c6SChris Fallin /// subsequently unpublished). 47517fbd3c6SChris Fallin pub fn text_mut(&mut self) -> &mut [u8] { 47617fbd3c6SChris Fallin assert!(!self.published); 47717fbd3c6SChris Fallin // SAFETY: we assert !published, which means we either have 47817fbd3c6SChris Fallin // not yet applied readonly + execute permissinos, or we have 47917fbd3c6SChris Fallin // undone that and flipped back to read-write via unpublish. 48017fbd3c6SChris Fallin unsafe { &mut self.mmap.as_mut_slice()[self.text.clone()] } 48117fbd3c6SChris Fallin } 48217fbd3c6SChris Fallin 483d4242001SAdam Bratschi-Kaye unsafe fn register_unwind_info(&mut self) -> Result<()> { 484d4242001SAdam Bratschi-Kaye if self.unwind.len() == 0 { 485d4242001SAdam Bratschi-Kaye return Ok(()); 486d4242001SAdam Bratschi-Kaye } 4874afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 4884afa86b8SAlex Crichton { 489d4242001SAdam Bratschi-Kaye let text = self.text(); 490d4242001SAdam Bratschi-Kaye let unwind_info = &self.mmap[self.unwind.clone()]; 4910f457fadSAlex Crichton let registration = unsafe { 4920f457fadSAlex Crichton crate::runtime::vm::UnwindRegistration::new( 4934afa86b8SAlex Crichton text.as_ptr(), 4944afa86b8SAlex Crichton unwind_info.as_ptr(), 4954afa86b8SAlex Crichton unwind_info.len(), 4964afa86b8SAlex Crichton ) 4970f457fadSAlex Crichton .context("failed to create unwind info registration")? 4980f457fadSAlex Crichton }; 499ae3bf36fSSingleAccretion self.unwind_registration = Some(registration); 5004afa86b8SAlex Crichton return Ok(()); 5014afa86b8SAlex Crichton } 5024afa86b8SAlex Crichton #[cfg(not(has_host_compiler_backend))] 5034afa86b8SAlex Crichton { 5044afa86b8SAlex Crichton bail!("should not have unwind info for non-native backend") 5054afa86b8SAlex Crichton } 506ae3bf36fSSingleAccretion } 507ae3bf36fSSingleAccretion 508ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 509ae3bf36fSSingleAccretion fn register_debug_image(&mut self) -> Result<()> { 510ae3bf36fSSingleAccretion if !self.has_native_debug_info { 511ae3bf36fSSingleAccretion return Ok(()); 512ae3bf36fSSingleAccretion } 513ae3bf36fSSingleAccretion 514ae3bf36fSSingleAccretion // TODO-DebugInfo: we're copying the whole image here, which is pretty wasteful. 515ae3bf36fSSingleAccretion // Use the existing memory by teaching code here about relocations in DWARF sections 516ae3bf36fSSingleAccretion // and anything else necessary that is done in "create_gdbjit_image" right now. 517ae3bf36fSSingleAccretion let image = self.mmap().to_vec(); 518ae3bf36fSSingleAccretion let text: &[u8] = self.text(); 51902155232SChris Fallin let bytes = crate::native_debug::create_gdbjit_image(image, (text.as_ptr(), text.len()))?; 520ae3bf36fSSingleAccretion let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes); 521ae3bf36fSSingleAccretion self.debug_registration = Some(reg); 522d4242001SAdam Bratschi-Kaye Ok(()) 523d4242001SAdam Bratschi-Kaye } 52466dfa363SJamey Sharp 52566dfa363SJamey Sharp /// Looks up the given offset within this module's text section and returns 52666dfa363SJamey Sharp /// the trap code associated with that instruction, if there is one. 52766dfa363SJamey Sharp pub fn lookup_trap_code(&self, text_offset: usize) -> Option<Trap> { 52866dfa363SJamey Sharp lookup_trap_code(self.trap_data(), text_offset) 52966dfa363SJamey Sharp } 53099ecf728SChris Fallin 53199ecf728SChris Fallin /// Get the raw address range of this CodeMemory. 53299ecf728SChris Fallin pub(crate) fn raw_addr_range(&self) -> Range<usize> { 53399ecf728SChris Fallin let start = self.text().as_ptr().addr(); 53499ecf728SChris Fallin let end = start + self.text().len(); 53599ecf728SChris Fallin start..end 53699ecf728SChris Fallin } 53799ecf728SChris Fallin 53899ecf728SChris Fallin /// Create a "deep clone": a separate CodeMemory for the same code 53999ecf728SChris Fallin /// that can be patched or mutated independently. Also returns a 54099ecf728SChris Fallin /// "metadata and location" handle that can be registered with the 54199ecf728SChris Fallin /// global module registry and used for trap metadata lookups. 54299ecf728SChris Fallin #[cfg(feature = "debug")] 54399ecf728SChris Fallin pub(crate) fn deep_clone(self: &Arc<Self>, engine: &Engine) -> Result<CodeMemory> { 54499ecf728SChris Fallin let mmap = self.mmap.deep_clone()?; 54599ecf728SChris Fallin Self::new(engine, mmap) 54699ecf728SChris Fallin } 547d4242001SAdam Bratschi-Kaye } 548d4242001SAdam Bratschi-Kaye 549d4242001SAdam Bratschi-Kaye /// Returns the range of `inner` within `outer`, such that `outer[range]` is the 550d4242001SAdam Bratschi-Kaye /// same as `inner`. 551d4242001SAdam Bratschi-Kaye /// 552d4242001SAdam Bratschi-Kaye /// This method requires that `inner` is a sub-slice of `outer`, and if that 553d4242001SAdam Bratschi-Kaye /// isn't true then this method will panic. 554d4242001SAdam Bratschi-Kaye fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> { 555d4242001SAdam Bratschi-Kaye if inner.len() == 0 { 556d4242001SAdam Bratschi-Kaye return 0..0; 557d4242001SAdam Bratschi-Kaye } 558d4242001SAdam Bratschi-Kaye 559d4242001SAdam Bratschi-Kaye assert!(outer.as_ptr() <= inner.as_ptr()); 560d4242001SAdam Bratschi-Kaye assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _)); 561d4242001SAdam Bratschi-Kaye 562d4242001SAdam Bratschi-Kaye let start = inner.as_ptr() as usize - outer.as_ptr() as usize; 563d4242001SAdam Bratschi-Kaye start..start + inner.len() 564d4242001SAdam Bratschi-Kaye } 565