Path: blob/main/crates/cranelift/src/debug/transform/synthetic.rs
1693 views
use gimli::write::{1AttributeValue, LineProgram, Reference, StringTable, Unit, UnitEntryId, UnitId, UnitTable,2};3use wasmtime_environ::StaticModuleIndex;4use wasmtime_versioned_export_macros::versioned_stringify_ident;56use crate::debug::{Compilation, ModuleMemoryOffset};78/// Internal Wasm utility types DIEs such as WebAssemblyPtr and WasmtimeVMContext.9///10/// For unwrapping Wasm pointer, the WasmtimeVMContext has the `set()` method11/// that allows to control current Wasm memory to inspect.12/// Notice that "wasmtime_set_vmctx_memory" is an external/builtin subprogram13/// that is not part of Wasm code.14///15/// This CU is currently per-module since VMContext memory structure is per-module;16/// some of the contained types could be made global (per-Compilation).17pub struct ModuleSyntheticUnit {18unit_id: UnitId,19vmctx_ptr_die_id: UnitEntryId,20wasm_ptr_die_id: UnitEntryId,21}2223macro_rules! add_tag {24($unit:ident, $parent_id:ident, $tag:expr => $die:ident as $die_id:ident { $($a:path = $v:expr),* }) => {25let $die_id = $unit.add($parent_id, $tag);26let $die = $unit.get_mut($die_id);27$( $die.set($a, $v); )*28};29}3031impl ModuleSyntheticUnit {32pub fn new(33module: StaticModuleIndex,34compilation: &Compilation<'_>,35encoding: gimli::Encoding,36out_units: &mut UnitTable,37out_strings: &mut StringTable,38) -> Self {39let unit_id = Self::create_unit(encoding, out_units, out_strings);40let unit = out_units.get_mut(unit_id);41let vmctx_ptr_die_id = Self::create_vmctx_ptr_die(module, compilation, unit, out_strings);42let wasm_ptr_die_id = Self::create_wasm_ptr_die(unit, out_strings);4344Self {45unit_id,46vmctx_ptr_die_id,47wasm_ptr_die_id,48}49}5051pub fn vmctx_ptr_die_ref(&self) -> Reference {52Reference::Entry(self.unit_id, self.vmctx_ptr_die_id)53}5455pub fn wasm_ptr_die_ref(&self) -> Reference {56Reference::Entry(self.unit_id, self.wasm_ptr_die_id)57}5859fn create_unit(60encoding: gimli::Encoding,61out_units: &mut UnitTable,62out_strings: &mut StringTable,63) -> UnitId {64let unit_id = out_units.add(Unit::new(encoding, LineProgram::none()));65let unit = out_units.get_mut(unit_id);66let unit_die = unit.get_mut(unit.root());67unit_die.set(68gimli::DW_AT_name,69AttributeValue::StringRef(out_strings.add("WasmtimeModuleSyntheticUnit")),70);71unit_die.set(72gimli::DW_AT_producer,73AttributeValue::StringRef(out_strings.add("wasmtime")),74);75unit_die.set(76gimli::DW_AT_language,77AttributeValue::Language(gimli::DW_LANG_C11),78);79unit_id80}8182fn create_vmctx_ptr_die(83module: StaticModuleIndex,84compilation: &Compilation<'_>,85unit: &mut Unit,86out_strings: &mut StringTable,87) -> UnitEntryId {88// Build DW_TAG_base_type for Wasm byte:89// .. DW_AT_name = u890// .. DW_AT_encoding = DW_ATE_unsigned91// .. DW_AT_byte_size = 192let root_id = unit.root();93add_tag!(unit, root_id, gimli::DW_TAG_base_type => memory_byte_die as memory_byte_die_id {94gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("u8")),95gimli::DW_AT_encoding = AttributeValue::Encoding(gimli::DW_ATE_unsigned),96gimli::DW_AT_byte_size = AttributeValue::Data1(1)97});9899// Build DW_TAG_pointer_type that references Wasm bytes:100// .. DW_AT_name = "u8*"101// .. DW_AT_type = <memory_byte_die>102add_tag!(unit, root_id, gimli::DW_TAG_pointer_type => memory_bytes_die as memory_bytes_die_id {103gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("u8*")),104gimli::DW_AT_type = AttributeValue::UnitRef(memory_byte_die_id)105});106107// Create artificial VMContext type and its reference for convenience viewing108// its fields (such as memory ref) in a debugger. Build DW_TAG_structure_type:109// .. DW_AT_name = "WasmtimeVMContext"110let vmctx_die_id = unit.add(root_id, gimli::DW_TAG_structure_type);111let vmctx_die = unit.get_mut(vmctx_die_id);112vmctx_die.set(113gimli::DW_AT_name,114AttributeValue::StringRef(out_strings.add("WasmtimeVMContext")),115);116117// TODO multiple memories118match compilation.module_memory_offsets[module] {119ModuleMemoryOffset::Defined(memory_offset) => {120// The context has defined memory: extend the WasmtimeVMContext size121// past the "memory" field.122const MEMORY_FIELD_SIZE_PLUS_PADDING: u32 = 8;123vmctx_die.set(124gimli::DW_AT_byte_size,125AttributeValue::Data4(memory_offset + MEMORY_FIELD_SIZE_PLUS_PADDING),126);127128// Define the "memory" field which is a direct pointer to allocated Wasm memory.129// Build DW_TAG_member:130// .. DW_AT_name = "memory"131// .. DW_AT_type = <memory_bytes_die>132// .. DW_AT_data_member_location = `memory_offset`133add_tag!(unit, vmctx_die_id, gimli::DW_TAG_member => m_die as m_die_id {134gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("memory")),135gimli::DW_AT_type = AttributeValue::UnitRef(memory_bytes_die_id),136gimli::DW_AT_data_member_location = AttributeValue::Udata(memory_offset as u64)137});138}139ModuleMemoryOffset::Imported { .. } => {140// TODO implement convenience pointer to and additional types for VMMemoryImport.141}142ModuleMemoryOffset::None => (),143}144145// Build DW_TAG_pointer_type for `WasmtimeVMContext*`:146// .. DW_AT_name = "WasmtimeVMContext*"147// .. DW_AT_type = <vmctx_die>148add_tag!(unit, root_id, gimli::DW_TAG_pointer_type => vmctx_ptr_die as vmctx_ptr_die_id {149gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("WasmtimeVMContext*")),150gimli::DW_AT_type = AttributeValue::UnitRef(vmctx_die_id)151});152153// Build vmctx_die's DW_TAG_subprogram for `set` method:154// .. DW_AT_linkage_name = "wasmtime_set_vmctx_memory"155// .. DW_AT_name = "set"156// .. DW_TAG_formal_parameter157// .. .. DW_AT_type = <vmctx_ptr_die>158// .. .. DW_AT_artificial = 1159add_tag!(unit, vmctx_die_id, gimli::DW_TAG_subprogram => vmctx_set as vmctx_set_id {160gimli::DW_AT_linkage_name = AttributeValue::StringRef(out_strings.add(versioned_stringify_ident!(wasmtime_set_vmctx_memory))),161gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("set"))162});163add_tag!(unit, vmctx_set_id, gimli::DW_TAG_formal_parameter => vmctx_set_this_param as vmctx_set_this_param_id {164gimli::DW_AT_type = AttributeValue::UnitRef(vmctx_ptr_die_id),165gimli::DW_AT_artificial = AttributeValue::Flag(true)166});167168vmctx_ptr_die_id169}170171fn create_wasm_ptr_die(unit: &mut Unit, out_strings: &mut StringTable) -> UnitEntryId {172// Build DW_TAG_base_type for generic `WebAssemblyPtr`.173// .. DW_AT_name = "WebAssemblyPtr"174// .. DW_AT_byte_size = 4175// .. DW_AT_encoding = DW_ATE_unsigned176const WASM_PTR_LEN: u8 = 4;177let root_id = unit.root();178add_tag!(unit, root_id, gimli::DW_TAG_base_type => wp_die as wp_die_id {179gimli::DW_AT_name = AttributeValue::StringRef(out_strings.add("WebAssemblyPtr")),180gimli::DW_AT_byte_size = AttributeValue::Data1(WASM_PTR_LEN),181gimli::DW_AT_encoding = AttributeValue::Encoding(gimli::DW_ATE_unsigned)182});183184wp_die_id185}186}187188189