1 //! Debug utils for WebAssembly using Cranelift. 2 3 use crate::CompiledFunctionMetadata; 4 use cranelift_codegen::isa::TargetIsa; 5 use object::write::SymbolId; 6 use std::collections::HashMap; 7 use wasmtime_environ::{ 8 DefinedFuncIndex, DefinedMemoryIndex, EntityRef, MemoryIndex, ModuleTranslation, 9 OwnedMemoryIndex, PrimaryMap, PtrSize, StaticModuleIndex, Tunables, VMOffsets, 10 }; 11 12 /// Memory definition offset in the VMContext structure. 13 #[derive(Debug, Clone)] 14 pub enum ModuleMemoryOffset { 15 /// Not available. 16 None, 17 /// Offset to the defined memory. 18 Defined(u32), 19 /// This memory is imported. 20 Imported { 21 /// Offset, in bytes, to the `*mut VMMemoryDefinition` structure within 22 /// `VMContext`. 23 offset_to_vm_memory_definition: u32, 24 /// Offset, in bytes within `VMMemoryDefinition` where the `base` field 25 /// lies. 26 offset_to_memory_base: u32, 27 }, 28 } 29 30 type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>; 31 32 /// "Package structure" to collect together various artifacts/results of a 33 /// compilation. 34 /// 35 /// This structure is threaded through a number of top-level functions of DWARF 36 /// processing within in this submodule to pass along all the bits-and-pieces of 37 /// the compilation context. 38 pub struct Compilation<'a> { 39 /// All module translations which were present in this compilation. 40 /// 41 /// This map has one entry for core wasm modules and may have multiple (or 42 /// zero) for components. 43 translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>, 44 45 /// Accessor of a particular compiled function for a module. 46 /// 47 /// This returns the `object`-based-symbol for the function as well as the 48 /// `&CompiledFunction`. 49 get_func: 50 &'a dyn Fn(StaticModuleIndex, DefinedFuncIndex) -> (SymbolId, &'a CompiledFunctionMetadata), 51 52 /// Optionally-specified `*.dwp` file, currently only supported for core 53 /// wasm modules. 54 dwarf_package_bytes: Option<&'a [u8]>, 55 56 /// Compilation settings used when producing functions. 57 tunables: &'a Tunables, 58 59 /// Translation between `SymbolId` and a `usize`-based symbol which gimli 60 /// uses. 61 symbol_index_to_id: Vec<SymbolId>, 62 symbol_id_to_index: HashMap<SymbolId, (usize, StaticModuleIndex, DefinedFuncIndex)>, 63 64 /// The `ModuleMemoryOffset` for each module within `translations`. 65 /// 66 /// Note that this doesn't support multi-memory at this time. 67 module_memory_offsets: PrimaryMap<StaticModuleIndex, ModuleMemoryOffset>, 68 } 69 70 impl<'a> Compilation<'a> { 71 pub fn new( 72 isa: &dyn TargetIsa, 73 translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>, 74 get_func: &'a dyn Fn( 75 StaticModuleIndex, 76 DefinedFuncIndex, 77 ) -> (SymbolId, &'a CompiledFunctionMetadata), 78 dwarf_package_bytes: Option<&'a [u8]>, 79 tunables: &'a Tunables, 80 ) -> Compilation<'a> { 81 // Build the `module_memory_offsets` map based on the modules in 82 // `translations`. 83 let mut module_memory_offsets = PrimaryMap::new(); 84 for (i, translation) in translations { 85 let ofs = VMOffsets::new( 86 isa.triple().architecture.pointer_width().unwrap().bytes(), 87 &translation.module, 88 ); 89 90 let memory_offset = if ofs.num_imported_memories > 0 { 91 let index = MemoryIndex::new(0); 92 ModuleMemoryOffset::Imported { 93 offset_to_vm_memory_definition: ofs.vmctx_vmmemory_import(index) 94 + u32::from(ofs.vmmemory_import_from()), 95 offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(), 96 } 97 } else if ofs.num_owned_memories > 0 { 98 let index = OwnedMemoryIndex::new(0); 99 ModuleMemoryOffset::Defined(ofs.vmctx_vmmemory_definition_base(index)) 100 } else if ofs.num_defined_memories > 0 { 101 let index = DefinedMemoryIndex::new(0); 102 ModuleMemoryOffset::Imported { 103 offset_to_vm_memory_definition: ofs.vmctx_vmmemory_pointer(index), 104 offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(), 105 } 106 } else { 107 ModuleMemoryOffset::None 108 }; 109 let j = module_memory_offsets.push(memory_offset); 110 assert_eq!(i, j); 111 } 112 113 // Build the `symbol <=> usize` mappings 114 let mut symbol_index_to_id = Vec::new(); 115 let mut symbol_id_to_index = HashMap::new(); 116 117 for (module, translation) in translations { 118 for func in translation.module.defined_func_indices() { 119 let (sym, _func) = get_func(module, func); 120 symbol_id_to_index.insert(sym, (symbol_index_to_id.len(), module, func)); 121 symbol_index_to_id.push(sym); 122 } 123 } 124 125 Compilation { 126 translations, 127 get_func, 128 dwarf_package_bytes, 129 tunables, 130 symbol_index_to_id, 131 symbol_id_to_index, 132 module_memory_offsets, 133 } 134 } 135 136 /// Returns an iterator over all function indexes present in this 137 /// compilation. 138 /// 139 /// Each function is additionally accompanied with its module index. 140 fn indexes(&self) -> impl Iterator<Item = (StaticModuleIndex, DefinedFuncIndex)> + '_ { 141 self.translations 142 .iter() 143 .flat_map(|(i, t)| t.module.defined_func_indices().map(move |j| (i, j))) 144 } 145 146 /// Returns an iterator of all functions with their module, symbol, and 147 /// function metadata that were produced during compilation. 148 fn functions( 149 &self, 150 ) -> impl Iterator<Item = (StaticModuleIndex, usize, &'a CompiledFunctionMetadata)> + '_ { 151 self.indexes().map(move |(module, func)| { 152 let (sym, func) = self.function(module, func); 153 (module, sym, func) 154 }) 155 } 156 157 /// Returns the symbol and metadata associated with a specific function. 158 fn function( 159 &self, 160 module: StaticModuleIndex, 161 func: DefinedFuncIndex, 162 ) -> (usize, &'a CompiledFunctionMetadata) { 163 let (sym, func) = (self.get_func)(module, func); 164 (self.symbol_id_to_index[&sym].0, func) 165 } 166 167 /// Maps a `usize`-based symbol used by gimli to the object-based 168 /// `SymbolId`. 169 pub fn symbol_id(&self, sym: usize) -> SymbolId { 170 self.symbol_index_to_id[sym] 171 } 172 } 173 174 pub use write_debuginfo::{emit_dwarf, DwarfSectionRelocTarget}; 175 176 mod gc; 177 mod transform; 178 mod write_debuginfo; 179