From 04df87300c3977763c8e929e172b643e2ed7853a Mon Sep 17 00:00:00 2001 From: Rainy Sinclair <844493+itsrainy@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:49:54 -0400 Subject: [PATCH] Include globals and memories in core dumps Co-authored-by: Nick Fitzgerald --- crates/runtime/src/instance.rs | 43 +++++++++++++++ crates/wasmtime/src/coredump.rs | 2 +- crates/wasmtime/src/instance.rs | 9 ++++ crates/wasmtime/src/store.rs | 69 ++++++++++++++++++------ crates/wasmtime/src/store/data.rs | 6 +++ crates/wasmtime/src/trampoline/global.rs | 4 +- crates/wasmtime/src/trap.rs | 2 +- crates/wasmtime/src/types.rs | 9 ++++ 8 files changed, 125 insertions(+), 19 deletions(-) diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index d6db99df9e70..d0edc54b3e54 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -351,6 +351,13 @@ impl Instance { unsafe { *self.vmctx_plus_offset(self.offsets().vmctx_vmmemory_pointer(index)) } } + /// Return the memories defined in this instance + pub fn defined_memories<'a>( + &'a self, + ) -> impl ExactSizeIterator + 'a { + self.memories.iter() + } + /// Return the indexed `VMGlobalDefinition`. fn global(&mut self, index: DefinedGlobalIndex) -> &VMGlobalDefinition { unsafe { &*self.global_ptr(index) } @@ -376,6 +383,25 @@ impl Instance { } } + /// Get the globals defined in this instance + pub fn defined_globals<'a>( + &'a mut self, + ) -> impl ExactSizeIterator + 'a { + let module = self.module().clone(); + module + .globals + .keys() + .skip(module.num_imported_globals) + .map(move |global_idx| { + let def_idx = module.defined_global_index(global_idx).unwrap(); + let global = ExportGlobal { + definition: self.global_ptr(def_idx), + global: self.module().globals[global_idx], + }; + (def_idx, global) + }) + } + /// Return a pointer to the interrupts structure pub fn runtime_limits(&mut self) -> *mut *const VMRuntimeLimits { unsafe { self.vmctx_plus_offset_mut(self.offsets().vmctx_runtime_limits()) } @@ -1323,6 +1349,23 @@ impl InstanceHandle { self.instance_mut().get_table_with_lazy_init(index, range) } + /// Return the memories defined in this instance + pub fn defined_memories<'a>(&'a mut self) -> impl ExactSizeIterator + 'a { + let idxs = (0..self.module().memory_plans.len()) + .skip(self.module().num_imported_memories) + .map(|i| MemoryIndex::new(i)) + .collect::>(); + idxs.into_iter() + .map(|memidx| self.get_exported_memory(memidx)) + } + + /// Get the globals defined in this instance + pub fn defined_globals<'a>( + &'a mut self, + ) -> impl ExactSizeIterator + 'a { + self.instance_mut().defined_globals() + } + /// Return a reference to the contained `Instance`. #[inline] pub(crate) fn instance(&self) -> &Instance { diff --git a/crates/wasmtime/src/coredump.rs b/crates/wasmtime/src/coredump.rs index d7047c5102dc..de254391aee9 100644 --- a/crates/wasmtime/src/coredump.rs +++ b/crates/wasmtime/src/coredump.rs @@ -34,7 +34,7 @@ pub struct WasmCoreDump { } impl WasmCoreDump { - pub(crate) fn new(store: &StoreOpaque, backtrace: WasmBacktrace) -> WasmCoreDump { + pub(crate) fn new(store: &mut StoreOpaque, backtrace: WasmBacktrace) -> WasmCoreDump { let modules: Vec<_> = store.modules().all_modules().cloned().collect(); let instances: Vec = store.all_instances().collect(); let store_memories: Vec = store.all_memories().collect(); diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 1489903012ab..380321c1db51 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -42,6 +42,15 @@ pub(crate) struct InstanceData { exports: Vec>, } +impl InstanceData { + pub fn from_index(idx: usize) -> InstanceData { + InstanceData { + id: InstanceId::from_index(idx), + exports: vec![], + } + } +} + impl Instance { /// Creates a new [`Instance`] from the previously compiled [`Module`] and /// list of `imports` specified. diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 437db281e33c..ccf75a0c4d6e 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -96,9 +96,9 @@ use std::sync::atomic::AtomicU64; use std::sync::Arc; use std::task::{Context, Poll}; use wasmtime_runtime::{ - ExportGlobal, ExportMemory, InstanceAllocationRequest, InstanceAllocator, InstanceHandle, - ModuleInfo, OnDemandInstanceAllocator, SignalHandler, StoreBox, StorePtr, VMContext, - VMExternRef, VMExternRefActivationsTable, VMFuncRef, VMRuntimeLimits, WasmFault, + ExportGlobal, InstanceAllocationRequest, InstanceAllocator, InstanceHandle, ModuleInfo, + OnDemandInstanceAllocator, SignalHandler, StoreBox, StorePtr, VMContext, VMExternRef, + VMExternRefActivationsTable, VMFuncRef, VMRuntimeLimits, WasmFault, }; mod context; @@ -1263,22 +1263,61 @@ impl StoreOpaque { &mut self.instances[id.0].handle } - pub fn all_instances(&self) -> impl ExactSizeIterator { - self.store_data() - .iter::() - .map(Instance::from_stored) + pub fn all_instances<'a>(&'a mut self) -> impl ExactSizeIterator + 'a { + let instances = self + .instances + .iter() + .enumerate() + .map(|(idx, _)| InstanceData::from_index(idx)) + .collect::>(); + instances + .into_iter() + .map(|i| Instance::from_wasmtime(i, self)) } - pub fn all_memories(&self) -> impl ExactSizeIterator { - self.store_data() - .iter::() - .map(Memory::from_stored) + pub fn all_memories<'a>(&'a mut self) -> impl Iterator + 'a { + unsafe { + let mems = self + .instances + .iter_mut() + .flat_map(|instance| instance.handle.defined_memories()) + .collect::>(); + mems.into_iter() + .map(|memory| Memory::from_wasmtime_memory(memory, self)) + } } - pub fn all_globals(&self) -> impl ExactSizeIterator { - self.store_data() - .iter::() - .map(Global::from_stored) + // TODO: have this (and the above methods) put these into a hashset and dedupe them + // (from_wasmtime_global inserts duplicates into the store, so dedupe here) + pub fn all_globals<'a>(&'a mut self) -> impl Iterator + 'a { + unsafe { + // host globals first + let host_globals = self + .host_globals() + .iter() + .map(|global| ExportGlobal { + definition: &mut (*global.get()).global as *mut _, + global: (*global.get()).ty.to_wasm_type(), + }) + .collect::>(); + + let host_globals = host_globals + .into_iter() + .map(|g| Global::from_wasmtime_global(g, self)) + .collect::>(); + + // then go through all the instances and emit their globals + let globals = self + .instances + .iter_mut() + .flat_map(|instance| instance.handle.defined_globals()) + .collect::>(); + host_globals.into_iter().chain( + globals + .into_iter() + .map(|(_, global)| Global::from_wasmtime_global(global, self)), + ) + } } #[cfg_attr(not(target_os = "linux"), allow(dead_code))] // not used on all platforms diff --git a/crates/wasmtime/src/store/data.rs b/crates/wasmtime/src/store/data.rs index 08764d293258..390374985f90 100644 --- a/crates/wasmtime/src/store/data.rs +++ b/crates/wasmtime/src/store/data.rs @@ -13,6 +13,12 @@ use std::sync::atomic::{AtomicU64, Ordering::Relaxed}; #[derive(Copy, Clone)] pub struct InstanceId(pub(super) usize); +impl InstanceId { + pub fn from_index(idx: usize) -> InstanceId { + InstanceId(idx) + } +} + pub struct StoreData { id: StoreId, funcs: Vec, diff --git a/crates/wasmtime/src/trampoline/global.rs b/crates/wasmtime/src/trampoline/global.rs index 1e9c44403134..98ed341937df 100644 --- a/crates/wasmtime/src/trampoline/global.rs +++ b/crates/wasmtime/src/trampoline/global.rs @@ -5,8 +5,8 @@ use wasmtime_runtime::{StoreBox, VMGlobalDefinition}; #[repr(C)] pub struct VMHostGlobalContext { - ty: GlobalType, - global: VMGlobalDefinition, + pub(crate) ty: GlobalType, + pub(crate) global: VMGlobalDefinition, } impl Drop for VMHostGlobalContext { diff --git a/crates/wasmtime/src/trap.rs b/crates/wasmtime/src/trap.rs index e62ba73b1f46..1d0437aa1b28 100644 --- a/crates/wasmtime/src/trap.rs +++ b/crates/wasmtime/src/trap.rs @@ -77,7 +77,7 @@ pub(crate) unsafe fn raise(error: anyhow::Error) -> ! { #[cold] // traps are exceptional, this helps move handling off the main path pub(crate) fn from_runtime_box( - store: &StoreOpaque, + store: &mut StoreOpaque, runtime_trap: Box, ) -> Error { let wasmtime_runtime::Trap { diff --git a/crates/wasmtime/src/types.rs b/crates/wasmtime/src/types.rs index b1d33709417a..98b3ca73a67b 100644 --- a/crates/wasmtime/src/types.rs +++ b/crates/wasmtime/src/types.rs @@ -272,6 +272,15 @@ impl GlobalType { self.mutability } + pub(crate) fn to_wasm_type(&self) -> Global { + let wasm_ty = self.content().to_wasm_type(); + let mutability = matches!(self.mutability(), Mutability::Var); + Global { + wasm_ty, + mutability, + } + } + /// Returns `None` if the wasmtime global has a type that we can't /// represent, but that should only very rarely happen and indicate a bug. pub(crate) fn from_wasmtime_global(global: &Global) -> GlobalType {