diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 9dc5c758c6f..4243ade8cb0 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -178,6 +178,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 5aef12ad8d4..ae7e1de9669 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -199,6 +199,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: OpcodeLocation) { if self.context.delete_breakpoint(&location) { println!("Breakpoint at opcode {location} deleted"); @@ -475,6 +493,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! {