diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 9741749df64..254b79c7eb4 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -429,6 +429,12 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { .filter(|v: &Vec| !v.is_empty()) } + /// Returns the `FileId` of the file associated with the innermost function on the call stack. + pub(super) fn get_current_file(&mut self) -> Option { + self.get_current_source_location() + .and_then(|locations| locations.last().map(|location| location.file)) + } + /// Returns the (possible) stack of source locations corresponding to the /// given opcode location. Due to compiler inlining it's possible for this /// function to return multiple source locations. An empty vector means that diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 24c3e4ffc64..e6edd652c0c 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -243,6 +243,24 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } + fn add_breakpoint_at_line(&mut self, line_number: i64) { + let Some(current_file) = self.context.get_current_file() else { + println!("No current file."); + return; + }; + + let best_location = + self.context.find_opcode_for_source_location(¤t_file, line_number); + + match best_location { + Some(location) => { + println!("Added breakpoint at line {}", line_number); + self.add_breakpoint_at(location) + } + None => println!("No opcode at line {}", line_number), + } + } + fn delete_breakpoint_at(&mut self, location: DebugLocation) { if self.context.delete_breakpoint(&location) { println!("Breakpoint at {location} deleted"); @@ -536,6 +554,16 @@ pub fn run>( } }, ) + .add( + "break", + command! { + "add a breakpoint at a line of the current file", + (line_number: i64) => |line_number| { + ref_context.borrow_mut().add_breakpoint_at_line(line_number); + Ok(CommandStatus::Done) + } + }, + ) .add( "break", command! {