From 05fb40c17c3ac2d7e132650e2ace6450efa1555d Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Tue, 2 Jul 2019 13:31:02 +0300 Subject: [PATCH] debugger: Add Deref expression. i.e: r5 = *r6 r5 = *(u8*)r6 r5 = *(u16*)0x08000000 Former-commit-id: 962dade8e3c0b9f291115285137cf51b0abde266 --- src/arm7tdmi/mod.rs | 1 + src/debugger/command.rs | 104 +++++++++++++++++++++++++++++++++++- src/debugger/mod.rs | 115 +++++----------------------------------- src/debugger/parser.rs | 67 +++++++++++++++++++++-- 4 files changed, 181 insertions(+), 106 deletions(-) diff --git a/src/arm7tdmi/mod.rs b/src/arm7tdmi/mod.rs index c86b58c..ebdbcb7 100644 --- a/src/arm7tdmi/mod.rs +++ b/src/arm7tdmi/mod.rs @@ -6,6 +6,7 @@ use arm::{ArmDecodeError, ArmInstruction}; pub mod cpu; pub use cpu::*; pub mod bus; +pub use bus::Bus; mod exception; mod psr; diff --git a/src/debugger/command.rs b/src/debugger/command.rs index 7506483..bef1139 100644 --- a/src/debugger/command.rs +++ b/src/debugger/command.rs @@ -1,8 +1,9 @@ use crate::arm7tdmi::bus::Bus; -use crate::arm7tdmi::{reg_string, REG_PC}; -use crate::debugger::Debugger; +use crate::arm7tdmi::{reg_string, Addr, REG_PC}; use crate::disass::Disassembler; +use super::{parser::Value, Debugger, DebuggerError, DebuggerResult}; + use ansi_term::Colour; use colored::*; @@ -111,3 +112,102 @@ impl Command { } } } + +impl Debugger { + pub fn eval_command(&self, command: Value, args: Vec) -> DebuggerResult { + 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 ".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)), + } + } +} diff --git a/src/debugger/mod.rs b/src/debugger/mod.rs index e1720d3..e3441b3 100644 --- a/src/debugger/mod.rs +++ b/src/debugger/mod.rs @@ -4,10 +4,11 @@ use rustyline::Editor; use colored::*; use super::arm7tdmi; +use super::arm7tdmi::{Addr, Bus}; use super::sysbus::SysBus; mod parser; -use parser::{parse_expr, Expr, Value}; +use parser::{parse_expr, DerefType, Expr, Value}; mod command; use command::Command; @@ -99,7 +100,7 @@ impl Debugger { } } - fn val_address(&self, arg: &Value) -> DebuggerResult { + fn val_address(&self, arg: &Value) -> DebuggerResult { match arg { Value::Num(n) => Ok(*n), Value::Name(reg) => { @@ -113,107 +114,19 @@ impl Debugger { } } - fn eval_command(&self, command: Value, args: Vec) -> DebuggerResult { - 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 ".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)), - } - } - fn eval_assignment(&mut self, lvalue: Value, rvalue: Value) -> DebuggerResult<()> { let lvalue = self.val_reg(&lvalue)?; - let rvalue = self.val_address(&rvalue)?; - + let rvalue = match rvalue { + Value::Deref(addr_value, deref_type) => { + let addr = self.val_address(&addr_value)?; + match deref_type { + DerefType::Word => self.sysbus.read_32(addr), + DerefType::HalfWord => self.sysbus.read_16(addr) as u32, + DerefType::Byte => self.sysbus.read_8(addr) as u32, + } + } + _ => self.val_address(&rvalue)?, + }; self.cpu.set_reg(lvalue, rvalue); Ok(()) } diff --git a/src/debugger/parser.rs b/src/debugger/parser.rs index bf02853..1fe73e7 100644 --- a/src/debugger/parser.rs +++ b/src/debugger/parser.rs @@ -1,22 +1,32 @@ use std::fmt; +use crate::arm7tdmi::Addr; + use nom; use nom::branch::alt; use nom::bytes::complete::{tag, take_while_m_n}; use nom::character::complete::{alphanumeric1, char, digit1, multispace0, multispace1}; -use nom::combinator::{cut, map, map_res}; +use nom::combinator::{cut, map, map_res, opt}; use nom::error::{context, convert_error, ParseError, VerboseError}; use nom::multi::separated_list; -use nom::sequence::{preceded, separated_pair, terminated, tuple}; +use nom::sequence::{delimited, preceded, separated_pair, terminated, tuple}; use nom::IResult; use super::{DebuggerError, DebuggerResult}; +#[derive(Debug, PartialEq, Clone)] +pub enum DerefType { + Word, + HalfWord, + Byte, +} + #[derive(Debug, PartialEq, Clone)] pub enum Value { Num(u32), Boolean(bool), Name(String), + Deref(Box, DerefType), } #[derive(Debug, PartialEq)] @@ -57,8 +67,42 @@ fn parse_name<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value, map(alphanumeric1, |s: &str| Value::Name(String::from(s)))(i) } +fn parse_deref_type<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, DerefType, E> { + delimited( + char('('), + alt(( + map(tag("u32*"), |_| DerefType::Word), + map(tag("u16*"), |_| DerefType::HalfWord), + map(tag("u8*"), |_| DerefType::Byte), + )), + char(')'), + )(i) +} + +fn parse_deref<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value, E> { + context( + "deref", + preceded( + char('*'), + cut(map( + tuple(( + map(opt(parse_deref_type), |t| match t { + Some(t) => t, + None => DerefType::Word, + }), + alt((parse_num, parse_name)), + )), + |(t, v)| Value::Deref(Box::new(v), t), + )), + ), + )(i) +} + fn parse_value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Value, E> { - context("argument", alt((parse_boolean, parse_num, parse_name)))(i) + context( + "argument", + alt((parse_boolean, parse_deref, parse_num, parse_name)), + )(i) } fn parse_command<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&str, Expr, E> { @@ -165,4 +209,21 @@ mod tests { ); } + #[test] + fn test_parse_deref() { + assert_eq!( + parse_deref::>("*(u16*)0x1234"), + Ok(( + "", + Value::Deref(Box::new(Value::Num(0x1234)), DerefType::HalfWord) + )) + ); + assert_eq!( + parse_deref::>("*r10"), + Ok(( + "", + Value::Deref(Box::new(Value::Name("r10".to_string())), DerefType::Word) + )) + ); + } }