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