diff --git a/Cargo.lock b/Cargo.lock index 127653f..19dbfa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "elf" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9c86cae88373e32c872967c296dcdd3b25771dcc7da1c4ba060b4a68fd8db7" + [[package]] name = "errno" version = "0.2.8" @@ -354,6 +360,7 @@ version = "0.1.0" dependencies = [ "bitvec", "derive-try-from-primitive", + "elf", "human-repr", "inventory", "itertools", diff --git a/Cargo.toml b/Cargo.toml index a990c59..c9808b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] bitvec = "1.0.0" derive-try-from-primitive = "1.0.0" +elf = "0.0.12" human-repr = { version = "1.0.1", features = ["iec", "space"] } inventory = "0.3.1" itertools = "0.10.5" diff --git a/src/main.rs b/src/main.rs index bea31d6..b8d1a26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use crate::{ m68k::{BusError, M68K}, }; use disas::DisassemblyError; +use elf::types::Symbol; use itertools::Itertools; use parse_int::parse; use reedline_repl_rs::{ @@ -155,6 +156,11 @@ impl TryFrom for PeekSize { } } +struct EmuState { + cpu: M68K, + symbols: Vec, +} + fn main() -> Result<(), ReplError> { let config: Mapping = serde_yaml::from_str( &fs::read_to_string("config.yaml").expect("Could not read config file"), @@ -178,7 +184,7 @@ fn main() -> Result<(), ReplError> { Err(e) => panic!("{}", e), }; } - Repl::<_, Error>::new(M68K::new(backplane)) + Repl::<_, Error>::new(EmuState {cpu: M68K::new(backplane), symbols: Vec::new()}) .with_name("68KEmu") .with_version("0.1.0") .with_banner("68K Backplane Computer Emulator") @@ -198,9 +204,9 @@ fn main() -> Result<(), ReplError> { .takes_value(true), ) .about("Send a command to a card"), - |args, cpu| { + |args, state| { let num = args.get_one::("num").unwrap().parse::()?; - cpu.bus_mut() + state.cpu.bus_mut() .cards_mut() .get_mut(num as usize) .ok_or(Error::InvalidCard(num))? @@ -216,10 +222,10 @@ fn main() -> Result<(), ReplError> { ) .with_command( Command::new("ls").about("List the cards in the system"), - |_, cpu| { + |_, state| { #[allow(unstable_name_collisions)] Ok(Some( - cpu.bus_mut() + state.cpu.bus_mut() .cards() .iter() .enumerate() @@ -231,7 +237,7 @@ fn main() -> Result<(), ReplError> { ) .with_command( Command::new("regs").about("Show CPU registers"), - |_, cpu| Ok(Some(format!("{}", cpu))), + |_, state| Ok(Some(format!("{}", state.cpu))), ) .with_command( Command::new("step") @@ -255,22 +261,23 @@ fn main() -> Result<(), ReplError> { .help("Print ending registers") ) .about("Step the CPU"), - |args, cpu| { + |args, state| { let count = parse::(args.get_one::("count").map_or("1", String::as_str))?; let mut out = String::new(); for _ in 0..count { - if cpu.stopped { - out += &format!("CPU stopped at PC {:#x}\n", cpu.pc()); + if state.cpu.stopped { + out += &format!("CPU stopped at PC {:#x}\n", state.cpu.pc()); break; } if args.get_flag("print_ins") { - out += &disas_fmt(cpu, cpu.pc()).0; + let pc = state.cpu.pc(); + out += &disas_fmt(&mut state.cpu, pc).0; } - cpu.step(); + state.cpu.step(); } if args.get_flag("print_regs") { - out += &format!("{}\n", cpu); + out += &format!("{}\n", state.cpu); } if out.is_empty() { Ok(None) @@ -295,34 +302,36 @@ fn main() -> Result<(), ReplError> { .help("Print all executed instructions") ) .about("Run the CPU"), - |args, cpu| { + |args, state| { let mut out = String::new(); - while !cpu.stopped { + while !state.cpu.stopped { let stop_addr = args .get_one::("stop_addr") .map(|s| parse::(s)) .transpose()?; - if stop_addr.map(|a| cpu.pc() == a).unwrap_or(false) { + if stop_addr.map(|a| state.cpu.pc() == a).unwrap_or(false) { break; } if args.get_flag("print_ins") { - out += &disas_fmt(cpu, cpu.pc()).0; + let pc = state.cpu.pc(); + out += &disas_fmt(&mut state.cpu, pc).0; } - cpu.step(); + state.cpu.step(); } - out += &format!("{}\n", cpu); - out += &disas_fmt(cpu, cpu.pc()).0; + out += &format!("{}\n", state.cpu); + let pc = state.cpu.pc(); + out += &disas_fmt(&mut state.cpu, pc).0; out.pop(); // Remove trailing newline Ok(Some(out)) }, ) .with_command( Command::new("reset").about("Reset the cards and CPU, in that order"), - |_, cpu| { - for card in cpu.bus_mut().cards_mut() { + |_, state| { + for card in state.cpu.bus_mut().cards_mut() { card.reset(); } - cpu.reset(); + state.cpu.reset(); Ok(None) }, ) @@ -332,7 +341,7 @@ fn main() -> Result<(), ReplError> { .arg(Arg::new("fmt").short('f').required(true).takes_value(true)) .arg(Arg::new("addr").required(true)) .about("Peek a memory address"), - |args, cpu| { + |args, state| { let fmt_str = args.get_one::("fmt").unwrap(); if fmt_str.len() != 2 { return Err(Error::Misc("Peek format length must be 2")); @@ -344,7 +353,7 @@ fn main() -> Result<(), ReplError> { let addr = parse::(args.get_one::("addr").unwrap())?; let mut data = Vec::new(); - let bus = cpu.bus_mut(); + let bus = state.cpu.bus_mut(); for i in 0..count { match size { PeekSize::Byte => data.push(bus.read_byte(addr + i)? as u32), @@ -387,15 +396,15 @@ fn main() -> Result<(), ReplError> { .help("Count of instructions to disassemble. Defaults to 1"), ) .about("Disassemble a region of memory"), - |args, cpu| { + |args, state| { let mut addr = args .get_one::("addr") - .map_or(Ok(cpu.pc()), |s| parse::(s))?; + .map_or(Ok(state.cpu.pc()), |s| parse::(s))?; let count = parse::(args.get_one::("count").map_or("1", String::as_str))?; let mut out = String::new(); for _ in 0..count { - let (fmt, res) = disas_fmt(cpu, addr); + let (fmt, res) = disas_fmt(&mut state.cpu, addr); out += &fmt; match res { Ok(new_addr) => { @@ -410,6 +419,24 @@ fn main() -> Result<(), ReplError> { Ok(Some(out)) }, ) + .with_command( + Command::new("sym") + .arg( + Arg::new("file") + .required(true) + .help("The ELF file to load symbols from"), + ) + .about("Load symbols from an ELF file"), + |args, state| { + let file = args + .get_one::("file").unwrap(); + let file = elf::File::open_path(file).unwrap(); + let symtab = file.get_section(".symtab").ok_or(Error::Misc("Could not find symbol table section"))?; + let symbols = file.get_symbols(symtab).unwrap(); + state.symbols = symbols; + Ok(None) + }, + ) .with_command(Command::new("quit") .visible_alias("q") .visible_alias("exit")