diff --git a/src/debug_target/stopped_target.rs b/src/debug_target/stopped_target.rs index 0b2fdf9..15311e8 100644 --- a/src/debug_target/stopped_target.rs +++ b/src/debug_target/stopped_target.rs @@ -30,20 +30,26 @@ impl StoppedTarget { Ok(self.breakpoints.contains_key(&(rip - 1))) } - pub fn cont(mut self) -> Result { + fn breakpoint_remove_and_rewind(&mut self) -> Result<(), DebugError> { let mut registers = self.get_registers()?; - if self.breakpoints.contains_key(&(registers.rip - 1)) { // We are on a breakpoint, we remove it - self = self.remove_breakpoint(registers.rip - 1)?; - registers.rip -= 1; - nix::sys::ptrace::setregs(self.pid, registers).map_err(PTraceError)?; - } + self.remove_breakpoint(registers.rip - 1)?; + registers.rip -= 1; + nix::sys::ptrace::setregs(self.pid, registers).map_err(PTraceError)?; + Ok(()) + } + pub fn cont(mut self) -> Result { + if self.on_breakpoint()? { + self.breakpoint_remove_and_rewind()?; + } nix::sys::ptrace::cont(self.pid, None).map_err(PTraceError)?; Ok(self.to_running()) } - pub fn stepi(self) -> Result { - todo!("Take into account breakpoints also for stepi"); + pub fn stepi(mut self) -> Result { + if self.on_breakpoint()? { + self.breakpoint_remove_and_rewind()?; + } nix::sys::ptrace::step(self.pid, None).map_err(PTraceError)?; Ok(self.to_running()) } @@ -62,7 +68,7 @@ impl StoppedTarget { } #[cfg(target_endian = "little")] // With a bit more work it could be implemented on both architectures, but I only have little-endian computers 🤷 - pub fn add_breakpoint(mut self, address: u64) -> Result { + pub fn add_breakpoint(&mut self, address: u64) -> Result<(), DebugError> { if self.breakpoints.contains_key(&address) { return Err(DebugError::DuplicateBreakpoint { address }); } @@ -72,18 +78,18 @@ impl StoppedTarget { nix::sys::ptrace::write(self.pid, address as *mut c_void, new_content).map_err(PTraceError)?; self.breakpoints.insert(address, target_byte); - Ok(self) + Ok(()) } #[cfg(target_endian = "little")] // Same as add_breakpoint - pub fn remove_breakpoint(mut self, address: u64) -> Result { + pub fn remove_breakpoint(&mut self, address: u64) -> Result<(), DebugError> { match self.breakpoints.remove(&address) { None => Err(DebugError::NonExistingBreakpoint { address }), Some(original_byte) => { let content = nix::sys::ptrace::read(self.pid, address as *mut c_void).map_err(PTraceError)?; let new_content = (content & (!0xff as c_long)) | (original_byte as c_long); nix::sys::ptrace::write(self.pid, address as *mut c_void, new_content).map_err(PTraceError)?; - Ok(self) + Ok(()) } } } diff --git a/src/main.rs b/src/main.rs index eaf71db..4e081e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -103,18 +103,20 @@ fn main() -> color_eyre::Result<()> { Ok(ForkResult::Parent { child: child_pid }) => { println!("✔️ Created child {child_pid}"); - let target = StoppedTarget::new(child_pid)?; + let mut target = StoppedTarget::new(child_pid)?; println!("✔️ Child ready!"); - let target = target.add_breakpoint(0x401019)?; + let breakpoint1 = 0x401019; + println!("🛑 Adding breakpoint at {breakpoint1:#x}"); + target.add_breakpoint(breakpoint1)?; let target = target.cont()?.wait_for_something()?; match target { Either::Left(t) => { - println!("🔎 rip: {:#x}", t.get_registers()?.rip); if t.on_breakpoint()? { println!("🚧 We are on a breakpoint!") } - t.cont()?.wait_for_exit()?; + println!("🔎 rip: {:#x}", t.get_registers()?.rip); + single_step_all(t)?; } Either::Right(ExitedTarget { exit_code, .. }) => { println!("👋 Child exited with code {exit_code}");