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