chore: cleanup calling logic of disasm/interp

This commit is contained in:
2025-07-08 10:43:02 +09:00
parent 8c1a07b9e6
commit cae4a03c26
4 changed files with 44 additions and 39 deletions

View File

@@ -87,6 +87,7 @@ pub struct Disassembler {
pub aout: Aout, // the aout binary pub aout: Aout, // the aout binary
pub instruction: Instruction, // the instruction, which is currently being parsed pub instruction: Instruction, // the instruction, which is currently being parsed
instructions: Vec<Instruction>, // all parsed instructions instructions: Vec<Instruction>, // all parsed instructions
dump: bool, // Dump dissambly progress, if an error occurs
} }
impl Disassembler { impl Disassembler {
@@ -98,13 +99,15 @@ impl Disassembler {
aout, aout,
instruction: Instruction::new(), instruction: Instruction::new(),
instructions: Vec::new(), instructions: Vec::new(),
dump: args.dump,
} }
} }
/// Start the disassmble and allow for some error handling wrapped around /// Start the disassmble and allow for some error handling wrapped around
/// the actual decoding function. /// the actual [`Self::decode_all_instructions()`] function.
pub fn disassemble(&mut self, dump: bool) -> Result<Vec<Instruction>, DisasmError> { /// Also removes NULL padding from the end of the disassembly.
let is_ok = self.decode_instructions(); 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 // a.out pads the text section to byte align, so the fasely interpreted
// instructions have to be removed. // instructions have to be removed.
@@ -114,19 +117,28 @@ impl Disassembler {
// to allow some error's to act as warnings (see below) // to allow some error's to act as warnings (see below)
let instructions = self.instructions.clone(); 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 // allow for warning-type errors to pass through, as they are not fatal
match is_ok { match is_ok {
Ok(_) => Ok(instructions), Ok(_) => {
dump(instructions);
Ok(())
}
Err(e) => match e { Err(e) => match e {
// not an error per-se
DisasmError::EndOfTextSection => { DisasmError::EndOfTextSection => {
log::debug!("Solo padded 0-byte at end of file was found. Ignoring."); log::debug!("Solo padded 0-byte at end of file was found. Ignoring.");
Ok(instructions) dump(instructions);
Ok(())
} }
// actual errors
_ => { _ => {
if dump { if self.dump {
self.instructions.iter().for_each(|i| println!("{i}")); dump(instructions);
println!( 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 { } else {
println!( println!(
@@ -483,9 +495,11 @@ impl Disassembler {
self.instructions.truncate(until); 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() { 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 // Advance offset to hover the next potential opcode
self.offset += 1; self.offset += 1;
@@ -494,11 +508,11 @@ impl Disassembler {
Ok(()) Ok(())
} }
/// Decode an instruction by matching byte signature to their mnemonics and /// Decode the instruction at `self.offset` by matching byte signature to
/// depending on the instruction, parsing some operands afterwards. /// their mnemonics and depending on the instruction, parsing some operands
/// All parsing is done in capsulated functions, here everything just /// afterwards. All parsing is done in capsulated functions, here everything
/// gets consolodated. /// just gets consolodated.
pub fn decode_instruction(&mut self) -> Result<(), DisasmError> { pub fn decode_instruction(&mut self) -> Result<Instruction, DisasmError> {
// reset mutable current instruction // reset mutable current instruction
self.instruction = Instruction::new(); self.instruction = Instruction::new();
self.instruction.addr = self.offset; self.instruction.addr = self.offset;
@@ -899,11 +913,8 @@ impl Disassembler {
} }
}; };
// Save parsed instruction
log::debug!("Parsed {}", self.instruction); log::debug!("Parsed {}", self.instruction);
self.instructions.push(self.instruction.clone()); Ok(self.instruction.clone())
Ok(())
} }
} }

View File

@@ -48,10 +48,8 @@ impl fmt::Display for InterpreterError {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Interpreter { pub struct Interpreter {
computer: Computer, computer: Computer, // current cpu state
text: Vec<u8>, disassembler: Disassembler, // fetcher, currently holds all instruction data
ip: usize,
disassembler: Disassembler,
} }
impl Interpreter { impl Interpreter {
@@ -59,34 +57,32 @@ impl Interpreter {
let aout = Aout::new_from_args(args); let aout = Aout::new_from_args(args);
Self { Self {
computer: Computer::new(aout.data), computer: Computer::new(aout.data),
text: aout.text,
ip: 0,
disassembler: Disassembler::new(args), disassembler: Disassembler::new(args),
} }
} }
/// Sets instruction pointer in compliance with [`Register::CS`]. /// Sets instruction pointer in compliance with [`Register::CS`].
pub fn set_ip(&mut self, ip: usize) { 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`]. /// Gets instruction pointer in compliance with [`Register::CS`].
pub fn get_ip(&self) -> usize { 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> { 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... ==============="); log::debug!("=============== Fetching next instruction... ===============");
self.disassembler.offset = self.ip; self.disassembler.offset = self.computer.regs.ip;
self.disassembler let current_instruction = self
.disassembler
.decode_instruction() .decode_instruction()
.map_err(|e| InterpreterError::FetchError(e.to_string()))?; .map_err(|e| InterpreterError::FetchError(e.to_string()))?;
let current_instruction = self.disassembler.instruction.clone();
log::info!( log::info!(
"({:04x}) {:<32} {}", "({:04x}) {:<32} {}",
current_instruction.addr, self.computer.regs.ip,
current_instruction.mnemonic.to_string(), current_instruction.mnemonic.to_string(),
self.computer, self.computer,
); );
@@ -845,7 +841,7 @@ impl Interpreter {
} }
// Go to next instruction // Go to next instruction
self.ip += current_instruction.raw.len(); self.computer.regs.ip += current_instruction.raw.len();
} }
Ok(()) Ok(())

View File

@@ -11,6 +11,7 @@ pub struct Register {
pub bp: Word, pub bp: Word,
pub si: Word, pub si: Word,
pub di: Word, pub di: Word,
pub ip: usize,
} }
impl Register { impl Register {
@@ -24,6 +25,7 @@ impl Register {
bp: 0, bp: 0,
si: 0, si: 0,
di: 0, di: 0,
ip: 0,
} }
} }

View File

@@ -55,12 +55,8 @@ fn main() {
match args.command { match args.command {
Command::Disassemble => { Command::Disassemble => {
let mut disasm = Disassembler::new(&args); let mut disassembler = Disassembler::new(&args);
let instructions = disasm.disassemble(args.dump); disassembler.disassemble().unwrap();
match instructions {
Ok(instrs) => instrs.iter().for_each(|i| println!("{i}")),
_ => {}
}
} }
Command::Interpret => { Command::Interpret => {
let mut interpreter = Interpreter::new(&args); let mut interpreter = Interpreter::new(&args);