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::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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user