wasmtime/runtime/
instantiate.rs1use 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 CompiledFunctionInfo, CompiledModuleInfo, DefinedFuncIndex, FuncIndex, FunctionLoc,
13 FunctionName, Metadata, Module, ModuleInternedTypeIndex, PrimaryMap, StackMapInformation,
14 WasmFunctionInfo,
15};
16
17pub struct CompiledModule {
19 module: Arc<Module>,
20 funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>,
21 wasm_to_array_trampolines: Vec<(ModuleInternedTypeIndex, FunctionLoc)>,
22 meta: Metadata,
23 code_memory: Arc<CodeMemory>,
24 #[cfg(feature = "debug-builtins")]
25 dbg_jit_registration: Option<crate::runtime::vm::GdbJitImageRegistration>,
26 unique_id: CompiledModuleId,
28 func_names: Vec<FunctionName>,
29}
30
31impl CompiledModule {
32 pub fn from_artifacts(
49 code_memory: Arc<CodeMemory>,
50 info: CompiledModuleInfo,
51 profiler: &dyn ProfilingAgent,
52 ) -> Result<Self> {
53 let mut ret = Self {
54 module: Arc::new(info.module),
55 funcs: info.funcs,
56 wasm_to_array_trampolines: info.wasm_to_array_trampolines,
57 #[cfg(feature = "debug-builtins")]
58 dbg_jit_registration: None,
59 code_memory,
60 meta: info.meta,
61 unique_id: CompiledModuleId::new(),
62 func_names: info.func_names,
63 };
64 ret.register_debug_and_profiling(profiler)?;
65
66 Ok(ret)
67 }
68
69 fn register_debug_and_profiling(&mut self, profiler: &dyn ProfilingAgent) -> Result<()> {
70 #[cfg(feature = "debug-builtins")]
71 if self.meta.native_debug_info_present {
72 let text = self.text();
73 let bytes = crate::debug::create_gdbjit_image(
74 self.mmap().to_vec(),
75 (text.as_ptr(), text.len()),
76 )
77 .context("failed to create jit image for gdb")?;
78 let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes);
79 self.dbg_jit_registration = Some(reg);
80 }
81 profiler.register_module(&self.code_memory.mmap()[..], &|addr| {
82 let (idx, _) = self.func_by_text_offset(addr)?;
83 let idx = self.module.func_index(idx);
84 let name = self.func_name(idx)?;
85 let mut demangled = String::new();
86 wasmtime_environ::demangle_function_name(&mut demangled, name).unwrap();
87 Some(demangled)
88 });
89 Ok(())
90 }
91
92 pub fn unique_id(&self) -> CompiledModuleId {
95 self.unique_id
96 }
97
98 pub fn mmap(&self) -> &MmapVec {
101 self.code_memory.mmap()
102 }
103
104 pub fn code_memory(&self) -> &Arc<CodeMemory> {
106 &self.code_memory
107 }
108
109 #[inline]
113 pub fn text(&self) -> &[u8] {
114 self.code_memory.text()
115 }
116
117 pub fn module(&self) -> &Arc<Module> {
119 &self.module
120 }
121
122 pub fn func_name(&self, idx: FuncIndex) -> Option<&str> {
125 let i = self.func_names.binary_search_by_key(&idx, |n| n.idx).ok()?;
127 let name = &self.func_names[i];
128
129 let data = self.code_memory().func_name_data();
134 Some(str::from_utf8(&data[name.offset as usize..][..name.len as usize]).unwrap())
135 }
136
137 pub fn module_mut(&mut self) -> Option<&mut Module> {
139 Arc::get_mut(&mut self.module)
140 }
141
142 #[inline]
145 pub fn finished_functions(
146 &self,
147 ) -> impl ExactSizeIterator<Item = (DefinedFuncIndex, &[u8])> + '_ {
148 self.funcs
149 .iter()
150 .map(move |(i, _)| (i, self.finished_function(i)))
151 }
152
153 #[inline]
155 pub fn finished_function(&self, index: DefinedFuncIndex) -> &[u8] {
156 let loc = self.funcs[index].wasm_func_loc;
157 &self.text()[loc.start as usize..][..loc.length as usize]
158 }
159
160 pub fn array_to_wasm_trampoline(&self, index: DefinedFuncIndex) -> Option<&[u8]> {
168 let loc = self.funcs[index].array_to_wasm_trampoline?;
169 Some(&self.text()[loc.start as usize..][..loc.length as usize])
170 }
171
172 pub fn wasm_to_array_trampoline(&self, signature: ModuleInternedTypeIndex) -> &[u8] {
178 let idx = match self
179 .wasm_to_array_trampolines
180 .binary_search_by_key(&signature, |entry| entry.0)
181 {
182 Ok(idx) => idx,
183 Err(_) => panic!("missing trampoline for {signature:?}"),
184 };
185
186 let (_, loc) = self.wasm_to_array_trampolines[idx];
187 &self.text()[loc.start as usize..][..loc.length as usize]
188 }
189
190 pub fn stack_maps(&self) -> impl Iterator<Item = (&[u8], &[StackMapInformation])> {
196 self.finished_functions().map(|(_, f)| f).zip(
197 self.funcs
198 .values()
199 .map(|f| &f.wasm_func_info.stack_maps[..]),
200 )
201 }
202
203 pub fn func_by_text_offset(&self, text_offset: usize) -> Option<(DefinedFuncIndex, u32)> {
208 let text_offset = u32::try_from(text_offset).unwrap();
209
210 let index = match self.funcs.binary_search_values_by_key(&text_offset, |e| {
211 debug_assert!(e.wasm_func_loc.length > 0);
212 e.wasm_func_loc.start + e.wasm_func_loc.length - 1
214 }) {
215 Ok(k) => {
216 k
218 }
219 Err(k) => {
220 k
224 }
225 };
226
227 let CompiledFunctionInfo { wasm_func_loc, .. } = self.funcs.get(index)?;
228 let start = wasm_func_loc.start;
229 let end = wasm_func_loc.start + wasm_func_loc.length;
230
231 if text_offset < start || end < text_offset {
232 return None;
233 }
234
235 Some((index, text_offset - wasm_func_loc.start))
236 }
237
238 pub fn func_loc(&self, index: DefinedFuncIndex) -> &FunctionLoc {
240 &self
241 .funcs
242 .get(index)
243 .expect("defined function should be present")
244 .wasm_func_loc
245 }
246
247 pub fn wasm_func_info(&self, index: DefinedFuncIndex) -> &WasmFunctionInfo {
249 &self
250 .funcs
251 .get(index)
252 .expect("defined function should be present")
253 .wasm_func_info
254 }
255
256 #[cfg(feature = "addr2line")]
262 pub fn symbolize_context(&self) -> Result<Option<SymbolizeContext<'_>>> {
263 use gimli::EndianSlice;
264 if !self.meta.has_wasm_debuginfo {
265 return Ok(None);
266 }
267 let dwarf = gimli::Dwarf::load(|id| -> Result<_> {
268 let data = self
274 .meta
275 .dwarf
276 .binary_search_by_key(&(id as u8), |(id, _)| *id)
277 .map(|i| {
278 let (_, range) = &self.meta.dwarf[i];
279 &self.code_memory().dwarf()[range.start as usize..range.end as usize]
280 })
281 .unwrap_or(&[]);
282 Ok(EndianSlice::new(data, gimli::LittleEndian))
283 })?;
284 let cx = addr2line::Context::from_dwarf(dwarf)
285 .context("failed to create addr2line dwarf mapping context")?;
286 Ok(Some(SymbolizeContext {
287 inner: cx,
288 code_section_offset: self.meta.code_section_offset,
289 }))
290 }
291
292 pub fn has_unparsed_debuginfo(&self) -> bool {
295 self.meta.has_unparsed_debuginfo
296 }
297
298 pub fn has_address_map(&self) -> bool {
304 !self.code_memory.address_map_data().is_empty()
305 }
306}
307
308#[cfg(feature = "addr2line")]
309type Addr2LineContext<'a> = addr2line::Context<gimli::EndianSlice<'a, gimli::LittleEndian>>;
310
311#[cfg(feature = "addr2line")]
314pub struct SymbolizeContext<'a> {
315 inner: Addr2LineContext<'a>,
316 code_section_offset: u64,
317}
318
319#[cfg(feature = "addr2line")]
320impl<'a> SymbolizeContext<'a> {
321 pub fn addr2line(&self) -> &Addr2LineContext<'a> {
324 &self.inner
325 }
326
327 pub fn code_section_offset(&self) -> u64 {
330 self.code_section_offset
331 }
332}