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