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