milestone 6
This commit is contained in:
parent
db1805fe27
commit
e82503703a
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user