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}