chore: cleanup calling logic of disasm/interp
This commit is contained in:
@@ -87,6 +87,7 @@ pub struct Disassembler {
|
||||
pub aout: Aout, // the aout binary
|
||||
pub instruction: Instruction, // the instruction, which is currently being parsed
|
||||
instructions: Vec<Instruction>, // all parsed instructions
|
||||
dump: bool, // Dump dissambly progress, if an error occurs
|
||||
}
|
||||
|
||||
impl Disassembler {
|
||||
@@ -98,13 +99,15 @@ impl Disassembler {
|
||||
aout,
|
||||
instruction: Instruction::new(),
|
||||
instructions: Vec::new(),
|
||||
dump: args.dump,
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the disassmble and allow for some error handling wrapped around
|
||||
/// the actual decoding function.
|
||||
pub fn disassemble(&mut self, dump: bool) -> Result<Vec<Instruction>, DisasmError> {
|
||||
let is_ok = self.decode_instructions();
|
||||
/// the actual [`Self::decode_all_instructions()`] function.
|
||||
/// Also removes NULL padding from the end of the disassembly.
|
||||
pub fn disassemble(&mut self) -> Result<(), DisasmError> {
|
||||
let is_ok = self.decode_all_instructions();
|
||||
|
||||
// a.out pads the text section to byte align, so the fasely interpreted
|
||||
// instructions have to be removed.
|
||||
@@ -114,19 +117,28 @@ impl Disassembler {
|
||||
// to allow some error's to act as warnings (see below)
|
||||
let instructions = self.instructions.clone();
|
||||
|
||||
let dump =
|
||||
|instructions: Vec<Instruction>| instructions.iter().for_each(|i| println!("{i}"));
|
||||
|
||||
// allow for warning-type errors to pass through, as they are not fatal
|
||||
match is_ok {
|
||||
Ok(_) => Ok(instructions),
|
||||
Ok(_) => {
|
||||
dump(instructions);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => match e {
|
||||
// not an error per-se
|
||||
DisasmError::EndOfTextSection => {
|
||||
log::debug!("Solo padded 0-byte at end of file was found. Ignoring.");
|
||||
Ok(instructions)
|
||||
dump(instructions);
|
||||
Ok(())
|
||||
}
|
||||
// actual errors
|
||||
_ => {
|
||||
if dump {
|
||||
self.instructions.iter().for_each(|i| println!("{i}"));
|
||||
if self.dump {
|
||||
dump(instructions);
|
||||
println!(
|
||||
"Encountered error during disassembly, but this is the process so far...\n{e}\nRun with RUST_LOG=debug for furhter information."
|
||||
"Encountered error during disassembly, but this is the process so far...\n{e}\nRun with RUST_LOG=debug for further information."
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
@@ -483,9 +495,11 @@ impl Disassembler {
|
||||
self.instructions.truncate(until);
|
||||
}
|
||||
|
||||
fn decode_instructions(&mut self) -> Result<(), DisasmError> {
|
||||
/// Decode all available instruction, starting from `self.offset`.
|
||||
fn decode_all_instructions(&mut self) -> Result<(), DisasmError> {
|
||||
while self.offset < self.aout.text.len() {
|
||||
self.decode_instruction()?;
|
||||
let instruction = self.decode_instruction()?;
|
||||
self.instructions.push(instruction);
|
||||
|
||||
// Advance offset to hover the next potential opcode
|
||||
self.offset += 1;
|
||||
@@ -494,11 +508,11 @@ impl Disassembler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decode an instruction by matching byte signature to their mnemonics and
|
||||
/// depending on the instruction, parsing some operands afterwards.
|
||||
/// All parsing is done in capsulated functions, here everything just
|
||||
/// gets consolodated.
|
||||
pub fn decode_instruction(&mut self) -> Result<(), DisasmError> {
|
||||
/// Decode the instruction at `self.offset` by matching byte signature to
|
||||
/// their mnemonics and depending on the instruction, parsing some operands
|
||||
/// afterwards. All parsing is done in capsulated functions, here everything
|
||||
/// just gets consolodated.
|
||||
pub fn decode_instruction(&mut self) -> Result<Instruction, DisasmError> {
|
||||
// reset mutable current instruction
|
||||
self.instruction = Instruction::new();
|
||||
self.instruction.addr = self.offset;
|
||||
@@ -899,11 +913,8 @@ impl Disassembler {
|
||||
}
|
||||
};
|
||||
|
||||
// Save parsed instruction
|
||||
log::debug!("Parsed {}", self.instruction);
|
||||
self.instructions.push(self.instruction.clone());
|
||||
|
||||
Ok(())
|
||||
Ok(self.instruction.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,10 +48,8 @@ impl fmt::Display for InterpreterError {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Interpreter {
|
||||
computer: Computer,
|
||||
text: Vec<u8>,
|
||||
ip: usize,
|
||||
disassembler: Disassembler,
|
||||
computer: Computer, // current cpu state
|
||||
disassembler: Disassembler, // fetcher, currently holds all instruction data
|
||||
}
|
||||
|
||||
impl Interpreter {
|
||||
@@ -59,34 +57,32 @@ impl Interpreter {
|
||||
let aout = Aout::new_from_args(args);
|
||||
Self {
|
||||
computer: Computer::new(aout.data),
|
||||
text: aout.text,
|
||||
ip: 0,
|
||||
disassembler: Disassembler::new(args),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets instruction pointer in compliance with [`Register::CS`].
|
||||
pub fn set_ip(&mut self, ip: usize) {
|
||||
self.ip = ip + (self.computer.sregs.cs * 16) as usize
|
||||
self.computer.regs.ip = ip + (self.computer.sregs.cs * 16) as usize
|
||||
}
|
||||
|
||||
/// Gets instruction pointer in compliance with [`Register::CS`].
|
||||
pub fn get_ip(&self) -> usize {
|
||||
self.ip + (self.computer.sregs.cs * 16) as usize
|
||||
self.computer.regs.ip + (self.computer.sregs.cs * 16) as usize
|
||||
}
|
||||
|
||||
pub fn interpret(&mut self) -> Result<(), InterpreterError> {
|
||||
while self.ip < self.text.len() {
|
||||
while self.computer.regs.ip < self.disassembler.aout.text.len() {
|
||||
log::debug!("=============== Fetching next instruction... ===============");
|
||||
self.disassembler.offset = self.ip;
|
||||
self.disassembler
|
||||
self.disassembler.offset = self.computer.regs.ip;
|
||||
let current_instruction = self
|
||||
.disassembler
|
||||
.decode_instruction()
|
||||
.map_err(|e| InterpreterError::FetchError(e.to_string()))?;
|
||||
let current_instruction = self.disassembler.instruction.clone();
|
||||
|
||||
log::info!(
|
||||
"({:04x}) {:<32} {}",
|
||||
current_instruction.addr,
|
||||
self.computer.regs.ip,
|
||||
current_instruction.mnemonic.to_string(),
|
||||
self.computer,
|
||||
);
|
||||
@@ -845,7 +841,7 @@ impl Interpreter {
|
||||
}
|
||||
|
||||
// Go to next instruction
|
||||
self.ip += current_instruction.raw.len();
|
||||
self.computer.regs.ip += current_instruction.raw.len();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -11,6 +11,7 @@ pub struct Register {
|
||||
pub bp: Word,
|
||||
pub si: Word,
|
||||
pub di: Word,
|
||||
pub ip: usize,
|
||||
}
|
||||
|
||||
impl Register {
|
||||
@@ -24,6 +25,7 @@ impl Register {
|
||||
bp: 0,
|
||||
si: 0,
|
||||
di: 0,
|
||||
ip: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,12 +55,8 @@ fn main() {
|
||||
|
||||
match args.command {
|
||||
Command::Disassemble => {
|
||||
let mut disasm = Disassembler::new(&args);
|
||||
let instructions = disasm.disassemble(args.dump);
|
||||
match instructions {
|
||||
Ok(instrs) => instrs.iter().for_each(|i| println!("{i}")),
|
||||
_ => {}
|
||||
}
|
||||
let mut disassembler = Disassembler::new(&args);
|
||||
disassembler.disassemble().unwrap();
|
||||
}
|
||||
Command::Interpret => {
|
||||
let mut interpreter = Interpreter::new(&args);
|
||||
|
||||
Reference in New Issue
Block a user