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> {
function_frame_info( &mut self, module: StaticModuleIndex, func: DefinedFuncIndex, ) -> expression::FunctionFrameInfo<'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 
load_dwp<'data>( translation: ModuleTranslation<'data>, buffer: &'data [u8], ) -> Result<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>>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.
read_dwarf_package_from_bytes<'data>( dwp_bytes: &'data [u8], buffer: &'data [u8], tunables: &Tunables, ) -> Option<DwarfPackage<gimli::EndianSlice<'data, gimli::LittleEndian>>>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 
transform_dwarf( isa: &dyn TargetIsa, compilation: &mut Compilation<'_>, ) -> Result<write::Dwarf, Error>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