1 use self::debug_transform_logging::dbi_log; 2 use self::refs::DebugInfoRefsMap; 3 use self::simulate::generate_simulated_dwarf; 4 use self::unit::clone_unit; 5 use crate::debug::gc::build_dependencies; 6 use crate::debug::Compilation; 7 use anyhow::Error; 8 use cranelift_codegen::isa::TargetIsa; 9 use gimli::{write, Dwarf, DwarfPackage, LittleEndian, Section, Unit, UnitSectionOffset}; 10 use std::{collections::HashSet, fmt::Debug}; 11 use synthetic::ModuleSyntheticUnit; 12 use thiserror::Error; 13 use wasmtime_environ::{ 14 DefinedFuncIndex, ModuleTranslation, PrimaryMap, StaticModuleIndex, Tunables, 15 }; 16 17 pub use address_transform::AddressTransform; 18 19 mod address_transform; 20 mod attr; 21 mod debug_transform_logging; 22 mod expression; 23 mod line_program; 24 mod range_info_builder; 25 mod refs; 26 mod simulate; 27 mod synthetic; 28 mod unit; 29 mod utils; 30 31 impl<'a> Compilation<'a> { 32 fn function_frame_info( 33 &mut self, 34 module: StaticModuleIndex, 35 func: DefinedFuncIndex, 36 ) -> expression::FunctionFrameInfo<'a> { 37 let (_, func) = self.function(module, func); 38 39 expression::FunctionFrameInfo { 40 value_ranges: &func.value_labels_ranges, 41 memory_offset: self.module_memory_offsets[module].clone(), 42 } 43 } 44 } 45 46 pub(crate) trait Reader: gimli::Reader<Offset = usize> + Send + Sync {} 47 48 impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where 49 Endian: gimli::Endianity + Send + Sync 50 { 51 } 52 53 #[derive(Error, Debug)] 54 #[error("Debug info transform error: {0}")] 55 pub struct TransformError(&'static str); 56 57 pub(crate) struct DebugInputContext<'a> { 58 reachable: &'a HashSet<UnitSectionOffset>, 59 } 60 61 fn load_dwp<'data>( 62 translation: ModuleTranslation<'data>, 63 buffer: &'data [u8], 64 ) -> anyhow::Result<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>> { 65 let endian_slice = gimli::EndianSlice::new(buffer, LittleEndian); 66 67 let dwarf_package = DwarfPackage::load( 68 |id| -> anyhow::Result<_> { 69 let slice = match id { 70 gimli::SectionId::DebugAbbrev => { 71 translation.debuginfo.dwarf.debug_abbrev.reader().slice() 72 } 73 gimli::SectionId::DebugInfo => { 74 translation.debuginfo.dwarf.debug_info.reader().slice() 75 } 76 gimli::SectionId::DebugLine => { 77 translation.debuginfo.dwarf.debug_line.reader().slice() 78 } 79 gimli::SectionId::DebugStr => { 80 translation.debuginfo.dwarf.debug_str.reader().slice() 81 } 82 gimli::SectionId::DebugStrOffsets => translation 83 .debuginfo 84 .dwarf 85 .debug_str_offsets 86 .reader() 87 .slice(), 88 gimli::SectionId::DebugLoc => translation.debuginfo.debug_loc.reader().slice(), 89 gimli::SectionId::DebugLocLists => { 90 translation.debuginfo.debug_loclists.reader().slice() 91 } 92 gimli::SectionId::DebugRngLists => { 93 translation.debuginfo.debug_rnglists.reader().slice() 94 } 95 gimli::SectionId::DebugTypes => { 96 translation.debuginfo.dwarf.debug_types.reader().slice() 97 } 98 gimli::SectionId::DebugCuIndex => { 99 translation.debuginfo.debug_cu_index.reader().slice() 100 } 101 gimli::SectionId::DebugTuIndex => { 102 translation.debuginfo.debug_tu_index.reader().slice() 103 } 104 _ => &buffer, 105 }; 106 107 Ok(gimli::EndianSlice::new(slice, gimli::LittleEndian)) 108 }, 109 endian_slice, 110 )?; 111 112 Ok(dwarf_package) 113 } 114 115 /// Attempts to load a DWARF package using the passed bytes. 116 fn read_dwarf_package_from_bytes<'data>( 117 dwp_bytes: &'data [u8], 118 buffer: &'data [u8], 119 tunables: &Tunables, 120 ) -> Option<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>> { 121 let mut validator = wasmparser::Validator::new(); 122 let parser = wasmparser::Parser::new(0); 123 let mut types = wasmtime_environ::ModuleTypesBuilder::new(&validator); 124 let translation = 125 match wasmtime_environ::ModuleEnvironment::new(tunables, &mut validator, &mut types) 126 .translate(parser, dwp_bytes) 127 { 128 Ok(translation) => translation, 129 Err(e) => { 130 log::warn!("failed to parse wasm dwarf package: {e:?}"); 131 return None; 132 } 133 }; 134 135 match load_dwp(translation, buffer) { 136 Ok(package) => Some(package), 137 Err(err) => { 138 log::warn!("Failed to load Dwarf package {}", err); 139 None 140 } 141 } 142 } 143 144 pub fn transform_dwarf( 145 isa: &dyn TargetIsa, 146 compilation: &mut Compilation<'_>, 147 ) -> Result<write::Dwarf, Error> { 148 dbi_log!("Commencing DWARF transform for {:?}", compilation); 149 150 let mut transforms = PrimaryMap::new(); 151 for (i, _) in compilation.translations.iter() { 152 transforms.push(AddressTransform::new(compilation, i)); 153 } 154 155 let buffer = Vec::new(); 156 157 let dwarf_package = compilation 158 .dwarf_package_bytes 159 .map( 160 |bytes| -> Option<DwarfPackage<gimli::EndianSlice<'_, gimli::LittleEndian>>> { 161 read_dwarf_package_from_bytes(bytes, &buffer, compilation.tunables) 162 }, 163 ) 164 .flatten(); 165 166 let reachable = build_dependencies(compilation, &dwarf_package, &transforms)?.get_reachable(); 167 168 let out_encoding = gimli::Encoding { 169 format: gimli::Format::Dwarf32, 170 version: 4, // TODO: this should be configurable 171 address_size: isa.pointer_bytes(), 172 }; 173 let mut out_strings = write::StringTable::default(); 174 let mut out_units = write::UnitTable::default(); 175 176 let out_line_strings = write::LineStringTable::default(); 177 let mut pending_di_refs = Vec::new(); 178 let mut di_ref_map = DebugInfoRefsMap::new(); 179 let mut vmctx_ptr_die_refs = PrimaryMap::new(); 180 181 let mut translated = HashSet::new(); 182 183 for (module, translation) in compilation.translations.iter() { 184 dbi_log!("[== Transforming CUs for module #{} ==]", module.as_u32()); 185 186 let addr_tr = &transforms[module]; 187 let di = &translation.debuginfo; 188 let context = DebugInputContext { 189 reachable: &reachable, 190 }; 191 let out_module_synthetic_unit = ModuleSyntheticUnit::new( 192 module, 193 compilation, 194 out_encoding, 195 &mut out_units, 196 &mut out_strings, 197 ); 198 // TODO-DebugInfo-Cleanup: move the simulation code to be per-module and delete this map. 199 vmctx_ptr_die_refs.push(out_module_synthetic_unit.vmctx_ptr_die_ref()); 200 201 let mut iter = di.dwarf.debug_info.units(); 202 while let Some(header) = iter.next().unwrap_or(None) { 203 let unit = di.dwarf.unit(header)?; 204 205 let mut resolved_unit = None; 206 let mut split_dwarf = None; 207 208 if unit.dwo_id.is_some() { 209 if let Some(dwarf_package) = &dwarf_package { 210 if let Some((fused, fused_dwarf)) = 211 replace_unit_from_split_dwarf(&unit, dwarf_package, &di.dwarf) 212 { 213 resolved_unit = Some(fused); 214 split_dwarf = Some(fused_dwarf); 215 } 216 } 217 } 218 219 if let Some((id, ref_map, pending_refs)) = clone_unit( 220 compilation, 221 module, 222 &unit, 223 resolved_unit.as_ref(), 224 split_dwarf.as_ref(), 225 &context, 226 &addr_tr, 227 out_encoding, 228 &out_module_synthetic_unit, 229 &mut out_units, 230 &mut out_strings, 231 &mut translated, 232 isa, 233 )? { 234 di_ref_map.insert(&header, id, ref_map); 235 pending_di_refs.push((id, pending_refs)); 236 } 237 } 238 } 239 di_ref_map.patch(pending_di_refs.into_iter(), &mut out_units); 240 241 generate_simulated_dwarf( 242 compilation, 243 &transforms, 244 &translated, 245 out_encoding, 246 &vmctx_ptr_die_refs, 247 &mut out_units, 248 &mut out_strings, 249 isa, 250 )?; 251 252 Ok(write::Dwarf { 253 units: out_units, 254 line_programs: vec![], 255 line_strings: out_line_strings, 256 strings: out_strings, 257 }) 258 } 259 260 fn replace_unit_from_split_dwarf<'a>( 261 unit: &'a Unit<gimli::EndianSlice<'a, gimli::LittleEndian>, usize>, 262 dwp: &DwarfPackage<gimli::EndianSlice<'a, gimli::LittleEndian>>, 263 parent: &Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>>, 264 ) -> Option<( 265 Unit<gimli::EndianSlice<'a, gimli::LittleEndian>, usize>, 266 Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>>, 267 )> { 268 let dwo_id = unit.dwo_id?; 269 let split_unit_dwarf = dwp.find_cu(dwo_id, parent).ok()??; 270 let unit_header = split_unit_dwarf.debug_info.units().next().ok()??; 271 let mut split_unit = split_unit_dwarf.unit(unit_header).ok()?; 272 split_unit.copy_relocated_attributes(unit); 273 Some((split_unit, split_unit_dwarf)) 274 } 275