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 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())
}
}

View File

@@ -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(())

View File

@@ -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,
}
}

View File

@@ -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);