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}