Change to latest git comit of elf crate, add basic symbol support to run, and format code
This commit is contained in:
parent
1ecd6083a6
commit
f4f8890a5d
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -180,8 +180,7 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "elf"
|
name = "elf"
|
||||||
version = "0.0.12"
|
version = "0.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/cole14/rust-elf?rev=a4a747071316b1a900962dd83cbf2ab4ca4665fa#a4a747071316b1a900962dd83cbf2ab4ca4665fa"
|
||||||
checksum = "4b9c86cae88373e32c872967c296dcdd3b25771dcc7da1c4ba060b4a68fd8db7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bitvec = "1.0.0"
|
bitvec = "1.0.0"
|
||||||
derive-try-from-primitive = "1.0.0"
|
derive-try-from-primitive = "1.0.0"
|
||||||
elf = "0.0.12"
|
elf = { git = "https://github.com/cole14/rust-elf", rev = "a4a747071316b1a900962dd83cbf2ab4ca4665fa" }
|
||||||
human-repr = { version = "1.0.1", features = ["iec", "space"] }
|
human-repr = { version = "1.0.1", features = ["iec", "space"] }
|
||||||
inventory = "0.3.1"
|
inventory = "0.3.1"
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
|
529
src/main.rs
529
src/main.rs
@ -14,7 +14,7 @@ use crate::{
|
|||||||
m68k::{BusError, M68K},
|
m68k::{BusError, M68K},
|
||||||
};
|
};
|
||||||
use disas::DisassemblyError;
|
use disas::DisassemblyError;
|
||||||
use elf::types::Symbol;
|
use elf::symbol::Symbol;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parse_int::parse;
|
use parse_int::parse;
|
||||||
use reedline_repl_rs::{
|
use reedline_repl_rs::{
|
||||||
@ -22,7 +22,7 @@ use reedline_repl_rs::{
|
|||||||
Error as ReplError, Repl,
|
Error as ReplError, Repl,
|
||||||
};
|
};
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::{convert::TryFrom, fmt::Display, fs, num::ParseIntError, process};
|
use std::{convert::TryFrom, error, fmt::Display, fs, num::ParseIntError, process};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
@ -33,6 +33,13 @@ enum Error {
|
|||||||
InvalidPeekSize,
|
InvalidPeekSize,
|
||||||
Disassembly(DisassemblyError<BusError>),
|
Disassembly(DisassemblyError<BusError>),
|
||||||
Misc(&'static str),
|
Misc(&'static str),
|
||||||
|
MiscDyn(Box<dyn error::Error>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<dyn error::Error>> for Error {
|
||||||
|
fn from(v: Box<dyn error::Error>) -> Self {
|
||||||
|
Self::MiscDyn(v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DisassemblyError<BusError>> for Error {
|
impl From<DisassemblyError<BusError>> for Error {
|
||||||
@ -69,6 +76,7 @@ impl Display for Error {
|
|||||||
Self::InvalidPeekSize => f.write_str("Invalid peek size"),
|
Self::InvalidPeekSize => f.write_str("Invalid peek size"),
|
||||||
Self::Disassembly(e) => e.fmt(f),
|
Self::Disassembly(e) => e.fmt(f),
|
||||||
Self::Misc(s) => f.write_str(s),
|
Self::Misc(s) => f.write_str(s),
|
||||||
|
Self::MiscDyn(e) => e.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,269 +192,282 @@ fn main() -> Result<(), ReplError> {
|
|||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Repl::<_, Error>::new(EmuState {cpu: M68K::new(backplane), symbols: Vec::new()})
|
Repl::<_, Error>::new(EmuState {
|
||||||
.with_name("68KEmu")
|
cpu: M68K::new(backplane),
|
||||||
.with_version("0.1.0")
|
symbols: Vec::new(),
|
||||||
.with_banner("68K Backplane Computer Emulator")
|
})
|
||||||
.with_description("68K Backplane Computer Emulator")
|
.with_name("68KEmu")
|
||||||
.with_command(
|
.with_version("0.1.0")
|
||||||
Command::new("card")
|
.with_banner("68K Backplane Computer Emulator")
|
||||||
.trailing_var_arg(true)
|
.with_description("68K Backplane Computer Emulator")
|
||||||
.arg(
|
.with_command(
|
||||||
Arg::new("num")
|
Command::new("card")
|
||||||
.required(true)
|
.trailing_var_arg(true)
|
||||||
.help("The card number to send the command to"),
|
.arg(
|
||||||
)
|
Arg::new("num")
|
||||||
.arg(
|
.required(true)
|
||||||
Arg::new("args")
|
.help("The card number to send the command to"),
|
||||||
.required(true)
|
)
|
||||||
.multiple_values(true)
|
.arg(
|
||||||
.takes_value(true),
|
Arg::new("args")
|
||||||
)
|
.required(true)
|
||||||
.about("Send a command to a card"),
|
.multiple_values(true)
|
||||||
|args, state| {
|
.takes_value(true),
|
||||||
let num = args.get_one::<String>("num").unwrap().parse::<u8>()?;
|
)
|
||||||
state.cpu.bus_mut()
|
.about("Send a command to a card"),
|
||||||
.cards_mut()
|
|args, state| {
|
||||||
.get_mut(num as usize)
|
let num = args.get_one::<String>("num").unwrap().parse::<u8>()?;
|
||||||
.ok_or(Error::InvalidCard(num))?
|
state
|
||||||
.cmd(
|
.cpu
|
||||||
&args
|
.bus_mut()
|
||||||
.get_many::<String>("args")
|
.cards_mut()
|
||||||
.unwrap()
|
.get_mut(num as usize)
|
||||||
.map(String::as_str)
|
.ok_or(Error::InvalidCard(num))?
|
||||||
.collect_vec(),
|
.cmd(
|
||||||
);
|
&args
|
||||||
Ok(None)
|
.get_many::<String>("args")
|
||||||
},
|
.unwrap()
|
||||||
)
|
.map(String::as_str)
|
||||||
.with_command(
|
.collect_vec(),
|
||||||
Command::new("ls").about("List the cards in the system"),
|
);
|
||||||
|_, state| {
|
Ok(None)
|
||||||
#[allow(unstable_name_collisions)]
|
},
|
||||||
Ok(Some(
|
)
|
||||||
state.cpu.bus_mut()
|
.with_command(
|
||||||
.cards()
|
Command::new("ls").about("List the cards in the system"),
|
||||||
.iter()
|
|_, state| {
|
||||||
.enumerate()
|
#[allow(unstable_name_collisions)]
|
||||||
.map(|(i, card)| format!("Card {i}: {card}"))
|
Ok(Some(
|
||||||
.intersperse('\n'.to_string())
|
state
|
||||||
.collect(),
|
.cpu
|
||||||
))
|
.bus_mut()
|
||||||
},
|
.cards()
|
||||||
)
|
.iter()
|
||||||
.with_command(
|
.enumerate()
|
||||||
Command::new("regs").about("Show CPU registers"),
|
.map(|(i, card)| format!("Card {i}: {card}"))
|
||||||
|_, state| Ok(Some(format!("{}", state.cpu))),
|
.intersperse('\n'.to_string())
|
||||||
)
|
.collect(),
|
||||||
.with_command(
|
))
|
||||||
Command::new("step")
|
},
|
||||||
.arg(
|
)
|
||||||
Arg::new("count")
|
.with_command(
|
||||||
.takes_value(true)
|
Command::new("regs").about("Show CPU registers"),
|
||||||
.help("Count of instructions to step by. Defaults to 1"),
|
|_, state| Ok(Some(format!("{}", state.cpu))),
|
||||||
)
|
)
|
||||||
.arg(
|
.with_command(
|
||||||
Arg::new("print_ins")
|
Command::new("step")
|
||||||
.long("print_ins")
|
.arg(
|
||||||
.short('i')
|
Arg::new("count")
|
||||||
.action(ArgAction::SetTrue)
|
.takes_value(true)
|
||||||
.help("Print instructions")
|
.help("Count of instructions to step by. Defaults to 1"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("print_regs")
|
Arg::new("print_ins")
|
||||||
.long("print_regs")
|
.long("print_ins")
|
||||||
.short('r')
|
.short('i')
|
||||||
.action(ArgAction::SetTrue)
|
.action(ArgAction::SetTrue)
|
||||||
.help("Print ending registers")
|
.help("Print instructions"),
|
||||||
)
|
)
|
||||||
.about("Step the CPU"),
|
.arg(
|
||||||
|args, state| {
|
Arg::new("print_regs")
|
||||||
let count =
|
.long("print_regs")
|
||||||
parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
|
.short('r')
|
||||||
let mut out = String::new();
|
.action(ArgAction::SetTrue)
|
||||||
for _ in 0..count {
|
.help("Print ending registers"),
|
||||||
if state.cpu.stopped {
|
)
|
||||||
out += &format!("CPU stopped at PC {:#x}\n", state.cpu.pc());
|
.about("Step the CPU"),
|
||||||
break;
|
|args, state| {
|
||||||
}
|
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
|
||||||
if args.get_flag("print_ins") {
|
let mut out = String::new();
|
||||||
let pc = state.cpu.pc();
|
for _ in 0..count {
|
||||||
out += &disas_fmt(&mut state.cpu, pc).0;
|
if state.cpu.stopped {
|
||||||
}
|
out += &format!("CPU stopped at PC {:#x}\n", state.cpu.pc());
|
||||||
state.cpu.step();
|
break;
|
||||||
}
|
}
|
||||||
if args.get_flag("print_regs") {
|
if args.get_flag("print_ins") {
|
||||||
out += &format!("{}\n", state.cpu);
|
let pc = state.cpu.pc();
|
||||||
}
|
out += &disas_fmt(&mut state.cpu, pc).0;
|
||||||
if out.is_empty() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
out.pop(); // Remove trailing newline
|
|
||||||
Ok(Some(out))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.with_command(
|
|
||||||
Command::new("run")
|
|
||||||
.arg(
|
|
||||||
Arg::new("stop_addr")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("Optional address to stop execution at. Works as a breakpoint only for this run")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("print_ins")
|
|
||||||
.long("print_ins")
|
|
||||||
.short('p')
|
|
||||||
.action(ArgAction::SetTrue)
|
|
||||||
.help("Print all executed instructions")
|
|
||||||
)
|
|
||||||
.about("Run the CPU"),
|
|
||||||
|args, state| {
|
|
||||||
let mut out = String::new();
|
|
||||||
while !state.cpu.stopped {
|
|
||||||
let stop_addr = args
|
|
||||||
.get_one::<String>("stop_addr")
|
|
||||||
.map(|s| parse::<u32>(s))
|
|
||||||
.transpose()?;
|
|
||||||
if stop_addr.map(|a| state.cpu.pc() == a).unwrap_or(false) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if args.get_flag("print_ins") {
|
|
||||||
let pc = state.cpu.pc();
|
|
||||||
out += &disas_fmt(&mut state.cpu, pc).0;
|
|
||||||
}
|
|
||||||
state.cpu.step();
|
|
||||||
}
|
}
|
||||||
|
state.cpu.step();
|
||||||
|
}
|
||||||
|
if args.get_flag("print_regs") {
|
||||||
out += &format!("{}\n", state.cpu);
|
out += &format!("{}\n", state.cpu);
|
||||||
let pc = state.cpu.pc();
|
}
|
||||||
out += &disas_fmt(&mut state.cpu, pc).0;
|
if out.is_empty() {
|
||||||
out.pop(); // Remove trailing newline
|
|
||||||
Ok(Some(out))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.with_command(
|
|
||||||
Command::new("reset").about("Reset the cards and CPU, in that order"),
|
|
||||||
|_, state| {
|
|
||||||
for card in state.cpu.bus_mut().cards_mut() {
|
|
||||||
card.reset();
|
|
||||||
}
|
|
||||||
state.cpu.reset();
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
} else {
|
||||||
)
|
|
||||||
.with_command(
|
|
||||||
Command::new("peek")
|
|
||||||
.arg(Arg::new("count").short('c').takes_value(true))
|
|
||||||
.arg(Arg::new("fmt").short('f').required(true).takes_value(true))
|
|
||||||
.arg(Arg::new("addr").required(true))
|
|
||||||
.about("Peek a memory address"),
|
|
||||||
|args, state| {
|
|
||||||
let fmt_str = args.get_one::<String>("fmt").unwrap();
|
|
||||||
if fmt_str.len() != 2 {
|
|
||||||
return Err(Error::Misc("Peek format length must be 2"));
|
|
||||||
}
|
|
||||||
let fmt = PeekFormat::try_from(fmt_str.chars().next().unwrap())?;
|
|
||||||
let size = PeekSize::try_from(fmt_str.chars().nth(1).unwrap())?;
|
|
||||||
let count =
|
|
||||||
parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
|
|
||||||
let addr = parse::<u32>(args.get_one::<String>("addr").unwrap())?;
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
let bus = state.cpu.bus_mut();
|
|
||||||
for i in 0..count {
|
|
||||||
match size {
|
|
||||||
PeekSize::Byte => data.push(bus.read_byte(addr + i)? as u32),
|
|
||||||
PeekSize::Word => data.push(bus.read_word(addr + (i * 2))? as u32),
|
|
||||||
PeekSize::LongWord => data.push(
|
|
||||||
(bus.read_word(addr + (i * 4))? as u32) << 16
|
|
||||||
| (bus.read_word(addr + (i * 4) + 2)? as u32),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[allow(unstable_name_collisions)]
|
|
||||||
Ok(Some(
|
|
||||||
data.chunks(size.chunk_size())
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, c)| {
|
|
||||||
format!(
|
|
||||||
"0x{:x}: ",
|
|
||||||
addr + (size.chunk_size() * size.byte_count() * i) as u32
|
|
||||||
) + &c
|
|
||||||
.iter()
|
|
||||||
.map(|d| fmt.format(*d, size))
|
|
||||||
.intersperse(" ".to_string())
|
|
||||||
.collect::<String>()
|
|
||||||
})
|
|
||||||
.intersperse("\n".to_string())
|
|
||||||
.collect::<String>(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.with_command(
|
|
||||||
Command::new("disas")
|
|
||||||
.arg(
|
|
||||||
Arg::new("addr")
|
|
||||||
.help("Address to start disassembly at. Defaults to current PC"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("count")
|
|
||||||
.short('c')
|
|
||||||
.takes_value(true)
|
|
||||||
.help("Count of instructions to disassemble. Defaults to 1"),
|
|
||||||
)
|
|
||||||
.about("Disassemble a region of memory"),
|
|
||||||
|args, state| {
|
|
||||||
let mut addr = args
|
|
||||||
.get_one::<String>("addr")
|
|
||||||
.map_or(Ok(state.cpu.pc()), |s| parse::<u32>(s))?;
|
|
||||||
let count =
|
|
||||||
parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
|
|
||||||
let mut out = String::new();
|
|
||||||
for _ in 0..count {
|
|
||||||
let (fmt, res) = disas_fmt(&mut state.cpu, addr);
|
|
||||||
out += &fmt;
|
|
||||||
match res {
|
|
||||||
Ok(new_addr) => {
|
|
||||||
addr = new_addr;
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.pop(); // Remove trailing newline
|
out.pop(); // Remove trailing newline
|
||||||
Ok(Some(out))
|
Ok(Some(out))
|
||||||
},
|
}
|
||||||
)
|
},
|
||||||
.with_command(
|
)
|
||||||
Command::new("sym")
|
.with_command(
|
||||||
.arg(
|
Command::new("run")
|
||||||
Arg::new("file")
|
.arg(Arg::new("stop_addr").takes_value(true).help(
|
||||||
|
"Optional address to stop execution at. Works as a breakpoint only for this run",
|
||||||
|
))
|
||||||
|
.arg(
|
||||||
|
Arg::new("print_ins")
|
||||||
|
.long("print_ins")
|
||||||
|
.short('p')
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
.help("Print all executed instructions"),
|
||||||
|
)
|
||||||
|
.about("Run the CPU"),
|
||||||
|
|args, state| {
|
||||||
|
let mut out = String::new();
|
||||||
|
while !state.cpu.stopped {
|
||||||
|
let stop_addr = args.get_one::<String>("stop_addr");
|
||||||
|
|
||||||
|
let stop_addr = stop_addr
|
||||||
|
.map(|s| {
|
||||||
|
parse::<u32>(s).or_else(|_| {
|
||||||
|
state
|
||||||
|
.symbols
|
||||||
|
.iter()
|
||||||
|
.find(|sym| &sym.name == s)
|
||||||
|
.map(|sym| sym.value as u32)
|
||||||
|
.ok_or(Error::Misc("No such symbol"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
if stop_addr.map(|a| state.cpu.pc() == a).unwrap_or(false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if args.get_flag("print_ins") {
|
||||||
|
let pc = state.cpu.pc();
|
||||||
|
out += &disas_fmt(&mut state.cpu, pc).0;
|
||||||
|
}
|
||||||
|
state.cpu.step();
|
||||||
|
}
|
||||||
|
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"),
|
||||||
|
|_, state| {
|
||||||
|
for card in state.cpu.bus_mut().cards_mut() {
|
||||||
|
card.reset();
|
||||||
|
}
|
||||||
|
state.cpu.reset();
|
||||||
|
Ok(None)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_command(
|
||||||
|
Command::new("peek")
|
||||||
|
.arg(Arg::new("count").short('c').takes_value(true))
|
||||||
|
.arg(Arg::new("fmt").short('f').required(true).takes_value(true))
|
||||||
|
.arg(Arg::new("addr").required(true))
|
||||||
|
.about("Peek a memory address"),
|
||||||
|
|args, state| {
|
||||||
|
let fmt_str = args.get_one::<String>("fmt").unwrap();
|
||||||
|
if fmt_str.len() != 2 {
|
||||||
|
return Err(Error::Misc("Peek format length must be 2"));
|
||||||
|
}
|
||||||
|
let fmt = PeekFormat::try_from(fmt_str.chars().next().unwrap())?;
|
||||||
|
let size = PeekSize::try_from(fmt_str.chars().nth(1).unwrap())?;
|
||||||
|
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
|
||||||
|
let addr = parse::<u32>(args.get_one::<String>("addr").unwrap())?;
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let bus = state.cpu.bus_mut();
|
||||||
|
for i in 0..count {
|
||||||
|
match size {
|
||||||
|
PeekSize::Byte => data.push(bus.read_byte(addr + i)? as u32),
|
||||||
|
PeekSize::Word => data.push(bus.read_word(addr + (i * 2))? as u32),
|
||||||
|
PeekSize::LongWord => data.push(
|
||||||
|
(bus.read_word(addr + (i * 4))? as u32) << 16
|
||||||
|
| (bus.read_word(addr + (i * 4) + 2)? as u32),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(unstable_name_collisions)]
|
||||||
|
Ok(Some(
|
||||||
|
data.chunks(size.chunk_size())
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, c)| {
|
||||||
|
format!(
|
||||||
|
"0x{:x}: ",
|
||||||
|
addr + (size.chunk_size() * size.byte_count() * i) as u32
|
||||||
|
) + &c
|
||||||
|
.iter()
|
||||||
|
.map(|d| fmt.format(*d, size))
|
||||||
|
.intersperse(" ".to_string())
|
||||||
|
.collect::<String>()
|
||||||
|
})
|
||||||
|
.intersperse("\n".to_string())
|
||||||
|
.collect::<String>(),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_command(
|
||||||
|
Command::new("disas")
|
||||||
|
.arg(Arg::new("addr").help("Address to start disassembly at. Defaults to current PC"))
|
||||||
|
.arg(
|
||||||
|
Arg::new("count")
|
||||||
|
.short('c')
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Count of instructions to disassemble. Defaults to 1"),
|
||||||
|
)
|
||||||
|
.about("Disassemble a region of memory"),
|
||||||
|
|args, state| {
|
||||||
|
let mut addr = args
|
||||||
|
.get_one::<String>("addr")
|
||||||
|
.map_or(Ok(state.cpu.pc()), |s| parse::<u32>(s))?;
|
||||||
|
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
|
||||||
|
let mut out = String::new();
|
||||||
|
for _ in 0..count {
|
||||||
|
let (fmt, res) = disas_fmt(&mut state.cpu, addr);
|
||||||
|
out += &fmt;
|
||||||
|
match res {
|
||||||
|
Ok(new_addr) => {
|
||||||
|
addr = new_addr;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.pop(); // Remove trailing newline
|
||||||
|
Ok(Some(out))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_command(
|
||||||
|
Command::new("sym")
|
||||||
|
.arg(
|
||||||
|
Arg::new("file")
|
||||||
.required(true)
|
.required(true)
|
||||||
.help("The ELF file to load symbols from"),
|
.help("The ELF file to load symbols from"),
|
||||||
)
|
)
|
||||||
.about("Load symbols from an ELF file"),
|
.about("Load symbols from an ELF file"),
|
||||||
|args, state| {
|
|args, state| {
|
||||||
let file = args
|
let file = args.get_one::<String>("file").unwrap();
|
||||||
.get_one::<String>("file").unwrap();
|
let file = elf::File::open_path(file).map_err(<Box<dyn error::Error>>::from)?;
|
||||||
let file = elf::File::open_path(file).unwrap();
|
let symtab = file
|
||||||
let symtab = file.get_section(".symtab").ok_or(Error::Misc("Could not find symbol table section"))?;
|
.get_section(".symtab")
|
||||||
let symbols = file.get_symbols(symtab).unwrap();
|
.ok_or(Error::Misc("Could not find symbol table section"))?;
|
||||||
state.symbols = symbols;
|
let symbols = file
|
||||||
Ok(None)
|
.get_symbols(&symtab)
|
||||||
},
|
.map_err(<Box<dyn error::Error>>::from)?;
|
||||||
)
|
state.symbols = symbols;
|
||||||
.with_command(Command::new("quit")
|
Ok(None)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_command(
|
||||||
|
Command::new("quit")
|
||||||
.visible_alias("q")
|
.visible_alias("q")
|
||||||
.visible_alias("exit")
|
.visible_alias("exit")
|
||||||
.about("Quit"),
|
.about("Quit"),
|
||||||
|_, _| process::exit(0)
|
|_, _| process::exit(0),
|
||||||
)
|
)
|
||||||
// Visible aliases don't actually work, so fake it with hidden subcommands
|
// Visible aliases don't actually work, so fake it with hidden subcommands
|
||||||
.with_command(Command::new("q").hide(true), |_, _| process::exit(0))
|
.with_command(Command::new("q").hide(true), |_, _| process::exit(0))
|
||||||
.with_command(Command::new("exit").hide(true), |_, _| process::exit(0))
|
.with_command(Command::new("exit").hide(true), |_, _| process::exit(0))
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disas_fmt(cpu: &mut M68K, addr: u32) -> (String, Result<u32, DisassemblyError<BusError>>) {
|
fn disas_fmt(cpu: &mut M68K, addr: u32) -> (String, Result<u32, DisassemblyError<BusError>>) {
|
||||||
|
Loading…
Reference in New Issue
Block a user