Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/debug.rs
1691 views
1
//! Debug utils for WebAssembly using Cranelift.
2
3
// FIXME: this whole crate opts-in to these two noisier-than-default lints, but
4
// this module has lots of hits on this warning which aren't the easiest to
5
// resolve. Ideally all warnings would be resolved here though.
6
#![expect(
7
clippy::cast_possible_truncation,
8
clippy::cast_sign_loss,
9
reason = "haven't had a chance to fix these yet"
10
)]
11
12
use crate::CompiledFunctionMetadata;
13
use core::fmt;
14
use cranelift_codegen::isa::TargetIsa;
15
use object::write::SymbolId;
16
use std::collections::HashMap;
17
use wasmtime_environ::{
18
DefinedFuncIndex, DefinedMemoryIndex, EntityRef, MemoryIndex, ModuleTranslation,
19
OwnedMemoryIndex, PrimaryMap, PtrSize, StaticModuleIndex, Tunables, VMOffsets,
20
};
21
22
/// Memory definition offset in the VMContext structure.
23
#[derive(Debug, Clone)]
24
pub enum ModuleMemoryOffset {
25
/// Not available.
26
None,
27
/// Offset to the defined memory.
28
Defined(u32),
29
/// This memory is imported.
30
Imported {
31
/// Offset, in bytes, to the `*mut VMMemoryDefinition` structure within
32
/// `VMContext`.
33
offset_to_vm_memory_definition: u32,
34
/// Offset, in bytes within `VMMemoryDefinition` where the `base` field
35
/// lies.
36
offset_to_memory_base: u32,
37
},
38
}
39
40
type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
41
42
/// "Package structure" to collect together various artifacts/results of a
43
/// compilation.
44
///
45
/// This structure is threaded through a number of top-level functions of DWARF
46
/// processing within in this submodule to pass along all the bits-and-pieces of
47
/// the compilation context.
48
pub struct Compilation<'a> {
49
/// All module translations which were present in this compilation.
50
///
51
/// This map has one entry for core wasm modules and may have multiple (or
52
/// zero) for components.
53
translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
54
55
/// Accessor of a particular compiled function for a module.
56
///
57
/// This returns the `object`-based-symbol for the function as well as the
58
/// `&CompiledFunction`.
59
get_func:
60
&'a dyn Fn(StaticModuleIndex, DefinedFuncIndex) -> (SymbolId, &'a CompiledFunctionMetadata),
61
62
/// Optionally-specified `*.dwp` file, currently only supported for core
63
/// wasm modules.
64
dwarf_package_bytes: Option<&'a [u8]>,
65
66
/// Compilation settings used when producing functions.
67
tunables: &'a Tunables,
68
69
/// Translation between `SymbolId` and a `usize`-based symbol which gimli
70
/// uses.
71
symbol_index_to_id: Vec<SymbolId>,
72
symbol_id_to_index: HashMap<SymbolId, (usize, StaticModuleIndex, DefinedFuncIndex)>,
73
74
/// The `ModuleMemoryOffset` for each module within `translations`.
75
///
76
/// Note that this doesn't support multi-memory at this time.
77
module_memory_offsets: PrimaryMap<StaticModuleIndex, ModuleMemoryOffset>,
78
}
79
80
impl<'a> Compilation<'a> {
81
pub fn new(
82
isa: &dyn TargetIsa,
83
translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
84
get_func: &'a dyn Fn(
85
StaticModuleIndex,
86
DefinedFuncIndex,
87
) -> (SymbolId, &'a CompiledFunctionMetadata),
88
dwarf_package_bytes: Option<&'a [u8]>,
89
tunables: &'a Tunables,
90
) -> Compilation<'a> {
91
// Build the `module_memory_offsets` map based on the modules in
92
// `translations`.
93
let mut module_memory_offsets = PrimaryMap::new();
94
for (i, translation) in translations {
95
let ofs = VMOffsets::new(
96
isa.triple().architecture.pointer_width().unwrap().bytes(),
97
&translation.module,
98
);
99
100
let memory_offset = if ofs.num_imported_memories > 0 {
101
let index = MemoryIndex::new(0);
102
ModuleMemoryOffset::Imported {
103
offset_to_vm_memory_definition: ofs.vmctx_vmmemory_import(index)
104
+ u32::from(ofs.vmmemory_import_from()),
105
offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),
106
}
107
} else if ofs.num_owned_memories > 0 {
108
let index = OwnedMemoryIndex::new(0);
109
ModuleMemoryOffset::Defined(ofs.vmctx_vmmemory_definition_base(index))
110
} else if ofs.num_defined_memories > 0 {
111
let index = DefinedMemoryIndex::new(0);
112
ModuleMemoryOffset::Imported {
113
offset_to_vm_memory_definition: ofs.vmctx_vmmemory_pointer(index),
114
offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),
115
}
116
} else {
117
ModuleMemoryOffset::None
118
};
119
let j = module_memory_offsets.push(memory_offset);
120
assert_eq!(i, j);
121
}
122
123
// Build the `symbol <=> usize` mappings
124
let mut symbol_index_to_id = Vec::new();
125
let mut symbol_id_to_index = HashMap::new();
126
127
for (module, translation) in translations {
128
for func in translation.module.defined_func_indices() {
129
let (sym, _func) = get_func(module, func);
130
symbol_id_to_index.insert(sym, (symbol_index_to_id.len(), module, func));
131
symbol_index_to_id.push(sym);
132
}
133
}
134
135
Compilation {
136
translations,
137
get_func,
138
dwarf_package_bytes,
139
tunables,
140
symbol_index_to_id,
141
symbol_id_to_index,
142
module_memory_offsets,
143
}
144
}
145
146
/// Returns an iterator over all function indexes present in this
147
/// compilation.
148
///
149
/// Each function is additionally accompanied with its module index.
150
fn indexes(&self) -> impl Iterator<Item = (StaticModuleIndex, DefinedFuncIndex)> + use<'_> {
151
self.translations
152
.iter()
153
.flat_map(|(i, t)| t.module.defined_func_indices().map(move |j| (i, j)))
154
}
155
156
/// Returns an iterator of all functions with their module, symbol, and
157
/// function metadata that were produced during compilation.
158
fn functions(
159
&self,
160
) -> impl Iterator<Item = (StaticModuleIndex, usize, &'a CompiledFunctionMetadata)> + '_ {
161
self.indexes().map(move |(module, func)| {
162
let (sym, func) = self.function(module, func);
163
(module, sym, func)
164
})
165
}
166
167
/// Returns the symbol and metadata associated with a specific function.
168
fn function(
169
&self,
170
module: StaticModuleIndex,
171
func: DefinedFuncIndex,
172
) -> (usize, &'a CompiledFunctionMetadata) {
173
let (sym, func) = (self.get_func)(module, func);
174
(self.symbol_id_to_index[&sym].0, func)
175
}
176
177
/// Maps a `usize`-based symbol used by gimli to the object-based
178
/// `SymbolId`.
179
pub fn symbol_id(&self, sym: usize) -> SymbolId {
180
self.symbol_index_to_id[sym]
181
}
182
}
183
184
impl<'a> fmt::Debug for Compilation<'a> {
185
// Sample output: '[#0: OneModule, #1: TwoModule, #3]'.
186
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187
write!(f, "[")?;
188
let mut is_first_module = true;
189
for (i, translation) in self.translations {
190
if !is_first_module {
191
write!(f, ", ")?;
192
} else {
193
is_first_module = false;
194
}
195
write!(f, "#{}", i.as_u32())?;
196
if let Some(name) = translation.debuginfo.name_section.module_name {
197
write!(f, ": {name}")?;
198
}
199
}
200
write!(f, "]")
201
}
202
}
203
204
pub use write_debuginfo::{DwarfSectionRelocTarget, emit_dwarf};
205
206
mod gc;
207
mod transform;
208
mod write_debuginfo;
209
210