Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/debug/transform/mod.rs
1693 views
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::Compilation;
6
use crate::debug::gc::build_dependencies;
7
use anyhow::Error;
8
use cranelift_codegen::isa::TargetIsa;
9
use gimli::{Dwarf, DwarfPackage, LittleEndian, Section, Unit, UnitSectionOffset, write};
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 = match wasmtime_environ::ModuleEnvironment::new(
125
tunables,
126
&mut validator,
127
&mut types,
128
StaticModuleIndex::from_u32(0),
129
)
130
.translate(parser, dwp_bytes)
131
{
132
Ok(translation) => translation,
133
Err(e) => {
134
log::warn!("failed to parse wasm dwarf package: {e:?}");
135
return None;
136
}
137
};
138
139
match load_dwp(translation, buffer) {
140
Ok(package) => Some(package),
141
Err(err) => {
142
log::warn!("Failed to load Dwarf package {err}");
143
None
144
}
145
}
146
}
147
148
pub fn transform_dwarf(
149
isa: &dyn TargetIsa,
150
compilation: &mut Compilation<'_>,
151
) -> Result<write::Dwarf, Error> {
152
dbi_log!("Commencing DWARF transform for {:?}", compilation);
153
154
let mut transforms = PrimaryMap::new();
155
for (i, _) in compilation.translations.iter() {
156
transforms.push(AddressTransform::new(compilation, i));
157
}
158
159
let buffer = Vec::new();
160
161
let dwarf_package = compilation
162
.dwarf_package_bytes
163
.map(
164
|bytes| -> Option<DwarfPackage<gimli::EndianSlice<'_, gimli::LittleEndian>>> {
165
read_dwarf_package_from_bytes(bytes, &buffer, compilation.tunables)
166
},
167
)
168
.flatten();
169
170
let out_encoding = gimli::Encoding {
171
format: gimli::Format::Dwarf32,
172
version: 4, // TODO: this should be configurable
173
address_size: isa.pointer_bytes(),
174
};
175
let mut out_strings = write::StringTable::default();
176
let mut out_units = write::UnitTable::default();
177
178
let out_line_strings = write::LineStringTable::default();
179
let mut pending_di_refs = Vec::new();
180
let mut di_ref_map = DebugInfoRefsMap::new();
181
let mut vmctx_ptr_die_refs = PrimaryMap::new();
182
183
let mut translated = HashSet::new();
184
185
for (module, translation) in compilation.translations.iter() {
186
dbi_log!("[== Transforming CUs for module #{} ==]", module.as_u32());
187
188
let addr_tr = &transforms[module];
189
let di = &translation.debuginfo;
190
let reachable = build_dependencies(&di.dwarf, addr_tr)?.get_reachable();
191
192
let out_module_synthetic_unit = ModuleSyntheticUnit::new(
193
module,
194
compilation,
195
out_encoding,
196
&mut out_units,
197
&mut out_strings,
198
);
199
// TODO-DebugInfo-Cleanup: move the simulation code to be per-module and delete this map.
200
vmctx_ptr_die_refs.push(out_module_synthetic_unit.vmctx_ptr_die_ref());
201
202
let mut iter = di.dwarf.debug_info.units();
203
while let Some(header) = iter.next().unwrap_or(None) {
204
let unit = di.dwarf.unit(header)?;
205
206
let mut split_unit = None;
207
let mut split_dwarf = None;
208
let mut split_reachable = None;
209
210
if unit.dwo_id.is_some() {
211
if let Some(dwarf_package) = &dwarf_package {
212
if let Some((fused, fused_dwarf)) =
213
replace_unit_from_split_dwarf(&unit, dwarf_package, &di.dwarf)
214
{
215
split_reachable =
216
Some(build_dependencies(&fused_dwarf, addr_tr)?.get_reachable());
217
split_unit = Some(fused);
218
split_dwarf = Some(fused_dwarf);
219
}
220
}
221
}
222
let context = DebugInputContext {
223
reachable: split_reachable.as_ref().unwrap_or(&reachable),
224
};
225
226
if let Some((id, ref_map, pending_refs)) = clone_unit(
227
compilation,
228
module,
229
&unit,
230
split_unit.as_ref(),
231
split_dwarf.as_ref(),
232
&context,
233
&addr_tr,
234
out_encoding,
235
&out_module_synthetic_unit,
236
&mut out_units,
237
&mut out_strings,
238
&mut translated,
239
isa,
240
)? {
241
di_ref_map.insert(&header, id, ref_map);
242
pending_di_refs.push((id, pending_refs));
243
}
244
}
245
}
246
di_ref_map.patch(pending_di_refs.into_iter(), &mut out_units);
247
248
generate_simulated_dwarf(
249
compilation,
250
&transforms,
251
&translated,
252
out_encoding,
253
&vmctx_ptr_die_refs,
254
&mut out_units,
255
&mut out_strings,
256
isa,
257
)?;
258
259
Ok(write::Dwarf {
260
units: out_units,
261
line_programs: vec![],
262
line_strings: out_line_strings,
263
strings: out_strings,
264
})
265
}
266
267
fn replace_unit_from_split_dwarf<'a>(
268
unit: &'a Unit<gimli::EndianSlice<'a, gimli::LittleEndian>, usize>,
269
dwp: &DwarfPackage<gimli::EndianSlice<'a, gimli::LittleEndian>>,
270
parent: &Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>>,
271
) -> Option<(
272
Unit<gimli::EndianSlice<'a, gimli::LittleEndian>, usize>,
273
Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>>,
274
)> {
275
let dwo_id = unit.dwo_id?;
276
let split_unit_dwarf = dwp.find_cu(dwo_id, parent).ok()??;
277
let unit_header = split_unit_dwarf.debug_info.units().next().ok()??;
278
let mut split_unit = split_unit_dwarf.unit(unit_header).ok()?;
279
split_unit.copy_relocated_attributes(unit);
280
Some((split_unit, split_unit_dwarf))
281
}
282
283