Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/environ/src/compile/module_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,12 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
params: sig.params().into(),
});
}
if self.tunables.debug_guest {
// All functions are potentially reachable and
// callable by the guest debugger, so they must
// all be flagged as escaping.
self.flag_func_escaped(func_index);
}
Comment thread
cfallin marked this conversation as resolved.
self.result
.function_body_inputs
.push(FunctionBodyData { validator, body });
Expand Down
225 changes: 224 additions & 1 deletion crates/wasmtime/src/runtime/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use core::{ffi::c_void, ptr::NonNull};
use wasmtime_environ::FrameTable;
use wasmtime_environ::{
DefinedFuncIndex, FrameInstPos, FrameStackShape, FrameStateSlot, FrameStateSlotOffset,
FrameTableBreakpointData, FrameTableDescriptorIndex, FrameValType, FuncKey, Trap,
FrameTableBreakpointData, FrameTableDescriptorIndex, FrameValType, FuncIndex, FuncKey,
GlobalIndex, MemoryIndex, TableIndex, TagIndex, Trap,
};
use wasmtime_unwinder::Frame;

Expand Down Expand Up @@ -65,6 +66,228 @@ impl<'a, T> StoreContextMut<'a, T> {
}
}

impl Instance {
/// Get access to a global within this instance's globals index
/// space.
///
/// This permits accessing globals whether they are exported or
/// not. However, it is only available for purposes of debugging,
/// and so is only permitted when `guest_debug` is enabled in the
/// Engine's configuration. The intent of the Wasmtime API is to
/// enforce the Wasm type system's encapsulation even in the host
/// API, except where necessary for developer tooling.
///
/// `None` is returned for any global index that is out-of-bounds.
///
/// `None` is returned if guest-debugging is not enabled in the
/// engine configuration for this Store.
pub fn debug_global(
&self,
mut store: impl AsContextMut,
global_index: u32,
) -> Option<crate::Global> {
let store = store.as_context_mut().0;
if !store.engine().tunables().debug_guest {
return None;
}

let instance = &store[self.id];
let env_module = self.module(&store).env_module();
// N.B.: `from_bits` here rather than `from_u32` so we don't
// panic on `u32::MAX`. A `u32::MAX` will become an invalid
// entity index which will properly return `None` below.
let global = GlobalIndex::from_bits(global_index);
if env_module.globals.is_valid(global) {
Some(instance.get_exported_global(store.id(), global))
} else {
None
}
}

/// Get access to a memory (unshared only) within this instance's
/// memory index space.
///
/// This permits accessing memories whether they are exported or
/// not. However, it is only available for purposes of debugging,
/// and so is only permitted when `guest_debug` is enabled in the
/// Engine's configuration. The intent of the Wasmtime API is to
/// enforce the Wasm type system's encapsulation even in the host
/// API, except where necessary for developer tooling.
///
/// `None` is returned for any memory index that is out-of-bounds.
///
/// `None` is returned for any shared memory (use
/// `debug_shared_memory` instead).
///
/// `None` is returned if guest-debugging is not enabled in the
/// engine configuration for this Store.
pub fn debug_memory(
&self,
mut store: impl AsContextMut,
memory_index: u32,
) -> Option<crate::Memory> {
let store = store.as_context_mut().0;
if !store.engine().tunables().debug_guest {
return None;
}

let instance = &store[self.id];
let env_module = self.module(&store).env_module();
let memory = MemoryIndex::from_bits(memory_index);
if env_module.memories.is_valid(memory) {
Some(
instance
.get_exported_memory(store.id(), memory)
.unshared()?,
)
} else {
None
}
}

/// Get access to a shared memory within this instance's memory
/// index space.
///
/// This permits accessing memories whether they are exported or
/// not. However, it is only available for purposes of debugging,
/// and so is only permitted when `guest_debug` is enabled in the
/// Engine's configuration. The intent of the Wasmtime API is to
/// enforce the Wasm type system's encapsulation even in the host
/// API, except where necessary for developer tooling.
///
/// `None` is returned for any memory index that is out-of-bounds.
///
/// `None` is returned for any unshared memory (use `debug_memory`
/// instead).
///
/// `None` is returned if guest-debugging is not enabled in the
/// engine configuration for this Store.
pub fn debug_shared_memory(
&self,
mut store: impl AsContextMut,
memory_index: u32,
) -> Option<crate::SharedMemory> {
let store = store.as_context_mut().0;
if !store.engine().tunables().debug_guest {
return None;
}

let instance = &store[self.id];
let env_module = self.module(&store).env_module();
let memory = MemoryIndex::from_bits(memory_index);
if env_module.memories.is_valid(memory) {
Some(crate::SharedMemory::from_raw(
instance.get_exported_memory(store.id(), memory).shared()?,
store.engine().clone(),
))
} else {
None
}
}

/// Get access to a table within this instance's table index
/// space.
///
/// This permits accessing tables whether they are exported or
/// not. However, it is only available for purposes of debugging,
/// and so is only permitted when `guest_debug` is enabled in the
/// Engine's configuration. The intent of the Wasmtime API is to
/// enforce the Wasm type system's encapsulation even in the host
/// API, except where necessary for developer tooling.
///
/// `None` is returned for any table index that is out-of-bounds.
///
/// `None` is returned if guest-debugging is not enabled in the
/// engine configuration for this Store.
pub fn debug_table(
&self,
mut store: impl AsContextMut,
table_index: u32,
) -> Option<crate::Table> {
let store = store.as_context_mut().0;
if !store.engine().tunables().debug_guest {
return None;
}

let instance = &store[self.id];
let env_module = self.module(&store).env_module();
let table = TableIndex::from_bits(table_index);
if env_module.tables.is_valid(table) {
Some(instance.get_exported_table(store.id(), table))
} else {
None
}
}

/// Get access to a function within this instance's function index
/// space.
///
/// This permits accessing functions whether they are exported or
/// not. However, it is only available for purposes of debugging,
/// and so is only permitted when `guest_debug` is enabled in the
/// Engine's configuration. The intent of the Wasmtime API is to
/// enforce the Wasm type system's encapsulation even in the host
/// API, except where necessary for developer tooling.
///
/// `None` is returned for any function index that is
/// out-of-bounds.
///
/// `None` is returned if guest-debugging is not enabled in the
/// engine configuration for this Store.
pub fn debug_function(
&self,
mut store: impl AsContextMut,
function_index: u32,
) -> Option<crate::Func> {
let store = store.as_context_mut().0;
if !store.engine().tunables().debug_guest {
return None;
}

let env_module = self.module(&store).env_module();
let func = FuncIndex::from_bits(function_index);
if env_module.functions.is_valid(func) {
let store_id = store.id();
let (instance, registry) = store.instance_and_module_registry_mut(self.id());
// SAFETY: the `store` and `registry` are associated with
// this instance as we fetched teh instance directly from
// the store above.
unsafe { Some(instance.get_exported_func(registry, store_id, func)) }
} else {
None
}
}

/// Get access to a tag within this instance's tag index space.
///
/// This permits accessing tags whether they are exported or
/// not. However, it is only available for purposes of debugging,
/// and so is only permitted when `guest_debug` is enabled in the
/// Engine's configuration. The intent of the Wasmtime API is to
/// enforce the Wasm type system's encapsulation even in the host
/// API, except where necessary for developer tooling.
///
/// `None` is returned for any tag index that is out-of-bounds.
///
/// `None` is returned if guest-debugging is not enabled in the
/// engine configuration for this Store.
pub fn debug_tag(&self, mut store: impl AsContextMut, tag_index: u32) -> Option<crate::Tag> {
let store = store.as_context_mut().0;
if !store.engine().tunables().debug_guest {
return None;
}

let instance = &store[self.id];
let env_module = self.module(&store).env_module();
let tag = TagIndex::from_bits(tag_index);
if env_module.tags.is_valid(tag) {
Some(instance.get_exported_tag(store.id(), tag))
} else {
None
}
}
}

impl<'a, T> StoreContext<'a, T> {
/// Return all breakpoints.
pub fn breakpoints(self) -> Option<impl Iterator<Item = Breakpoint> + 'a> {
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use wasmtime_environ::{
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Instance {
id: StoreInstanceId,
pub(crate) id: StoreInstanceId,
Comment thread
cfallin marked this conversation as resolved.
}

// Double-check that the C representation in `instance.h` matches our in-Rust
Expand Down
6 changes: 6 additions & 0 deletions crates/wasmtime/src/runtime/vm/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,10 @@ impl ExportMemory {
ExportMemory::Shared(..) => None,
}
}
pub fn shared(self) -> Option<SharedMemory> {
match self {
ExportMemory::Unshared(_) => None,
ExportMemory::Shared(m, _) => Some(m),
}
}
}
Loading