1 use self::debug_transform_logging::dbi_log; 2 use self::simulate::generate_simulated_dwarf; 3 use self::unit::clone_unit; 4 use crate::debug::Compilation; 5 use crate::debug::gc::build_dependencies; 6 use cranelift_codegen::isa::TargetIsa; 7 use gimli::{DwarfPackage, LittleEndian, Section, write}; 8 use std::collections::HashSet; 9 use synthetic::ModuleSyntheticUnit; 10 use wasmtime_environ::error::Error; 11 use wasmtime_environ::{ 12 DefinedFuncIndex, ModuleTranslation, PrimaryMap, StaticModuleIndex, Tunables, prelude::*, 13 }; 14 15 pub use address_transform::AddressTransform; 16 17 mod address_transform; 18 mod attr; 19 mod debug_transform_logging; 20 mod expression; 21 mod line_program; 22 mod range_info_builder; 23 mod simulate; 24 mod synthetic; 25 mod unit; 26 mod utils; 27 28 impl<'a> Compilation<'a> { 29 fn function_frame_info( 30 &mut self, 31 module: StaticModuleIndex, 32 func: DefinedFuncIndex, 33 ) -> expression::FunctionFrameInfo<'a> { 34 let (_, func) = self.function(module, func); 35 36 expression::FunctionFrameInfo { 37 value_ranges: &func.value_labels_ranges, 38 memory_offset: self.module_memory_offsets[module].clone(), 39 } 40 } 41 } 42 43 fn load_dwp<'data>( 44 translation: ModuleTranslation<'data>, 45 buffer: &'data [u8], 46 ) -> Result<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>> { 47 let endian_slice = gimli::EndianSlice::new(buffer, LittleEndian); 48 49 let dwarf_package = DwarfPackage::load( 50 |id| -> Result<_> { 51 let slice = match id { 52 gimli::SectionId::DebugAbbrev => { 53 translation.debuginfo.dwarf.debug_abbrev.reader().slice() 54 } 55 gimli::SectionId::DebugInfo => { 56 translation.debuginfo.dwarf.debug_info.reader().slice() 57 } 58 gimli::SectionId::DebugLine => { 59 translation.debuginfo.dwarf.debug_line.reader().slice() 60 } 61 gimli::SectionId::DebugStr => { 62 translation.debuginfo.dwarf.debug_str.reader().slice() 63 } 64 gimli::SectionId::DebugStrOffsets => translation 65 .debuginfo 66 .dwarf 67 .debug_str_offsets 68 .reader() 69 .slice(), 70 gimli::SectionId::DebugLoc => translation.debuginfo.debug_loc.reader().slice(), 71 gimli::SectionId::DebugLocLists => { 72 translation.debuginfo.debug_loclists.reader().slice() 73 } 74 gimli::SectionId::DebugRngLists => { 75 translation.debuginfo.debug_rnglists.reader().slice() 76 } 77 gimli::SectionId::DebugTypes => { 78 translation.debuginfo.dwarf.debug_types.reader().slice() 79 } 80 gimli::SectionId::DebugCuIndex => { 81 translation.debuginfo.debug_cu_index.reader().slice() 82 } 83 gimli::SectionId::DebugTuIndex => { 84 translation.debuginfo.debug_tu_index.reader().slice() 85 } 86 _ => &buffer, 87 }; 88 89 Ok(gimli::EndianSlice::new(slice, gimli::LittleEndian)) 90 }, 91 endian_slice, 92 )?; 93 94 Ok(dwarf_package) 95 } 96 97 /// Attempts to load a DWARF package using the passed bytes. 98 fn read_dwarf_package_from_bytes<'data>( 99 dwp_bytes: &'data [u8], 100 buffer: &'data [u8], 101 tunables: &Tunables, 102 ) -> Option<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>> { 103 let mut validator = wasmparser::Validator::new(); 104 let parser = wasmparser::Parser::new(0); 105 let mut types = wasmtime_environ::ModuleTypesBuilder::new(&validator); 106 let translation = match wasmtime_environ::ModuleEnvironment::new( 107 tunables, 108 &mut validator, 109 &mut types, 110 StaticModuleIndex::from_u32(0), 111 ) 112 .translate(parser, dwp_bytes) 113 { 114 Ok(translation) => translation, 115 Err(e) => { 116 log::warn!("failed to parse wasm dwarf package: {e:?}"); 117 return None; 118 } 119 }; 120 121 match load_dwp(translation, buffer) { 122 Ok(package) => Some(package), 123 Err(err) => { 124 log::warn!("Failed to load Dwarf package {err}"); 125 None 126 } 127 } 128 } 129 130 pub fn transform_dwarf( 131 isa: &dyn TargetIsa, 132 compilation: &mut Compilation<'_>, 133 ) -> Result<write::Dwarf, Error> { 134 dbi_log!("Commencing DWARF transform for {:?}", compilation); 135 136 let mut transforms = PrimaryMap::new(); 137 for (i, _) in compilation.translations.iter() { 138 transforms.push(AddressTransform::new(compilation, i)); 139 } 140 141 let buffer = Vec::new(); 142 143 let dwarf_package = compilation 144 .dwarf_package_bytes 145 .map( 146 |bytes| -> Option<DwarfPackage<gimli::EndianSlice<'_, gimli::LittleEndian>>> { 147 read_dwarf_package_from_bytes(bytes, &buffer, compilation.tunables) 148 }, 149 ) 150 .flatten(); 151 152 let out_encoding = gimli::Encoding { 153 format: gimli::Format::Dwarf32, 154 version: 4, // TODO: this should be configurable 155 address_size: isa.pointer_bytes(), 156 }; 157 let mut out_dwarf = write::Dwarf::default(); 158 159 let mut vmctx_ptr_die_refs = PrimaryMap::new(); 160 161 let mut translated = HashSet::new(); 162 163 for (module, translation) in compilation.translations.iter() { 164 dbi_log!("[== Transforming CUs for module #{} ==]", module.as_u32()); 165 166 let addr_tr = &transforms[module]; 167 let di = &translation.debuginfo; 168 169 let out_module_synthetic_unit = ModuleSyntheticUnit::new( 170 module, 171 compilation, 172 out_encoding, 173 &mut out_dwarf.units, 174 &mut out_dwarf.strings, 175 ); 176 // TODO-DebugInfo-Cleanup: move the simulation code to be per-module and delete this map. 177 vmctx_ptr_die_refs.push(out_module_synthetic_unit.vmctx_ptr_die_ref()); 178 179 let mut filter = write::FilterUnitSection::new(&di.dwarf)?; 180 build_dependencies(&mut filter, addr_tr)?; 181 let mut convert = out_dwarf.convert_with_filter(filter)?; 182 while let Some((mut unit, root_entry)) = convert.read_unit()? { 183 if let Some(dwp) = dwarf_package.as_ref() 184 && let Some(dwo_id) = unit.read_unit.dwo_id 185 && let Ok(Some(split_dwarf)) = dwp.find_cu(dwo_id, unit.read_unit.dwarf) 186 { 187 let mut split_filter = 188 write::FilterUnitSection::new_split(&split_dwarf, unit.read_unit)?; 189 build_dependencies(&mut split_filter, addr_tr)?; 190 let mut convert_split = unit.convert_split_with_filter(split_filter)?; 191 let (mut split_unit, split_root_entry) = convert_split.read_unit()?; 192 split_unit.unit.set_encoding(out_encoding); 193 clone_unit( 194 compilation, 195 module, 196 &mut split_unit, 197 &split_root_entry, 198 Some(&root_entry), 199 &addr_tr, 200 &out_module_synthetic_unit, 201 &mut translated, 202 isa, 203 )?; 204 } else { 205 unit.unit.set_encoding(out_encoding); 206 clone_unit( 207 compilation, 208 module, 209 &mut unit, 210 &root_entry, 211 None, 212 &addr_tr, 213 &out_module_synthetic_unit, 214 &mut translated, 215 isa, 216 )?; 217 } 218 } 219 } 220 221 generate_simulated_dwarf( 222 compilation, 223 &transforms, 224 &translated, 225 out_encoding, 226 &vmctx_ptr_die_refs, 227 &mut out_dwarf.units, 228 &mut out_dwarf.strings, 229 isa, 230 )?; 231 232 Ok(out_dwarf) 233 } 234