From e82503703a466bd25f8b7cf71cab36b9782edf0d Mon Sep 17 00:00:00 2001 From: ridethepig Date: Tue, 7 Mar 2023 15:00:50 +0800 Subject: [PATCH] milestone 6 --- proj-1/deet/src/debugger.rs | 201 ++++++++++++++++++++++++------------ proj-1/deet/src/inferior.rs | 13 ++- 2 files changed, 143 insertions(+), 71 deletions(-) diff --git a/proj-1/deet/src/debugger.rs b/proj-1/deet/src/debugger.rs index a33a91d..bc29d99 100644 --- a/proj-1/deet/src/debugger.rs +++ b/proj-1/deet/src/debugger.rs @@ -1,6 +1,9 @@ +use std::collections::HashMap; + use crate::debugger_command::DebuggerCommand; use crate::dwarf_data::{DwarfData, Error as DwarfError}; use crate::inferior::{Inferior, Status}; +use nix::sys::signal::Signal::SIGTRAP; use rustyline::error::ReadlineError; use rustyline::Editor; @@ -10,7 +13,16 @@ pub struct Debugger { readline: Editor<()>, inferior: Option, debug_data: DwarfData, - breakpoints: Vec, + breakpoint_vec: Vec, + breakpoint_map: HashMap, + current_state: Status, +} + +#[derive(Clone)] +#[allow(unused)] +struct Breakpoint { + addr: usize, + orig_byte: u8, } fn parse_address(addr: &str) -> Option { @@ -49,30 +61,77 @@ impl Debugger { readline, inferior: None, debug_data, - breakpoints: Vec::new(), + breakpoint_vec: Vec::new(), + breakpoint_map: HashMap::new(), + current_state: Status::Exited(0), } } fn _try_kill(&mut self) { if self.inferior.is_some() { - let kill_result = self.inferior.as_mut().unwrap().kill(); - if let Ok(_) = kill_result { - println!( - "Killing running inferior (pid {})", - self.inferior.as_ref().unwrap().pid() - ); - } else { - eprintln!("Error killing running inferior"); - } + let kill_result = self.inferior.as_mut().unwrap().kill().unwrap(); + println!( + "Killing running inferior (pid {}, {:?})", + self.inferior.as_ref().unwrap().pid(), + kill_result + ); } } - fn _install_breakpoints(&mut self) { - for addr in &self.breakpoints { - let res = self.inferior.as_mut().unwrap().breakpoint(*addr); - if let Err(res) = res { - eprintln!("Failed to install breakpoint at {:#x}: {}", addr, res); + fn _install_breakpoint(&mut self, addr: usize) { + if self.inferior.is_some() { + let orig_byte = self + .inferior + .as_mut() + .unwrap() + .write_byte(addr, 0xcc) + .unwrap(); + self.breakpoint_map + .insert(addr, Breakpoint { addr, orig_byte }); + } + } + + fn _continue(&mut self) { + let res = self.inferior.as_mut().unwrap().cont(); + if let Ok(res) = res { + match res { + Status::Exited(exit_status) => { + println!("Child exited (status {})", exit_status); + self.inferior = None + } + Status::Signaled(_) => (), + Status::Stopped(_signal, _rip) => { + println!("Child stopped (signal {})", _signal); + let file_line = self.debug_data.get_line_from_addr(_rip).unwrap_or( + crate::dwarf_data::Line { + file: String::from("Unknown"), + number: 0, + address: 0, + }, + ); + println!("Stopped at {}[rip={:#x}]", file_line, _rip); + if _signal == SIGTRAP { + let target_addr = _rip - 1; + if self.breakpoint_map.contains_key(&target_addr) { + let orig_byte = self.breakpoint_map[&target_addr].orig_byte; + let break_0xcc = self + .inferior + .as_mut() + .unwrap() + .write_byte(target_addr, orig_byte).unwrap(); + assert_eq!(break_0xcc, 0xcc); + self.inferior + .as_mut() + .unwrap() + .restore_rip(target_addr as u64) + .expect("Failed to set reg"); + } + } + } } + self.current_state = res; + } else { + eprintln!("Error continuing subprocess"); } } @@ -84,32 +143,29 @@ impl Debugger { if let Some(inferior) = Inferior::new(&self.target, &args) { // Create the inferior self.inferior = Some(inferior); - self._install_breakpoints(); - // You may use self.inferior.as_mut().unwrap() to get a mutable reference - // to the Inferior object - let res = self.inferior.as_mut().unwrap().cont(); - if let Ok(res) = res { - match res { - Status::Exited(exit_status) => { - println!("Child exited (status {})", exit_status); - self.inferior = None + // install all breakpoints defined before running + for break_addr in &self.breakpoint_vec { + // 并不能调用另一个 fn func(&mut self) 类似的方法,会报错 &self 不可变借用,而函数需要一个可变借用 + // 虽然实际上写的时候并不会去修改这个东西,但是在调用方法的时候,会要求完整取得引用的所有权,大概是这个意思 + // self._install_breakpoint(*break_addr); + let addr = *break_addr; + let break_res = self.inferior.as_mut().unwrap().write_byte(addr, 0xcc); + match break_res { + Ok(orig_byte) => { + self.breakpoint_map + .insert(addr, Breakpoint { addr, orig_byte }); } - Status::Signaled(_) => (), - Status::Stopped(_signal, _rip) => { - println!("Child stopped (signal {})", _signal); - let file_line = self.debug_data.get_line_from_addr(_rip).unwrap_or( - crate::dwarf_data::Line { - file: String::from("Unknown"), - number: 0, - address: 0, - }, + Err(break_err) => { + eprintln!( + "Failed to install breakpoint at {:#x}: {}", + addr, break_err ); - println!("Stopped at {}[rip={:#x}]", file_line, _rip); } } - } else { - eprintln!("Error running subprocess"); } + // You may use self.inferior.as_mut().unwrap() to get a mutable reference + // to the Inferior object + self._continue(); } else { println!("Error starting subprocess"); } @@ -123,51 +179,60 @@ impl Debugger { eprintln!("No inferior process running"); continue; } - self._install_breakpoints(); - let res = self.inferior.as_mut().unwrap().cont(); - if let Ok(res) = res { - match res { - Status::Exited(exit_status) => { - println!("Child exited (status {})", exit_status); - self.inferior = None - } - Status::Signaled(_) => (), - Status::Stopped(_signal, _rip) => { - println!("Child stopped (signal {})", _signal); - let file_line = self.debug_data.get_line_from_addr(_rip).unwrap_or( - crate::dwarf_data::Line { - file: String::from("Unknown"), - number: 0, - address: 0, - }, - ); - println!("Stopped at {}[rip={:#x}]", file_line, _rip); + if let Status::Stopped(_signal, _rip) = self.current_state { + // println!("cont after SIGTRAP: {:?}", self.current_state); + if _signal == SIGTRAP { + let res = self.inferior.as_mut().unwrap().step().unwrap(); + // println!("status after step: {:?}", res); + match res { + Status::Exited(exit_status) => { + println!("Child exited (status {})", exit_status); + self.inferior = None; + continue; // skip the process below + } + Status::Signaled(_) => {} + Status::Stopped(_signal_step, _rip_step) => { + if _signal_step == SIGTRAP { + // println!("reinstall"); + self._install_breakpoint(_rip); + } else { + eprintln!( + "Warning, after single step, there should be a SIGTRAP" + ); + } + } } + self.current_state = res; } - } else { - eprintln!("Error continuing subprocess"); } + self._continue(); } DebuggerCommand::Backtrace => { - let res = self + if self.inferior.is_none() { + eprintln!("No inferior process running"); + continue; + } + if let Err(res) = self .inferior .as_ref() .unwrap() - .print_backtrace(&self.debug_data); - if let Err(res) = res { + .print_backtrace(&self.debug_data) + { eprintln!("Error backtracing: {}", res); } } DebuggerCommand::Break(arg_string) => { let arg_str = arg_string.as_str(); if arg_str.starts_with("*") { - let break_rip = parse_address(&arg_str[1..]); - if break_rip.is_some() { - let break_rip = break_rip.unwrap(); - println!("Set breakpoint {} at {:#x}", self.breakpoints.len(), break_rip); - self.breakpoints.push(break_rip); - } - else { + if let Some(addr) = parse_address(&arg_str[1..]) { + println!( + "Set breakpoint {} at {:#x}", + self.breakpoint_vec.len(), + addr + ); + self.breakpoint_vec.push(addr); + self._install_breakpoint(addr); + } else { eprintln!("Unable to parse breakpoint \"{}\"", arg_string); } } diff --git a/proj-1/deet/src/inferior.rs b/proj-1/deet/src/inferior.rs index 831f470..ab8c6a5 100644 --- a/proj-1/deet/src/inferior.rs +++ b/proj-1/deet/src/inferior.rs @@ -127,7 +127,7 @@ impl Inferior { Ok(()) } - fn write_byte(&mut self, addr: usize, val: u8) -> Result { + pub fn write_byte(&mut self, addr: usize, val: u8) -> Result { let aligned_addr = align_addr_to_word(addr); let byte_offset = addr - aligned_addr; let word = ptrace::read(self.pid(), aligned_addr as ptrace::AddressType)? as u64; @@ -142,7 +142,14 @@ impl Inferior { Ok(orig_byte as u8) } - pub fn breakpoint(&mut self, addr: usize) -> Result { - self.write_byte(addr, 0xcc) + pub fn step(&mut self) -> Result { + ptrace::step(self.pid(), None).unwrap(); + self.wait(None) + } + + pub fn restore_rip(&mut self, rip: u64) -> Result<(), nix::Error>{ + let mut regs = ptrace::getregs(self.pid()).unwrap(); + regs.rip = rip; + ptrace::setregs(self.pid(), regs) } }