wasmtime_jit/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_memory::CodeMemory;
7use crate::profiling::ProfilingAgent;
8use anyhow::{bail, Error, Result};
9use object::write::{Object, SectionId, StandardSegment, WritableBuffer};
10use object::SectionKind;
11use serde_derive::{Deserialize, Serialize};
12use std::convert::TryFrom;
13use std::ops::Range;
14use std::str;
15use std::sync::Arc;
16use wasmtime_environ::obj;
17use wasmtime_environ::{
18 DefinedFuncIndex, FuncIndex, FunctionLoc, MemoryInitialization, Module, ModuleTranslation,
19 PrimaryMap, SignatureIndex, StackMapInformation, Tunables, WasmFunctionInfo,
20};
21use wasmtime_runtime::{CompiledModuleId, CompiledModuleIdAllocator, MmapVec};
22
23/// Secondary in-memory results of function compilation.
24#[derive(Serialize, Deserialize)]
25pub struct CompiledFunctionInfo {
26 wasm_func_info: WasmFunctionInfo,
27 wasm_func_loc: FunctionLoc,
28 array_to_wasm_trampoline: Option<FunctionLoc>,
29 native_to_wasm_trampoline: Option<FunctionLoc>,
30}
31
32impl CompiledFunctionInfo {
33 /// Create a new `CompiledFunctionInfo`.
34 pub fn new(
35 wasm_func_info: WasmFunctionInfo,
36 wasm_func_loc: FunctionLoc,
37 array_to_wasm_trampoline: Option<FunctionLoc>,
38 native_to_wasm_trampoline: Option<FunctionLoc>,
39 ) -> CompiledFunctionInfo {
40 CompiledFunctionInfo {
41 wasm_func_info,
42 wasm_func_loc,
43 array_to_wasm_trampoline,
44 native_to_wasm_trampoline,
45 }
46 }
47}
48
49/// Secondary in-memory results of module compilation.
50///
51/// This opaque structure can be optionally passed back to
52/// `CompiledModule::from_artifacts` to avoid decoding extra information there.
53#[derive(Serialize, Deserialize)]
54pub struct CompiledModuleInfo {
55 /// Type information about the compiled WebAssembly module.
56 pub module: Module,
57
58 /// Metadata about each compiled function.
59 funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>,
60
61 /// Sorted list, by function index, of names we have for this module.
62 func_names: Vec<FunctionName>,
63
64 /// Metadata about wasm-to-native trampolines. Used when exposing a native
65 /// callee (e.g. `Func::wrap`) to a Wasm caller. Sorted by signature index.
66 wasm_to_native_trampolines: Vec<(SignatureIndex, FunctionLoc)>,
67
68 /// General compilation metadata.
69 meta: Metadata,
70}
71
72#[derive(Serialize, Deserialize)]
73struct FunctionName {
74 idx: FuncIndex,
75 offset: u32,
76 len: u32,
77}
78
79#[derive(Serialize, Deserialize)]
80struct Metadata {
81 /// Whether or not native debug information is available in `obj`
82 native_debug_info_present: bool,
83
84 /// Whether or not the original wasm module contained debug information that
85 /// we skipped and did not parse.
86 has_unparsed_debuginfo: bool,
87
88 /// Offset in the original wasm file to the code section.
89 code_section_offset: u64,
90
91 /// Whether or not custom wasm-specific dwarf sections were inserted into
92 /// the ELF image.
93 ///
94 /// Note that even if this flag is `true` sections may be missing if they
95 /// weren't found in the original wasm module itself.
96 has_wasm_debuginfo: bool,
97
98 /// Dwarf sections and the offsets at which they're stored in the
99 /// ELF_WASMTIME_DWARF
100 dwarf: Vec<(u8, Range<u64>)>,
101}
102
103/// Helper structure to create an ELF file as a compilation artifact.
104///
105/// This structure exposes the process which Wasmtime will encode a core wasm
106/// module into an ELF file, notably managing data sections and all that good
107/// business going into the final file.
108pub struct ObjectBuilder<'a> {
109 /// The `object`-crate-defined ELF file write we're using.
110 obj: Object<'a>,
111
112 /// General compilation configuration.
113 tunables: &'a Tunables,
114
115 /// The section identifier for "rodata" which is where wasm data segments
116 /// will go.
117 data: SectionId,
118
119 /// The section identifier for function name information, or otherwise where
120 /// the `name` custom section of wasm is copied into.
121 ///
122 /// This is optional and lazily created on demand.
123 names: Option<SectionId>,
124
125 /// The section identifier for dwarf information copied from the original
126 /// wasm files.
127 ///
128 /// This is optional and lazily created on demand.
129 dwarf: Option<SectionId>,
130}
131
132impl<'a> ObjectBuilder<'a> {
133 /// Creates a new builder for the `obj` specified.
134 pub fn new(mut obj: Object<'a>, tunables: &'a Tunables) -> ObjectBuilder<'a> {
135 let data = obj.add_section(
136 obj.segment_name(StandardSegment::Data).to_vec(),
137 obj::ELF_WASM_DATA.as_bytes().to_vec(),
138 SectionKind::ReadOnlyData,
139 );
140 ObjectBuilder {
141 obj,
142 tunables,
143 data,
144 names: None,
145 dwarf: None,
146 }
147 }
148
149 /// Completes compilation of the `translation` specified, inserting
150 /// everything necessary into the `Object` being built.
151 ///
152 /// This function will consume the final results of compiling a wasm module
153 /// and finish the ELF image in-progress as part of `self.obj` by appending
154 /// any compiler-agnostic sections.
155 ///
156 /// The auxiliary `CompiledModuleInfo` structure returned here has also been
157 /// serialized into the object returned, but if the caller will quickly
158 /// turn-around and invoke `CompiledModule::from_artifacts` after this then
159 /// the information can be passed to that method to avoid extra
160 /// deserialization. This is done to avoid a serialize-then-deserialize for
161 /// API calls like `Module::new` where the compiled module is immediately
162 /// going to be used.
163 ///
164 /// The various arguments here are:
165 ///
166 /// * `translation` - the core wasm translation that's being completed.
167 ///
168 /// * `funcs` - compilation metadata about functions within the translation
169 /// as well as where the functions are located in the text section.
170 ///
171 /// * `array_to_wasm_trampolines` - list of all trampolines necessary for
172 /// array callers (e.g. `Func::new`) calling Wasm callees. One for each
173 /// defined function that escapes. Must be sorted by `DefinedFuncIndex`.
174 ///
175 /// * `native_to_wasm_trampolines` - list of all trampolines necessary for
176 /// native callers (e.g. `Func::wrap`) calling Wasm callees. One for each
177 /// defined function that escapes. Must be sorted by `DefinedFuncIndex`.
178 ///
179 /// * `wasm_to_native_trampolines` - list of all trampolines necessary for
180 /// Wasm callers calling native callees (e.g. `Func::wrap`). One for each
181 /// function signature in the module. Must be sorted by `SignatureIndex`.
182 ///
183 /// Returns the `CompiledModuleInfo` corresponding to this core Wasm module
184 /// as a result of this append operation. This is then serialized into the
185 /// final artifact by the caller.
186 pub fn append(
187 &mut self,
188 translation: ModuleTranslation<'_>,
189 funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>,
190 wasm_to_native_trampolines: Vec<(SignatureIndex, FunctionLoc)>,
191 ) -> Result<CompiledModuleInfo> {
192 let ModuleTranslation {
193 mut module,
194 debuginfo,
195 has_unparsed_debuginfo,
196 data,
197 data_align,
198 passive_data,
199 ..
200 } = translation;
201
202 // Place all data from the wasm module into a section which will the
203 // source of the data later at runtime. This additionally keeps track of
204 // the offset of
205 let mut total_data_len = 0;
206 let data_offset = self
207 .obj
208 .append_section_data(self.data, &[], data_align.unwrap_or(1));
209 for (i, data) in data.iter().enumerate() {
210 // The first data segment has its alignment specified as the alignment
211 // for the entire section, but everything afterwards is adjacent so it
212 // has alignment of 1.
213 let align = if i == 0 { data_align.unwrap_or(1) } else { 1 };
214 self.obj.append_section_data(self.data, data, align);
215 total_data_len += data.len();
216 }
217 for data in passive_data.iter() {
218 self.obj.append_section_data(self.data, data, 1);
219 }
220
221 // If any names are present in the module then the `ELF_NAME_DATA` section
222 // is create and appended.
223 let mut func_names = Vec::new();
224 if debuginfo.name_section.func_names.len() > 0 {
225 let name_id = *self.names.get_or_insert_with(|| {
226 self.obj.add_section(
227 self.obj.segment_name(StandardSegment::Data).to_vec(),
228 obj::ELF_NAME_DATA.as_bytes().to_vec(),
229 SectionKind::ReadOnlyData,
230 )
231 });
232 let mut sorted_names = debuginfo.name_section.func_names.iter().collect::<Vec<_>>();
233 sorted_names.sort_by_key(|(idx, _name)| *idx);
234 for (idx, name) in sorted_names {
235 let offset = self.obj.append_section_data(name_id, name.as_bytes(), 1);
236 let offset = match u32::try_from(offset) {
237 Ok(offset) => offset,
238 Err(_) => bail!("name section too large (> 4gb)"),
239 };
240 let len = u32::try_from(name.len()).unwrap();
241 func_names.push(FunctionName {
242 idx: *idx,
243 offset,
244 len,
245 });
246 }
247 }
248
249 // Data offsets in `MemoryInitialization` are offsets within the
250 // `translation.data` list concatenated which is now present in the data
251 // segment that's appended to the object. Increase the offsets by
252 // `self.data_size` to account for any previously added module.
253 let data_offset = u32::try_from(data_offset).unwrap();
254 match &mut module.memory_initialization {
255 MemoryInitialization::Segmented(list) => {
256 for segment in list {
257 segment.data.start = segment.data.start.checked_add(data_offset).unwrap();
258 segment.data.end = segment.data.end.checked_add(data_offset).unwrap();
259 }
260 }
261 MemoryInitialization::Static { map } => {
262 for (_, segment) in map {
263 if let Some(segment) = segment {
264 segment.data.start = segment.data.start.checked_add(data_offset).unwrap();
265 segment.data.end = segment.data.end.checked_add(data_offset).unwrap();
266 }
267 }
268 }
269 }
270
271 // Data offsets for passive data are relative to the start of
272 // `translation.passive_data` which was appended to the data segment
273 // of this object, after active data in `translation.data`. Update the
274 // offsets to account prior modules added in addition to active data.
275 let data_offset = data_offset + u32::try_from(total_data_len).unwrap();
276 for (_, range) in module.passive_data_map.iter_mut() {
277 range.start = range.start.checked_add(data_offset).unwrap();
278 range.end = range.end.checked_add(data_offset).unwrap();
279 }
280
281 // Insert the wasm raw wasm-based debuginfo into the output, if
282 // requested. Note that this is distinct from the native debuginfo
283 // possibly generated by the native compiler, hence these sections
284 // getting wasm-specific names.
285 let mut dwarf = Vec::new();
286 if self.tunables.parse_wasm_debuginfo {
287 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_abbrev);
288 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_addr);
289 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_aranges);
290 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_info);
291 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_line);
292 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_line_str);
293 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_str);
294 self.push_debug(&mut dwarf, &debuginfo.dwarf.debug_str_offsets);
295 self.push_debug(&mut dwarf, &debuginfo.debug_ranges);
296 self.push_debug(&mut dwarf, &debuginfo.debug_rnglists);
297 }
298 // Sort this for binary-search-lookup later in `symbolize_context`.
299 dwarf.sort_by_key(|(id, _)| *id);
300
301 Ok(CompiledModuleInfo {
302 module,
303 funcs,
304 wasm_to_native_trampolines,
305 func_names,
306 meta: Metadata {
307 native_debug_info_present: self.tunables.generate_native_debuginfo,
308 has_unparsed_debuginfo,
309 code_section_offset: debuginfo.wasm_file.code_section_offset,
310 has_wasm_debuginfo: self.tunables.parse_wasm_debuginfo,
311 dwarf,
312 },
313 })
314 }
315
316 fn push_debug<'b, T>(&mut self, dwarf: &mut Vec<(u8, Range<u64>)>, section: &T)
317 where
318 T: gimli::Section<gimli::EndianSlice<'b, gimli::LittleEndian>>,
319 {
320 let data = section.reader().slice();
321 if data.is_empty() {
322 return;
323 }
324 let section_id = *self.dwarf.get_or_insert_with(|| {
325 self.obj.add_section(
326 self.obj.segment_name(StandardSegment::Debug).to_vec(),
327 obj::ELF_WASMTIME_DWARF.as_bytes().to_vec(),
328 SectionKind::Debug,
329 )
330 });
331 let offset = self.obj.append_section_data(section_id, data, 1);
332 dwarf.push((T::id() as u8, offset..offset + data.len() as u64));
333 }
334
335 /// Creates the `ELF_WASMTIME_INFO` section from the given serializable data
336 /// structure.
337 pub fn serialize_info<T>(&mut self, info: &T)
338 where
339 T: serde::Serialize,
340 {
341 let section = self.obj.add_section(
342 self.obj.segment_name(StandardSegment::Data).to_vec(),
343 obj::ELF_WASMTIME_INFO.as_bytes().to_vec(),
344 SectionKind::ReadOnlyData,
345 );
346 let data = bincode::serialize(info).unwrap();
347 self.obj.set_section_data(section, data, 1);
348 }
349
350 /// Creates a new `MmapVec` from `self.`
351 ///
352 /// The returned `MmapVec` will contain the serialized version of `self`
353 /// and is sized appropriately to the exact size of the object serialized.
354 pub fn finish(self) -> Result<MmapVec> {
355 let mut result = ObjectMmap::default();
356 return match self.obj.emit(&mut result) {
357 Ok(()) => {
358 assert!(result.mmap.is_some(), "no reserve");
359 let mmap = result.mmap.expect("reserve not called");
360 assert_eq!(mmap.len(), result.len);
361 Ok(mmap)
362 }
363 Err(e) => match result.err.take() {
364 Some(original) => Err(original.context(e)),
365 None => Err(e.into()),
366 },
367 };
368
369 /// Helper struct to implement the `WritableBuffer` trait from the `object`
370 /// crate.
371 ///
372 /// This enables writing an object directly into an mmap'd memory so it's
373 /// immediately usable for execution after compilation. This implementation
374 /// relies on a call to `reserve` happening once up front with all the needed
375 /// data, and the mmap internally does not attempt to grow afterwards.
376 #[derive(Default)]
377 struct ObjectMmap {
378 mmap: Option<MmapVec>,
379 len: usize,
380 err: Option<Error>,
381 }
382
383 impl WritableBuffer for ObjectMmap {
384 fn len(&self) -> usize {
385 self.len
386 }
387
388 fn reserve(&mut self, additional: usize) -> Result<(), ()> {
389 assert!(self.mmap.is_none(), "cannot reserve twice");
390 self.mmap = match MmapVec::with_capacity(additional) {
391 Ok(mmap) => Some(mmap),
392 Err(e) => {
393 self.err = Some(e);
394 return Err(());
395 }
396 };
397 Ok(())
398 }
399
400 fn resize(&mut self, new_len: usize) {
401 // Resizing always appends 0 bytes and since new mmaps start out as 0
402 // bytes we don't actually need to do anything as part of this other
403 // than update our own length.
404 if new_len <= self.len {
405 return;
406 }
407 self.len = new_len;
408 }
409
410 fn write_bytes(&mut self, val: &[u8]) {
411 let mmap = self.mmap.as_mut().expect("write before reserve");
412 mmap[self.len..][..val.len()].copy_from_slice(val);
413 self.len += val.len();
414 }
415 }
416 }
417}
418
419/// A compiled wasm module, ready to be instantiated.
420pub struct CompiledModule {
421 module: Arc<Module>,
422 funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>,
423 wasm_to_native_trampolines: Vec<(SignatureIndex, FunctionLoc)>,
424 meta: Metadata,
425 code_memory: Arc<CodeMemory>,
426 #[cfg(feature = "debug-builtins")]
427 dbg_jit_registration: Option<wasmtime_runtime::GdbJitImageRegistration>,
428 /// A unique ID used to register this module with the engine.
429 unique_id: CompiledModuleId,
430 func_names: Vec<FunctionName>,
431}
432
433impl CompiledModule {
434 /// Creates `CompiledModule` directly from a precompiled artifact.
435 ///
436 /// The `code_memory` argument is expected to be the result of a previous
437 /// call to `ObjectBuilder::finish` above. This is an ELF image, at this
438 /// time, which contains all necessary information to create a
439 /// `CompiledModule` from a compilation.
440 ///
441 /// This method also takes `info`, an optionally-provided deserialization
442 /// of the artifacts' compilation metadata section. If this information is
443 /// not provided then the information will be
444 /// deserialized from the image of the compilation artifacts. Otherwise it
445 /// will be assumed to be what would otherwise happen if the section were
446 /// to be deserialized.
447 ///
448 /// The `profiler` argument here is used to inform JIT profiling runtimes
449 /// about new code that is loaded.
450 pub fn from_artifacts(
451 code_memory: Arc<CodeMemory>,
452 info: CompiledModuleInfo,
453 profiler: &dyn ProfilingAgent,
454 id_allocator: &CompiledModuleIdAllocator,
455 ) -> Result<Self> {
456 let mut ret = Self {
457 module: Arc::new(info.module),
458 funcs: info.funcs,
459 wasm_to_native_trampolines: info.wasm_to_native_trampolines,
460 #[cfg(feature = "debug-builtins")]
461 dbg_jit_registration: None,
462 code_memory,
463 meta: info.meta,
464 unique_id: id_allocator.alloc(),
465 func_names: info.func_names,
466 };
467 ret.register_debug_and_profiling(profiler)?;
468
469 Ok(ret)
470 }
471
472 fn register_debug_and_profiling(&mut self, profiler: &dyn ProfilingAgent) -> Result<()> {
473 #[cfg(feature = "debug-builtins")]
474 if self.meta.native_debug_info_present {
475 use anyhow::Context;
476
477 let text = self.text();
478 let bytes = crate::debug::create_gdbjit_image(
479 self.mmap().to_vec(),
480 (text.as_ptr(), text.len()),
481 )
482 .context("failed to create jit image for gdb")?;
483 let reg = wasmtime_runtime::GdbJitImageRegistration::register(bytes);
484 self.dbg_jit_registration = Some(reg);
485 }
486 profiler.register_module(&self.code_memory, &|addr| {
487 let (idx, _) = self.func_by_text_offset(addr)?;
488 let idx = self.module.func_index(idx);
489 let name = self.func_name(idx)?;
490 let mut demangled = String::new();
491 crate::demangling::demangle_function_name(&mut demangled, name).unwrap();
492 Some(demangled)
493 });
494 Ok(())
495 }
496
497 /// Get this module's unique ID. It is unique with respect to a
498 /// single allocator (which is ordinarily held on a Wasm engine).
499 pub fn unique_id(&self) -> CompiledModuleId {
500 self.unique_id
501 }
502
503 /// Returns the underlying memory which contains the compiled module's
504 /// image.
505 pub fn mmap(&self) -> &MmapVec {
506 self.code_memory.mmap()
507 }
508
509 /// Returns the underlying owned mmap of this compiled image.
510 pub fn code_memory(&self) -> &Arc<CodeMemory> {
511 &self.code_memory
512 }
513
514 /// Returns the text section of the ELF image for this compiled module.
515 ///
516 /// This memory should have the read/execute permissions.
517 #[inline]
518 pub fn text(&self) -> &[u8] {
519 self.code_memory.text()
520 }
521
522 /// Return a reference-counting pointer to a module.
523 pub fn module(&self) -> &Arc<Module> {
524 &self.module
525 }
526
527 /// Looks up the `name` section name for the function index `idx`, if one
528 /// was specified in the original wasm module.
529 pub fn func_name(&self, idx: FuncIndex) -> Option<&str> {
530 // Find entry for `idx`, if present.
531 let i = self.func_names.binary_search_by_key(&idx, |n| n.idx).ok()?;
532 let name = &self.func_names[i];
533
534 // Here we `unwrap` the `from_utf8` but this can theoretically be a
535 // `from_utf8_unchecked` if we really wanted since this section is
536 // guaranteed to only have valid utf-8 data. Until it's a problem it's
537 // probably best to double-check this though.
538 let data = self.code_memory().func_name_data();
539 Some(str::from_utf8(&data[name.offset as usize..][..name.len as usize]).unwrap())
540 }
541
542 /// Return a reference to a mutable module (if possible).
543 pub fn module_mut(&mut self) -> Option<&mut Module> {
544 Arc::get_mut(&mut self.module)
545 }
546
547 /// Returns an iterator over all functions defined within this module with
548 /// their index and their body in memory.
549 #[inline]
550 pub fn finished_functions(
551 &self,
552 ) -> impl ExactSizeIterator<Item = (DefinedFuncIndex, &[u8])> + '_ {
553 self.funcs
554 .iter()
555 .map(move |(i, _)| (i, self.finished_function(i)))
556 }
557
558 /// Returns the body of the function that `index` points to.
559 #[inline]
560 pub fn finished_function(&self, index: DefinedFuncIndex) -> &[u8] {
561 let loc = self.funcs[index].wasm_func_loc;
562 &self.text()[loc.start as usize..][..loc.length as usize]
563 }
564
565 /// Get the array-to-Wasm trampoline for the function `index` points to.
566 ///
567 /// If the function `index` points to does not escape, then `None` is
568 /// returned.
569 ///
570 /// These trampolines are used for array callers (e.g. `Func::new`)
571 /// calling Wasm callees.
572 pub fn array_to_wasm_trampoline(&self, index: DefinedFuncIndex) -> Option<&[u8]> {
573 let loc = self.funcs[index].array_to_wasm_trampoline?;
574 Some(&self.text()[loc.start as usize..][..loc.length as usize])
575 }
576
577 /// Get the native-to-Wasm trampoline for the function `index` points to.
578 ///
579 /// If the function `index` points to does not escape, then `None` is
580 /// returned.
581 ///
582 /// These trampolines are used for native callers (e.g. `Func::wrap`)
583 /// calling Wasm callees.
584 #[inline]
585 pub fn native_to_wasm_trampoline(&self, index: DefinedFuncIndex) -> Option<&[u8]> {
586 let loc = self.funcs[index].native_to_wasm_trampoline?;
587 Some(&self.text()[loc.start as usize..][..loc.length as usize])
588 }
589
590 /// Get the Wasm-to-native trampoline for the given signature.
591 ///
592 /// These trampolines are used for filling in
593 /// `VMFuncRef::wasm_call` for `Func::wrap`-style host funcrefs
594 /// that don't have access to a compiler when created.
595 pub fn wasm_to_native_trampoline(&self, signature: SignatureIndex) -> &[u8] {
596 let idx = self
597 .wasm_to_native_trampolines
598 .binary_search_by_key(&signature, |entry| entry.0)
599 .expect("should have a Wasm-to-native trampline for all signatures");
600 let (_, loc) = self.wasm_to_native_trampolines[idx];
601 &self.text()[loc.start as usize..][..loc.length as usize]
602 }
603
604 /// Returns the stack map information for all functions defined in this
605 /// module.
606 ///
607 /// The iterator returned iterates over the span of the compiled function in
608 /// memory with the stack maps associated with those bytes.
609 pub fn stack_maps(&self) -> impl Iterator<Item = (&[u8], &[StackMapInformation])> {
610 self.finished_functions().map(|(_, f)| f).zip(
611 self.funcs
612 .values()
613 .map(|f| &f.wasm_func_info.stack_maps[..]),
614 )
615 }
616
617 /// Lookups a defined function by a program counter value.
618 ///
619 /// Returns the defined function index and the relative address of
620 /// `text_offset` within the function itself.
621 pub fn func_by_text_offset(&self, text_offset: usize) -> Option<(DefinedFuncIndex, u32)> {
622 let text_offset = u32::try_from(text_offset).unwrap();
623
624 let index = match self.funcs.binary_search_values_by_key(&text_offset, |e| {
625 debug_assert!(e.wasm_func_loc.length > 0);
626 // Return the inclusive "end" of the function
627 e.wasm_func_loc.start + e.wasm_func_loc.length - 1
628 }) {
629 Ok(k) => {
630 // Exact match, pc is at the end of this function
631 k
632 }
633 Err(k) => {
634 // Not an exact match, k is where `pc` would be "inserted"
635 // Since we key based on the end, function `k` might contain `pc`,
636 // so we'll validate on the range check below
637 k
638 }
639 };
640
641 let CompiledFunctionInfo { wasm_func_loc, .. } = self.funcs.get(index)?;
642 let start = wasm_func_loc.start;
643 let end = wasm_func_loc.start + wasm_func_loc.length;
644
645 if text_offset < start || end < text_offset {
646 return None;
647 }
648
649 Some((index, text_offset - wasm_func_loc.start))
650 }
651
652 /// Gets the function location information for a given function index.
653 pub fn func_loc(&self, index: DefinedFuncIndex) -> &FunctionLoc {
654 &self
655 .funcs
656 .get(index)
657 .expect("defined function should be present")
658 .wasm_func_loc
659 }
660
661 /// Gets the function information for a given function index.
662 pub fn wasm_func_info(&self, index: DefinedFuncIndex) -> &WasmFunctionInfo {
663 &self
664 .funcs
665 .get(index)
666 .expect("defined function should be present")
667 .wasm_func_info
668 }
669
670 /// Creates a new symbolication context which can be used to further
671 /// symbolicate stack traces.
672 ///
673 /// Basically this makes a thing which parses debuginfo and can tell you
674 /// what filename and line number a wasm pc comes from.
675 #[cfg(feature = "addr2line")]
676 pub fn symbolize_context(&self) -> Result<Option<SymbolizeContext<'_>>> {
677 use anyhow::Context;
678 use gimli::EndianSlice;
679 if !self.meta.has_wasm_debuginfo {
680 return Ok(None);
681 }
682 let dwarf = gimli::Dwarf::load(|id| -> Result<_> {
683 // Lookup the `id` in the `dwarf` array prepared for this module
684 // during module serialization where it's sorted by the `id` key. If
685 // found this is a range within the general module's concatenated
686 // dwarf section which is extracted here, otherwise it's just an
687 // empty list to represent that it's not present.
688 let data = self
689 .meta
690 .dwarf
691 .binary_search_by_key(&(id as u8), |(id, _)| *id)
692 .map(|i| {
693 let (_, range) = &self.meta.dwarf[i];
694 &self.code_memory().dwarf()[range.start as usize..range.end as usize]
695 })
696 .unwrap_or(&[]);
697 Ok(EndianSlice::new(data, gimli::LittleEndian))
698 })?;
699 let cx = addr2line::Context::from_dwarf(dwarf)
700 .context("failed to create addr2line dwarf mapping context")?;
701 Ok(Some(SymbolizeContext {
702 inner: cx,
703 code_section_offset: self.meta.code_section_offset,
704 }))
705 }
706
707 /// Returns whether the original wasm module had unparsed debug information
708 /// based on the tunables configuration.
709 pub fn has_unparsed_debuginfo(&self) -> bool {
710 self.meta.has_unparsed_debuginfo
711 }
712
713 /// Indicates whether this module came with n address map such that lookups
714 /// via `wasmtime_environ::lookup_file_pos` will succeed.
715 ///
716 /// If this function returns `false` then `lookup_file_pos` will always
717 /// return `None`.
718 pub fn has_address_map(&self) -> bool {
719 !self.code_memory.address_map_data().is_empty()
720 }
721
722 /// Returns the bounds, in host memory, of where this module's compiled
723 /// image resides.
724 pub fn image_range(&self) -> Range<usize> {
725 let base = self.mmap().as_ptr() as usize;
726 let len = self.mmap().len();
727 base..base + len
728 }
729}
730
731#[cfg(feature = "addr2line")]
732type Addr2LineContext<'a> = addr2line::Context<gimli::EndianSlice<'a, gimli::LittleEndian>>;
733
734/// A context which contains dwarf debug information to translate program
735/// counters back to filenames and line numbers.
736#[cfg(feature = "addr2line")]
737pub struct SymbolizeContext<'a> {
738 inner: Addr2LineContext<'a>,
739 code_section_offset: u64,
740}
741
742#[cfg(feature = "addr2line")]
743impl<'a> SymbolizeContext<'a> {
744 /// Returns access to the [`addr2line::Context`] which can be used to query
745 /// frame information with.
746 pub fn addr2line(&self) -> &Addr2LineContext<'a> {
747 &self.inner
748 }
749
750 /// Returns the offset of the code section in the original wasm file, used
751 /// to calculate lookup values into the DWARF.
752 pub fn code_section_offset(&self) -> u64 {
753 self.code_section_offset
754 }
755}
756
757/// Returns the range of `inner` within `outer`, such that `outer[range]` is the
758/// same as `inner`.
759///
760/// This method requires that `inner` is a sub-slice of `outer`, and if that
761/// isn't true then this method will panic.
762pub fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> {
763 if inner.len() == 0 {
764 return 0..0;
765 }
766
767 assert!(outer.as_ptr() <= inner.as_ptr());
768 assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _));
769
770 let start = inner.as_ptr() as usize - outer.as_ptr() as usize;
771 start..start + inner.len()
772}