Refactor disassembler to a struct.
Implement more commands;
This commit is contained in:
Michel Heily 2019-06-25 13:28:02 +03:00
parent 22a915ec85
commit e5d93f689f
8 changed files with 174 additions and 38 deletions

33
Cargo.lock generated
View file

@ -22,6 +22,15 @@ dependencies = [
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "arrayvec"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.4.10" version = "0.4.10"
@ -202,6 +211,20 @@ name = "fuchsia-cprng"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hexdump"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.3.0" version = "1.3.0"
@ -285,6 +308,11 @@ name = "numtoa"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "odds"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.30" version = "0.4.30"
@ -390,6 +418,7 @@ dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "enum-primitive-derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hexdump 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "nom 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"rustyline 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -611,6 +640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "06f59fe10306bb78facd90d28c2038ad23ffaaefa85bac43c8a434cde383334f"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
@ -633,6 +663,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum hexdump 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "850f3f2c33d20c0f96c4485e087dd580ff041d720988ebf4c84a42acf739262b"
"checksum itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c4a9b56eb56058f43dc66e58f40a214b2ccbc9f3df51861b63d51dec7b65bc3f"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum lexical-core 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d224b31f370c8dfc0dea1932d9e6bd451e65aef6f5f2318846664c04b42a796" "checksum lexical-core 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d224b31f370c8dfc0dea1932d9e6bd451e65aef6f5f2318846664c04b42a796"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
@ -644,6 +676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4eae0151b9dacf24fcc170d9995e511669a082856a91f958a2fe380bfab3fb22"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"

View file

@ -12,4 +12,5 @@ bit = "^0.1"
clap = {version = "2.33", features = ["color", "yaml"]} clap = {version = "2.33", features = ["color", "yaml"]}
rustyline = "5.0.0" rustyline = "5.0.0"
nom = "5.0.0" nom = "5.0.0"
colored = "1.8" colored = "1.8"
hexdump = "0.1.0"

View file

@ -1,19 +1,35 @@
use super::super::cpu::{Core, CpuPipelineAction, CpuError, CpuInstruction, CpuExecResult}; use super::super::cpu::{Core, CpuState, CpuPipelineAction, CpuError, CpuInstruction, CpuResult, CpuExecResult};
use super::super::sysbus::SysBus; use super::super::sysbus::SysBus;
use super::{ArmInstruction, ArmInstructionFormat}; use super::{ArmInstruction, ArmInstructionFormat};
use crate::bit::BitIndex;
impl Core { impl Core {
pub fn exec_arm(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { fn exec_b_bl(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuResult<CpuPipelineAction> {
match insn.fmt { if insn.link_flag() {
ArmInstructionFormat::BX => { self.set_reg(14, self.pc & !0b1);
self.pc = self.get_reg(insn.rn());
Ok((CpuInstruction::Arm(insn), CpuPipelineAction::Branch))
},
ArmInstructionFormat::B_BL => {
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32;
Ok((CpuInstruction::Arm(insn), CpuPipelineAction::Branch))
}
fmt => Err(CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn))),
} }
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32;
Ok(CpuPipelineAction::Branch)
}
fn exec_bx(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuResult<CpuPipelineAction> {
let rn = self.get_reg(insn.rn());
if rn.bit(0) {
self.set_state(CpuState::THUMB);
} else {
self.set_state(CpuState::ARM);
}
Ok(CpuPipelineAction::Branch)
}
pub fn exec_arm(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
let action = match insn.fmt {
ArmInstructionFormat::BX => self.exec_bx(sysbus, insn),
ArmInstructionFormat::B_BL => self.exec_b_bl(sysbus, insn),
fmt => Err(CpuError::UnimplementedCpuInstruction(CpuInstruction::Arm(insn))),
}?;
Ok((CpuInstruction::Arm(insn), action))
} }
} }

View file

@ -127,6 +127,10 @@ impl Core {
} }
} }
pub fn set_state(&mut self, s: CpuState) {
self.state = s;
}
/// Resets the cpu /// Resets the cpu
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.pc = 0; self.pc = 0;

View file

