11//! Debugging API.
22
33use super :: store:: AsStoreOpaque ;
4+ use crate :: code:: StoreCode ;
5+ use crate :: module:: RegisterBreakpointState ;
46use crate :: store:: StoreId ;
57use crate :: vm:: { Activation , Backtrace } ;
68use crate :: {
@@ -1007,15 +1009,34 @@ impl BreakpointState {
10071009 pub ( crate ) fn is_single_step ( & self ) -> bool {
10081010 self . single_step
10091011 }
1012+
1013+ /// Internal helper to patch a new module for
1014+ /// single-stepping. When a module is newly registered in a
1015+ /// `Store`, we need to patch all breakpoints into the copy for
1016+ /// this `Store` if single-stepping is currently enabled.
1017+ pub ( crate ) fn patch_new_module ( & self , code : & mut StoreCode , module : & Module ) -> Result < ( ) > {
1018+ // Apply single-step state if single-stepping is enabled. Note
1019+ // that no other individual breakpoints will exist yet (as
1020+ // this is a newly registered module).
1021+ if self . single_step {
1022+ let mem = code. code_memory_mut ( ) . unwrap ( ) ;
1023+ mem. unpublish ( ) ?;
1024+ BreakpointEdit :: apply_single_step ( mem, module, true , |_key| false ) ?;
1025+ mem. publish ( ) ?;
1026+ }
1027+ Ok ( ( ) )
1028+ }
10101029}
10111030
10121031impl < ' a > BreakpointEdit < ' a > {
10131032 fn get_code_memory < ' b > (
1033+ breakpoints : & BreakpointState ,
10141034 registry : & ' b mut ModuleRegistry ,
10151035 dirty_modules : & mut BTreeSet < StoreCodePC > ,
10161036 module : & Module ,
10171037 ) -> Result < & ' b mut CodeMemory > {
1018- let store_code_pc = registry. store_code_base_or_register ( module) ?;
1038+ let store_code_pc =
1039+ registry. store_code_base_or_register ( module, RegisterBreakpointState ( breakpoints) ) ?;
10191040 let code_memory = registry
10201041 . store_code_mut ( store_code_pc)
10211042 . expect ( "Just checked presence above" )
@@ -1052,7 +1073,8 @@ impl<'a> BreakpointEdit<'a> {
10521073 let key = BreakpointKey :: from_raw ( module, pc) ;
10531074 self . state . breakpoints . insert ( key) ;
10541075 log:: trace!( "patching in breakpoint {key:?}" ) ;
1055- let mem = Self :: get_code_memory ( self . registry , & mut self . dirty_modules , module) ?;
1076+ let mem =
1077+ Self :: get_code_memory ( self . state , self . registry , & mut self . dirty_modules , module) ?;
10561078 let frame_table = module
10571079 . frame_table ( )
10581080 . expect ( "Frame table must be present when guest-debug is enabled" ) ;
@@ -1069,7 +1091,8 @@ impl<'a> BreakpointEdit<'a> {
10691091 let key = BreakpointKey :: from_raw ( module, pc) ;
10701092 self . state . breakpoints . remove ( & key) ;
10711093 if !self . state . single_step {
1072- let mem = Self :: get_code_memory ( self . registry , & mut self . dirty_modules , module) ?;
1094+ let mem =
1095+ Self :: get_code_memory ( self . state , self . registry , & mut self . dirty_modules , module) ?;
10731096 let frame_table = module
10741097 . frame_table ( )
10751098 . expect ( "Frame table must be present when guest-debug is enabled" ) ;
@@ -1079,6 +1102,26 @@ impl<'a> BreakpointEdit<'a> {
10791102 Ok ( ( ) )
10801103 }
10811104
1105+ fn apply_single_step < F : Fn ( & BreakpointKey ) -> bool > (
1106+ mem : & mut CodeMemory ,
1107+ module : & Module ,
1108+ enabled : bool ,
1109+ key_enabled : F ,
1110+ ) -> Result < ( ) > {
1111+ let table = module
1112+ . frame_table ( )
1113+ . expect ( "Frame table must be present when guest-debug is enabled" ) ;
1114+ for ( wasm_pc, patch) in table. breakpoint_patches ( ) {
1115+ let key = BreakpointKey :: from_raw ( & module, wasm_pc) ;
1116+ let this_enabled = enabled || key_enabled ( & key) ;
1117+ log:: trace!(
1118+ "single_step: enabled {enabled} key {key:?} -> this_enabled {this_enabled}"
1119+ ) ;
1120+ Self :: patch ( core:: iter:: once ( patch) , mem, this_enabled) ;
1121+ }
1122+ Ok ( ( ) )
1123+ }
1124+
10821125 /// Turn on or off single-step mode.
10831126 ///
10841127 /// In single-step mode, a breakpoint event is emitted at every
@@ -1095,18 +1138,11 @@ impl<'a> BreakpointEdit<'a> {
10951138 }
10961139 let modules = self . registry . all_modules ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
10971140 for module in modules {
1098- let mem = Self :: get_code_memory ( self . registry , & mut self . dirty_modules , & module) ?;
1099- let table = module
1100- . frame_table ( )
1101- . expect ( "Frame table must be present when guest-debug is enabled" ) ;
1102- for ( wasm_pc, patch) in table. breakpoint_patches ( ) {
1103- let key = BreakpointKey :: from_raw ( & module, wasm_pc) ;
1104- let this_enabled = enabled || self . state . breakpoints . contains ( & key) ;
1105- log:: trace!(
1106- "single_step: enabled {enabled} key {key:?} -> this_enabled {this_enabled}"
1107- ) ;
1108- Self :: patch ( core:: iter:: once ( patch) , mem, this_enabled) ;
1109- }
1141+ let mem =
1142+ Self :: get_code_memory ( self . state , self . registry , & mut self . dirty_modules , & module) ?;
1143+ Self :: apply_single_step ( mem, & module, enabled, |key| {
1144+ self . state . breakpoints . contains ( key)
1145+ } ) ?;
11101146 }
11111147
11121148 self . state . single_step = enabled;
0 commit comments