Path: blob/main/crates/cranelift/src/debug.rs
1691 views
//! Debug utils for WebAssembly using Cranelift.12// FIXME: this whole crate opts-in to these two noisier-than-default lints, but3// this module has lots of hits on this warning which aren't the easiest to4// resolve. Ideally all warnings would be resolved here though.5#![expect(6clippy::cast_possible_truncation,7clippy::cast_sign_loss,8reason = "haven't had a chance to fix these yet"9)]1011use crate::CompiledFunctionMetadata;12use core::fmt;13use cranelift_codegen::isa::TargetIsa;14use object::write::SymbolId;15use std::collections::HashMap;16use wasmtime_environ::{17DefinedFuncIndex, DefinedMemoryIndex, EntityRef, MemoryIndex, ModuleTranslation,18OwnedMemoryIndex, PrimaryMap, PtrSize, StaticModuleIndex, Tunables, VMOffsets,19};2021/// Memory definition offset in the VMContext structure.22#[derive(Debug, Clone)]23pub enum ModuleMemoryOffset {24/// Not available.25None,26/// Offset to the defined memory.27Defined(u32),28/// This memory is imported.29Imported {30/// Offset, in bytes, to the `*mut VMMemoryDefinition` structure within31/// `VMContext`.32offset_to_vm_memory_definition: u32,33/// Offset, in bytes within `VMMemoryDefinition` where the `base` field34/// lies.35offset_to_memory_base: u32,36},37}3839type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;4041/// "Package structure" to collect together various artifacts/results of a42/// compilation.43///44/// This structure is threaded through a number of top-level functions of DWARF45/// processing within in this submodule to pass along all the bits-and-pieces of46/// the compilation context.47pub struct Compilation<'a> {48/// All module translations which were present in this compilation.49///50/// This map has one entry for core wasm modules and may have multiple (or51/// zero) for components.52translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,5354/// Accessor of a particular compiled function for a module.55///56/// This returns the `object`-based-symbol for the function as well as the57/// `&CompiledFunction`.58get_func:59&'a dyn Fn(StaticModuleIndex, DefinedFuncIndex) -> (SymbolId, &'a CompiledFunctionMetadata),6061/// Optionally-specified `*.dwp` file, currently only supported for core62/// wasm modules.63dwarf_package_bytes: Option<&'a [u8]>,6465/// Compilation settings used when producing functions.66tunables: &'a Tunables,6768/// Translation between `SymbolId` and a `usize`-based symbol which gimli69/// uses.70symbol_index_to_id: Vec<SymbolId>,71symbol_id_to_index: HashMap<SymbolId, (usize, StaticModuleIndex, DefinedFuncIndex)>,7273/// The `ModuleMemoryOffset` for each module within `translations`.74///75/// Note that this doesn't support multi-memory at this time.76module_memory_offsets: PrimaryMap<StaticModuleIndex, ModuleMemoryOffset>,77}7879impl<'a> Compilation<'a> {80pub fn new(81isa: &dyn TargetIsa,82translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,83get_func: &'a dyn Fn(84StaticModuleIndex,85DefinedFuncIndex,86) -> (SymbolId, &'a CompiledFunctionMetadata),87dwarf_package_bytes: Option<&'a [u8]>,88tunables: &'a Tunables,89) -> Compilation<'a> {90// Build the `module_memory_offsets` map based on the modules in91// `translations`.92let mut module_memory_offsets = PrimaryMap::new();93for (i, translation) in translations {94let ofs = VMOffsets::new(95isa.triple().architecture.pointer_width().unwrap().bytes(),96&translation.module,97);9899let memory_offset = if ofs.num_imported_memories > 0 {100let index = MemoryIndex::new(0);101ModuleMemoryOffset::Imported {102offset_to_vm_memory_definition: ofs.vmctx_vmmemory_import(index)103+ u32::from(ofs.vmmemory_import_from()),104offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),105}106} else if ofs.num_owned_memories > 0 {107let index = OwnedMemoryIndex::new(0);108ModuleMemoryOffset::Defined(ofs.vmctx_vmmemory_definition_base(index))109} else if ofs.num_defined_memories > 0 {110let index = DefinedMemoryIndex::new(0);111ModuleMemoryOffset::Imported {112offset_to_vm_memory_definition: ofs.vmctx_vmmemory_pointer(index),113offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),114}115} else {116ModuleMemoryOffset::None117};118let j = module_memory_offsets.push(memory_offset);119assert_eq!(i, j);120}121122// Build the `symbol <=> usize` mappings123let mut symbol_index_to_id = Vec::new();124let mut symbol_id_to_index = HashMap::new();125126for (module, translation) in translations {127for func in translation.module.defined_func_indices() {128let (sym, _func) = get_func(module, func);129symbol_id_to_index.insert(sym, (symbol_index_to_id.len(), module, func));130symbol_index_to_id.push(sym);131}132}133134Compilation {135translations,136get_func,137dwarf_package_bytes,138tunables,139symbol_index_to_id,140symbol_id_to_index,141module_memory_offsets,142}143}144145/// Returns an iterator over all function indexes present in this146/// compilation.147///148/// Each function is additionally accompanied with its module index.149fn indexes(&self) -> impl Iterator<Item = (StaticModuleIndex, DefinedFuncIndex)> + use<'_> {150self.translations151.iter()152.flat_map(|(i, t)| t.module.defined_func_indices().map(move |j| (i, j)))153}154155/// Returns an iterator of all functions with their module, symbol, and156/// function metadata that were produced during compilation.157fn functions(158&self,159) -> impl Iterator<Item = (StaticModuleIndex, usize, &'a CompiledFunctionMetadata)> + '_ {160self.indexes().map(move |(module, func)| {161let (sym, func) = self.function(module, func);162(module, sym, func)163})164}165166/// Returns the symbol and metadata associated with a specific function.167fn function(168&self,169module: StaticModuleIndex,170func: DefinedFuncIndex,171) -> (usize, &'a CompiledFunctionMetadata) {172let (sym, func) = (self.get_func)(module, func);173(self.symbol_id_to_index[&sym].0, func)174}175176/// Maps a `usize`-based symbol used by gimli to the object-based177/// `SymbolId`.178pub fn symbol_id(&self, sym: usize) -> SymbolId {179self.symbol_index_to_id[sym]180}181}182183impl<'a> fmt::Debug for Compilation<'a> {184// Sample output: '[#0: OneModule, #1: TwoModule, #3]'.185fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {186write!(f, "[")?;187let mut is_first_module = true;188for (i, translation) in self.translations {189if !is_first_module {190write!(f, ", ")?;191} else {192is_first_module = false;193}194write!(f, "#{}", i.as_u32())?;195if let Some(name) = translation.debuginfo.name_section.module_name {196write!(f, ": {name}")?;197}198}199write!(f, "]")200}201}202203pub use write_debuginfo::{DwarfSectionRelocTarget, emit_dwarf};204205mod gc;206mod transform;207mod write_debuginfo;208209210