milestone 6

This commit is contained in:
ridethepig 2023-03-07 15:00:50 +08:00
parent db1805fe27
commit e82503703a
2 changed files with 143 additions and 71 deletions

View File

@ -1,6 +1,9 @@
use std::collections::HashMap;
use crate::debugger_command::DebuggerCommand; use crate::debugger_command::DebuggerCommand;
use crate::dwarf_data::{DwarfData, Error as DwarfError}; use crate::dwarf_data::{DwarfData, Error as DwarfError};
use crate::inferior::{Inferior, Status}; use crate::inferior::{Inferior, Status};
use nix::sys::signal::Signal::SIGTRAP;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::Editor; use rustyline::Editor;
@ -10,7 +13,16 @@ pub struct Debugger {
readline: Editor<()>, readline: Editor<()>,
inferior: Option<Inferior>, inferior: Option<Inferior>,
debug_data: DwarfData, debug_data: DwarfData,
breakpoints: Vec<usize>, breakpoint_vec: Vec<usize>,
breakpoint_map: HashMap<usize, Breakpoint>,
current_state: Status,
}
#[derive(Clone)]
#[allow(unused)]
struct Breakpoint {
addr: usize,
orig_byte: u8,
} }
fn parse_address(addr: &str) -> Option<usize> { fn parse_address(addr: &str) -> Option<usize> {
@ -49,44 +61,37 @@ impl Debugger {
readline, readline,
inferior: None, inferior: None,
debug_data, debug_data,
breakpoints: Vec::new(), breakpoint_vec: Vec::new(),
breakpoint_map: HashMap::new(),
current_state: Status::Exited(0),
} }
} }
fn _try_kill(&mut self) { fn _try_kill(&mut self) {
if self.inferior.is_some() { if self.inferior.is_some() {
let kill_result = self.inferior.as_mut().unwrap().kill(); let kill_result = self.inferior.as_mut().unwrap().kill().unwrap();
if let Ok(_) = kill_result {
println!( println!(
"Killing running inferior (pid {})", "Killing running inferior (pid {}, {:?})",
self.inferior.as_ref().unwrap().pid() self.inferior.as_ref().unwrap().pid(),
kill_result
); );
} else {
eprintln!("Error killing running inferior");
}
} }
} }
fn _install_breakpoints(&mut self) { fn _install_breakpoint(&mut self, addr: usize) {
for addr in &self.breakpoints { if self.inferior.is_some() {
let res = self.inferior.as_mut().unwrap().breakpoint(*addr); let orig_byte = self
if let Err(res) = res { .inferior
eprintln!("Failed to install breakpoint at {:#x}: {}", addr, res); .as_mut()
} .unwrap()
.write_byte(addr, 0xcc)
.unwrap();
self.breakpoint_map
.insert(addr, Breakpoint { addr, orig_byte });
} }
} }
pub fn run(&mut self) { fn _continue(&mut self) {
loop {
match self.get_next_command() {
DebuggerCommand::Run(args) => {
self._try_kill();
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(); let res = self.inferior.as_mut().unwrap().cont();
if let Ok(res) = res { if let Ok(res) = res {
match res { match res {
@ -105,11 +110,62 @@ impl Debugger {
}, },
); );
println!("Stopped at {}[rip={:#x}]", file_line, _rip); 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 { } else {
eprintln!("Error running subprocess"); eprintln!("Error continuing subprocess");
} }
}
pub fn run(&mut self) {
loop {
match self.get_next_command() {
DebuggerCommand::Run(args) => {
self._try_kill();
if let Some(inferior) = Inferior::new(&self.target, &args) {
// Create the inferior
self.inferior = Some(inferior);
// 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 });
}
Err(break_err) => {
eprintln!(
"Failed to install breakpoint at {:#x}: {}",
addr, break_err
);
}
}
}
// You may use self.inferior.as_mut().unwrap() to get a mutable reference
// to the Inferior object
self._continue();
} else { } else {
println!("Error starting subprocess"); println!("Error starting subprocess");
} }
@ -123,51 +179,60 @@ impl Debugger {
eprintln!("No inferior process running"); eprintln!("No inferior process running");
continue; continue;
} }
self._install_breakpoints(); if let Status::Stopped(_signal, _rip) = self.current_state {
let res = self.inferior.as_mut().unwrap().cont(); // println!("cont after SIGTRAP: {:?}", self.current_state);
if let Ok(res) = res { if _signal == SIGTRAP {
let res = self.inferior.as_mut().unwrap().step().unwrap();
// println!("status after step: {:?}", res);
match res { match res {
Status::Exited(exit_status) => { Status::Exited(exit_status) => {
println!("Child exited (status {})", exit_status); println!("Child exited (status {})", exit_status);
self.inferior = None self.inferior = None;
} continue; // skip the process below
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);
}
} }
Status::Signaled(_) => {}
Status::Stopped(_signal_step, _rip_step) => {
if _signal_step == SIGTRAP {
// println!("reinstall");
self._install_breakpoint(_rip);
} else { } else {
eprintln!("Error continuing subprocess"); eprintln!(
"Warning, after single step, there should be a SIGTRAP"
);
} }
} }
}
self.current_state = res;
}
}
self._continue();
}
DebuggerCommand::Backtrace => { DebuggerCommand::Backtrace => {
let res = self if self.inferior.is_none() {
eprintln!("No inferior process running");
continue;
}
if let Err(res) = self
.inferior .inferior
.as_ref() .as_ref()
.unwrap() .unwrap()
.print_backtrace(&self.debug_data); .print_backtrace(&self.debug_data)
if let Err(res) = res { {
eprintln!("Error backtracing: {}", res); eprintln!("Error backtracing: {}", res);
} }
} }
DebuggerCommand::Break(arg_string) => { DebuggerCommand::Break(arg_string) => {
let arg_str = arg_string.as_str(); let arg_str = arg_string.as_str();
if arg_str.starts_with("*") { if arg_str.starts_with("*") {
let break_rip = parse_address(&arg_str[1..]); if let Some(addr) = parse_address(&arg_str[1..]) {
if break_rip.is_some() { println!(
let break_rip = break_rip.unwrap(); "Set breakpoint {} at {:#x}",
println!("Set breakpoint {} at {:#x}", self.breakpoints.len(), break_rip); self.breakpoint_vec.len(),
self.breakpoints.push(break_rip); addr
} );
else { self.breakpoint_vec.push(addr);
self._install_breakpoint(addr);
} else {
eprintln!("Unable to parse breakpoint \"{}\"", arg_string); eprintln!("Unable to parse breakpoint \"{}\"", arg_string);
} }
} }

View File

@ -127,7 +127,7 @@ impl Inferior {
Ok(()) Ok(())
} }
fn write_byte(&mut self, addr: usize, val: u8) -> Result<u8, nix::Error> { pub fn write_byte(&mut self, addr: usize, val: u8) -> Result<u8, nix::Error> {
let aligned_addr = align_addr_to_word(addr); let aligned_addr = align_addr_to_word(addr);
let byte_offset = addr - aligned_addr; let byte_offset = addr - aligned_addr;
let word = ptrace::read(self.pid(), aligned_addr as ptrace::AddressType)? as u64; let word = ptrace::read(self.pid(), aligned_addr as ptrace::AddressType)? as u64;
@ -142,7 +142,14 @@ impl Inferior {
Ok(orig_byte as u8) Ok(orig_byte as u8)
} }
pub fn breakpoint(&mut self, addr: usize) -> Result<u8, nix::Error> { pub fn step(&mut self) -> Result<Status, nix::Error> {
self.write_byte(addr, 0xcc) 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)
} }
} }