1d4242001SAdam Bratschi-Kaye //! Memory management for executable code.
2d4242001SAdam Bratschi-Kaye 
381a89169SAlex Crichton use crate::prelude::*;
472004aadSNick Fitzgerald use crate::runtime::vm::{libcalls, MmapVec, UnwindRegistration};
581a89169SAlex Crichton use core::ops::Range;
6*57cd5a9eSAlex Crichton use object::endian::Endianness;
7f3340930SAlex Crichton use object::read::{elf::ElfFile64, Object, ObjectSection};
8d3132c9dSAlex Crichton use object::{ObjectSymbol, SectionFlags};
966dfa363SJamey Sharp use wasmtime_environ::{lookup_trap_code, obj, Trap};
10d4242001SAdam Bratschi-Kaye 
11d4242001SAdam Bratschi-Kaye /// Management of executable memory within a `MmapVec`
12d4242001SAdam Bratschi-Kaye ///
13d4242001SAdam Bratschi-Kaye /// This type consumes ownership of a region of memory and will manage the
14d4242001SAdam Bratschi-Kaye /// executable permissions of the contained JIT code as necessary.
15d4242001SAdam Bratschi-Kaye pub struct CodeMemory {
16ae3bf36fSSingleAccretion     mmap: MmapVec,
17ae3bf36fSSingleAccretion     unwind_registration: Option<UnwindRegistration>,
18ae3bf36fSSingleAccretion     #[cfg(feature = "debug-builtins")]
19ae3bf36fSSingleAccretion     debug_registration: Option<crate::runtime::vm::GdbJitImageRegistration>,
20d4242001SAdam Bratschi-Kaye     published: bool,
21d4242001SAdam Bratschi-Kaye     enable_branch_protection: bool,
22d3132c9dSAlex Crichton     needs_executable: bool,
23ae3bf36fSSingleAccretion     #[cfg(feature = "debug-builtins")]
24ae3bf36fSSingleAccretion     has_native_debug_info: bool,
25d4242001SAdam Bratschi-Kaye 
26d4242001SAdam Bratschi-Kaye     relocations: Vec<(usize, obj::LibCall)>,
27d4242001SAdam Bratschi-Kaye 
28d4242001SAdam Bratschi-Kaye     // Ranges within `self.mmap` of where the particular sections lie.
29d4242001SAdam Bratschi-Kaye     text: Range<usize>,
30d4242001SAdam Bratschi-Kaye     unwind: Range<usize>,
31d4242001SAdam Bratschi-Kaye     trap_data: Range<usize>,
32d4242001SAdam Bratschi-Kaye     wasm_data: Range<usize>,
33d4242001SAdam Bratschi-Kaye     address_map_data: Range<usize>,
34d4242001SAdam Bratschi-Kaye     func_name_data: Range<usize>,
35d4242001SAdam Bratschi-Kaye     info_data: Range<usize>,
36ae3bf36fSSingleAccretion     wasm_dwarf: Range<usize>,
37d4242001SAdam Bratschi-Kaye }
38d4242001SAdam Bratschi-Kaye 
39d4242001SAdam Bratschi-Kaye impl Drop for CodeMemory {
40d4242001SAdam Bratschi-Kaye     fn drop(&mut self) {
41ae3bf36fSSingleAccretion         // Drop the registrations before `self.mmap` since they (implicitly) refer to it.
42ae3bf36fSSingleAccretion         let _ = self.unwind_registration.take();
43ae3bf36fSSingleAccretion         #[cfg(feature = "debug-builtins")]
44ae3bf36fSSingleAccretion         let _ = self.debug_registration.take();
45d4242001SAdam Bratschi-Kaye     }
46d4242001SAdam Bratschi-Kaye }
47d4242001SAdam Bratschi-Kaye 
48d4242001SAdam Bratschi-Kaye fn _assert() {
49d4242001SAdam Bratschi-Kaye     fn _assert_send_sync<T: Send + Sync>() {}
50d4242001SAdam Bratschi-Kaye     _assert_send_sync::<CodeMemory>();
51d4242001SAdam Bratschi-Kaye }
52d4242001SAdam Bratschi-Kaye 
53d4242001SAdam Bratschi-Kaye impl CodeMemory {
54d4242001SAdam Bratschi-Kaye     /// Creates a new `CodeMemory` by taking ownership of the provided
55d4242001SAdam Bratschi-Kaye     /// `MmapVec`.
56d4242001SAdam Bratschi-Kaye     ///
57d4242001SAdam Bratschi-Kaye     /// The returned `CodeMemory` manages the internal `MmapVec` and the
58d4242001SAdam Bratschi-Kaye     /// `publish` method is used to actually make the memory executable.
59d4242001SAdam Bratschi-Kaye     pub fn new(mmap: MmapVec) -> Result<Self> {
60*57cd5a9eSAlex Crichton         let obj = ElfFile64::<Endianness>::parse(&mmap[..])
6181a89169SAlex Crichton             .err2anyhow()
62d4242001SAdam Bratschi-Kaye             .with_context(|| "failed to parse internal compilation artifact")?;
63d4242001SAdam Bratschi-Kaye 
64d4242001SAdam Bratschi-Kaye         let mut relocations = Vec::new();
65d4242001SAdam Bratschi-Kaye         let mut text = 0..0;
66d4242001SAdam Bratschi-Kaye         let mut unwind = 0..0;
67d4242001SAdam Bratschi-Kaye         let mut enable_branch_protection = None;
68d3132c9dSAlex Crichton         let mut needs_executable = true;
69ae3bf36fSSingleAccretion         #[cfg(feature = "debug-builtins")]
70ae3bf36fSSingleAccretion         let mut has_native_debug_info = false;
71d4242001SAdam Bratschi-Kaye         let mut trap_data = 0..0;
72d4242001SAdam Bratschi-Kaye         let mut wasm_data = 0..0;
73d4242001SAdam Bratschi-Kaye         let mut address_map_data = 0..0;
74d4242001SAdam Bratschi-Kaye         let mut func_name_data = 0..0;
75d4242001SAdam Bratschi-Kaye         let mut info_data = 0..0;
76ae3bf36fSSingleAccretion         let mut wasm_dwarf = 0..0;
77d4242001SAdam Bratschi-Kaye         for section in obj.sections() {
7881a89169SAlex Crichton             let data = section.data().err2anyhow()?;
7981a89169SAlex Crichton             let name = section.name().err2anyhow()?;
80d4242001SAdam Bratschi-Kaye             let range = subslice_range(data, &mmap);
81d4242001SAdam Bratschi-Kaye 
82d4242001SAdam Bratschi-Kaye             // Double-check that sections are all aligned properly.
83d4242001SAdam Bratschi-Kaye             if section.align() != 0 && data.len() != 0 {
84d4242001SAdam Bratschi-Kaye                 if (data.as_ptr() as u64 - mmap.as_ptr() as u64) % section.align() != 0 {
85d4242001SAdam Bratschi-Kaye                     bail!(
86d4242001SAdam Bratschi-Kaye                         "section `{}` isn't aligned to {:#x}",
87d4242001SAdam Bratschi-Kaye                         section.name().unwrap_or("ERROR"),
88d4242001SAdam Bratschi-Kaye                         section.align()
89d4242001SAdam Bratschi-Kaye                     );
90d4242001SAdam Bratschi-Kaye                 }
91d4242001SAdam Bratschi-Kaye             }
92d4242001SAdam Bratschi-Kaye 
93d4242001SAdam Bratschi-Kaye             match name {
94d4242001SAdam Bratschi-Kaye                 obj::ELF_WASM_BTI => match data.len() {
95d4242001SAdam Bratschi-Kaye                     1 => enable_branch_protection = Some(data[0] != 0),
96d4242001SAdam Bratschi-Kaye                     _ => bail!("invalid `{name}` section"),
97d4242001SAdam Bratschi-Kaye                 },
98d4242001SAdam Bratschi-Kaye                 ".text" => {
99d4242001SAdam Bratschi-Kaye                     text = range;
100d4242001SAdam Bratschi-Kaye 
101d3132c9dSAlex Crichton                     if let SectionFlags::Elf { sh_flags } = section.flags() {
102d3132c9dSAlex Crichton                         if sh_flags & obj::SH_WASMTIME_NOT_EXECUTED != 0 {
103d3132c9dSAlex Crichton                             needs_executable = false;
104d3132c9dSAlex Crichton                         }
105d3132c9dSAlex Crichton                     }
106d3132c9dSAlex Crichton 
107d4242001SAdam Bratschi-Kaye                     // The text section might have relocations for things like
108d4242001SAdam Bratschi-Kaye                     // libcalls which need to be applied, so handle those here.
109d4242001SAdam Bratschi-Kaye                     //
110d4242001SAdam Bratschi-Kaye                     // Note that only a small subset of possible relocations are
111d4242001SAdam Bratschi-Kaye                     // handled. Only those required by the compiler side of
112d4242001SAdam Bratschi-Kaye                     // things are processed.
113d4242001SAdam Bratschi-Kaye                     for (offset, reloc) in section.relocations() {
114d4242001SAdam Bratschi-Kaye                         assert_eq!(reloc.kind(), object::RelocationKind::Absolute);
115d4242001SAdam Bratschi-Kaye                         assert_eq!(reloc.encoding(), object::RelocationEncoding::Generic);
11681a89169SAlex Crichton                         assert_eq!(usize::from(reloc.size()), core::mem::size_of::<usize>() * 8);
117d4242001SAdam Bratschi-Kaye                         assert_eq!(reloc.addend(), 0);
118d4242001SAdam Bratschi-Kaye                         let sym = match reloc.target() {
119d4242001SAdam Bratschi-Kaye                             object::RelocationTarget::Symbol(id) => id,
120d4242001SAdam Bratschi-Kaye                             other => panic!("unknown relocation target {other:?}"),
121d4242001SAdam Bratschi-Kaye                         };
122d4242001SAdam Bratschi-Kaye                         let sym = obj.symbol_by_index(sym).unwrap().name().unwrap();
123d4242001SAdam Bratschi-Kaye                         let libcall = obj::LibCall::from_str(sym)
124d4242001SAdam Bratschi-Kaye                             .unwrap_or_else(|| panic!("unknown symbol relocation: {sym}"));
125d4242001SAdam Bratschi-Kaye 
126d4242001SAdam Bratschi-Kaye                         let offset = usize::try_from(offset).unwrap();
127d4242001SAdam Bratschi-Kaye                         relocations.push((offset, libcall));
128d4242001SAdam Bratschi-Kaye                     }
129d4242001SAdam Bratschi-Kaye                 }
130d4242001SAdam Bratschi-Kaye                 UnwindRegistration::SECTION_NAME => unwind = range,
131d4242001SAdam Bratschi-Kaye                 obj::ELF_WASM_DATA => wasm_data = range,
132d4242001SAdam Bratschi-Kaye                 obj::ELF_WASMTIME_ADDRMAP => address_map_data = range,
133d4242001SAdam Bratschi-Kaye                 obj::ELF_WASMTIME_TRAPS => trap_data = range,
134d4242001SAdam Bratschi-Kaye                 obj::ELF_NAME_DATA => func_name_data = range,
135d4242001SAdam Bratschi-Kaye                 obj::ELF_WASMTIME_INFO => info_data = range,
136ae3bf36fSSingleAccretion                 obj::ELF_WASMTIME_DWARF => wasm_dwarf = range,
137ae3bf36fSSingleAccretion                 #[cfg(feature = "debug-builtins")]
138ae3bf36fSSingleAccretion                 ".debug_info" => has_native_debug_info = true,
139d4242001SAdam Bratschi-Kaye 
140d4242001SAdam Bratschi-Kaye                 _ => log::debug!("ignoring section {name}"),
141d4242001SAdam Bratschi-Kaye             }
142d4242001SAdam Bratschi-Kaye         }
143d4242001SAdam Bratschi-Kaye         Ok(Self {
144ae3bf36fSSingleAccretion             mmap,
145ae3bf36fSSingleAccretion             unwind_registration: None,
146ae3bf36fSSingleAccretion             #[cfg(feature = "debug-builtins")]
147ae3bf36fSSingleAccretion             debug_registration: None,
148d4242001SAdam Bratschi-Kaye             published: false,
149d4242001SAdam Bratschi-Kaye             enable_branch_protection: enable_branch_protection
150d4242001SAdam Bratschi-Kaye                 .ok_or_else(|| anyhow!("missing `{}` section", obj::ELF_WASM_BTI))?,
151d3132c9dSAlex Crichton             needs_executable,
152ae3bf36fSSingleAccretion             #[cfg(feature = "debug-builtins")]
153ae3bf36fSSingleAccretion             has_native_debug_info,
154d4242001SAdam Bratschi-Kaye             text,
155d4242001SAdam Bratschi-Kaye             unwind,
156d4242001SAdam Bratschi-Kaye             trap_data,
157d4242001SAdam Bratschi-Kaye             address_map_data,
158d4242001SAdam Bratschi-Kaye             func_name_data,
159ae3bf36fSSingleAccretion             wasm_dwarf,
160d4242001SAdam Bratschi-Kaye             info_data,
161d4242001SAdam Bratschi-Kaye             wasm_data,
162d4242001SAdam Bratschi-Kaye             relocations,
163d4242001SAdam Bratschi-Kaye         })
164d4242001SAdam Bratschi-Kaye     }
165d4242001SAdam Bratschi-Kaye 
166d4242001SAdam Bratschi-Kaye     /// Returns a reference to the underlying `MmapVec` this memory owns.
167d4242001SAdam Bratschi-Kaye     #[inline]
168d4242001SAdam Bratschi-Kaye     pub fn mmap(&self) -> &MmapVec {
169d4242001SAdam Bratschi-Kaye         &self.mmap
170d4242001SAdam Bratschi-Kaye     }
171d4242001SAdam Bratschi-Kaye 
172d4242001SAdam Bratschi-Kaye     /// Returns the contents of the text section of the ELF executable this
173d4242001SAdam Bratschi-Kaye     /// represents.
174d4242001SAdam Bratschi-Kaye     #[inline]
175d4242001SAdam Bratschi-Kaye     pub fn text(&self) -> &[u8] {
176d4242001SAdam Bratschi-Kaye         &self.mmap[self.text.clone()]
177d4242001SAdam Bratschi-Kaye     }
178d4242001SAdam Bratschi-Kaye 
179d4242001SAdam Bratschi-Kaye     /// Returns the contents of the `ELF_WASMTIME_DWARF` section.
180d4242001SAdam Bratschi-Kaye     #[inline]
181ae3bf36fSSingleAccretion     pub fn wasm_dwarf(&self) -> &[u8] {
182ae3bf36fSSingleAccretion         &self.mmap[self.wasm_dwarf.clone()]
183d4242001SAdam Bratschi-Kaye     }
184d4242001SAdam Bratschi-Kaye 
185d4242001SAdam Bratschi-Kaye     /// Returns the data in the `ELF_NAME_DATA` section.
186d4242001SAdam Bratschi-Kaye     #[inline]
187d4242001SAdam Bratschi-Kaye     pub fn func_name_data(&self) -> &[u8] {
188d4242001SAdam Bratschi-Kaye         &self.mmap[self.func_name_data.clone()]
189d4242001SAdam Bratschi-Kaye     }
190d4242001SAdam Bratschi-Kaye 
191d4242001SAdam Bratschi-Kaye     /// Returns the concatenated list of all data associated with this wasm
192d4242001SAdam Bratschi-Kaye     /// module.
193d4242001SAdam Bratschi-Kaye     ///
194d4242001SAdam Bratschi-Kaye     /// This is used for initialization of memories and all data ranges stored
195d4242001SAdam Bratschi-Kaye     /// in a `Module` are relative to the slice returned here.
196d4242001SAdam Bratschi-Kaye     #[inline]
197d4242001SAdam Bratschi-Kaye     pub fn wasm_data(&self) -> &[u8] {
198d4242001SAdam Bratschi-Kaye         &self.mmap[self.wasm_data.clone()]
199d4242001SAdam Bratschi-Kaye     }
200d4242001SAdam Bratschi-Kaye 
201d4242001SAdam Bratschi-Kaye     /// Returns the encoded address map section used to pass to
202d4242001SAdam Bratschi-Kaye     /// `wasmtime_environ::lookup_file_pos`.
203d4242001SAdam Bratschi-Kaye     #[inline]
204d4242001SAdam Bratschi-Kaye     pub fn address_map_data(&self) -> &[u8] {
205d4242001SAdam Bratschi-Kaye         &self.mmap[self.address_map_data.clone()]
206d4242001SAdam Bratschi-Kaye     }
207d4242001SAdam Bratschi-Kaye 
208d4242001SAdam Bratschi-Kaye     /// Returns the contents of the `ELF_WASMTIME_INFO` section, or an empty
209d4242001SAdam Bratschi-Kaye     /// slice if it wasn't found.
210d4242001SAdam Bratschi-Kaye     #[inline]
211d4242001SAdam Bratschi-Kaye     pub fn wasmtime_info(&self) -> &[u8] {
212d4242001SAdam Bratschi-Kaye         &self.mmap[self.info_data.clone()]
213d4242001SAdam Bratschi-Kaye     }
214d4242001SAdam Bratschi-Kaye 
215d4242001SAdam Bratschi-Kaye     /// Returns the contents of the `ELF_WASMTIME_TRAPS` section, or an empty
216d4242001SAdam Bratschi-Kaye     /// slice if it wasn't found.
217d4242001SAdam Bratschi-Kaye     #[inline]
218d4242001SAdam Bratschi-Kaye     pub fn trap_data(&self) -> &[u8] {
219d4242001SAdam Bratschi-Kaye         &self.mmap[self.trap_data.clone()]
220d4242001SAdam Bratschi-Kaye     }
221d4242001SAdam Bratschi-Kaye 
222d4242001SAdam Bratschi-Kaye     /// Publishes the internal ELF image to be ready for execution.
223d4242001SAdam Bratschi-Kaye     ///
224d4242001SAdam Bratschi-Kaye     /// This method can only be called once and will panic if called twice. This
225d4242001SAdam Bratschi-Kaye     /// will parse the ELF image from the original `MmapVec` and do everything
226d4242001SAdam Bratschi-Kaye     /// necessary to get it ready for execution, including:
227d4242001SAdam Bratschi-Kaye     ///
228d4242001SAdam Bratschi-Kaye     /// * Change page protections from read/write to read/execute.
229d4242001SAdam Bratschi-Kaye     /// * Register unwinding information with the OS
230ae3bf36fSSingleAccretion     /// * Register this image with the debugger if native DWARF is present
231d4242001SAdam Bratschi-Kaye     ///
232d4242001SAdam Bratschi-Kaye     /// After this function executes all JIT code should be ready to execute.
233d4242001SAdam Bratschi-Kaye     pub fn publish(&mut self) -> Result<()> {
234d4242001SAdam Bratschi-Kaye         assert!(!self.published);
235d4242001SAdam Bratschi-Kaye         self.published = true;
236d4242001SAdam Bratschi-Kaye 
237d4242001SAdam Bratschi-Kaye         if self.text().is_empty() {
238d4242001SAdam Bratschi-Kaye             return Ok(());
239d4242001SAdam Bratschi-Kaye         }
240d4242001SAdam Bratschi-Kaye 
241d4242001SAdam Bratschi-Kaye         // The unsafety here comes from a few things:
242d4242001SAdam Bratschi-Kaye         //
243d4242001SAdam Bratschi-Kaye         // * We're actually updating some page protections to executable memory.
244d4242001SAdam Bratschi-Kaye         //
245d4242001SAdam Bratschi-Kaye         // * We're registering unwinding information which relies on the
246d4242001SAdam Bratschi-Kaye         //   correctness of the information in the first place. This applies to
247d4242001SAdam Bratschi-Kaye         //   both the actual unwinding tables as well as the validity of the
248d4242001SAdam Bratschi-Kaye         //   pointers we pass in itself.
249d4242001SAdam Bratschi-Kaye         unsafe {
250d4242001SAdam Bratschi-Kaye             // First, if necessary, apply relocations. This can happen for
251d4242001SAdam Bratschi-Kaye             // things like libcalls which happen late in the lowering process
252d4242001SAdam Bratschi-Kaye             // that don't go through the Wasm-based libcalls layer that's
253d4242001SAdam Bratschi-Kaye             // indirected through the `VMContext`. Note that most modules won't
254d4242001SAdam Bratschi-Kaye             // have relocations, so this typically doesn't do anything.
255d4242001SAdam Bratschi-Kaye             self.apply_relocations()?;
256d4242001SAdam Bratschi-Kaye 
257d4242001SAdam Bratschi-Kaye             // Next freeze the contents of this image by making all of the
258d4242001SAdam Bratschi-Kaye             // memory readonly. Nothing after this point should ever be modified
259d4242001SAdam Bratschi-Kaye             // so commit everything. For a compiled-in-memory image this will
260d4242001SAdam Bratschi-Kaye             // mean IPIs to evict writable mappings from other cores. For
261d4242001SAdam Bratschi-Kaye             // loaded-from-disk images this shouldn't result in IPIs so long as
262d4242001SAdam Bratschi-Kaye             // there weren't any relocations because nothing should have
263d4242001SAdam Bratschi-Kaye             // otherwise written to the image at any point either.
264d3132c9dSAlex Crichton             //
265d3132c9dSAlex Crichton             // Note that if virtual memory is disabled this is skipped because
266d3132c9dSAlex Crichton             // we aren't able to make it readonly, but this is just a
267d3132c9dSAlex Crichton             // defense-in-depth measure and isn't required for correctness.
268d3132c9dSAlex Crichton             #[cfg(feature = "signals-based-traps")]
269d4242001SAdam Bratschi-Kaye             self.mmap.make_readonly(0..self.mmap.len())?;
270d4242001SAdam Bratschi-Kaye 
271d3132c9dSAlex Crichton             // Switch the executable portion from readonly to read/execute.
272d3132c9dSAlex Crichton             if self.needs_executable {
273d3132c9dSAlex Crichton                 #[cfg(feature = "signals-based-traps")]
274d3132c9dSAlex Crichton                 {
275d4242001SAdam Bratschi-Kaye                     let text = self.text();
276d4242001SAdam Bratschi-Kaye 
277d3132c9dSAlex Crichton                     use wasmtime_jit_icache_coherence as icache_coherence;
278d3132c9dSAlex Crichton 
279d4242001SAdam Bratschi-Kaye                     // Clear the newly allocated code from cache if the processor requires it
280d4242001SAdam Bratschi-Kaye                     //
281d4242001SAdam Bratschi-Kaye                     // Do this before marking the memory as R+X, technically we should be able to do it after
282d4242001SAdam Bratschi-Kaye                     // but there are some CPU's that have had errata about doing this with read only memory.
283d4242001SAdam Bratschi-Kaye                     icache_coherence::clear_cache(text.as_ptr().cast(), text.len())
284d4242001SAdam Bratschi-Kaye                         .expect("Failed cache clear");
285d4242001SAdam Bratschi-Kaye 
286d4242001SAdam Bratschi-Kaye                     self.mmap
287d4242001SAdam Bratschi-Kaye                         .make_executable(self.text.clone(), self.enable_branch_protection)
288d4242001SAdam Bratschi-Kaye                         .context("unable to make memory executable")?;
289d4242001SAdam Bratschi-Kaye 
290d4242001SAdam Bratschi-Kaye                     // Flush any in-flight instructions from the pipeline
291d4242001SAdam Bratschi-Kaye                     icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush");
292d3132c9dSAlex Crichton                 }
293d3132c9dSAlex Crichton                 #[cfg(not(feature = "signals-based-traps"))]
294d3132c9dSAlex Crichton                 bail!("this target requires virtual memory to be enabled");
295d3132c9dSAlex Crichton             }
296d4242001SAdam Bratschi-Kaye 
297d4242001SAdam Bratschi-Kaye             // With all our memory set up use the platform-specific
298d4242001SAdam Bratschi-Kaye             // `UnwindRegistration` implementation to inform the general
299d4242001SAdam Bratschi-Kaye             // runtime that there's unwinding information available for all
300d4242001SAdam Bratschi-Kaye             // our just-published JIT functions.
301d4242001SAdam Bratschi-Kaye             self.register_unwind_info()?;
302ae3bf36fSSingleAccretion 
303ae3bf36fSSingleAccretion             #[cfg(feature = "debug-builtins")]
304ae3bf36fSSingleAccretion             self.register_debug_image()?;
305d4242001SAdam Bratschi-Kaye         }
306d4242001SAdam Bratschi-Kaye 
307d4242001SAdam Bratschi-Kaye         Ok(())
308d4242001SAdam Bratschi-Kaye     }
309d4242001SAdam Bratschi-Kaye 
310d4242001SAdam Bratschi-Kaye     unsafe fn apply_relocations(&mut self) -> Result<()> {
311d4242001SAdam Bratschi-Kaye         if self.relocations.is_empty() {
312d4242001SAdam Bratschi-Kaye             return Ok(());
313d4242001SAdam Bratschi-Kaye         }
314d4242001SAdam Bratschi-Kaye 
315d4242001SAdam Bratschi-Kaye         for (offset, libcall) in self.relocations.iter() {
316d4242001SAdam Bratschi-Kaye             let offset = self.text.start + offset;
317d4242001SAdam Bratschi-Kaye             let libcall = match libcall {
318d4242001SAdam Bratschi-Kaye                 obj::LibCall::FloorF32 => libcalls::relocs::floorf32 as usize,
319d4242001SAdam Bratschi-Kaye                 obj::LibCall::FloorF64 => libcalls::relocs::floorf64 as usize,
320d4242001SAdam Bratschi-Kaye                 obj::LibCall::NearestF32 => libcalls::relocs::nearestf32 as usize,
321d4242001SAdam Bratschi-Kaye                 obj::LibCall::NearestF64 => libcalls::relocs::nearestf64 as usize,
322d4242001SAdam Bratschi-Kaye                 obj::LibCall::CeilF32 => libcalls::relocs::ceilf32 as usize,
323d4242001SAdam Bratschi-Kaye                 obj::LibCall::CeilF64 => libcalls::relocs::ceilf64 as usize,
324d4242001SAdam Bratschi-Kaye                 obj::LibCall::TruncF32 => libcalls::relocs::truncf32 as usize,
325d4242001SAdam Bratschi-Kaye                 obj::LibCall::TruncF64 => libcalls::relocs::truncf64 as usize,
326d4242001SAdam Bratschi-Kaye                 obj::LibCall::FmaF32 => libcalls::relocs::fmaf32 as usize,
327d4242001SAdam Bratschi-Kaye                 obj::LibCall::FmaF64 => libcalls::relocs::fmaf64 as usize,
328d4242001SAdam Bratschi-Kaye                 #[cfg(target_arch = "x86_64")]
329d4242001SAdam Bratschi-Kaye                 obj::LibCall::X86Pshufb => libcalls::relocs::x86_pshufb as usize,
330d4242001SAdam Bratschi-Kaye                 #[cfg(not(target_arch = "x86_64"))]
331d4242001SAdam Bratschi-Kaye                 obj::LibCall::X86Pshufb => unreachable!(),
332d4242001SAdam Bratschi-Kaye             };
333d4242001SAdam Bratschi-Kaye             self.mmap
334d3132c9dSAlex Crichton                 .as_mut_slice()
335d4242001SAdam Bratschi-Kaye                 .as_mut_ptr()
336d4242001SAdam Bratschi-Kaye                 .add(offset)
337d4242001SAdam Bratschi-Kaye                 .cast::<usize>()
338d4242001SAdam Bratschi-Kaye                 .write_unaligned(libcall);
339d4242001SAdam Bratschi-Kaye         }
340d4242001SAdam Bratschi-Kaye         Ok(())
341d4242001SAdam Bratschi-Kaye     }
342d4242001SAdam Bratschi-Kaye 
343d4242001SAdam Bratschi-Kaye     unsafe fn register_unwind_info(&mut self) -> Result<()> {
344d4242001SAdam Bratschi-Kaye         if self.unwind.len() == 0 {
345d4242001SAdam Bratschi-Kaye             return Ok(());
346d4242001SAdam Bratschi-Kaye         }
347d4242001SAdam Bratschi-Kaye         let text = self.text();
348d4242001SAdam Bratschi-Kaye         let unwind_info = &self.mmap[self.unwind.clone()];
349d4242001SAdam Bratschi-Kaye         let registration =
350d4242001SAdam Bratschi-Kaye             UnwindRegistration::new(text.as_ptr(), unwind_info.as_ptr(), unwind_info.len())
351d4242001SAdam Bratschi-Kaye                 .context("failed to create unwind info registration")?;
352ae3bf36fSSingleAccretion         self.unwind_registration = Some(registration);
353ae3bf36fSSingleAccretion         Ok(())
354ae3bf36fSSingleAccretion     }
355ae3bf36fSSingleAccretion 
356ae3bf36fSSingleAccretion     #[cfg(feature = "debug-builtins")]
357ae3bf36fSSingleAccretion     fn register_debug_image(&mut self) -> Result<()> {
358ae3bf36fSSingleAccretion         if !self.has_native_debug_info {
359ae3bf36fSSingleAccretion             return Ok(());
360ae3bf36fSSingleAccretion         }
361ae3bf36fSSingleAccretion 
362ae3bf36fSSingleAccretion         // TODO-DebugInfo: we're copying the whole image here, which is pretty wasteful.
363ae3bf36fSSingleAccretion         // Use the existing memory by teaching code here about relocations in DWARF sections
364ae3bf36fSSingleAccretion         // and anything else necessary that is done in "create_gdbjit_image" right now.
365ae3bf36fSSingleAccretion         let image = self.mmap().to_vec();
366ae3bf36fSSingleAccretion         let text: &[u8] = self.text();
367ae3bf36fSSingleAccretion         let bytes = crate::debug::create_gdbjit_image(image, (text.as_ptr(), text.len()))?;
368ae3bf36fSSingleAccretion         let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes);
369ae3bf36fSSingleAccretion         self.debug_registration = Some(reg);
370d4242001SAdam Bratschi-Kaye         Ok(())
371d4242001SAdam Bratschi-Kaye     }
37266dfa363SJamey Sharp 
37366dfa363SJamey Sharp     /// Looks up the given offset within this module's text section and returns
37466dfa363SJamey Sharp     /// the trap code associated with that instruction, if there is one.
37566dfa363SJamey Sharp     pub fn lookup_trap_code(&self, text_offset: usize) -> Option<Trap> {
37666dfa363SJamey Sharp         lookup_trap_code(self.trap_data(), text_offset)
37766dfa363SJamey Sharp     }
378d4242001SAdam Bratschi-Kaye }
379d4242001SAdam Bratschi-Kaye 
380d4242001SAdam Bratschi-Kaye /// Returns the range of `inner` within `outer`, such that `outer[range]` is the
381d4242001SAdam Bratschi-Kaye /// same as `inner`.
382d4242001SAdam Bratschi-Kaye ///
383d4242001SAdam Bratschi-Kaye /// This method requires that `inner` is a sub-slice of `outer`, and if that
384d4242001SAdam Bratschi-Kaye /// isn't true then this method will panic.
385d4242001SAdam Bratschi-Kaye fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> {
386d4242001SAdam Bratschi-Kaye     if inner.len() == 0 {
387d4242001SAdam Bratschi-Kaye         return 0..0;
388d4242001SAdam Bratschi-Kaye     }
389d4242001SAdam Bratschi-Kaye 
390d4242001SAdam Bratschi-Kaye     assert!(outer.as_ptr() <= inner.as_ptr());
391d4242001SAdam Bratschi-Kaye     assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _));
392d4242001SAdam Bratschi-Kaye 
393d4242001SAdam Bratschi-Kaye     let start = inner.as_ptr() as usize - outer.as_ptr() as usize;
394d4242001SAdam Bratschi-Kaye     start..start + inner.len()
395d4242001SAdam Bratschi-Kaye }
396