Skip to content

Commit bc6483b

Browse files
authored
Debugging: add debug_all_modules() / debug_all_instances() accessors on Store. (#12637)
* Debugging: add `debug_all_modules()` / `debug_all_instances()` accessors on `Store`. When writing a debugger top-half using Wasmtime's debug APIs, it is essential to be able to list all moules, and all instances, within a `Store`. This PR adds those APIs. The way in which the debug APIs are placed on Store/StoreContextMut/Caller/etc is also refactored to be more uniform. * ignore new test with compilation in miri
1 parent 1e0b0b4 commit bc6483b

2 files changed

Lines changed: 126 additions & 20 deletions

File tree

crates/wasmtime/src/runtime/debug.rs

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,86 @@ impl<T> Store<T> {
4747
pub fn edit_breakpoints<'a>(&'a mut self) -> Option<BreakpointEdit<'a>> {
4848
self.as_store_opaque().edit_breakpoints()
4949
}
50+
51+
/// Get a vector of all Instances held in the Store, for debug
52+
/// purposes.
53+
///
54+
/// Guest debugging must be enabled for this accessor to return
55+
/// any instances. If it is not, an empty vector is returend.
56+
pub fn debug_all_instances(&mut self) -> Vec<Instance> {
57+
self.as_store_opaque().debug_all_instances()
58+
}
59+
60+
/// Get a vector of all Modules held in the Store, for debug
61+
/// purposes.
62+
///
63+
/// Guest debugging must be enabled for this accessor to return
64+
/// any modules. If it is not, an empty vector is returend.
65+
pub fn debug_all_modules(&mut self) -> Vec<Module> {
66+
self.as_store_opaque().debug_all_modules()
67+
}
68+
}
69+
70+
impl<'a, T> StoreContextMut<'a, T> {
71+
/// Provide a frame handle for all activations, in order from
72+
/// innermost (most recently called) to outermost on the stack.
73+
///
74+
/// See [`Store::debug_exit_frames`] for more details.
75+
pub fn debug_exit_frames(&mut self) -> impl Iterator<Item = FrameHandle> {
76+
self.0.as_store_opaque().debug_exit_frames()
77+
}
78+
79+
/// Start an edit session to update breakpoints.
80+
pub fn edit_breakpoints(self) -> Option<BreakpointEdit<'a>> {
81+
self.0.as_store_opaque().edit_breakpoints()
82+
}
83+
84+
/// Get a vector of all Instances held in the Store, for debug
85+
/// purposes.
86+
///
87+
/// See [`Store::debug_all_instances`] for more details.
88+
pub fn debug_all_instances(self) -> Vec<Instance> {
89+
self.0.as_store_opaque().debug_all_instances()
90+
}
91+
92+
/// Get a vector of all Modules held in the Store, for debug
93+
/// purposes.
94+
///
95+
/// See [`Store::debug_all_modules`] for more details.
96+
pub fn debug_all_modules(self) -> Vec<Module> {
97+
self.0.as_store_opaque().debug_all_modules()
98+
}
99+
}
100+
101+
impl<'a, T> Caller<'a, T> {
102+
/// Provide a frame handle for all activations, in order from
103+
/// innermost (most recently called) to outermost on the stack.
104+
///
105+
/// See [`Store::debug_exit_frames`] for more details.
106+
pub fn debug_exit_frames(&mut self) -> impl Iterator<Item = FrameHandle> {
107+
self.store.0.as_store_opaque().debug_exit_frames()
108+
}
109+
110+
/// Start an edit session to update breakpoints.
111+
pub fn edit_breakpoints<'b>(&'b mut self) -> Option<BreakpointEdit<'b>> {
112+
self.store.0.as_store_opaque().edit_breakpoints()
113+
}
114+
115+
/// Get a vector of all Instances held in the Store, for debug
116+
/// purposes.
117+
///
118+
/// See [`Store::debug_all_instances`] for more details.
119+
pub fn debug_all_instances(&mut self) -> Vec<Instance> {
120+
self.store.0.as_store_opaque().debug_all_instances()
121+
}
122+
123+
/// Get a vector of all Modules held in the Store, for debug
124+
/// purposes.
125+
///
126+
/// See [`Store::debug_all_modules`] for more details.
127+
pub fn debug_all_modules(&mut self) -> Vec<Module> {
128+
self.store.0.as_store_opaque().debug_all_modules()
129+
}
50130
}
51131

