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