Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/debug/transform/synthetic.rs
1693 views
1
use gimli::write::{
2
AttributeValue, LineProgram, Reference, StringTable, Unit, UnitEntryId, UnitId, UnitTable,
3
};
4
use wasmtime_environ::StaticModuleIndex;
5
use wasmtime_versioned_export_macros::versioned_stringify_ident;
6
7
use crate::debug::{Compilation, ModuleMemoryOffset};
8
9
/// Internal Wasm utility types DIEs such as WebAssemblyPtr and WasmtimeVMContext.
10
///
11
/// For unwrapping Wasm pointer, the WasmtimeVMContext has the `set()` method
12
/// that allows to control current Wasm memory to inspect.
13
/// Notice that "wasmtime_set_vmctx_memory" is an external/builtin subprogram
14
/// that is not part of Wasm code.
15
///
16
/// This CU is currently per-module since VMContext memory structure is per-module;
17
/// some of the contained types could be made global (per-Compilation).
18
pub struct ModuleSyntheticUnit {
19
unit_id: UnitId,
20
vmctx_ptr_die_id: UnitEntryId,
21
wasm_ptr_die_id: UnitEntryId,
22
}
23
24
macro_rules! add_tag {
25
($unit:ident, $parent_id:ident, $tag:expr => $die:ident as $die_id:ident { $($a:path = $v:expr),* }) => {
26
let $die_id = $unit.add($parent_id, $tag);
27
let $die = $unit.get_mut($die_id);
28
$( $die.set($a, $v); )*
29
};
30
}
31
32
impl ModuleSyntheticUnit {
33
pub fn new(
34
module: StaticModuleIndex,
35
compilation: &Compilation<'_>,
36
encoding: gimli::Encoding,
37
out_units: &mut UnitTable,
38
out_strings: &mut StringTable,
39
) -> Self {
40
let unit_id = Self::create_unit(encoding, out_units, out_strings);
41
let unit = out_units.get_mut(unit_id);
42
let vmctx_ptr_die_id = Self::create_vmctx_ptr_die(module, compilation, unit, out_strings);
43
let wasm_ptr_die_id = Self::create_wasm_ptr_die(unit, out_strings);
44
45
Self {
46
unit_id,
47
vmctx_ptr_die_id,
48
wasm_ptr_die_id,
49
}
50
}
51
52
pub fn vmctx_ptr_die_ref(&self) -> Reference {
53
Reference::Entry(self.unit_id, self.vmctx_ptr_die_id)
54
}
55
56
pub fn wasm_ptr_die_ref(&self) -> Reference {
57
Reference::Entry(self.unit_id, self.wasm_ptr_die_id)
58
}
59
60
fn create_unit(
61
encoding: gimli::Encoding,
62
out_units: &mut UnitTable,
63
out_strings: &mut StringTable,
64
) -> UnitId {
65
let unit_id = out_units.add(Unit::new(encoding, LineProgram::none()));
66
let unit = out_units.get_mut(unit_id);
67
let unit_die = unit.get_mut(unit.root());
68
unit_die.set(
69
gimli::DW_AT_name,
70
AttributeValue::StringRef(out_strings.add("WasmtimeModuleSyntheticUnit")),
71
);
72
unit_die.set(
73
gimli::DW_AT_producer,
74
AttributeValue::StringRef(out_strings.add("wasmtime")),
75
);
76
unit_die.set(
77
gimli::DW_AT_language,
78
AttributeValue::Language(gimli::DW_LANG_C11),
79
);
80
unit_id
81
}
82
83
fn create_vmctx_ptr_die(
84
module: StaticModuleIndex,
85
compilation: &Compilation<'_>,
86
unit: &mut Unit,
87
out_strings: &mut StringTable,
88
) -> UnitEntryId {
89
// Build DW_TAG_base_type for Wasm byte:
90
// .. DW_AT_name = u8
91
// .. DW_AT_encoding = DW_ATE_unsigned
92
// .. DW_AT_byte_size = 1
93
let root_id = unit.root();
94
add_tag!(unit, root_id, gimli::DW_TAG_base_type => memory_byte_die as memory_byte_die_id {
95
gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("u8")),
96
gimli::DW_AT_encoding = AttributeValue::Encoding(gimli::DW_ATE_unsigned),
97
gimli::DW_AT_byte_size = AttributeValue::Data1(1)
98
});
99
100
// Build DW_TAG_pointer_type that references Wasm bytes:
101
// .. DW_AT_name = "u8*"
102
// .. DW_AT_type = <memory_byte_die>
103
add_tag!(unit, root_id, gimli::DW_TAG_pointer_type => memory_bytes_die as memory_bytes_die_id {
104
gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("u8*")),
105
gimli::DW_AT_type = AttributeValue::UnitRef(memory_byte_die_id)
106
});
107
108
// Create artificial VMContext type and its reference for convenience viewing
109
// its fields (such as memory ref) in a debugger. Build DW_TAG_structure_type:
110
// .. DW_AT_name = "WasmtimeVMContext"
111
let vmctx_die_id = unit.add(root_id, gimli::DW_TAG_structure_type);
112
let vmctx_die = unit.get_mut(vmctx_die_id);
113
vmctx_die.set(
114
gimli::DW_AT_name,
115
AttributeValue::StringRef(out_strings.add("WasmtimeVMContext")),
116
);
117
118
// TODO multiple memories
119
match compilation.module_memory_offsets[module] {
120
ModuleMemoryOffset::Defined(memory_offset) => {
121
// The context has defined memory: extend the WasmtimeVMContext size
122
// past the "memory" field.
123
const MEMORY_FIELD_SIZE_PLUS_PADDING: u32 = 8;
124
vmctx_die.set(
125
gimli::DW_AT_byte_size,
126
AttributeValue::Data4(memory_offset + MEMORY_FIELD_SIZE_PLUS_PADDING),
127
);
128
129
// Define the "memory" field which is a direct pointer to allocated Wasm memory.
130
// Build DW_TAG_member:
131
// .. DW_AT_name = "memory"
132
// .. DW_AT_type = <memory_bytes_die>
133
// .. DW_AT_data_member_location = `memory_offset`
134
add_tag!(unit, vmctx_die_id, gimli::DW_TAG_member => m_die as m_die_id {
135
gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("memory")),
136
gimli::DW_AT_type = AttributeValue::UnitRef(memory_bytes_die_id),
137
gimli::DW_AT_data_member_location = AttributeValue::Udata(memory_offset as u64)
138
});
139
}
140
ModuleMemoryOffset::Imported { .. } => {
141
// TODO implement convenience pointer to and additional types for VMMemoryImport.
142
}
143
ModuleMemoryOffset::None => (),
144
}
145
146
// Build DW_TAG_pointer_type for `WasmtimeVMContext*`:
147
// .. DW_AT_name = "WasmtimeVMContext*"
148
// .. DW_AT_type = <vmctx_die>
149
add_tag!(unit, root_id, gimli::DW_TAG_pointer_type => vmctx_ptr_die as vmctx_ptr_die_id {
150
gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("WasmtimeVMContext*")),
151
gimli::DW_AT_type = AttributeValue::UnitRef(vmctx_die_id)
152
});
153
154
// Build vmctx_die's DW_TAG_subprogram for `set` method:
155
// .. DW_AT_linkage_name = "wasmtime_set_vmctx_memory"
156
// .. DW_AT_name = "set"
157
// .. DW_TAG_formal_parameter
158
// .. .. DW_AT_type = <vmctx_ptr_die>
159
// .. .. DW_AT_artificial = 1
160
add_tag!(unit, vmctx_die_id, gimli::DW_TAG_subprogram => vmctx_set as vmctx_set_id {
161
gimli::DW_AT_linkage_name = AttributeValue::StringRef(out_strings.add(versioned_stringify_ident!(wasmtime_set_vmctx_memory))),
162
gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("set"))
163
});
164
add_tag!(unit, vmctx_set_id, gimli::DW_TAG_formal_parameter => vmctx_set_this_param as vmctx_set_this_param_id {
165
gimli::DW_AT_type = AttributeValue::UnitRef(vmctx_ptr_die_id),
166
gimli::DW_AT_artificial = AttributeValue::Flag(true)
167
});
168
169
vmctx_ptr_die_id
170
}
171
172
fn create_wasm_ptr_die(unit: &mut Unit, out_strings: &mut StringTable) -> UnitEntryId {
173
// Build DW_TAG_base_type for generic `WebAssemblyPtr`.
174
// .. DW_AT_name = "WebAssemblyPtr"
175
// .. DW_AT_byte_size = 4
176
// .. DW_AT_encoding = DW_ATE_unsigned
177
const WASM_PTR_LEN: u8 = 4;
178
let root_id = unit.root();
179
add_tag!(unit, root_id, gimli::DW_TAG_base_type => wp_die as wp_die_id {
180
gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("WebAssemblyPtr")),
181
gimli::DW_AT_byte_size = AttributeValue::Data1(WASM_PTR_LEN),
182
gimli::DW_AT_encoding = AttributeValue::Encoding(gimli::DW_ATE_unsigned)
183
});
184
185
wp_die_id
186
}
187
}
188
189