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}