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::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<Inferior>,
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> {
@ -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);
}
}

View File

@ -127,7 +127,7 @@ impl Inferior {
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 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<u8, nix::Error> {
self.write_byte(addr, 0xcc)
pub fn step(&mut self) -> Result<Status, nix::Error> {
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)
}
}