@ -1,20 +1,20 @@
use std::str::FromStr;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::Editor; use rustyline::Editor;
use colored::*; use colored::*;
use nom; use nom;
use nom::bytes;
use nom::IResult; use nom::IResult;
use nom::bytes::complete::{tag, take_till1, take_till, take_while_m_n, take_while1}; use nom::bytes::complete::{tag, take_till1, take_till, take_while_m_n, take_while1};
use nom::combinator::map_res; use nom::combinator::map_res;
use super::arm7tdmi::arm; use hexdump;
use super::arm7tdmi::cpu; use super::arm7tdmi::cpu;
use super::sysbus::SysBus; use super::sysbus::SysBus;
use crate::disass::Disassembler;
#[derive(Debug)] #[derive(Debug)]
pub struct Debugger { pub struct Debugger {
cpu: cpu::Core, cpu: cpu::Core,
@ -50,6 +50,7 @@ enum DebuggerCommand {
Info, Info,
SingleStep, SingleStep,
Continue, Continue,
HexDump(u32, usize),
Disass { addr: u32, num_opcodes: usize }, Disass { addr: u32, num_opcodes: usize },
AddBreakpoint(u32), AddBreakpoint(u32),
ListBreakpoints, ListBreakpoints,
@ -92,6 +93,14 @@ fn parse_debugger_command(input: &str) -> DebuggerResult<DebuggerCommand> {
"i" | "info" => Ok(Info), "i" | "info" => Ok(Info),
"s" | "step" => Ok(SingleStep), "s" | "step" => Ok(SingleStep),
"c" | "continue" => Ok(Continue), "c" | "continue" => Ok(Continue),
"xxd" => {
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
let (input, addr) = parse_hex_num(input)?;
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
let (_, nbytes) = parse_num(input)?;
let nbytes = nbytes as usize;
Ok(HexDump(addr, nbytes))
}
"d" | "disass" => { "d" | "disass" => {
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?; let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
let (input, addr) = parse_hex_num(input)?; let (input, addr) = parse_hex_num(input)?;
@ -167,6 +176,30 @@ impl Debugger {
println!("breakpoint 0x{:08x} reached!", self.cpu.pc) println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
} }
} }
},
HexDump(addr, nbytes) => {
let bytes = match self.sysbus.get_bytes(addr, nbytes) {
Some(bytes) => bytes,
None => {
println!("requested content out of bounds");
return
}
};
hexdump::hexdump(bytes);
}
Disass{ addr, num_opcodes } => {
let bytes = match self.sysbus.get_bytes(addr, 4*num_opcodes) {
Some(bytes) => bytes,
None => {
println!("requested content out of bounds");
return
}
};
let disass = Disassembler::new(addr, bytes);
for line in disass {
println!("{}", line)
}
} }
Quit => { Quit => {
print!("Quitting!"); print!("Quitting!");

55
src/disass.rs Normal file
View file

@ -0,0 +1,55 @@
use std::convert::TryFrom;
use std::io::ErrorKind;
use std::io::{Cursor, Seek, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};
use super::arm7tdmi::arm;
pub struct Disassembler<'a> {
base: u32,
rdr: Cursor<&'a [u8]>,
}
impl<'a> Disassembler<'a> {
pub fn new(base: u32, bin: &'a [u8]) -> Disassembler {
Disassembler {
base: base,
rdr: Cursor::new(bin),
}
}
}
impl<'a> Seek for Disassembler<'a> {
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
self.rdr.seek(pos)
}
}
impl<'a> Iterator for Disassembler<'a> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
let mut line = String::new();
let value: u32 = match self.rdr.read_u32::<LittleEndian>() {
Ok(value) => value,
Err(e) => match e.kind() {
ErrorKind::UnexpectedEof => {
return None;
}
_ => panic!("unexpected error"),
},
};
let addr = self.base + (self.rdr.position() - 4) as u32;
line.push_str(&format!("{:8x}:\t{:08x} \t", addr, value));
match arm::ArmInstruction::try_from((value, addr)) {
Ok(insn) => line.push_str(&format!("{}", insn)),
Err(_) => line.push_str("<UNDEFINED>"),
};
Some(line)
}
}

View file

@ -1,8 +1,6 @@
use std::convert::TryFrom;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::ErrorKind;
#[macro_use] #[macro_use]
extern crate enum_primitive_derive; extern crate enum_primitive_derive;
@ -11,7 +9,6 @@ extern crate num_traits;
extern crate bit; extern crate bit;
extern crate byteorder; extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
@ -33,6 +30,9 @@ use arm7tdmi::cpu;
mod debugger; mod debugger;
use debugger::{Debugger, DebuggerError}; use debugger::{Debugger, DebuggerError};
mod disass;
use disass::Disassembler;
#[derive(Debug)] #[derive(Debug)]
pub enum GBAError { pub enum GBAError {
IO(io::Error), IO(io::Error),
@ -79,25 +79,10 @@ fn run_disass(matches: &ArgMatches) -> GBAResult<()> {
let input = matches.value_of("INPUT").unwrap(); let input = matches.value_of("INPUT").unwrap();
let bin = read_bin_file(&input)?; let bin = read_bin_file(&input)?;
let mut rdr = io::Cursor::new(bin); let disassembler = Disassembler::new(0, &bin);
loop { for line in disassembler {
let value: u32 = match rdr.read_u32::<LittleEndian>() { println!("{}", line)
Ok(value) => Ok(value),
Err(e) => match e.kind() {
ErrorKind::UnexpectedEof => {
break;
}
_ => Err(e),
},
}?;
let addr = (rdr.position() - 4) as u32;
print!("{:8x}:\t{:08x} \t", addr, value);
match arm::ArmInstruction::try_from((value, addr)) {
Ok(insn) => println!("{}", insn),
Err(_) => println!("<UNDEFINED>"),
};
} }
Ok(()) Ok(())
} }

View file

@ -31,4 +31,13 @@ impl SysBus {
.read_u16::<LittleEndian>() .read_u16::<LittleEndian>()
.unwrap() .unwrap()
} }
pub fn get_bytes(&self, addr: u32, size: usize) -> Option<&[u8]> {
let addr = addr as usize;
if addr + size > self.bios_rom.len() {
None
} else {
Some(&self.bios_rom[addr..addr + size])
}
}
} }