This repository has been archived on 2024-06-01. You can view files and clone it, but cannot push or open issues or pull requests.
rustboyadvance-ng/src/debugger/command.rs

214 lines
7.6 KiB
Rust
Raw Normal View History

use crate::arm7tdmi::bus::Bus;
use crate::arm7tdmi::{reg_string, Addr, REG_PC};
2019-06-27 10:55:28 +01:00
use crate::disass::Disassembler;
use super::{parser::Value, Debugger, DebuggerError, DebuggerResult};
use ansi_term::Colour;
2019-06-27 10:55:28 +01:00
use colored::*;
use hexdump;
#[derive(Debug, PartialEq, Clone)]
pub enum Command {
Info,
SingleStep(bool),
2019-06-27 10:55:28 +01:00
Continue,
HexDump(u32, usize),
Disass(u32, usize),
AddBreakpoint(u32),
DelBreakpoint(u32),
ClearBreakpoints,
ListBreakpoints,
Reset,
Quit,
}
impl Command {
pub fn run(&self, debugger: &mut Debugger) {
use Command::*;
match *self {
Info => println!("{}", debugger.cpu),
SingleStep(_cycle) => {
2019-06-27 10:55:28 +01:00
if let Some(bp) = debugger.check_breakpoint() {
2019-06-28 13:06:38 +01:00
println!("hit breakpoint #0x{:08x}!", bp);
2019-06-27 10:55:28 +01:00
debugger.delete_breakpoint(bp);
} else {
match debugger.cpu.step_debugger(&mut debugger.sysbus) {
Ok(insn) => {
println!("{}\n", debugger.cpu);
println!(
"Executed at @0x{:08x}:\n\t{}",
insn.pc,
Colour::Yellow.italic().paint(format!("{} ", insn))
);
println!("Next instruction at @0x{:08x}", debugger.cpu.get_next_pc())
}
2019-06-27 10:55:28 +01:00
Err(e) => {
println!("{}: {}", "cpu encountered an error".red(), e);
println!("cpu: {:x?}", debugger.cpu)
2019-06-27 10:55:28 +01:00
}
}
}
}
Continue => loop {
if let Some(bp) = debugger.check_breakpoint() {
2019-06-28 13:06:38 +01:00
println!("hit breakpoint #0x{:08x}!", bp);
2019-06-27 10:55:28 +01:00
debugger.delete_breakpoint(bp);
break;
}
match debugger.cpu.step_debugger(&mut debugger.sysbus) {
Ok(insn) => {
println!(
"@0x{:08x}:\n\t{}",
insn.pc,
Colour::Yellow.italic().paint(format!("{} ", insn))
);
}
2019-06-27 10:55:28 +01:00
Err(e) => {
println!("{}: {}", "cpu encountered an error".red(), e);
println!("cpu: {:x?}", debugger.cpu);
2019-06-27 10:55:28 +01:00
break;
}
};
},
HexDump(addr, nbytes) => {
let bytes = debugger.sysbus.get_bytes(addr, nbytes);
2019-06-27 10:55:28 +01:00
hexdump::hexdump(bytes);
}
Disass(addr, n) => {
let bytes = debugger.sysbus.get_bytes(addr, 4 * n);
2019-06-27 10:55:28 +01:00
let disass = Disassembler::new(addr, bytes);
for (_, line) in disass {
2019-06-27 10:55:28 +01:00
println!("{}", line)
}
}
Quit => {
print!("Quitting!");
debugger.stop();
}
AddBreakpoint(addr) => {
if !debugger.breakpoints.contains(&addr) {
let new_index = debugger.breakpoints.len();
debugger.breakpoints.push(addr);
println!("added breakpoint [{}] 0x{:08x}", new_index, addr);
} else {
println!("breakpoint already exists!")
}
}
DelBreakpoint(addr) => debugger.delete_breakpoint(addr),
ClearBreakpoints => debugger.breakpoints.clear(),
ListBreakpoints => {
println!("breakpoint list:");
for (i, b) in debugger.breakpoints.iter().enumerate() {
println!("[{}] 0x{:08x}", i, b)
}
}
Reset => {
println!("resetting cpu...");
debugger.cpu.reset();
println!("cpu is restarted!")
}
}
}
}
impl Debugger {
pub fn eval_command(&self, command: Value, args: Vec<Value>) -> DebuggerResult<Command> {
let command = match command {
Value::Name(command) => command,
_ => {
return Err(DebuggerError::InvalidCommand("expected a name".to_string()));
}
};
match command.as_ref() {
"i" | "info" => Ok(Command::Info),
"s" | "step" => Ok(Command::SingleStep(false)),
"sc" | "stepcycle" => Ok(Command::SingleStep(true)),
"c" | "continue" => Ok(Command::Continue),
"x" | "hexdump" => {
let (addr, n) = match args.len() {
2 => {
let addr = self.val_address(&args[0])?;
let n = self.val_number(&args[1])?;
(addr, n as usize)
}
1 => {
let addr = self.val_address(&args[0])?;
(addr, 0x100)
}
0 => {
if let Some(Command::HexDump(addr, n)) = self.previous_command {
(addr + (4 * n as u32), 0x100)
} else {
(self.cpu.get_reg(15), 0x100)
}
}
_ => {
return Err(DebuggerError::InvalidCommandFormat(
"xxd [addr] [n]".to_string(),
))
}
};
Ok(Command::HexDump(addr, n))
}
"d" | "disass" => {
let (addr, n) = match args.len() {
2 => {
let addr = self.val_address(&args[0])?;
let n = self.val_number(&args[1])?;
(addr, n as usize)
}
1 => {
let addr = self.val_address(&args[0])?;
(addr, 10)
}
0 => {
if let Some(Command::Disass(addr, n)) = self.previous_command {
(addr + (4 * n as u32), 10)
} else {
(self.cpu.get_next_pc(), 10)
}
}
_ => {
return Err(DebuggerError::InvalidCommandFormat(
"disass [addr] [n]".to_string(),
))
}
};
Ok(Command::Disass(addr, n))
}
"b" | "break" => {
if args.len() != 1 {
Err(DebuggerError::InvalidCommandFormat(
"break <addr>".to_string(),
))
} else {
let addr = self.val_address(&args[0])?;
Ok(Command::AddBreakpoint(addr))
}
}
"bd" | "breakdel" => match args.len() {
0 => Ok(Command::ClearBreakpoints),
1 => {
let addr = self.val_address(&args[0])?;
Ok(Command::DelBreakpoint(addr))
}
_ => Err(DebuggerError::InvalidCommandFormat(String::from(
"breakdel [addr]",
))),
},
"bl" => Ok(Command::ListBreakpoints),
"q" | "quit" => Ok(Command::Quit),
"r" | "reset" => Ok(Command::Reset),
_ => Err(DebuggerError::InvalidCommand(command)),
}
}
}