pub struct CodeMemory { /* private fields */ }
Expand description

Management of executable memory within a MmapVec

This type consumes ownership of a region of memory and will manage the executable permissions of the contained JIT code as necessary.

Implementations§

Creates a new CodeMemory by taking ownership of the provided MmapVec.

The returned CodeMemory manages the internal MmapVec and the publish method is used to actually make the memory executable.

Returns a reference to the underlying MmapVec this memory owns.

Examples found in repository?
src/instantiate.rs (line 444)
443
444
445
    pub fn mmap(&self) -> &MmapVec {
        self.code_memory.mmap()
    }

Returns the contents of the text section of the ELF executable this represents.

Examples found in repository?
src/instantiate.rs (line 456)
455
456
457
    pub fn text(&self) -> &[u8] {
        self.code_memory.text()
    }
More examples
Hide additional examples
src/code_memory.rs (line 229)
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    pub unsafe fn vmtrampoline(&self, loc: FunctionLoc) -> VMTrampoline {
        let ptr = self.text()[loc.start as usize..][..loc.length as usize].as_ptr();
        mem::transmute::<*const u8, VMTrampoline>(ptr)
    }

    /// Publishes the internal ELF image to be ready for execution.
    ///
    /// This method can only be called once and will panic if called twice. This
    /// will parse the ELF image from the original `MmapVec` and do everything
    /// necessary to get it ready for execution, including:
    ///
    /// * Change page protections from read/write to read/execute.
    /// * Register unwinding information with the OS
    ///
    /// After this function executes all JIT code should be ready to execute.
    pub fn publish(&mut self) -> Result<()> {
        assert!(!self.published);
        self.published = true;

        if self.text().is_empty() {
            return Ok(());
        }

        // The unsafety here comes from a few things:
        //
        // * We're actually updating some page protections to executable memory.
        //
        // * We're registering unwinding information which relies on the
        //   correctness of the information in the first place. This applies to
        //   both the actual unwinding tables as well as the validity of the
        //   pointers we pass in itself.
        unsafe {
            let text = self.text();

            // Clear the newly allocated code from cache if the processor requires it
            //
            // Do this before marking the memory as R+X, technically we should be able to do it after
            // but there are some CPU's that have had errata about doing this with read only memory.
            icache_coherence::clear_cache(text.as_ptr().cast(), text.len())
                .expect("Failed cache clear");

            // Switch the executable portion from read/write to
            // read/execute, notably not using read/write/execute to prevent
            // modifications.
            self.mmap
                .make_executable(self.text.clone(), self.enable_branch_protection)
                .expect("unable to make memory executable");

            // Flush any in-flight instructions from the pipeline
            icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush");

            // With all our memory set up use the platform-specific
            // `UnwindRegistration` implementation to inform the general
            // runtime that there's unwinding information available for all
            // our just-published JIT functions.
            self.register_unwind_info()?;
        }

        Ok(())
    }

    unsafe fn register_unwind_info(&mut self) -> Result<()> {
        if self.unwind.len() == 0 {
            return Ok(());
        }
        let text = self.text();
        let unwind_info = &self.mmap[self.unwind.clone()];
        let registration =
            UnwindRegistration::new(text.as_ptr(), unwind_info.as_ptr(), unwind_info.len())
                .context("failed to create unwind info registration")?;
        *self.unwind_registration = Some(registration);
        Ok(())
    }

Returns the data in the corresponding dwarf section, or an empty slice if the section wasn’t present.

Examples found in repository?
src/instantiate.rs (line 594)
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
    pub fn symbolize_context(&self) -> Result<Option<SymbolizeContext<'_>>> {
        use gimli::EndianSlice;
        if !self.meta.has_wasm_debuginfo {
            return Ok(None);
        }
        let dwarf = gimli::Dwarf::load(|id| -> Result<_> {
            let data = self.code_memory().dwarf_section(id);
            Ok(EndianSlice::new(data, gimli::LittleEndian))
        })?;
        let cx = addr2line::Context::from_dwarf(dwarf)
            .context("failed to create addr2line dwarf mapping context")?;
        Ok(Some(SymbolizeContext {
            inner: cx,
            code_section_offset: self.meta.code_section_offset,
        }))
    }

Returns the data in the ELF_NAME_DATA section.

Examples found in repository?
src/instantiate.rs (line 475)
466
467
468
469
470
471
472
473
474
475
476
477
    pub fn func_name(&self, idx: FuncIndex) -> Option<&str> {
        // Find entry for `idx`, if present.
        let i = self.func_names.binary_search_by_key(&idx, |n| n.idx).ok()?;
        let name = &self.func_names[i];

        // Here we `unwrap` the `from_utf8` but this can theoretically be a
        // `from_utf8_unchecked` if we really wanted since this section is
        // guaranteed to only have valid utf-8 data. Until it's a problem it's
        // probably best to double-check this though.
        let data = self.code_memory().func_name_data();
        Some(str::from_utf8(&data[name.offset as usize..][..name.len as usize]).unwrap())
    }

Returns the concatenated list of all data associated with this wasm module.

This is used for initialization of memories and all data ranges stored in a Module are relative to the slice returned here.

Returns the encoded address map section used to pass to wasmtime_environ::lookup_file_pos.

Examples found in repository?
src/instantiate.rs (line 617)
616
617
618
    pub fn has_address_map(&self) -> bool {
        !self.code_memory.address_map_data().is_empty()
    }

Returns the contents of the ELF_WASMTIME_INFO section, or an empty slice if it wasn’t found.

Returns the contents of the ELF_WASMTIME_TRAPS section, or an empty slice if it wasn’t found.

Returns a VMTrampoline function pointer for the given function in the text section.

Unsafety

This function is unsafe as there’s no guarantee that the returned function pointer is valid.

Publishes the internal ELF image to be ready for execution.

This method can only be called once and will panic if called twice. This will parse the ELF image from the original MmapVec and do everything necessary to get it ready for execution, including:

  • Change page protections from read/write to read/execute.
  • Register unwinding information with the OS

After this function executes all JIT code should be ready to execute.

Trait Implementations§

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.