52132
impl StoreOpaque {
@@ -72,30 +152,21 @@ impl StoreOpaque {
72152
let (breakpoints, registry) = self.breakpoints_and_registry_mut();
73153
Some(breakpoints.edit(registry))
74154
}
75-
}
76155

77-
impl<'a, T> StoreContextMut<'a, T> {
78-
/// Provide a frame handle for all activations, in order from
79-
/// innermost (most recently called) to outermost on the stack.
80-
///
81-
/// See [`Store::debug_exit_frames`] for more details.
82-
pub fn debug_exit_frames(&mut self) -> impl Iterator<Item = FrameHandle> {
83-
self.0.as_store_opaque().debug_exit_frames()
84-
}
156+
fn debug_all_instances(&mut self) -> Vec<Instance> {
157+
if !self.engine().tunables().debug_guest {
158+
return vec![];
159+
}
85160

86-
/// Start an edit session to update breakpoints.
87-
pub fn edit_breakpoints(self) -> Option<BreakpointEdit<'a>> {
88-
self.0.as_store_opaque().edit_breakpoints()
161+
self.all_instances().collect()
89162
}
90-
}
91163

92-
impl<'a, T> Caller<'a, T> {
93-
/// Provide a frame handle for all activations, in order from
94-
/// innermost (most recently called) to outermost on the stack.
95-
///
96-
/// See [`Store::debug_exit_frames`] for more details.
97-
pub fn debug_exit_frames(&mut self) -> impl Iterator<Item = FrameHandle> {
98-
self.store.0.as_store_opaque().debug_exit_frames()
164+
fn debug_all_modules(&self) -> Vec<Module> {
165+
if !self.engine().tunables().debug_guest {
166+
return vec![];
167+
}
168+
169+
self.modules().all_modules().cloned().collect()
99170
}
100171
}
101172

tests/all/debug.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,41 @@ fn private_entity_access_shared_memory() -> wasmtime::Result<()> {
499499
Ok(())
500500
}
501501

502+
#[test]
503+
#[cfg_attr(miri, ignore)]
504+
fn all_instances_and_modules_in_store() -> wasmtime::Result<()> {
505+
let mut config = Config::default();
506+
config.guest_debug(true);
507+
let engine = Engine::new(&config)?;
508+
let mut store = Store::new(&engine, ());
509+
let m1 = Module::new(
510+
&engine,
511+
r#"
512+
(module (func (param i32) (result i32) (local.get 0)))
513+
"#,
514+
)?;
515+
let m2 = Module::new(
516+
&engine,
517+
r#"
518+
(module (func (param i32) (result i32) (local.get 0)))
519+
"#,
520+
)?;
521+
let i1 = Instance::new(&mut store, &m1, &[])?;
522+
let i2 = Instance::new(&mut store, &m2, &[])?;
523+
524+
let instances = store.debug_all_instances();
525+
let modules = store.debug_all_modules();
526+
assert_eq!(instances.len(), 2);
527+
assert_eq!(modules.len(), 2);
528+
assert!(
529+
(Module::same(&modules[0], &m1) && Module::same(&modules[1], &m2))
530+
|| (Module::same(&modules[1], &m1) && Module::same(&modules[0], &m2))
531+
);
532+
assert!(instances[0] == i1);
533+
assert!(instances[1] == i2);
534+
Ok(())
535+
}
536+
502537
macro_rules! debug_event_checker {
503538
($ty:tt,
504539
$store:tt,

0 commit comments

Comments
 (0)