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, 25d4242001SAdam Bratschi-Kaye enable_branch_protection: bool, 26d3132c9dSAlex Crichton needs_executable: bool, 27ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 28ae3bf36fSSingleAccretion has_native_debug_info: bool, 295eee6313SChris Fallin custom_code_memory: Option<Arc<dyn CustomCodeMemory>>, 30d4242001SAdam Bratschi-Kaye 31d4242001SAdam Bratschi-Kaye // Ranges within `self.mmap` of where the particular sections lie. 32d4242001SAdam Bratschi-Kaye text: Range<usize>, 33d4242001SAdam Bratschi-Kaye unwind: Range<usize>, 34d4242001SAdam Bratschi-Kaye trap_data: Range<usize>, 35d4242001SAdam Bratschi-Kaye wasm_data: Range<usize>, 36d4242001SAdam Bratschi-Kaye address_map_data: Range<usize>, 37452086fbSAlex Crichton stack_map_data: Range<usize>, 382d25f862SChris Fallin exception_data: Range<usize>, 39*02155232SChris Fallin frame_tables_data: Range<usize>, 40d4242001SAdam Bratschi-Kaye func_name_data: Range<usize>, 41d4242001SAdam Bratschi-Kaye info_data: Range<usize>, 42ae3bf36fSSingleAccretion wasm_dwarf: Range<usize>, 43d4242001SAdam Bratschi-Kaye } 44d4242001SAdam Bratschi-Kaye 45d4242001SAdam Bratschi-Kaye impl Drop for CodeMemory { 46d4242001SAdam Bratschi-Kaye fn drop(&mut self) { 475eee6313SChris Fallin // If there is a custom code memory handler, restore the 485eee6313SChris Fallin // original (non-executable) state of the memory. 495eee6313SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 504e8dc9d0SPaul Osborne if self.published && self.needs_executable { 515eee6313SChris Fallin let text = self.text(); 525eee6313SChris Fallin mem.unpublish_executable(text.as_ptr(), text.len()) 535eee6313SChris Fallin .expect("Executable memory unpublish failed"); 545eee6313SChris Fallin } 554e8dc9d0SPaul Osborne } 565eee6313SChris Fallin 57ae3bf36fSSingleAccretion // Drop the registrations before `self.mmap` since they (implicitly) refer to it. 584afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 59ae3bf36fSSingleAccretion let _ = self.unwind_registration.take(); 60ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 61ae3bf36fSSingleAccretion let _ = self.debug_registration.take(); 62d4242001SAdam Bratschi-Kaye } 63d4242001SAdam Bratschi-Kaye } 64d4242001SAdam Bratschi-Kaye 65d4242001SAdam Bratschi-Kaye fn _assert() { 66d4242001SAdam Bratschi-Kaye fn _assert_send_sync<T: Send + Sync>() {} 67d4242001SAdam Bratschi-Kaye _assert_send_sync::<CodeMemory>(); 68d4242001SAdam Bratschi-Kaye } 69d4242001SAdam Bratschi-Kaye 705eee6313SChris Fallin /// Interface implemented by an embedder to provide custom 715eee6313SChris Fallin /// implementations of code-memory protection and execute permissions. 725eee6313SChris Fallin pub trait CustomCodeMemory: Send + Sync { 735eee6313SChris Fallin /// The minimal alignment granularity for an address region that 745eee6313SChris Fallin /// can be made executable. 755eee6313SChris Fallin /// 765eee6313SChris Fallin /// Wasmtime does not assume the system page size for this because 775eee6313SChris Fallin /// custom code-memory protection can be used when all other uses 785eee6313SChris Fallin /// of virtual memory are disabled. 795eee6313SChris Fallin fn required_alignment(&self) -> usize; 805eee6313SChris Fallin 815eee6313SChris Fallin /// Publish a region of memory as executable. 825eee6313SChris Fallin /// 835eee6313SChris Fallin /// This should update permissions from the default RW 845eee6313SChris Fallin /// (readable/writable but not executable) to RX 855eee6313SChris Fallin /// (readable/executable but not writable), enforcing W^X 865eee6313SChris Fallin /// discipline. 875eee6313SChris Fallin /// 885eee6313SChris Fallin /// If the platform requires any data/instruction coherence 895eee6313SChris Fallin /// action, that should be performed as part of this hook as well. 905eee6313SChris Fallin /// 915eee6313SChris Fallin /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 925eee6313SChris Fallin /// per `required_alignment()`. 935eee6313SChris Fallin fn publish_executable(&self, ptr: *const u8, len: usize) -> anyhow::Result<()>; 945eee6313SChris Fallin 955eee6313SChris Fallin /// Unpublish a region of memory. 965eee6313SChris Fallin /// 975eee6313SChris Fallin /// This should perform the opposite effect of `make_executable`, 985eee6313SChris Fallin /// switching a range of memory back from RX (readable/executable) 995eee6313SChris Fallin /// to RW (readable/writable). It is guaranteed that no code is 1005eee6313SChris Fallin /// running anymore from this region. 1015eee6313SChris Fallin /// 1025eee6313SChris Fallin /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 1035eee6313SChris Fallin /// per `required_alignment()`. 1045eee6313SChris Fallin fn unpublish_executable(&self, ptr: *const u8, len: usize) -> anyhow::Result<()>; 1055eee6313SChris Fallin } 1065eee6313SChris Fallin 107d4242001SAdam Bratschi-Kaye impl CodeMemory { 108d4242001SAdam Bratschi-Kaye /// Creates a new `CodeMemory` by taking ownership of the provided 109d4242001SAdam Bratschi-Kaye /// `MmapVec`. 110d4242001SAdam Bratschi-Kaye /// 111d4242001SAdam Bratschi-Kaye /// The returned `CodeMemory` manages the internal `MmapVec` and the 112d4242001SAdam Bratschi-Kaye /// `publish` method is used to actually make the memory executable. 1135eee6313SChris Fallin pub fn new(engine: &Engine, mmap: MmapVec) -> Result<Self> { 11457cd5a9eSAlex Crichton let obj = ElfFile64::<Endianness>::parse(&mmap[..]) 1159034e101SAlex Crichton .map_err(obj::ObjectCrateErrorWrapper) 116d4242001SAdam Bratschi-Kaye .with_context(|| "failed to parse internal compilation artifact")?; 117d4242001SAdam Bratschi-Kaye 118d4242001SAdam Bratschi-Kaye let mut text = 0..0; 119d4242001SAdam Bratschi-Kaye let mut unwind = 0..0; 120d4242001SAdam Bratschi-Kaye let mut enable_branch_protection = None; 121d3132c9dSAlex Crichton let mut needs_executable = true; 122ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 123ae3bf36fSSingleAccretion let mut has_native_debug_info = false; 124d4242001SAdam Bratschi-Kaye let mut trap_data = 0..0; 1252d25f862SChris Fallin let mut exception_data = 0..0; 126*02155232SChris Fallin let mut frame_tables_data = 0..0; 127d4242001SAdam Bratschi-Kaye let mut wasm_data = 0..0; 128d4242001SAdam Bratschi-Kaye let mut address_map_data = 0..0; 129452086fbSAlex Crichton let mut stack_map_data = 0..0; 130d4242001SAdam Bratschi-Kaye let mut func_name_data = 0..0; 131d4242001SAdam Bratschi-Kaye let mut info_data = 0..0; 132ae3bf36fSSingleAccretion let mut wasm_dwarf = 0..0; 133d4242001SAdam Bratschi-Kaye for section in obj.sections() { 1349034e101SAlex Crichton let data = section.data().map_err(obj::ObjectCrateErrorWrapper)?; 1359034e101SAlex Crichton let name = section.name().map_err(obj::ObjectCrateErrorWrapper)?; 136d4242001SAdam Bratschi-Kaye let range = subslice_range(data, &mmap); 137d4242001SAdam Bratschi-Kaye 138d4242001SAdam Bratschi-Kaye // Double-check that sections are all aligned properly. 139d4242001SAdam Bratschi-Kaye if section.align() != 0 && data.len() != 0 { 140d4242001SAdam Bratschi-Kaye if (data.as_ptr() as u64 - mmap.as_ptr() as u64) % section.align() != 0 { 141d4242001SAdam Bratschi-Kaye bail!( 142d4242001SAdam Bratschi-Kaye "section `{}` isn't aligned to {:#x}", 143d4242001SAdam Bratschi-Kaye section.name().unwrap_or("ERROR"), 144d4242001SAdam Bratschi-Kaye section.align() 145d4242001SAdam Bratschi-Kaye ); 146d4242001SAdam Bratschi-Kaye } 147d4242001SAdam Bratschi-Kaye } 148d4242001SAdam Bratschi-Kaye 149d4242001SAdam Bratschi-Kaye match name { 150d4242001SAdam Bratschi-Kaye obj::ELF_WASM_BTI => match data.len() { 151d4242001SAdam Bratschi-Kaye 1 => enable_branch_protection = Some(data[0] != 0), 152d4242001SAdam Bratschi-Kaye _ => bail!("invalid `{name}` section"), 153d4242001SAdam Bratschi-Kaye }, 154d4242001SAdam Bratschi-Kaye ".text" => { 155d4242001SAdam Bratschi-Kaye text = range; 156d4242001SAdam Bratschi-Kaye 157d3132c9dSAlex Crichton if let SectionFlags::Elf { sh_flags } = section.flags() { 158d3132c9dSAlex Crichton if sh_flags & obj::SH_WASMTIME_NOT_EXECUTED != 0 { 159d3132c9dSAlex Crichton needs_executable = false; 160d3132c9dSAlex Crichton } 161d3132c9dSAlex Crichton } 162d3132c9dSAlex Crichton 163ee275a89SDan Gohman // Assert that Cranelift hasn't inserted any calls that need to be 164ee275a89SDan Gohman // relocated. We avoid using things like Cranelift's floor/ceil/etc. 165ee275a89SDan Gohman // operators in the Wasm-to-Cranelift translator specifically to 166ee275a89SDan Gohman // avoid having to do any relocations here. This also ensures that 167ee275a89SDan Gohman // all builtins use the same trampoline mechanism. 168ee275a89SDan Gohman assert!(section.relocations().next().is_none()); 169d4242001SAdam Bratschi-Kaye } 1704afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 1714afa86b8SAlex Crichton crate::runtime::vm::UnwindRegistration::SECTION_NAME => unwind = range, 172d4242001SAdam Bratschi-Kaye obj::ELF_WASM_DATA => wasm_data = range, 173d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_ADDRMAP => address_map_data = range, 174452086fbSAlex Crichton obj::ELF_WASMTIME_STACK_MAP => stack_map_data = range, 175d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_TRAPS => trap_data = range, 1762d25f862SChris Fallin obj::ELF_WASMTIME_EXCEPTIONS => exception_data = range, 177*02155232SChris Fallin obj::ELF_WASMTIME_FRAMES => frame_tables_data = range, 178d4242001SAdam Bratschi-Kaye obj::ELF_NAME_DATA => func_name_data = range, 179d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_INFO => info_data = range, 180ae3bf36fSSingleAccretion obj::ELF_WASMTIME_DWARF => wasm_dwarf = range, 181ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 182ae3bf36fSSingleAccretion ".debug_info" => has_native_debug_info = true, 183d4242001SAdam Bratschi-Kaye 184d4242001SAdam Bratschi-Kaye _ => log::debug!("ignoring section {name}"), 185d4242001SAdam Bratschi-Kaye } 186d4242001SAdam Bratschi-Kaye } 1875eee6313SChris Fallin 1884afa86b8SAlex Crichton // require mutability even when this is turned off 1894afa86b8SAlex Crichton #[cfg(not(has_host_compiler_backend))] 1904afa86b8SAlex Crichton let _ = &mut unwind; 1914afa86b8SAlex Crichton 1922d25f862SChris Fallin // Ensure that the exception table is well-formed. This parser 1932d25f862SChris Fallin // construction is cheap: it reads the header and validates 1942d25f862SChris Fallin // ranges but nothing else. We do this only in debug-assertion 1952d25f862SChris Fallin // builds because we otherwise require for safety that the 1962d25f862SChris Fallin // compiled artifact is as-produced-by this version of 1972d25f862SChris Fallin // Wasmtime, and we should always produce a correct exception 1982d25f862SChris Fallin // table (i.e., we are not expecting untrusted data here). 1992d25f862SChris Fallin if cfg!(debug_assertions) { 2002d25f862SChris Fallin let _ = ExceptionTable::parse(&mmap[exception_data.clone()])?; 2012d25f862SChris Fallin } 2022d25f862SChris Fallin 203d4242001SAdam Bratschi-Kaye Ok(Self { 204ae3bf36fSSingleAccretion mmap, 2054afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 206ae3bf36fSSingleAccretion unwind_registration: None, 207ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 208ae3bf36fSSingleAccretion debug_registration: None, 209d4242001SAdam Bratschi-Kaye published: false, 210d4242001SAdam Bratschi-Kaye enable_branch_protection: enable_branch_protection 211d4242001SAdam Bratschi-Kaye .ok_or_else(|| anyhow!("missing `{}` section", obj::ELF_WASM_BTI))?, 212d3132c9dSAlex Crichton needs_executable, 213ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 214ae3bf36fSSingleAccretion has_native_debug_info, 2155eee6313SChris Fallin custom_code_memory: engine.custom_code_memory().cloned(), 216d4242001SAdam Bratschi-Kaye text, 217d4242001SAdam Bratschi-Kaye unwind, 218d4242001SAdam Bratschi-Kaye trap_data, 219d4242001SAdam Bratschi-Kaye address_map_data, 220452086fbSAlex Crichton stack_map_data, 2212d25f862SChris Fallin exception_data, 222*02155232SChris Fallin frame_tables_data, 223d4242001SAdam Bratschi-Kaye func_name_data, 224ae3bf36fSSingleAccretion wasm_dwarf, 225d4242001SAdam Bratschi-Kaye info_data, 226d4242001SAdam Bratschi-Kaye wasm_data, 227d4242001SAdam Bratschi-Kaye }) 228d4242001SAdam Bratschi-Kaye } 229d4242001SAdam Bratschi-Kaye 230d4242001SAdam Bratschi-Kaye /// Returns a reference to the underlying `MmapVec` this memory owns. 231d4242001SAdam Bratschi-Kaye #[inline] 232d4242001SAdam Bratschi-Kaye pub fn mmap(&self) -> &MmapVec { 233d4242001SAdam Bratschi-Kaye &self.mmap 234d4242001SAdam Bratschi-Kaye } 235d4242001SAdam Bratschi-Kaye 236d4242001SAdam Bratschi-Kaye /// Returns the contents of the text section of the ELF executable this 237d4242001SAdam Bratschi-Kaye /// represents. 238d4242001SAdam Bratschi-Kaye #[inline] 239d4242001SAdam Bratschi-Kaye pub fn text(&self) -> &[u8] { 240d4242001SAdam Bratschi-Kaye &self.mmap[self.text.clone()] 241d4242001SAdam Bratschi-Kaye } 242d4242001SAdam Bratschi-Kaye 243d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_DWARF` section. 244d4242001SAdam Bratschi-Kaye #[inline] 245ae3bf36fSSingleAccretion pub fn wasm_dwarf(&self) -> &[u8] { 246ae3bf36fSSingleAccretion &self.mmap[self.wasm_dwarf.clone()] 247d4242001SAdam Bratschi-Kaye } 248d4242001SAdam Bratschi-Kaye 249d4242001SAdam Bratschi-Kaye /// Returns the data in the `ELF_NAME_DATA` section. 250d4242001SAdam Bratschi-Kaye #[inline] 251d4242001SAdam Bratschi-Kaye pub fn func_name_data(&self) -> &[u8] { 252d4242001SAdam Bratschi-Kaye &self.mmap[self.func_name_data.clone()] 253d4242001SAdam Bratschi-Kaye } 254d4242001SAdam Bratschi-Kaye 255d4242001SAdam Bratschi-Kaye /// Returns the concatenated list of all data associated with this wasm 256d4242001SAdam Bratschi-Kaye /// module. 257d4242001SAdam Bratschi-Kaye /// 258d4242001SAdam Bratschi-Kaye /// This is used for initialization of memories and all data ranges stored 259d4242001SAdam Bratschi-Kaye /// in a `Module` are relative to the slice returned here. 260d4242001SAdam Bratschi-Kaye #[inline] 261d4242001SAdam Bratschi-Kaye pub fn wasm_data(&self) -> &[u8] { 262d4242001SAdam Bratschi-Kaye &self.mmap[self.wasm_data.clone()] 263d4242001SAdam Bratschi-Kaye } 264d4242001SAdam Bratschi-Kaye 265d4242001SAdam Bratschi-Kaye /// Returns the encoded address map section used to pass to 266d4242001SAdam Bratschi-Kaye /// `wasmtime_environ::lookup_file_pos`. 267d4242001SAdam Bratschi-Kaye #[inline] 268d4242001SAdam Bratschi-Kaye pub fn address_map_data(&self) -> &[u8] { 269d4242001SAdam Bratschi-Kaye &self.mmap[self.address_map_data.clone()] 270d4242001SAdam Bratschi-Kaye } 271d4242001SAdam Bratschi-Kaye 272452086fbSAlex Crichton /// Returns the encoded stack map section used to pass to 273452086fbSAlex Crichton /// `wasmtime_environ::StackMap::lookup`. 274452086fbSAlex Crichton pub fn stack_map_data(&self) -> &[u8] { 275452086fbSAlex Crichton &self.mmap[self.stack_map_data.clone()] 276452086fbSAlex Crichton } 277452086fbSAlex Crichton 2782d25f862SChris Fallin /// Returns the encoded exception-tables section to pass to 2792d25f862SChris Fallin /// `wasmtime_unwinder::ExceptionTable::parse`. 2802d25f862SChris Fallin pub fn exception_tables(&self) -> &[u8] { 2812d25f862SChris Fallin &self.mmap[self.exception_data.clone()] 2822d25f862SChris Fallin } 2832d25f862SChris Fallin 284*02155232SChris Fallin /// Returns the encoded frame-tables section to pass to 285*02155232SChris Fallin /// `wasmtime_environ::FrameTable::parse`. 286*02155232SChris Fallin pub fn frame_tables(&self) -> &[u8] { 287*02155232SChris Fallin &self.mmap[self.frame_tables_data.clone()] 288*02155232SChris Fallin } 289*02155232SChris Fallin 290d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_INFO` section, or an empty 291d4242001SAdam Bratschi-Kaye /// slice if it wasn't found. 292d4242001SAdam Bratschi-Kaye #[inline] 293d4242001SAdam Bratschi-Kaye pub fn wasmtime_info(&self) -> &[u8] { 294d4242001SAdam Bratschi-Kaye &self.mmap[self.info_data.clone()] 295d4242001SAdam Bratschi-Kaye } 296d4242001SAdam Bratschi-Kaye 297d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_TRAPS` section, or an empty 298d4242001SAdam Bratschi-Kaye /// slice if it wasn't found. 299d4242001SAdam Bratschi-Kaye #[inline] 300d4242001SAdam Bratschi-Kaye pub fn trap_data(&self) -> &[u8] { 301d4242001SAdam Bratschi-Kaye &self.mmap[self.trap_data.clone()] 302d4242001SAdam Bratschi-Kaye } 303d4242001SAdam Bratschi-Kaye 304d4242001SAdam Bratschi-Kaye /// Publishes the internal ELF image to be ready for execution. 305d4242001SAdam Bratschi-Kaye /// 306d4242001SAdam Bratschi-Kaye /// This method can only be called once and will panic if called twice. This 307d4242001SAdam Bratschi-Kaye /// will parse the ELF image from the original `MmapVec` and do everything 308d4242001SAdam Bratschi-Kaye /// necessary to get it ready for execution, including: 309d4242001SAdam Bratschi-Kaye /// 310d4242001SAdam Bratschi-Kaye /// * Change page protections from read/write to read/execute. 311d4242001SAdam Bratschi-Kaye /// * Register unwinding information with the OS 312ae3bf36fSSingleAccretion /// * Register this image with the debugger if native DWARF is present 313d4242001SAdam Bratschi-Kaye /// 314d4242001SAdam Bratschi-Kaye /// After this function executes all JIT code should be ready to execute. 315d4242001SAdam Bratschi-Kaye pub fn publish(&mut self) -> Result<()> { 316d4242001SAdam Bratschi-Kaye assert!(!self.published); 317d4242001SAdam Bratschi-Kaye self.published = true; 318d4242001SAdam Bratschi-Kaye 319d4242001SAdam Bratschi-Kaye if self.text().is_empty() { 320d4242001SAdam Bratschi-Kaye return Ok(()); 321d4242001SAdam Bratschi-Kaye } 322d4242001SAdam Bratschi-Kaye 323d4242001SAdam Bratschi-Kaye // The unsafety here comes from a few things: 324d4242001SAdam Bratschi-Kaye // 325d4242001SAdam Bratschi-Kaye // * We're actually updating some page protections to executable memory. 326d4242001SAdam Bratschi-Kaye // 327d4242001SAdam Bratschi-Kaye // * We're registering unwinding information which relies on the 328d4242001SAdam Bratschi-Kaye // correctness of the information in the first place. This applies to 329d4242001SAdam Bratschi-Kaye // both the actual unwinding tables as well as the validity of the 330d4242001SAdam Bratschi-Kaye // pointers we pass in itself. 331d4242001SAdam Bratschi-Kaye unsafe { 332d4242001SAdam Bratschi-Kaye // Next freeze the contents of this image by making all of the 333d4242001SAdam Bratschi-Kaye // memory readonly. Nothing after this point should ever be modified 334d4242001SAdam Bratschi-Kaye // so commit everything. For a compiled-in-memory image this will 335d4242001SAdam Bratschi-Kaye // mean IPIs to evict writable mappings from other cores. For 336d4242001SAdam Bratschi-Kaye // loaded-from-disk images this shouldn't result in IPIs so long as 337d4242001SAdam Bratschi-Kaye // there weren't any relocations because nothing should have 338d4242001SAdam Bratschi-Kaye // otherwise written to the image at any point either. 339d3132c9dSAlex Crichton // 340d3132c9dSAlex Crichton // Note that if virtual memory is disabled this is skipped because 341d3132c9dSAlex Crichton // we aren't able to make it readonly, but this is just a 342d3132c9dSAlex Crichton // defense-in-depth measure and isn't required for correctness. 3437f9049b9SAlex Crichton #[cfg(has_virtual_memory)] 34499efc20bSPaul Osborne if self.mmap.supports_virtual_memory() { 345d4242001SAdam Bratschi-Kaye self.mmap.make_readonly(0..self.mmap.len())?; 34699efc20bSPaul Osborne } 347d4242001SAdam Bratschi-Kaye 348d3132c9dSAlex Crichton // Switch the executable portion from readonly to read/execute. 349d3132c9dSAlex Crichton if self.needs_executable { 3505eee6313SChris Fallin if !self.custom_publish()? { 35199efc20bSPaul Osborne if !self.mmap.supports_virtual_memory() { 35299efc20bSPaul Osborne bail!("this target requires virtual memory to be enabled"); 35399efc20bSPaul Osborne } 354dcfb6761SAlex Crichton #[cfg(has_virtual_memory)] 355d4242001SAdam Bratschi-Kaye self.mmap 356d4242001SAdam Bratschi-Kaye .make_executable(self.text.clone(), self.enable_branch_protection) 357d4242001SAdam Bratschi-Kaye .context("unable to make memory executable")?; 358d3132c9dSAlex Crichton } 3595eee6313SChris Fallin } 360d4242001SAdam Bratschi-Kaye 361d4242001SAdam Bratschi-Kaye // With all our memory set up use the platform-specific 362d4242001SAdam Bratschi-Kaye // `UnwindRegistration` implementation to inform the general 363d4242001SAdam Bratschi-Kaye // runtime that there's unwinding information available for all 364d4242001SAdam Bratschi-Kaye // our just-published JIT functions. 365d4242001SAdam Bratschi-Kaye self.register_unwind_info()?; 366ae3bf36fSSingleAccretion 367ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 368ae3bf36fSSingleAccretion self.register_debug_image()?; 369d4242001SAdam Bratschi-Kaye } 370d4242001SAdam Bratschi-Kaye 371d4242001SAdam Bratschi-Kaye Ok(()) 372d4242001SAdam Bratschi-Kaye } 373d4242001SAdam Bratschi-Kaye 3745eee6313SChris Fallin fn custom_publish(&mut self) -> Result<bool> { 3755eee6313SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 3765eee6313SChris Fallin let text = self.text(); 3775eee6313SChris Fallin // The text section should be aligned to 3785eee6313SChris Fallin // `custom_code_memory.required_alignment()` due to a 3795eee6313SChris Fallin // combination of two invariants: 3805eee6313SChris Fallin // 3815eee6313SChris Fallin // - MmapVec aligns its start address, even in owned-Vec mode; and 3825eee6313SChris Fallin // - The text segment inside the ELF image will be aligned according 3835eee6313SChris Fallin // to the platform's requirements. 3845eee6313SChris Fallin let text_addr = text.as_ptr() as usize; 3855eee6313SChris Fallin assert_eq!(text_addr & (mem.required_alignment() - 1), 0); 3865eee6313SChris Fallin 3875eee6313SChris Fallin // The custom code memory handler will ensure the 3885eee6313SChris Fallin // memory is executable and also handle icache 3895eee6313SChris Fallin // coherence. 3905eee6313SChris Fallin mem.publish_executable(text.as_ptr(), text.len())?; 3915eee6313SChris Fallin Ok(true) 3925eee6313SChris Fallin } else { 3935eee6313SChris Fallin Ok(false) 3945eee6313SChris Fallin } 3955eee6313SChris Fallin } 3965eee6313SChris Fallin 397d4242001SAdam Bratschi-Kaye unsafe fn register_unwind_info(&mut self) -> Result<()> { 398d4242001SAdam Bratschi-Kaye if self.unwind.len() == 0 { 399d4242001SAdam Bratschi-Kaye return Ok(()); 400d4242001SAdam Bratschi-Kaye } 4014afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 4024afa86b8SAlex Crichton { 403d4242001SAdam Bratschi-Kaye let text = self.text(); 404d4242001SAdam Bratschi-Kaye let unwind_info = &self.mmap[self.unwind.clone()]; 4050f457fadSAlex Crichton let registration = unsafe { 4060f457fadSAlex Crichton crate::runtime::vm::UnwindRegistration::new( 4074afa86b8SAlex Crichton text.as_ptr(), 4084afa86b8SAlex Crichton unwind_info.as_ptr(), 4094afa86b8SAlex Crichton unwind_info.len(), 4104afa86b8SAlex Crichton ) 4110f457fadSAlex Crichton .context("failed to create unwind info registration")? 4120f457fadSAlex Crichton }; 413ae3bf36fSSingleAccretion self.unwind_registration = Some(registration); 4144afa86b8SAlex Crichton return Ok(()); 4154afa86b8SAlex Crichton } 4164afa86b8SAlex Crichton #[cfg(not(has_host_compiler_backend))] 4174afa86b8SAlex Crichton { 4184afa86b8SAlex Crichton bail!("should not have unwind info for non-native backend") 4194afa86b8SAlex Crichton } 420ae3bf36fSSingleAccretion } 421ae3bf36fSSingleAccretion 422ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 423ae3bf36fSSingleAccretion fn register_debug_image(&mut self) -> Result<()> { 424ae3bf36fSSingleAccretion if !self.has_native_debug_info { 425ae3bf36fSSingleAccretion return Ok(()); 426ae3bf36fSSingleAccretion } 427ae3bf36fSSingleAccretion 428ae3bf36fSSingleAccretion // TODO-DebugInfo: we're copying the whole image here, which is pretty wasteful. 429ae3bf36fSSingleAccretion // Use the existing memory by teaching code here about relocations in DWARF sections 430ae3bf36fSSingleAccretion // and anything else necessary that is done in "create_gdbjit_image" right now. 431ae3bf36fSSingleAccretion let image = self.mmap().to_vec(); 432ae3bf36fSSingleAccretion let text: &[u8] = self.text(); 433*02155232SChris Fallin let bytes = crate::native_debug::create_gdbjit_image(image, (text.as_ptr(), text.len()))?; 434ae3bf36fSSingleAccretion let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes); 435ae3bf36fSSingleAccretion self.debug_registration = Some(reg); 436d4242001SAdam Bratschi-Kaye Ok(()) 437d4242001SAdam Bratschi-Kaye } 43866dfa363SJamey Sharp 43966dfa363SJamey Sharp /// Looks up the given offset within this module's text section and returns 44066dfa363SJamey Sharp /// the trap code associated with that instruction, if there is one. 44166dfa363SJamey Sharp pub fn lookup_trap_code(&self, text_offset: usize) -> Option<Trap> { 44266dfa363SJamey Sharp lookup_trap_code(self.trap_data(), text_offset) 44366dfa363SJamey Sharp } 444d4242001SAdam Bratschi-Kaye } 445d4242001SAdam Bratschi-Kaye 446d4242001SAdam Bratschi-Kaye /// Returns the range of `inner` within `outer`, such that `outer[range]` is the 447d4242001SAdam Bratschi-Kaye /// same as `inner`. 448d4242001SAdam Bratschi-Kaye /// 449d4242001SAdam Bratschi-Kaye /// This method requires that `inner` is a sub-slice of `outer`, and if that 450d4242001SAdam Bratschi-Kaye /// isn't true then this method will panic. 451d4242001SAdam Bratschi-Kaye fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> { 452d4242001SAdam Bratschi-Kaye if inner.len() == 0 { 453d4242001SAdam Bratschi-Kaye return 0..0; 454d4242001SAdam Bratschi-Kaye } 455d4242001SAdam Bratschi-Kaye 456d4242001SAdam Bratschi-Kaye assert!(outer.as_ptr() <= inner.as_ptr()); 457d4242001SAdam Bratschi-Kaye assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _)); 458d4242001SAdam Bratschi-Kaye 459d4242001SAdam Bratschi-Kaye let start = inner.as_ptr() as usize - outer.as_ptr() as usize; 460d4242001SAdam Bratschi-Kaye start..start + inner.len() 461d4242001SAdam Bratschi-Kaye } 462