Path: blob/main/crates/cranelift/src/debug/transform/mod.rs
1693 views
use self::debug_transform_logging::dbi_log;1use self::refs::DebugInfoRefsMap;2use self::simulate::generate_simulated_dwarf;3use self::unit::clone_unit;4use crate::debug::Compilation;5use crate::debug::gc::build_dependencies;6use anyhow::Error;7use cranelift_codegen::isa::TargetIsa;8use gimli::{Dwarf, DwarfPackage, LittleEndian, Section, Unit, UnitSectionOffset, write};9use std::{collections::HashSet, fmt::Debug};10use synthetic::ModuleSyntheticUnit;11use thiserror::Error;12use wasmtime_environ::{13DefinedFuncIndex, ModuleTranslation, PrimaryMap, StaticModuleIndex, Tunables,14};1516pub use address_transform::AddressTransform;1718mod address_transform;19mod attr;20mod debug_transform_logging;21mod expression;22mod line_program;23mod range_info_builder;24mod refs;25mod simulate;26mod synthetic;27mod unit;28mod utils;2930impl<'a> Compilation<'a> {31fn function_frame_info(32&mut self,33module: StaticModuleIndex,34func: DefinedFuncIndex,35) -> expression::FunctionFrameInfo<'a> {36let (_, func) = self.function(module, func);3738expression::FunctionFrameInfo {39value_ranges: &func.value_labels_ranges,40memory_offset: self.module_memory_offsets[module].clone(),41}42}43}4445pub(crate) trait Reader: gimli::Reader<Offset = usize> + Send + Sync {}4647impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where48Endian: gimli::Endianity + Send + Sync49{50}5152#[derive(Error, Debug)]53#[error("Debug info transform error: {0}")]54pub struct TransformError(&'static str);5556pub(crate) struct DebugInputContext<'a> {57reachable: &'a HashSet<UnitSectionOffset>,58}5960fn load_dwp<'data>(61translation: ModuleTranslation<'data>,62buffer: &'data [u8],63) -> anyhow::Result<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>> {64let endian_slice = gimli::EndianSlice::new(buffer, LittleEndian);6566let dwarf_package = DwarfPackage::load(67|id| -> anyhow::Result<_> {68let slice = match id {69gimli::SectionId::DebugAbbrev => {70translation.debuginfo.dwarf.debug_abbrev.reader().slice()71}72gimli::SectionId::DebugInfo => {73translation.debuginfo.dwarf.debug_info.reader().slice()74}75gimli::SectionId::DebugLine => {76translation.debuginfo.dwarf.debug_line.reader().slice()77}78gimli::SectionId::DebugStr => {79translation.debuginfo.dwarf.debug_str.reader().slice()80}81gimli::SectionId::DebugStrOffsets => translation82.debuginfo83.dwarf84.debug_str_offsets85.reader()86.slice(),87gimli::SectionId::DebugLoc => translation.debuginfo.debug_loc.reader().slice(),88gimli::SectionId::DebugLocLists => {89translation.debuginfo.debug_loclists.reader().slice()90}91gimli::SectionId::DebugRngLists => {92translation.debuginfo.debug_rnglists.reader().slice()93}94gimli::SectionId::DebugTypes => {95translation.debuginfo.dwarf.debug_types.reader().slice()96}97gimli::SectionId::DebugCuIndex => {98translation.debuginfo.debug_cu_index.reader().slice()99}100gimli::SectionId::DebugTuIndex => {101translation.debuginfo.debug_tu_index.reader().slice()102}103_ => &buffer,104};105106Ok(gimli::EndianSlice::new(slice, gimli::LittleEndian))107},108endian_slice,109)?;110111Ok(dwarf_package)112}113114/// Attempts to load a DWARF package using the passed bytes.115fn read_dwarf_package_from_bytes<'data>(116dwp_bytes: &'data [u8],117buffer: &'data [u8],118tunables: &Tunables,119) -> Option<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>> {120let mut validator = wasmparser::Validator::new();121let parser = wasmparser::Parser::new(0);122let mut types = wasmtime_environ::ModuleTypesBuilder::new(&validator);123let translation = match wasmtime_environ::ModuleEnvironment::new(124tunables,125&mut validator,126&mut types,127StaticModuleIndex::from_u32(0),128)129.translate(parser, dwp_bytes)130{131Ok(translation) => translation,132Err(e) => {133log::warn!("failed to parse wasm dwarf package: {e:?}");134return None;135}136};137138match load_dwp(translation, buffer) {139Ok(package) => Some(package),140Err(err) => {141log::warn!("Failed to load Dwarf package {err}");142None143}144}145}146147pub fn transform_dwarf(148isa: &dyn TargetIsa,149compilation: &mut Compilation<'_>,150) -> Result<write::Dwarf, Error> {151dbi_log!("Commencing DWARF transform for {:?}", compilation);152153let mut transforms = PrimaryMap::new();154for (i, _) in compilation.translations.iter() {155transforms.push(AddressTransform::new(compilation, i));156}157158let buffer = Vec::new();159160let dwarf_package = compilation161.dwarf_package_bytes162.map(163|bytes| -> Option<DwarfPackage<gimli::EndianSlice<'_, gimli::LittleEndian>>> {164read_dwarf_package_from_bytes(bytes, &buffer, compilation.tunables)165},166)167.flatten();168169let out_encoding = gimli::Encoding {170format: gimli::Format::Dwarf32,171version: 4, // TODO: this should be configurable172address_size: isa.pointer_bytes(),173};174let mut out_strings = write::StringTable::default();175let mut out_units = write::UnitTable::default();176177let out_line_strings = write::LineStringTable::default();178let mut pending_di_refs = Vec::new();179let mut di_ref_map = DebugInfoRefsMap::new();180let mut vmctx_ptr_die_refs = PrimaryMap::new();181182let mut translated = HashSet::new();183184for (module, translation) in compilation.translations.iter() {185dbi_log!("[== Transforming CUs for module #{} ==]", module.as_u32());186187let addr_tr = &transforms[module];188let di = &translation.debuginfo;189let reachable = build_dependencies(&di.dwarf, addr_tr)?.get_reachable();190191let out_module_synthetic_unit = ModuleSyntheticUnit::new(192module,193compilation,194out_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.199vmctx_ptr_die_refs.push(out_module_synthetic_unit.vmctx_ptr_die_ref());200201let mut iter = di.dwarf.debug_info.units();202while let Some(header) = iter.next().unwrap_or(None) {203let unit = di.dwarf.unit(header)?;204205let mut split_unit = None;206let mut split_dwarf = None;207let mut split_reachable = None;208209if unit.dwo_id.is_some() {210if let Some(dwarf_package) = &dwarf_package {211if let Some((fused, fused_dwarf)) =212replace_unit_from_split_dwarf(&unit, dwarf_package, &di.dwarf)213{214split_reachable =215Some(build_dependencies(&fused_dwarf, addr_tr)?.get_reachable());216split_unit = Some(fused);217split_dwarf = Some(fused_dwarf);218}219}220}221let context = DebugInputContext {222reachable: split_reachable.as_ref().unwrap_or(&reachable),223};224225if let Some((id, ref_map, pending_refs)) = clone_unit(226compilation,227module,228&unit,229split_unit.as_ref(),230split_dwarf.as_ref(),231&context,232&addr_tr,233out_encoding,234&out_module_synthetic_unit,235&mut out_units,236&mut out_strings,237&mut translated,238isa,239)? {240di_ref_map.insert(&header, id, ref_map);241pending_di_refs.push((id, pending_refs));242}243}244}245di_ref_map.patch(pending_di_refs.into_iter(), &mut out_units);246247generate_simulated_dwarf(248compilation,249&transforms,250&translated,251out_encoding,252&vmctx_ptr_die_refs,253&mut out_units,254&mut out_strings,255isa,256)?;257258Ok(write::Dwarf {259units: out_units,260line_programs: vec![],261line_strings: out_line_strings,262strings: out_strings,263})264}265266fn replace_unit_from_split_dwarf<'a>(267unit: &'a Unit<gimli::EndianSlice<'a, gimli::LittleEndian>, usize>,268dwp: &DwarfPackage<gimli::EndianSlice<'a, gimli::LittleEndian>>,269parent: &Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>>,270) -> Option<(271Unit<gimli::EndianSlice<'a, gimli::LittleEndian>, usize>,272Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>>,273)> {274let dwo_id = unit.dwo_id?;275let split_unit_dwarf = dwp.find_cu(dwo_id, parent).ok()??;276let unit_header = split_unit_dwarf.debug_info.units().next().ok()??;277let mut split_unit = split_unit_dwarf.unit(unit_header).ok()?;278split_unit.copy_relocated_attributes(unit);279Some((split_unit, split_unit_dwarf))280}281282283