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;
81a9339e2SNick Fitzgerald use object::read::elf::SectionTable;
9*a2cc11f3SPhilip Craig use object::{LittleEndian, SectionIndex, U32};
101a9339e2SNick Fitzgerald use object::{
111a9339e2SNick Fitzgerald     elf::{FileHeader64, SectionHeader64},
121a9339e2SNick Fitzgerald     endian::Endianness,
131a9339e2SNick Fitzgerald     read::elf::{FileHeader as _, SectionHeader as _},
141a9339e2SNick Fitzgerald };
15c07c94d2SChris Fallin use wasmtime_environ::StaticModuleIndex;
1690ac295eSAlex Crichton use wasmtime_environ::{Trap, lookup_trap_code, obj};
172d25f862SChris Fallin use wasmtime_unwinder::ExceptionTable;
18d4242001SAdam Bratschi-Kaye 
19d4242001SAdam Bratschi-Kaye /// Management of executable memory within a `MmapVec`
20d4242001SAdam Bratschi-Kaye ///
21d4242001SAdam Bratschi-Kaye /// This type consumes ownership of a region of memory and will manage the
22d4242001SAdam Bratschi-Kaye /// executable permissions of the contained JIT code as necessary.
23d4242001SAdam Bratschi-Kaye pub struct CodeMemory {
24ae3bf36fSSingleAccretion     mmap: MmapVec,
254afa86b8SAlex Crichton     #[cfg(has_host_compiler_backend)]
264afa86b8SAlex Crichton     unwind_registration: Option<crate::runtime::vm::UnwindRegistration>,
27ae3bf36fSSingleAccretion     #[cfg(feature = "debug-builtins")]
28ae3bf36fSSingleAccretion     debug_registration: Option<crate::runtime::vm::GdbJitImageRegistration>,
29d4242001SAdam Bratschi-Kaye     published: bool,
3017fbd3c6SChris Fallin     registered: bool,
31d4242001SAdam Bratschi-Kaye     enable_branch_protection: bool,
32d3132c9dSAlex Crichton     needs_executable: bool,
33ae3bf36fSSingleAccretion     #[cfg(feature = "debug-builtins")]
34ae3bf36fSSingleAccretion     has_native_debug_info: bool,
355eee6313SChris Fallin     custom_code_memory: Option<Arc<dyn CustomCodeMemory>>,
36d4242001SAdam Bratschi-Kaye 
37d4242001SAdam Bratschi-Kaye     // Ranges within `self.mmap` of where the particular sections lie.
38d4242001SAdam Bratschi-Kaye     text: Range<usize>,
39d4242001SAdam Bratschi-Kaye     unwind: Range<usize>,
40d4242001SAdam Bratschi-Kaye     trap_data: Range<usize>,
41d4242001SAdam Bratschi-Kaye     wasm_data: Range<usize>,
42d4242001SAdam Bratschi-Kaye     address_map_data: Range<usize>,
43452086fbSAlex Crichton     stack_map_data: Range<usize>,
442d25f862SChris Fallin     exception_data: Range<usize>,
4502155232SChris Fallin     frame_tables_data: Range<usize>,
46d4242001SAdam Bratschi-Kaye     func_name_data: Range<usize>,
47d4242001SAdam Bratschi-Kaye     info_data: Range<usize>,
48ae3bf36fSSingleAccretion     wasm_dwarf: Range<usize>,
49c07c94d2SChris Fallin     wasm_bytecode: Range<usize>,
50c07c94d2SChris Fallin     wasm_bytecode_ends: Range<usize>,
51d4242001SAdam Bratschi-Kaye }
52d4242001SAdam Bratschi-Kaye 
53d4242001SAdam Bratschi-Kaye impl Drop for CodeMemory {
drop(&mut self)54d4242001SAdam Bratschi-Kaye     fn drop(&mut self) {
555eee6313SChris Fallin         // If there is a custom code memory handler, restore the
565eee6313SChris Fallin         // original (non-executable) state of the memory.
5717fbd3c6SChris Fallin         //
5817fbd3c6SChris Fallin         // We do this rather than invoking `unpublish()` because we
5917fbd3c6SChris Fallin         // want to skip the mprotect() if we natively own the mmap and
6017fbd3c6SChris Fallin         // are going to munmap soon anyway.
615eee6313SChris Fallin         if let Some(mem) = self.custom_code_memory.as_ref() {
624e8dc9d0SPaul Osborne             if self.published && self.needs_executable {
635eee6313SChris Fallin                 let text = self.text();
645eee6313SChris Fallin                 mem.unpublish_executable(text.as_ptr(), text.len())
655eee6313SChris Fallin                     .expect("Executable memory unpublish failed");
665eee6313SChris Fallin             }
674e8dc9d0SPaul Osborne         }
685eee6313SChris Fallin 
69ae3bf36fSSingleAccretion         // Drop the registrations before `self.mmap` since they (implicitly) refer to it.
704afa86b8SAlex Crichton         #[cfg(has_host_compiler_backend)]
71ae3bf36fSSingleAccretion         let _ = self.unwind_registration.take();
72ae3bf36fSSingleAccretion         #[cfg(feature = "debug-builtins")]
73ae3bf36fSSingleAccretion         let _ = self.debug_registration.take();
74d4242001SAdam Bratschi-Kaye     }
75d4242001SAdam Bratschi-Kaye }
76d4242001SAdam Bratschi-Kaye 
_assert()77d4242001SAdam Bratschi-Kaye fn _assert() {
78d4242001SAdam Bratschi-Kaye     fn _assert_send_sync<T: Send + Sync>() {}
79d4242001SAdam Bratschi-Kaye     _assert_send_sync::<CodeMemory>();
80d4242001SAdam Bratschi-Kaye }
81d4242001SAdam Bratschi-Kaye 
825eee6313SChris Fallin /// Interface implemented by an embedder to provide custom
835eee6313SChris Fallin /// implementations of code-memory protection and execute permissions.
845eee6313SChris Fallin pub trait CustomCodeMemory: Send + Sync {
855eee6313SChris Fallin     /// The minimal alignment granularity for an address region that
865eee6313SChris Fallin     /// can be made executable.
875eee6313SChris Fallin     ///
885eee6313SChris Fallin     /// Wasmtime does not assume the system page size for this because
895eee6313SChris Fallin     /// custom code-memory protection can be used when all other uses
905eee6313SChris Fallin     /// of virtual memory are disabled.
required_alignment(&self) -> usize915eee6313SChris Fallin     fn required_alignment(&self) -> usize;
925eee6313SChris Fallin 
935eee6313SChris Fallin     /// Publish a region of memory as executable.
945eee6313SChris Fallin     ///
955eee6313SChris Fallin     /// This should update permissions from the default RW
965eee6313SChris Fallin     /// (readable/writable but not executable) to RX
975eee6313SChris Fallin     /// (readable/executable but not writable), enforcing W^X
985eee6313SChris Fallin     /// discipline.
995eee6313SChris Fallin     ///
1005eee6313SChris Fallin     /// If the platform requires any data/instruction coherence
1015eee6313SChris Fallin     /// action, that should be performed as part of this hook as well.
1025eee6313SChris Fallin     ///
1035eee6313SChris Fallin     /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as
1045eee6313SChris Fallin     /// per `required_alignment()`.
publish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>10596e19700SNick Fitzgerald     fn publish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>;
1065eee6313SChris Fallin 
1075eee6313SChris Fallin     /// Unpublish a region of memory.
1085eee6313SChris Fallin     ///
1095eee6313SChris Fallin     /// This should perform the opposite effect of `make_executable`,
1105eee6313SChris Fallin     /// switching a range of memory back from RX (readable/executable)
1115eee6313SChris Fallin     /// to RW (readable/writable). It is guaranteed that no code is
1125eee6313SChris Fallin     /// running anymore from this region.
1135eee6313SChris Fallin     ///
1145eee6313SChris Fallin     /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as
1155eee6313SChris Fallin     /// per `required_alignment()`.
unpublish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>11696e19700SNick Fitzgerald     fn unpublish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>;
1175eee6313SChris Fallin }
1185eee6313SChris Fallin 
119d4242001SAdam Bratschi-Kaye impl CodeMemory {
120d4242001SAdam Bratschi-Kaye     /// Creates a new `CodeMemory` by taking ownership of the provided
121d4242001SAdam Bratschi-Kaye     /// `MmapVec`.
122d4242001SAdam Bratschi-Kaye     ///
123d4242001SAdam Bratschi-Kaye     /// The returned `CodeMemory` manages the internal `MmapVec` and the
124d4242001SAdam Bratschi-Kaye     /// `publish` method is used to actually make the memory executable.
new(engine: &Engine, mmap: MmapVec) -> Result<Self>1255eee6313SChris Fallin     pub fn new(engine: &Engine, mmap: MmapVec) -> Result<Self> {
1261a9339e2SNick Fitzgerald         let mmap_data = &*mmap;
1271a9339e2SNick Fitzgerald         let header = FileHeader64::<Endianness>::parse(mmap_data)
1289034e101SAlex Crichton             .map_err(obj::ObjectCrateErrorWrapper)
1291a9339e2SNick Fitzgerald             .context("failed to parse precompiled artifact as an ELF")?;
1301a9339e2SNick Fitzgerald         let endian = header
1311a9339e2SNick Fitzgerald             .endian()
1321a9339e2SNick Fitzgerald             .context("failed to parse header endianness")?;
1331a9339e2SNick Fitzgerald 
1341a9339e2SNick Fitzgerald         let section_headers = header
1351a9339e2SNick Fitzgerald             .section_headers(endian, mmap_data)
1361a9339e2SNick Fitzgerald             .context("failed to parse section headers")?;
1371a9339e2SNick Fitzgerald         let strings = header
1381a9339e2SNick Fitzgerald             .section_strings(endian, mmap_data, section_headers)
1391a9339e2SNick Fitzgerald             .context("failed to parse strings table")?;
1401a9339e2SNick Fitzgerald         let sections = header
1411a9339e2SNick Fitzgerald             .sections(endian, mmap_data)
1421a9339e2SNick Fitzgerald             .context("failed to parse sections table")?;
143d4242001SAdam Bratschi-Kaye 
144d4242001SAdam Bratschi-Kaye         let mut text = 0..0;
145d4242001SAdam Bratschi-Kaye         let mut unwind = 0..0;
146d4242001SAdam Bratschi-Kaye         let mut enable_branch_protection = None;
147d3132c9dSAlex Crichton         let mut needs_executable = true;
148ae3bf36fSSingleAccretion         #[cfg(feature = "debug-builtins")]
149ae3bf36fSSingleAccretion         let mut has_native_debug_info = false;
150d4242001SAdam Bratschi-Kaye         let mut trap_data = 0..0;
1512d25f862SChris Fallin         let mut exception_data = 0..0;
15202155232SChris Fallin         let mut frame_tables_data = 0..0;
153d4242001SAdam Bratschi-Kaye         let mut wasm_data = 0..0;
154d4242001SAdam Bratschi-Kaye         let mut address_map_data = 0..0;
155452086fbSAlex Crichton         let mut stack_map_data = 0..0;
156d4242001SAdam Bratschi-Kaye         let mut func_name_data = 0..0;
157d4242001SAdam Bratschi-Kaye         let mut info_data = 0..0;
158ae3bf36fSSingleAccretion         let mut wasm_dwarf = 0..0;
159c07c94d2SChris Fallin         let mut wasm_bytecode = 0..0;
160c07c94d2SChris Fallin         let mut wasm_bytecode_ends = 0..0;
1611a9339e2SNick Fitzgerald         for section_header in sections.iter() {
1621a9339e2SNick Fitzgerald             let data = section_header
1631a9339e2SNick Fitzgerald                 .data(endian, mmap_data)
1641a9339e2SNick Fitzgerald                 .map_err(obj::ObjectCrateErrorWrapper)?;
1651a9339e2SNick Fitzgerald             let name = section_name(endian, strings, section_header)?;
166d4242001SAdam Bratschi-Kaye             let range = subslice_range(data, &mmap);
167d4242001SAdam Bratschi-Kaye 
168d4242001SAdam Bratschi-Kaye             // Double-check that sections are all aligned properly.
1691a9339e2SNick Fitzgerald             let section_align = usize::try_from(section_header.sh_addralign(endian))?;
1701a9339e2SNick Fitzgerald             if section_align != 0 && data.len() != 0 {
1711a9339e2SNick Fitzgerald                 let section_offset = data.as_ptr().addr() - mmap.as_ptr().addr();
1721a9339e2SNick Fitzgerald                 ensure!(
1731a9339e2SNick Fitzgerald                     section_offset % section_align == 0,
1741a9339e2SNick Fitzgerald                     "section {name:?} isn't aligned to {section_align:#x}",
175d4242001SAdam Bratschi-Kaye                 );
176d4242001SAdam Bratschi-Kaye             }
1771a9339e2SNick Fitzgerald 
1781a9339e2SNick Fitzgerald             // Check that we don't have any relocations, which would make
1791a9339e2SNick Fitzgerald             // loading precompiled Wasm modules slower and also force them to
1801a9339e2SNick Fitzgerald             // get paged into memory from disk.
1811a9339e2SNick Fitzgerald             //
1821a9339e2SNick Fitzgerald             // We avoid using things like Cranelift's `floor`, `ceil`,
1831a9339e2SNick Fitzgerald             // etc... operators in the Wasm-to-CLIF translator specifically to
1841a9339e2SNick Fitzgerald             // avoid having to do any relocations here. This also ensures that
1851a9339e2SNick Fitzgerald             // all builtins use the same trampoline mechanism.
1861a9339e2SNick Fitzgerald             //
1871a9339e2SNick Fitzgerald             // We do, however, allow relocations in `.debug_*` DWARF sections.
1881a9339e2SNick Fitzgerald             if let Some(target_section) = reloc_section_target(&sections, section_header, endian)? {
1891a9339e2SNick Fitzgerald                 let target_name = section_name(endian, strings, target_section)?;
1901a9339e2SNick Fitzgerald                 ensure!(
1911a9339e2SNick Fitzgerald                     target_name.starts_with(".debug_"),
1921a9339e2SNick Fitzgerald                     "section {target_name:?} has unexpected relocations \
1931a9339e2SNick Fitzgerald                      (defined in section {name:?})",
1941a9339e2SNick Fitzgerald                 );
195d4242001SAdam Bratschi-Kaye             }
196d4242001SAdam Bratschi-Kaye 
197d4242001SAdam Bratschi-Kaye             match name {
198d4242001SAdam Bratschi-Kaye                 obj::ELF_WASM_BTI => match data.len() {
199d4242001SAdam Bratschi-Kaye                     1 => enable_branch_protection = Some(data[0] != 0),
2001a9339e2SNick Fitzgerald                     _ => bail!("invalid {name:?} section"),
201d4242001SAdam Bratschi-Kaye                 },
202d4242001SAdam Bratschi-Kaye                 ".text" => {
203d4242001SAdam Bratschi-Kaye                     text = range;
204d4242001SAdam Bratschi-Kaye 
2051a9339e2SNick Fitzgerald                     if section_header.sh_flags(endian) & obj::SH_WASMTIME_NOT_EXECUTED != 0 {
206d3132c9dSAlex Crichton                         needs_executable = false;
207d3132c9dSAlex Crichton                     }
208d3132c9dSAlex Crichton                 }
2094afa86b8SAlex Crichton                 #[cfg(has_host_compiler_backend)]
2104afa86b8SAlex Crichton                 crate::runtime::vm::UnwindRegistration::SECTION_NAME => unwind = range,
211d4242001SAdam Bratschi-Kaye                 obj::ELF_WASM_DATA => wasm_data = range,
212d4242001SAdam Bratschi-Kaye                 obj::ELF_WASMTIME_ADDRMAP => address_map_data = range,
213452086fbSAlex Crichton                 obj::ELF_WASMTIME_STACK_MAP => stack_map_data = range,
214d4242001SAdam Bratschi-Kaye                 obj::ELF_WASMTIME_TRAPS => trap_data = range,
2152d25f862SChris Fallin                 obj::ELF_WASMTIME_EXCEPTIONS => exception_data = range,
21602155232SChris Fallin                 obj::ELF_WASMTIME_FRAMES => frame_tables_data = range,
217d4242001SAdam Bratschi-Kaye                 obj::ELF_NAME_DATA => func_name_data = range,
218d4242001SAdam Bratschi-Kaye                 obj::ELF_WASMTIME_INFO => info_data = range,
219ae3bf36fSSingleAccretion                 obj::ELF_WASMTIME_DWARF => wasm_dwarf = range,
220c07c94d2SChris Fallin                 obj::ELF_WASMTIME_WASM_BYTECODE => wasm_bytecode = range,
221c07c94d2SChris Fallin                 obj::ELF_WASMTIME_WASM_BYTECODE_ENDS => wasm_bytecode_ends = range,
2221a9339e2SNick Fitzgerald 
223ae3bf36fSSingleAccretion                 #[cfg(feature = "debug-builtins")]
224ae3bf36fSSingleAccretion                 ".debug_info" => has_native_debug_info = true,
225d4242001SAdam Bratschi-Kaye 
2261a9339e2SNick Fitzgerald                 // These sections are expected, but we do not need to retain any
2271a9339e2SNick Fitzgerald                 // info about them.
2281a9339e2SNick Fitzgerald                 "" | ".symtab" | ".strtab" | ".shstrtab" | ".xdata" | obj::ELF_WASM_ENGINE => {
2291a9339e2SNick Fitzgerald                     log::debug!("ignoring section {name:?}")
2301a9339e2SNick Fitzgerald                 }
2311a9339e2SNick Fitzgerald                 _ if name.starts_with(".debug_") || name.starts_with(".rela.debug_") => {
2321a9339e2SNick Fitzgerald                     log::debug!("ignoring debug section {name:?}")
2331a9339e2SNick Fitzgerald                 }
2341a9339e2SNick Fitzgerald 
2351a9339e2SNick Fitzgerald                 _ => bail!("unexpected section {name:?} in Wasm compilation artifact"),
236d4242001SAdam Bratschi-Kaye             }
237d4242001SAdam Bratschi-Kaye         }
2385eee6313SChris Fallin 
2391a9339e2SNick Fitzgerald         // Silence unused `mut` warning.
2404afa86b8SAlex Crichton         #[cfg(not(has_host_compiler_backend))]
2414afa86b8SAlex Crichton         let _ = &mut unwind;
2424afa86b8SAlex Crichton 
2432d25f862SChris Fallin         // Ensure that the exception table is well-formed. This parser
2442d25f862SChris Fallin         // construction is cheap: it reads the header and validates
2452d25f862SChris Fallin         // ranges but nothing else. We do this only in debug-assertion
2462d25f862SChris Fallin         // builds because we otherwise require for safety that the
2472d25f862SChris Fallin         // compiled artifact is as-produced-by this version of
2482d25f862SChris Fallin         // Wasmtime, and we should always produce a correct exception
2492d25f862SChris Fallin         // table (i.e., we are not expecting untrusted data here).
2502d25f862SChris Fallin         if cfg!(debug_assertions) {
2512d25f862SChris Fallin             let _ = ExceptionTable::parse(&mmap[exception_data.clone()])?;
2522d25f862SChris Fallin         }
2532d25f862SChris Fallin 
254d4242001SAdam Bratschi-Kaye         Ok(Self {
255ae3bf36fSSingleAccretion             mmap,
2564afa86b8SAlex Crichton             #[cfg(has_host_compiler_backend)]
257ae3bf36fSSingleAccretion             unwind_registration: None,
258ae3bf36fSSingleAccretion             #[cfg(feature = "debug-builtins")]
259ae3bf36fSSingleAccretion             debug_registration: None,
260d4242001SAdam Bratschi-Kaye             published: false,
26117fbd3c6SChris Fallin             registered: false,
262d4242001SAdam Bratschi-Kaye             enable_branch_protection: enable_branch_protection
263ff33e949SNick Fitzgerald                 .ok_or_else(|| format_err!("missing `{}` section", obj::ELF_WASM_BTI))?,
264d3132c9dSAlex Crichton             needs_executable,
265ae3bf36fSSingleAccretion             #[cfg(feature = "debug-builtins")]
266ae3bf36fSSingleAccretion             has_native_debug_info,
2675eee6313SChris Fallin             custom_code_memory: engine.custom_code_memory().cloned(),
268d4242001SAdam Bratschi-Kaye             text,
269d4242001SAdam Bratschi-Kaye             unwind,
270d4242001SAdam Bratschi-Kaye             trap_data,
271d4242001SAdam Bratschi-Kaye             address_map_data,
272452086fbSAlex Crichton             stack_map_data,
2732d25f862SChris Fallin             exception_data,
27402155232SChris Fallin             frame_tables_data,
275d4242001SAdam Bratschi-Kaye             func_name_data,
276ae3bf36fSSingleAccretion             wasm_dwarf,
277d4242001SAdam Bratschi-Kaye             info_data,
278d4242001SAdam Bratschi-Kaye             wasm_data,
279c07c94d2SChris Fallin             wasm_bytecode,
280c07c94d2SChris Fallin             wasm_bytecode_ends,
281d4242001SAdam Bratschi-Kaye         })
282d4242001SAdam Bratschi-Kaye     }
283d4242001SAdam Bratschi-Kaye 
284d4242001SAdam Bratschi-Kaye     /// Returns a reference to the underlying `MmapVec` this memory owns.
285d4242001SAdam Bratschi-Kaye     #[inline]
mmap(&self) -> &MmapVec286d4242001SAdam Bratschi-Kaye     pub fn mmap(&self) -> &MmapVec {
287d4242001SAdam Bratschi-Kaye         &self.mmap
288d4242001SAdam Bratschi-Kaye     }
289d4242001SAdam Bratschi-Kaye 
290d4242001SAdam Bratschi-Kaye     /// Returns the contents of the text section of the ELF executable this
291d4242001SAdam Bratschi-Kaye     /// represents.
292d4242001SAdam Bratschi-Kaye     #[inline]
text(&self) -> &[u8]293d4242001SAdam Bratschi-Kaye     pub fn text(&self) -> &[u8] {
294d4242001SAdam Bratschi-Kaye         &self.mmap[self.text.clone()]
295d4242001SAdam Bratschi-Kaye     }
296d4242001SAdam Bratschi-Kaye 
297d4242001SAdam Bratschi-Kaye     /// Returns the contents of the `ELF_WASMTIME_DWARF` section.
298d4242001SAdam Bratschi-Kaye     #[inline]
wasm_dwarf(&self) -> &[u8]299ae3bf36fSSingleAccretion     pub fn wasm_dwarf(&self) -> &[u8] {
300ae3bf36fSSingleAccretion         &self.mmap[self.wasm_dwarf.clone()]
301d4242001SAdam Bratschi-Kaye     }
302d4242001SAdam Bratschi-Kaye 
303d4242001SAdam Bratschi-Kaye     /// Returns the data in the `ELF_NAME_DATA` section.
304d4242001SAdam Bratschi-Kaye     #[inline]
func_name_data(&self) -> &[u8]305d4242001SAdam Bratschi-Kaye     pub fn func_name_data(&self) -> &[u8] {
306d4242001SAdam Bratschi-Kaye         &self.mmap[self.func_name_data.clone()]
307d4242001SAdam Bratschi-Kaye     }
308d4242001SAdam Bratschi-Kaye 
309d4242001SAdam Bratschi-Kaye     /// Returns the concatenated list of all data associated with this wasm
310d4242001SAdam Bratschi-Kaye     /// module.
311d4242001SAdam Bratschi-Kaye     ///
312d4242001SAdam Bratschi-Kaye     /// This is used for initialization of memories and all data ranges stored
313d4242001SAdam Bratschi-Kaye     /// in a `Module` are relative to the slice returned here.
314d4242001SAdam Bratschi-Kaye     #[inline]
wasm_data(&self) -> &[u8]315d4242001SAdam Bratschi-Kaye     pub fn wasm_data(&self) -> &[u8] {
316d4242001SAdam Bratschi-Kaye         &self.mmap[self.wasm_data.clone()]
317d4242001SAdam Bratschi-Kaye     }
318d4242001SAdam Bratschi-Kaye 
319d4242001SAdam Bratschi-Kaye     /// Returns the encoded address map section used to pass to
320d4242001SAdam Bratschi-Kaye     /// `wasmtime_environ::lookup_file_pos`.
321d4242001SAdam Bratschi-Kaye     #[inline]
address_map_data(&self) -> &[u8]322d4242001SAdam Bratschi-Kaye     pub fn address_map_data(&self) -> &[u8] {
323d4242001SAdam Bratschi-Kaye         &self.mmap[self.address_map_data.clone()]
324d4242001SAdam Bratschi-Kaye     }
325d4242001SAdam Bratschi-Kaye 
326452086fbSAlex Crichton     /// Returns the encoded stack map section used to pass to
327452086fbSAlex Crichton     /// `wasmtime_environ::StackMap::lookup`.
stack_map_data(&self) -> &[u8]328452086fbSAlex Crichton     pub fn stack_map_data(&self) -> &[u8] {
329452086fbSAlex Crichton         &self.mmap[self.stack_map_data.clone()]
330452086fbSAlex Crichton     }
331452086fbSAlex Crichton 
3322d25f862SChris Fallin     /// Returns the encoded exception-tables section to pass to
3332d25f862SChris Fallin     /// `wasmtime_unwinder::ExceptionTable::parse`.
exception_tables(&self) -> &[u8]3342d25f862SChris Fallin     pub fn exception_tables(&self) -> &[u8] {
3352d25f862SChris Fallin         &self.mmap[self.exception_data.clone()]
3362d25f862SChris Fallin     }
3372d25f862SChris Fallin 
33802155232SChris Fallin     /// Returns the encoded frame-tables section to pass to
33902155232SChris Fallin     /// `wasmtime_environ::FrameTable::parse`.
frame_tables(&self) -> &[u8]34002155232SChris Fallin     pub fn frame_tables(&self) -> &[u8] {
34102155232SChris Fallin         &self.mmap[self.frame_tables_data.clone()]
34202155232SChris Fallin     }
34302155232SChris Fallin 
344c07c94d2SChris Fallin     /// Returns the concatenated Wasm bytecode section, or an empty slice if
345c07c94d2SChris Fallin     /// the artifact was not compiled with `guest-debug` enabled.
wasm_bytecode(&self) -> &[u8]346c07c94d2SChris Fallin     pub fn wasm_bytecode(&self) -> &[u8] {
347c07c94d2SChris Fallin         &self.mmap[self.wasm_bytecode.clone()]
348c07c94d2SChris Fallin     }
349c07c94d2SChris Fallin 
350c07c94d2SChris Fallin     /// Returns the Wasm bytecode section end-offset array.
wasm_bytecode_ends(&self) -> &[u8]351c07c94d2SChris Fallin     pub fn wasm_bytecode_ends(&self) -> &[u8] {
352c07c94d2SChris Fallin         &self.mmap[self.wasm_bytecode_ends.clone()]
353c07c94d2SChris Fallin     }
354c07c94d2SChris Fallin 
355d4242001SAdam Bratschi-Kaye     /// Returns the contents of the `ELF_WASMTIME_INFO` section, or an empty
356d4242001SAdam Bratschi-Kaye     /// slice if it wasn't found.
357d4242001SAdam Bratschi-Kaye     #[inline]
wasmtime_info(&self) -> &[u8]358d4242001SAdam Bratschi-Kaye     pub fn wasmtime_info(&self) -> &[u8] {
359d4242001SAdam Bratschi-Kaye         &self.mmap[self.info_data.clone()]
360d4242001SAdam Bratschi-Kaye     }
361d4242001SAdam Bratschi-Kaye 
362d4242001SAdam Bratschi-Kaye     /// Returns the contents of the `ELF_WASMTIME_TRAPS` section, or an empty
363d4242001SAdam Bratschi-Kaye     /// slice if it wasn't found.
364d4242001SAdam Bratschi-Kaye     #[inline]
trap_data(&self) -> &[u8]365d4242001SAdam Bratschi-Kaye     pub fn trap_data(&self) -> &[u8] {
366d4242001SAdam Bratschi-Kaye         &self.mmap[self.trap_data.clone()]
367d4242001SAdam Bratschi-Kaye     }
368d4242001SAdam Bratschi-Kaye 
369c07c94d2SChris Fallin     /// Returns the Wasm bytecode section end-offset for a given core
370c07c94d2SChris Fallin     /// module, or `None` if no bytecode is present.
371c07c94d2SChris Fallin     ///
372c07c94d2SChris Fallin     /// # Panics
373c07c94d2SChris Fallin     ///
374c07c94d2SChris Fallin     /// Panics if index is out-of-range.
wasm_bytecode_end_for_module(&self, index: StaticModuleIndex) -> Option<usize>375c07c94d2SChris Fallin     fn wasm_bytecode_end_for_module(&self, index: StaticModuleIndex) -> Option<usize> {
376c07c94d2SChris Fallin         if self.wasm_bytecode_ends().is_empty() {
377c07c94d2SChris Fallin             return None;
378c07c94d2SChris Fallin         }
379c07c94d2SChris Fallin         let ends = self.wasm_bytecode_ends();
380c07c94d2SChris Fallin         let count = ends.len() / core::mem::size_of::<u32>();
381*a2cc11f3SPhilip Craig         let (ends, _) = object::slice_from_bytes::<U32<LittleEndian>>(ends, count)
382c07c94d2SChris Fallin             .expect("Invalid alignment of `ends` section");
383c07c94d2SChris Fallin         let index = usize::try_from(index.as_u32()).unwrap();
384c07c94d2SChris Fallin         Some(usize::try_from(ends[index].get(LittleEndian)).unwrap())
385c07c94d2SChris Fallin     }
386c07c94d2SChris Fallin 
387c07c94d2SChris Fallin     /// Returns the Wasm bytecode for the a core module in this
388c07c94d2SChris Fallin     /// artifact, or `None` if bytecode was not preserved.
wasm_bytecode_for_module(&self, index: StaticModuleIndex) -> Option<&[u8]>389c07c94d2SChris Fallin     pub(crate) fn wasm_bytecode_for_module(&self, index: StaticModuleIndex) -> Option<&[u8]> {
390c07c94d2SChris Fallin         let start = if index.as_u32() == 0 {
391c07c94d2SChris Fallin             0
392c07c94d2SChris Fallin         } else {
393c07c94d2SChris Fallin             self.wasm_bytecode_end_for_module(StaticModuleIndex::from_u32(index.as_u32() - 1))?
394c07c94d2SChris Fallin         };
395c07c94d2SChris Fallin         let end = self.wasm_bytecode_end_for_module(index)?;
396c07c94d2SChris Fallin         Some(&self.wasm_bytecode()[start..end])
397c07c94d2SChris Fallin     }
398c07c94d2SChris Fallin 
399d4242001SAdam Bratschi-Kaye     /// Publishes the internal ELF image to be ready for execution.
400d4242001SAdam Bratschi-Kaye     ///
40117fbd3c6SChris Fallin     /// This method can only be when the image is not published (its
40217fbd3c6SChris Fallin     /// default state) and will panic if called when already
40317fbd3c6SChris Fallin     /// published. This will parse the ELF image from the original
40417fbd3c6SChris Fallin     /// `MmapVec` and do everything necessary to get it ready for
40517fbd3c6SChris Fallin     /// execution, including:
406d4242001SAdam Bratschi-Kaye     ///
407d4242001SAdam Bratschi-Kaye     /// * Change page protections from read/write to read/execute.
408d4242001SAdam Bratschi-Kaye     /// * Register unwinding information with the OS
409ae3bf36fSSingleAccretion     /// * Register this image with the debugger if native DWARF is present
410d4242001SAdam Bratschi-Kaye     ///
411d4242001SAdam Bratschi-Kaye     /// After this function executes all JIT code should be ready to execute.
41217fbd3c6SChris Fallin     ///
413bc4582c3SAlex Crichton     /// The action may be reversed by calling [`Self::unpublish`], as long
41417fbd3c6SChris Fallin     /// as that method's safety requirements are upheld.
publish(&mut self) -> Result<()>415d4242001SAdam Bratschi-Kaye     pub fn publish(&mut self) -> Result<()> {
416d4242001SAdam Bratschi-Kaye         assert!(!self.published);
417d4242001SAdam Bratschi-Kaye         self.published = true;
418d4242001SAdam Bratschi-Kaye 
419d4242001SAdam Bratschi-Kaye         if self.text().is_empty() {
420d4242001SAdam Bratschi-Kaye             return Ok(());
421d4242001SAdam Bratschi-Kaye         }
422d4242001SAdam Bratschi-Kaye 
423d4242001SAdam Bratschi-Kaye         // The unsafety here comes from a few things:
424d4242001SAdam Bratschi-Kaye         //
425d4242001SAdam Bratschi-Kaye         // * We're actually updating some page protections to executable memory.
426d4242001SAdam Bratschi-Kaye         //
427d4242001SAdam Bratschi-Kaye         // * We're registering unwinding information which relies on the
428d4242001SAdam Bratschi-Kaye         //   correctness of the information in the first place. This applies to
429d4242001SAdam Bratschi-Kaye         //   both the actual unwinding tables as well as the validity of the
430d4242001SAdam Bratschi-Kaye         //   pointers we pass in itself.
431d4242001SAdam Bratschi-Kaye         unsafe {
432d4242001SAdam Bratschi-Kaye             // Next freeze the contents of this image by making all of the
433d4242001SAdam Bratschi-Kaye             // memory readonly. Nothing after this point should ever be modified
434d4242001SAdam Bratschi-Kaye             // so commit everything. For a compiled-in-memory image this will
435d4242001SAdam Bratschi-Kaye             // mean IPIs to evict writable mappings from other cores. For
436d4242001SAdam Bratschi-Kaye             // loaded-from-disk images this shouldn't result in IPIs so long as
437d4242001SAdam Bratschi-Kaye             // there weren't any relocations because nothing should have
438d4242001SAdam Bratschi-Kaye             // otherwise written to the image at any point either.
439d3132c9dSAlex Crichton             //
440d3132c9dSAlex Crichton             // Note that if virtual memory is disabled this is skipped because
441d3132c9dSAlex Crichton             // we aren't able to make it readonly, but this is just a
442d3132c9dSAlex Crichton             // defense-in-depth measure and isn't required for correctness.
4437f9049b9SAlex Crichton             #[cfg(has_virtual_memory)]
44499efc20bSPaul Osborne             if self.mmap.supports_virtual_memory() {
445d4242001SAdam Bratschi-Kaye                 self.mmap.make_readonly(0..self.mmap.len())?;
44699efc20bSPaul Osborne             }
447d4242001SAdam Bratschi-Kaye 
448d3132c9dSAlex Crichton             // Switch the executable portion from readonly to read/execute.
449d3132c9dSAlex Crichton             if self.needs_executable {
4505eee6313SChris Fallin                 if !self.custom_publish()? {
45199efc20bSPaul Osborne                     if !self.mmap.supports_virtual_memory() {
45299efc20bSPaul Osborne                         bail!("this target requires virtual memory to be enabled");
45399efc20bSPaul Osborne                     }
454dcfb6761SAlex Crichton                     #[cfg(has_virtual_memory)]
455d4242001SAdam Bratschi-Kaye                     self.mmap
456d4242001SAdam Bratschi-Kaye                         .make_executable(self.text.clone(), self.enable_branch_protection)
457d4242001SAdam Bratschi-Kaye                         .context("unable to make memory executable")?;
458d3132c9dSAlex Crichton                 }
4595eee6313SChris Fallin             }
460d4242001SAdam Bratschi-Kaye 
46117fbd3c6SChris Fallin             if !self.registered {
462d4242001SAdam Bratschi-Kaye                 // With all our memory set up use the platform-specific
463d4242001SAdam Bratschi-Kaye                 // `UnwindRegistration` implementation to inform the general
464d4242001SAdam Bratschi-Kaye                 // runtime that there's unwinding information available for all
465d4242001SAdam Bratschi-Kaye                 // our just-published JIT functions.
466d4242001SAdam Bratschi-Kaye                 self.register_unwind_info()?;
467ae3bf36fSSingleAccretion 
468ae3bf36fSSingleAccretion                 #[cfg(feature = "debug-builtins")]
469ae3bf36fSSingleAccretion                 self.register_debug_image()?;
47017fbd3c6SChris Fallin                 self.registered = true;
47117fbd3c6SChris Fallin             }
472d4242001SAdam Bratschi-Kaye         }
473d4242001SAdam Bratschi-Kaye 
474d4242001SAdam Bratschi-Kaye         Ok(())
475d4242001SAdam Bratschi-Kaye     }
476d4242001SAdam Bratschi-Kaye 
custom_publish(&mut self) -> Result<bool>4775eee6313SChris Fallin     fn custom_publish(&mut self) -> Result<bool> {
4785eee6313SChris Fallin         if let Some(mem) = self.custom_code_memory.as_ref() {
4795eee6313SChris Fallin             let text = self.text();
4805eee6313SChris Fallin             // The text section should be aligned to
4815eee6313SChris Fallin             // `custom_code_memory.required_alignment()` due to a
4825eee6313SChris Fallin             // combination of two invariants:
4835eee6313SChris Fallin             //
4845eee6313SChris Fallin             // - MmapVec aligns its start address, even in owned-Vec mode; and
4855eee6313SChris Fallin             // - The text segment inside the ELF image will be aligned according
4865eee6313SChris Fallin             //   to the platform's requirements.
4875eee6313SChris Fallin             let text_addr = text.as_ptr() as usize;
4885eee6313SChris Fallin             assert_eq!(text_addr & (mem.required_alignment() - 1), 0);
4895eee6313SChris Fallin 
4905eee6313SChris Fallin             // The custom code memory handler will ensure the
4915eee6313SChris Fallin             // memory is executable and also handle icache
4925eee6313SChris Fallin             // coherence.
4935eee6313SChris Fallin             mem.publish_executable(text.as_ptr(), text.len())?;
4945eee6313SChris Fallin             Ok(true)
4955eee6313SChris Fallin         } else {
4965eee6313SChris Fallin             Ok(false)
4975eee6313SChris Fallin         }
4985eee6313SChris Fallin     }
4995eee6313SChris Fallin 
50017fbd3c6SChris Fallin     /// "Unpublish" code memory (transition it from executable to read/writable).
50117fbd3c6SChris Fallin     ///
50217fbd3c6SChris Fallin     /// This may be used to edit the code image, as long as the
50317fbd3c6SChris Fallin     /// overall size of the memory remains the same. Note the hazards
50417fbd3c6SChris Fallin     /// inherent in editing code that may have been executed: any
50517fbd3c6SChris Fallin     /// stack frames with PC still active in this code must be
50617fbd3c6SChris Fallin     /// suspended (e.g., called into a hostcall that is then invoking
50717fbd3c6SChris Fallin     /// this method, or async-yielded) and any active PC values must
50817fbd3c6SChris Fallin     /// point to valid instructions. Thus this is mostly useful for
50917fbd3c6SChris Fallin     /// patching in-place at particular sites, such as by the use of
51017fbd3c6SChris Fallin     /// Cranelift's `patchable_call` instruction.
51117fbd3c6SChris Fallin     ///
51217fbd3c6SChris Fallin     /// If this fails, then the memory remains executable.
unpublish(&mut self) -> Result<()>51317fbd3c6SChris Fallin     pub fn unpublish(&mut self) -> Result<()> {
51417fbd3c6SChris Fallin         assert!(self.published);
51517fbd3c6SChris Fallin         self.published = false;
51617fbd3c6SChris Fallin 
51717fbd3c6SChris Fallin         if self.text().is_empty() {
51817fbd3c6SChris Fallin             return Ok(());
51917fbd3c6SChris Fallin         }
52017fbd3c6SChris Fallin 
52117fbd3c6SChris Fallin         if self.custom_unpublish()? {
52217fbd3c6SChris Fallin             return Ok(());
52317fbd3c6SChris Fallin         }
52417fbd3c6SChris Fallin 
52517fbd3c6SChris Fallin         if !self.mmap.supports_virtual_memory() {
52617fbd3c6SChris Fallin             bail!("this target requires virtual memory to be enabled");
52717fbd3c6SChris Fallin         }
52817fbd3c6SChris Fallin 
52917fbd3c6SChris Fallin         // SAFETY: we are guaranteed by our own safety conditions that
53017fbd3c6SChris Fallin         // we have exclusive access to this code and can change its
53117fbd3c6SChris Fallin         // permissions (removing the execute bit) without causing
53217fbd3c6SChris Fallin         // problems.
53317fbd3c6SChris Fallin         #[cfg(has_virtual_memory)]
53417fbd3c6SChris Fallin         unsafe {
53517fbd3c6SChris Fallin             self.mmap.make_readwrite(0..self.mmap.len())?;
53617fbd3c6SChris Fallin         }
53717fbd3c6SChris Fallin 
53817fbd3c6SChris Fallin         // Note that we do *not* unregister: we expect unpublish
53917fbd3c6SChris Fallin         // to be used for temporary edits, so we want the
54017fbd3c6SChris Fallin         // registration to "stick" after the initial publish and
54117fbd3c6SChris Fallin         // not toggle in subsequent unpublish/publish cycles.
54217fbd3c6SChris Fallin 
54317fbd3c6SChris Fallin         Ok(())
54417fbd3c6SChris Fallin     }
54517fbd3c6SChris Fallin 
custom_unpublish(&mut self) -> Result<bool>54617fbd3c6SChris Fallin     fn custom_unpublish(&mut self) -> Result<bool> {
54717fbd3c6SChris Fallin         if let Some(mem) = self.custom_code_memory.as_ref() {
54817fbd3c6SChris Fallin             let text = self.text();
54917fbd3c6SChris Fallin             mem.unpublish_executable(text.as_ptr(), text.len())?;
55017fbd3c6SChris Fallin             Ok(true)
55117fbd3c6SChris Fallin         } else {
55217fbd3c6SChris Fallin             Ok(false)
55317fbd3c6SChris Fallin         }
55417fbd3c6SChris Fallin     }
55517fbd3c6SChris Fallin 
55617fbd3c6SChris Fallin     /// Return a mutable borrow to the code, suitable for editing.
55717fbd3c6SChris Fallin     ///
55817fbd3c6SChris Fallin     /// Must not be published.
55917fbd3c6SChris Fallin     ///
56017fbd3c6SChris Fallin     /// # Panics
56117fbd3c6SChris Fallin     ///
56217fbd3c6SChris Fallin     /// This method panics if the code has been published (and not
56317fbd3c6SChris Fallin     /// subsequently unpublished).
text_mut(&mut self) -> &mut [u8]56417fbd3c6SChris Fallin     pub fn text_mut(&mut self) -> &mut [u8] {
56517fbd3c6SChris Fallin         assert!(!self.published);
56617fbd3c6SChris Fallin         // SAFETY: we assert !published, which means we either have
567ab78bd82SHo Kim         // not yet applied readonly + execute permissions, or we have
56817fbd3c6SChris Fallin         // undone that and flipped back to read-write via unpublish.
56917fbd3c6SChris Fallin         unsafe { &mut self.mmap.as_mut_slice()[self.text.clone()] }
57017fbd3c6SChris Fallin     }
57117fbd3c6SChris Fallin 
register_unwind_info(&mut self) -> Result<()>572d4242001SAdam Bratschi-Kaye     unsafe fn register_unwind_info(&mut self) -> Result<()> {
573d4242001SAdam Bratschi-Kaye         if self.unwind.len() == 0 {
574d4242001SAdam Bratschi-Kaye             return Ok(());
575d4242001SAdam Bratschi-Kaye         }
5764afa86b8SAlex Crichton         #[cfg(has_host_compiler_backend)]
5774afa86b8SAlex Crichton         {
578d4242001SAdam Bratschi-Kaye             let text = self.text();
579d4242001SAdam Bratschi-Kaye             let unwind_info = &self.mmap[self.unwind.clone()];
5800f457fadSAlex Crichton             let registration = unsafe {
5810f457fadSAlex Crichton                 crate::runtime::vm::UnwindRegistration::new(
5824afa86b8SAlex Crichton                     text.as_ptr(),
5834afa86b8SAlex Crichton                     unwind_info.as_ptr(),
5844afa86b8SAlex Crichton                     unwind_info.len(),
5854afa86b8SAlex Crichton                 )
5860f457fadSAlex Crichton                 .context("failed to create unwind info registration")?
5870f457fadSAlex Crichton             };
588ae3bf36fSSingleAccretion             self.unwind_registration = Some(registration);
5894afa86b8SAlex Crichton             return Ok(());
5904afa86b8SAlex Crichton         }
5914afa86b8SAlex Crichton         #[cfg(not(has_host_compiler_backend))]
5924afa86b8SAlex Crichton         {
5934afa86b8SAlex Crichton             bail!("should not have unwind info for non-native backend")
5944afa86b8SAlex Crichton         }
595ae3bf36fSSingleAccretion     }
596ae3bf36fSSingleAccretion 
597ae3bf36fSSingleAccretion     #[cfg(feature = "debug-builtins")]
register_debug_image(&mut self) -> Result<()>598ae3bf36fSSingleAccretion     fn register_debug_image(&mut self) -> Result<()> {
599ae3bf36fSSingleAccretion         if !self.has_native_debug_info {
600ae3bf36fSSingleAccretion             return Ok(());
601ae3bf36fSSingleAccretion         }
602ae3bf36fSSingleAccretion 
603ae3bf36fSSingleAccretion         // TODO-DebugInfo: we're copying the whole image here, which is pretty wasteful.
604ae3bf36fSSingleAccretion         // Use the existing memory by teaching code here about relocations in DWARF sections
605ae3bf36fSSingleAccretion         // and anything else necessary that is done in "create_gdbjit_image" right now.
606ae3bf36fSSingleAccretion         let image = self.mmap().to_vec();
607ae3bf36fSSingleAccretion         let text: &[u8] = self.text();
60802155232SChris Fallin         let bytes = crate::native_debug::create_gdbjit_image(image, (text.as_ptr(), text.len()))?;
609ae3bf36fSSingleAccretion         let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes);
610ae3bf36fSSingleAccretion         self.debug_registration = Some(reg);
611d4242001SAdam Bratschi-Kaye         Ok(())
612d4242001SAdam Bratschi-Kaye     }
61366dfa363SJamey Sharp 
61466dfa363SJamey Sharp     /// Looks up the given offset within this module's text section and returns
61566dfa363SJamey Sharp     /// the trap code associated with that instruction, if there is one.
lookup_trap_code(&self, text_offset: usize) -> Option<Trap>61666dfa363SJamey Sharp     pub fn lookup_trap_code(&self, text_offset: usize) -> Option<Trap> {
61766dfa363SJamey Sharp         lookup_trap_code(self.trap_data(), text_offset)
61866dfa363SJamey Sharp     }
61999ecf728SChris Fallin 
62099ecf728SChris Fallin     /// Get the raw address range of this CodeMemory.
raw_addr_range(&self) -> Range<usize>62199ecf728SChris Fallin     pub(crate) fn raw_addr_range(&self) -> Range<usize> {
62299ecf728SChris Fallin         let start = self.text().as_ptr().addr();
62399ecf728SChris Fallin         let end = start + self.text().len();
62499ecf728SChris Fallin         start..end
62599ecf728SChris Fallin     }
62699ecf728SChris Fallin 
62799ecf728SChris Fallin     /// Create a "deep clone": a separate CodeMemory for the same code
62899ecf728SChris Fallin     /// that can be patched or mutated independently. Also returns a
62999ecf728SChris Fallin     /// "metadata and location" handle that can be registered with the
63099ecf728SChris Fallin     /// global module registry and used for trap metadata lookups.
63199ecf728SChris Fallin     #[cfg(feature = "debug")]
deep_clone(self: &Arc<Self>, engine: &Engine) -> Result<CodeMemory>63299ecf728SChris Fallin     pub(crate) fn deep_clone(self: &Arc<Self>, engine: &Engine) -> Result<CodeMemory> {
63399ecf728SChris Fallin         let mmap = self.mmap.deep_clone()?;
63499ecf728SChris Fallin         Self::new(engine, mmap)
63599ecf728SChris Fallin     }
636d4242001SAdam Bratschi-Kaye }
637d4242001SAdam Bratschi-Kaye 
section_name<'a>( endian: Endianness, strings: object::StringTable<'a>, section_header: &SectionHeader64<Endianness>, ) -> Result<&'a str>6381a9339e2SNick Fitzgerald fn section_name<'a>(
6391a9339e2SNick Fitzgerald     endian: Endianness,
6401a9339e2SNick Fitzgerald     strings: object::StringTable<'a>,
6411a9339e2SNick Fitzgerald     section_header: &SectionHeader64<Endianness>,
6421a9339e2SNick Fitzgerald ) -> Result<&'a str> {
6431a9339e2SNick Fitzgerald     let name = section_header
6441a9339e2SNick Fitzgerald         .name(endian, strings)
6451a9339e2SNick Fitzgerald         .map_err(obj::ObjectCrateErrorWrapper)?;
6461a9339e2SNick Fitzgerald     Ok(str::from_utf8(name).context("invalid section name in Wasm compilation artifact")?)
6471a9339e2SNick Fitzgerald }
6481a9339e2SNick Fitzgerald 
is_reloc_section(section_header: &SectionHeader64<Endianness>, endian: Endianness) -> bool6491a9339e2SNick Fitzgerald fn is_reloc_section(section_header: &SectionHeader64<Endianness>, endian: Endianness) -> bool {
6501a9339e2SNick Fitzgerald     let sh_type = section_header.sh_type(endian);
6511a9339e2SNick Fitzgerald     matches!(
6521a9339e2SNick Fitzgerald         sh_type,
6531a9339e2SNick Fitzgerald         object::elf::SHT_REL | object::elf::SHT_RELA | object::elf::SHT_CREL
6541a9339e2SNick Fitzgerald     )
6551a9339e2SNick Fitzgerald }
6561a9339e2SNick Fitzgerald 
reloc_section_target<'a>( sections: &'a SectionTable<'a, FileHeader64<Endianness>, &'a [u8]>, section: &'a SectionHeader64<Endianness>, endian: Endianness, ) -> Result<Option<&'a SectionHeader64<Endianness>>>6571a9339e2SNick Fitzgerald fn reloc_section_target<'a>(
6581a9339e2SNick Fitzgerald     sections: &'a SectionTable<'a, FileHeader64<Endianness>, &'a [u8]>,
6591a9339e2SNick Fitzgerald     section: &'a SectionHeader64<Endianness>,
6601a9339e2SNick Fitzgerald     endian: Endianness,
6611a9339e2SNick Fitzgerald ) -> Result<Option<&'a SectionHeader64<Endianness>>> {
6621a9339e2SNick Fitzgerald     if !is_reloc_section(&section, endian) {
6631a9339e2SNick Fitzgerald         return Ok(None);
6641a9339e2SNick Fitzgerald     }
6651a9339e2SNick Fitzgerald 
6661a9339e2SNick Fitzgerald     let sh_info = section.info_link(endian);
6671a9339e2SNick Fitzgerald 
6681a9339e2SNick Fitzgerald     // Dynamic relocation.
6691a9339e2SNick Fitzgerald     if sh_info == SectionIndex(0) {
6701a9339e2SNick Fitzgerald         return Ok(None);
6711a9339e2SNick Fitzgerald     }
6721a9339e2SNick Fitzgerald 
6731a9339e2SNick Fitzgerald     ensure!(
6741a9339e2SNick Fitzgerald         sh_info.0 < sections.len(),
6751a9339e2SNick Fitzgerald         "invalid ELF `sh_info` for relocation section",
6761a9339e2SNick Fitzgerald     );
6771a9339e2SNick Fitzgerald 
6781a9339e2SNick Fitzgerald     Ok(Some(sections.section(sh_info)?))
6791a9339e2SNick Fitzgerald }
6801a9339e2SNick Fitzgerald 
681d4242001SAdam Bratschi-Kaye /// Returns the range of `inner` within `outer`, such that `outer[range]` is the
682d4242001SAdam Bratschi-Kaye /// same as `inner`.
683d4242001SAdam Bratschi-Kaye ///
684d4242001SAdam Bratschi-Kaye /// This method requires that `inner` is a sub-slice of `outer`, and if that
685d4242001SAdam Bratschi-Kaye /// isn't true then this method will panic.
subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize>686d4242001SAdam Bratschi-Kaye fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> {
687d4242001SAdam Bratschi-Kaye     if inner.len() == 0 {
688d4242001SAdam Bratschi-Kaye         return 0..0;
689d4242001SAdam Bratschi-Kaye     }
690d4242001SAdam Bratschi-Kaye 
691d4242001SAdam Bratschi-Kaye     assert!(outer.as_ptr() <= inner.as_ptr());
692d4242001SAdam Bratschi-Kaye     assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _));
693d4242001SAdam Bratschi-Kaye 
694d4242001SAdam Bratschi-Kaye     let start = inner.as_ptr() as usize - outer.as_ptr() as usize;
695d4242001SAdam Bratschi-Kaye     start..start + inner.len()
696d4242001SAdam Bratschi-Kaye }
697