wasmtime/runtime/
instantiate.rs

1//! Define the `instantiate` function, which takes a byte array containing an
2//! encoded wasm module and returns a live wasm instance. Also, define
3//! `CompiledModule` to allow compiling and instantiating to be done as separate
4//! steps.
5
6use crate::prelude::*;
7use crate::runtime::vm::{CompiledModuleId, MmapVec};
8use crate::{code_memory::CodeMemory, profiling_agent::ProfilingAgent};
9use alloc::sync::Arc;
10use core::str;
11use wasmtime_environ::{
12    CompiledFunctionsTable, CompiledModuleInfo, DefinedFuncIndex, EntityRef, FilePos, FuncIndex,
13    FuncKey, FunctionLoc, FunctionName, Metadata, Module, ModuleInternedTypeIndex,
14    StaticModuleIndex,
15};
16
17/// A compiled wasm module, ready to be instantiated.
18pub struct CompiledModule {
19    /// A unique ID used to register this module with the engine.
20    unique_id: CompiledModuleId,
21    code_memory: Arc<CodeMemory>,
22    module: Arc<Module>,
23    meta: Metadata,
24    index: Arc<CompiledFunctionsTable>,
25    /// Sorted list, by function index, of names we have for this module.
26    func_names: Vec<FunctionName>,
27}
28
29impl CompiledModule {
30    /// Creates `CompiledModule` directly from a precompiled artifact.
31    ///
32    /// The `code_memory` argument is expected to be the result of a previous
33    /// call to `ObjectBuilder::finish` above. This is an ELF image, at this
34    /// time, which contains all necessary information to create a
35    /// `CompiledModule` from a compilation.
36    ///
37    /// This method also takes `info`, an optionally-provided deserialization
38    /// of the artifacts' compilation metadata section. If this information is
39    /// not provided then the information will be
40    /// deserialized from the image of the compilation artifacts. Otherwise it
41    /// will be assumed to be what would otherwise happen if the section were
42    /// to be deserialized.
43    ///
44    /// The `profiler` argument here is used to inform JIT profiling runtimes
45    /// about new code that is loaded.
46    pub fn from_artifacts(
47        code_memory: Arc<CodeMemory>,
48        info: CompiledModuleInfo,
49        index: Arc<CompiledFunctionsTable>,
50        profiler: &dyn ProfilingAgent,
51    ) -> Result<Self> {
52        let mut ret = Self {
53            unique_id: CompiledModuleId::new(),
54            code_memory,
55            module: Arc::new(info.module),
56            meta: info.meta,
57            index,
58            func_names: info.func_names,
59        };
60        ret.register_profiling(profiler)?;
61
62        Ok(ret)
63    }
64
65    fn register_profiling(&mut self, profiler: &dyn ProfilingAgent) -> Result<()> {
66        // TODO-Bug?: "code_memory" is not exclusive for this module in the case of components,
67        // so we may be registering the same code range multiple times here.
68        profiler.register_module(&self.code_memory.mmap()[..], &|addr| {
69            let idx = self.func_by_text_offset(addr)?;
70            let idx = self.module.func_index(idx);
71            let name = self.func_name(idx)?;
72            let mut demangled = String::new();
73            wasmtime_environ::demangle_function_name(&mut demangled, name).unwrap();
74            Some(demangled)
75        });
76        Ok(())
77    }
78
79    /// Get this module's unique ID. It is unique with respect to a
80    /// single allocator (which is ordinarily held on a Wasm engine).
81    pub fn unique_id(&self) -> CompiledModuleId {
82        self.unique_id
83    }
84
85    /// Returns the underlying memory which contains the compiled module's
86    /// image.
87    pub fn mmap(&self) -> &MmapVec {
88        self.code_memory.mmap()
89    }
90
91    /// Returns the underlying owned mmap of this compiled image.
92    pub fn code_memory(&self) -> &Arc<CodeMemory> {
93        &self.code_memory
94    }
95
96    /// Returns the text section of the ELF image for this compiled module.
97    ///
98    /// This memory should have the read/execute permissions.
99    #[inline]
100    pub fn text(&self) -> &[u8] {
101        self.code_memory.text()
102    }
103
104    /// Return a reference-counting pointer to a module.
105    pub fn module(&self) -> &Arc<Module> {
106        &self.module
107    }
108
109    fn module_index(&self) -> StaticModuleIndex {
110        self.module.module_index
111    }
112
113    /// Looks up the `name` section name for the function index `idx`, if one
114    /// was specified in the original wasm module.
115    pub fn func_name(&self, idx: FuncIndex) -> Option<&str> {
116        // Find entry for `idx`, if present.
117        let i = self.func_names.binary_search_by_key(&idx, |n| n.idx).ok()?;
118        let name = &self.func_names[i];
119
120        // Here we `unwrap` the `from_utf8` but this can theoretically be a
121        // `from_utf8_unchecked` if we really wanted since this section is
122        // guaranteed to only have valid utf-8 data. Until it's a problem it's
123        // probably best to double-check this though.
124        let data = self.code_memory().func_name_data();
125        Some(str::from_utf8(&data[name.offset as usize..][..name.len as usize]).unwrap())
126    }
127
128    /// Returns an iterator over all functions defined within this module with
129    /// their index and their body in memory.
130    #[inline]
131    pub fn finished_functions(
132        &self,
133    ) -> impl ExactSizeIterator<Item = (DefinedFuncIndex, &[u8])> + '_ {
134        self.module
135            .defined_func_indices()
136            .map(|i| (i, self.finished_function(i)))
137    }
138
139    /// Returns the body of the function that `index` points to.
140    #[inline]
141    pub fn finished_function(&self, def_func_index: DefinedFuncIndex) -> &[u8] {
142        let loc = self.func_loc(def_func_index);
143        &self.text()[loc.start as usize..][..loc.length as usize]
144    }
145
146    /// Get the array-to-Wasm trampoline for the function `index` points to.
147    ///
148    /// If the function `index` points to does not escape, then `None` is
149    /// returned.
150    ///
151    /// These trampolines are used for array callers (e.g. `Func::new`)
152    /// calling Wasm callees.
153    pub fn array_to_wasm_trampoline(&self, def_func_index: DefinedFuncIndex) -> Option<&[u8]> {
154        assert!(def_func_index.index() < self.module.num_defined_funcs());
155        let key = FuncKey::ArrayToWasmTrampoline(self.module_index(), def_func_index);
156        let loc = self.index.func_loc(key)?;
157        Some(&self.text()[loc.start as usize..][..loc.length as usize])
158    }
159
160    /// Get the Wasm-to-array trampoline for the given signature.
161    ///
162    /// These trampolines are used for filling in
163    /// `VMFuncRef::wasm_call` for `Func::wrap`-style host funcrefs
164    /// that don't have access to a compiler when created.
165    pub fn wasm_to_array_trampoline(&self, signature: ModuleInternedTypeIndex) -> Option<&[u8]> {
166        let key = FuncKey::WasmToArrayTrampoline(signature);
167        let loc = self.index.func_loc(key)?;
168        Some(&self.text()[loc.start as usize..][..loc.length as usize])
169    }
170
171    /// Lookups a defined function by a program counter value.
172    ///
173    /// Returns the defined function index and the relative address of
174    /// `text_offset` within the function itself.
175    pub fn func_by_text_offset(&self, text_offset: usize) -> Option<DefinedFuncIndex> {
176        let text_offset = u32::try_from(text_offset).unwrap();
177        let key = self.index.func_by_text_offset(text_offset)?;
178        match key {
179            FuncKey::DefinedWasmFunction(module, def_func_index) => {
180                debug_assert_eq!(module, self.module_index());
181                Some(def_func_index)
182            }
183            _ => None,
184        }
185    }
186
187    /// Gets the function location information for a given function index.
188    pub fn func_loc(&self, def_func_index: DefinedFuncIndex) -> &FunctionLoc {
189        assert!(def_func_index.index() < self.module.num_defined_funcs());
190        let key = FuncKey::DefinedWasmFunction(self.module_index(), def_func_index);
191        self.index
192            .func_loc(key)
193            .expect("defined function should be present")
194    }
195
196    /// Returns the original binary offset in the file that `index` was defined
197    /// at.
198    pub fn func_start_srcloc(&self, def_func_index: DefinedFuncIndex) -> FilePos {
199        assert!(def_func_index.index() < self.module.num_defined_funcs());
200        let key = FuncKey::DefinedWasmFunction(self.module_index(), def_func_index);
201        self.index
202            .src_loc(key)
203            .expect("defined function should be present")
204    }
205
206    /// Creates a new symbolication context which can be used to further
207    /// symbolicate stack traces.
208    ///
209    /// Basically this makes a thing which parses debuginfo and can tell you
210    /// what filename and line number a wasm pc comes from.
211    #[cfg(feature = "addr2line")]
212    pub fn symbolize_context(&self) -> Result<Option<SymbolizeContext<'_>>> {
213        use gimli::EndianSlice;
214        if !self.meta.has_wasm_debuginfo {
215            return Ok(None);
216        }
217        let dwarf = gimli::Dwarf::load(|id| -> Result<_> {
218            // Lookup the `id` in the `dwarf` array prepared for this module
219            // during module serialization where it's sorted by the `id` key. If
220            // found this is a range within the general module's concatenated
221            // dwarf section which is extracted here, otherwise it's just an
222            // empty list to represent that it's not present.
223            let data = self
224                .meta
225                .dwarf
226                .binary_search_by_key(&(id as u8), |(id, _)| *id)
227                .ok()
228                .and_then(|i| {
229                    let (_, range) = &self.meta.dwarf[i];
230                    let start = range.start.try_into().ok()?;
231                    let end = range.end.try_into().ok()?;
232                    self.code_memory().wasm_dwarf().get(start..end)
233                })
234                .unwrap_or(&[]);
235            Ok(EndianSlice::new(data, gimli::LittleEndian))
236        })?;
237        let cx = addr2line::Context::from_dwarf(dwarf)
238            .context("failed to create addr2line dwarf mapping context")?;
239        Ok(Some(SymbolizeContext {
240            inner: cx,
241            code_section_offset: self.meta.code_section_offset,
242        }))
243    }
244
245    /// Returns whether the original wasm module had unparsed debug information
246    /// based on the tunables configuration.
247    pub fn has_unparsed_debuginfo(&self) -> bool {
248        self.meta.has_unparsed_debuginfo
249    }
250
251    /// Indicates whether this module came with n address map such that lookups
252    /// via `wasmtime_environ::lookup_file_pos` will succeed.
253    ///
254    /// If this function returns `false` then `lookup_file_pos` will always
255    /// return `None`.
256    pub fn has_address_map(&self) -> bool {
257        !self.code_memory.address_map_data().is_empty()
258    }
259}
260
261#[cfg(feature = "addr2line")]
262type Addr2LineContext<'a> = addr2line::Context<gimli::EndianSlice<'a, gimli::LittleEndian>>;
263
264/// A context which contains dwarf debug information to translate program
265/// counters back to filenames and line numbers.
266#[cfg(feature = "addr2line")]
267pub struct SymbolizeContext<'a> {
268    inner: Addr2LineContext<'a>,
269    code_section_offset: u64,
270}
271
272#[cfg(feature = "addr2line")]
273impl<'a> SymbolizeContext<'a> {
274    /// Returns access to the [`addr2line::Context`] which can be used to query
275    /// frame information with.
276    pub fn addr2line(&self) -> &Addr2LineContext<'a> {
277        &self.inner
278    }
279
280    /// Returns the offset of the code section in the original wasm file, used
281    /// to calculate lookup values into the DWARF.
282    pub fn code_section_offset(&self) -> u64 {
283        self.code_section_offset
284    }
285}