chore: replace all panic's with proper error propagation

This commit is contained in:
2025-05-25 15:45:09 +09:00
parent 73b1a99cbd
commit 74e936ab76
4 changed files with 278 additions and 243 deletions

View File

@@ -2,7 +2,7 @@
use crate::aout::Aout;
use crate::operands::{
DWord, Displacement, IByte, IWord, MemoryIndex, ModRmTarget, Operand, Pointer,
Byte, Displacement, IByte, IWord, MemoryIndex, ModRmTarget, Operand, Pointer, Word,
};
use crate::register::{Register, RegisterId, SegmentRegister};
use crate::{
@@ -19,7 +19,11 @@ pub enum DisasmError {
NoFile(Option<String>),
IoError(std::io::Error),
OpcodeUndefined(u8),
IndexOutOfBounds(usize),
IllegalGroupMnemonic(u8, u8),
IllegalModRMByteMode(u8),
IllegalModRMByteIndex(u8),
ReadBeyondTextSection(Disassembler),
UnknownRegister(usize),
}
impl From<std::io::Error> for DisasmError {
@@ -35,10 +39,33 @@ impl fmt::Display for DisasmError {
DisasmError::IoError(msg) => write!(f, "{}", msg),
DisasmError::OpcodeUndefined(opcode) => write!(
f,
"Instruction '{:#x} is considered undefined by the Spec",
"Error (Undefined Opcode). '{:#x} is considered undefined by the Spec",
opcode
),
DisasmError::IndexOutOfBounds(msg) => write!(f, "Out of bounds read at {}", msg),
DisasmError::IllegalGroupMnemonic(group, mnemonic) => write!(
f,
"Error (Illegal group mnemonic). While parsing the ModRM reg field for groups, the following bit-combination for GRP{group} is unknown: {}",
mnemonic
),
DisasmError::IllegalModRMByteMode(modrm) => write!(
f,
"Error (Illegal modrm byte). While deconstructing a ModRM byte, the following mode is unknown: {}",
modrm
),
DisasmError::IllegalModRMByteIndex(modrm) => write!(
f,
"Error (Illegal modrm byte). While deconstructing a ModRM byte, the following index is unknown: {}",
modrm
),
DisasmError::ReadBeyondTextSection(disasm) => write!(
f,
"Error (Out of bounds access). Disassembler state: {:?}",
disasm
),
DisasmError::UnknownRegister(id) => write!(
f,
"Error (Unknown register). The register with ID {id} is unknown",
),
}
}
}
@@ -68,7 +95,7 @@ fn path_to_buf(args: &Args) -> Result<Vec<u8>, DisasmError> {
Ok(buf)
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Disassembler {
pub offset: usize, // the current offset in the disasm process
pub text: Vec<u8>, // the aout binary
@@ -86,47 +113,48 @@ impl Disassembler {
/// Parse a single byte of binary, return it and advance the offset.
/// Returns the read byte.
pub fn parse_byte(&mut self) -> u8 {
pub fn parse_byte(&mut self) -> Result<Byte, DisasmError> {
log::debug!("Attempting to parse byte at {} ...", self.offset);
// advance to operand
self.offset += 1;
let byte = self.text[self.offset];
self.instruction.raw.push(byte);
byte
let byte = self
.text
.get(self.offset)
.ok_or(DisasmError::ReadBeyondTextSection(self.clone()))?;
self.instruction.raw.push(*byte);
Ok(*byte)
}
/// Parse a single word of binary, return it and advance the offset.
/// Parse a single word of binary.
/// Just a wrapper for parsing a byte twice.
/// Returns the read word.
pub fn parse_word(&mut self) -> u16 {
// advance to operand
self.offset += 1;
// XXX: wrap in Result<>
let byte1 = self.text[self.offset];
let byte2 = self.text[self.offset + 1];
// jump onto last operand
self.offset += 1;
pub fn parse_word(&mut self) -> Result<Word, DisasmError> {
log::debug!("Attempting to parse word at {} ...", self.offset);
let byte1 = self.parse_byte()?;
let byte2 = self.parse_byte()?;
self.instruction.raw.push(byte1);
self.instruction.raw.push(byte2);
u16::from_le_bytes([byte1, byte2])
Ok(u16::from_le_bytes([byte1, byte2]))
}
/// Parse a single byte of binary and advance the offset.
/// The returned IByte contains a relative offset to be added to the address
/// Parse a single byte of binary and interpret as as signed.
/// The isize contains a relative offset to be added to the address
/// of the subsequent instruction.
pub fn parse_j_byte(&mut self) -> isize {
pub fn parse_j_byte(&mut self) -> Result<isize, DisasmError> {
// first interpret as 2-complement, then cast for addition
let byte = self.parse_byte() as IByte as isize;
let byte = self.parse_byte()? as IByte as isize;
let next_addr = (self.offset + 1) as isize;
byte + next_addr
Ok(byte + next_addr)
}
/// Parse a single byte of binary and advance the offset.
/// The returned IByte contains a relative offset to be added to the address
/// Parse a single byte of binary and interpret as signed.
/// The isize contains a relative offset to be added to the address
/// of the subsequent instruction.
pub fn parse_j_word(&mut self) -> isize {
pub fn parse_j_word(&mut self) -> Result<isize, DisasmError> {
// first interpret as 2-complement, then cast for addition
let word = self.parse_word() as IWord as isize;
let word = self.parse_word()? as IWord as isize;
let next_addr = (self.offset + 1) as isize;
word + next_addr
Ok(word + next_addr)
}
/// Takes in a modrm byte and returns mod, reg and r/m.
@@ -140,7 +168,10 @@ impl Disassembler {
/// Parse a single modrm byte, return the resulting MemoryIndex and advance the offset.
/// Returns the parsed modrm target and the source register
pub fn parse_modrm_byte(&mut self, width: Operand) -> (ModRmTarget, RegisterId) {
pub fn parse_modrm_byte(
&mut self,
register_width: Operand,
) -> Result<(ModRmTarget, RegisterId), DisasmError> {
// advance to operand
self.offset += 1;
let modrm = self.text[self.offset];
@@ -161,39 +192,39 @@ impl Disassembler {
0b00 => {
if rm == 0b110 {
log::debug!("Additional word during ModRM parsing was read with mod 0.");
displacement = Some(Displacement::IWord(self.parse_word() as IWord));
return (
displacement = Some(Displacement::IWord(self.parse_word()? as IWord));
return Ok((
ModRmTarget::Memory(MemoryIndex {
base: None,
index: None,
displacement,
}),
reg,
);
));
} else {
displacement = None;
}
}
0b01 => {
log::debug!("Additional byte during ModRM parsing was read.");
displacement = Some(Displacement::IByte(self.parse_byte() as IByte))
displacement = Some(Displacement::IByte(self.parse_byte()? as IByte))
}
0b10 => {
log::debug!("Additional word during ModRM parsing was read.");
displacement = Some(Displacement::IWord(self.parse_word() as IWord));
displacement = Some(Displacement::IWord(self.parse_word()? as IWord));
}
0b11 => {
log::debug!("ModRM ({:#b}) to/from Register ({:#b})", rm, reg);
// XXX: find a nicer way instead of using Byte(0) and Word(0)
let target = match width {
Operand::Byte(_) => ModRmTarget::Register(Register::by_id(Operand::Byte(rm))),
let target = match register_width {
Operand::Byte(_) => ModRmTarget::Register(Register::by_id(Operand::Byte(rm))?),
Operand::Word(_) => {
ModRmTarget::Register(Register::by_id(Operand::Word(rm.into())))
ModRmTarget::Register(Register::by_id(Operand::Word(rm.into()))?)
}
};
return (target, reg);
return Ok((target, reg));
}
_ => panic!("Invalid ModRM byte encountered"),
_ => return Err(DisasmError::IllegalModRMByteMode(mode)),
};
let index = match rm {
@@ -237,39 +268,43 @@ impl Disassembler {
index: None,
displacement,
},
_ => panic!("Invalid ModRM byte encountered"),
_ => return Err(DisasmError::IllegalModRMByteIndex(rm)),
};
(ModRmTarget::Memory(index), reg)
Ok((ModRmTarget::Memory(index), reg))
}
/// Match the modrm reg bits to the GPR1 mnemonics.
/// Group 1 always have an ModRM target (all modrm bits, without reg) as
/// first and an imm value as second operand (which has to be parsed before
/// call to this function), but is available in both Byte and Word length.
pub fn modrm_reg_to_grp1(reg: u8, target: ModRmTarget, imm: Operand) -> Mnemonic {
pub fn modrm_reg_to_grp1(
reg: u8,
target: ModRmTarget,
imm: Operand,
) -> Result<Mnemonic, DisasmError> {
match imm {
Operand::Byte(b) => match reg {
0b000 => Mnemonic::ADD_Ib(target, b),
0b001 => Mnemonic::OR_Ib(target, b),
0b010 => Mnemonic::ADC_Ib(target, b),
0b011 => Mnemonic::SBB_Ib(target, b),
0b100 => Mnemonic::AND_Ib(target, b),
0b101 => Mnemonic::SUB_Ib(target, b),
0b110 => Mnemonic::XOR_Ib(target, b),
0b111 => Mnemonic::CMP_Ib(target, b),
_ => panic!("Illegal Group 1 mnemonic"),
0b000 => Ok(Mnemonic::ADD_Ib(target, b)),
0b001 => Ok(Mnemonic::OR_Ib(target, b)),
0b010 => Ok(Mnemonic::ADC_Ib(target, b)),
0b011 => Ok(Mnemonic::SBB_Ib(target, b)),
0b100 => Ok(Mnemonic::AND_Ib(target, b)),
0b101 => Ok(Mnemonic::SUB_Ib(target, b)),
0b110 => Ok(Mnemonic::XOR_Ib(target, b)),
0b111 => Ok(Mnemonic::CMP_Ib(target, b)),
_ => return Err(DisasmError::IllegalGroupMnemonic(1, reg)),
},
Operand::Word(w) => match reg {
0b000 => Mnemonic::ADD_Iv(target, w),
0b001 => Mnemonic::OR_Iv(target, w),
0b010 => Mnemonic::ADC_Iv(target, w),
0b011 => Mnemonic::SBB_Iv(target, w),
0b100 => Mnemonic::AND_Iv(target, w),
0b101 => Mnemonic::SUB_Iv(target, w),
0b110 => Mnemonic::XOR_Iv(target, w),
0b111 => Mnemonic::CMP_Iv(target, w),
_ => panic!("Illegal Group 1 mnemonic"),
0b000 => Ok(Mnemonic::ADD_Iv(target, w)),
0b001 => Ok(Mnemonic::OR_Iv(target, w)),
0b010 => Ok(Mnemonic::ADC_Iv(target, w)),
0b011 => Ok(Mnemonic::SBB_Iv(target, w)),
0b100 => Ok(Mnemonic::AND_Iv(target, w)),
0b101 => Ok(Mnemonic::SUB_Iv(target, w)),
0b110 => Ok(Mnemonic::XOR_Iv(target, w)),
0b111 => Ok(Mnemonic::CMP_Iv(target, w)),
_ => return Err(DisasmError::IllegalGroupMnemonic(1, reg)),
},
}
}
@@ -278,17 +313,17 @@ impl Disassembler {
/// Group 2 only has a single operand, the other one is either a constant
/// 1 (not present in the binary) or the CL register.
/// This function assumes the operand to be 1
pub fn modrm_reg_to_grp2_1(reg: u8, target: ModRmTarget) -> Mnemonic {
pub fn modrm_reg_to_grp2_1(reg: u8, target: ModRmTarget) -> Result<Mnemonic, DisasmError> {
match reg {
0b000 => Mnemonic::ROL_b(target, 1),
0b001 => Mnemonic::ROR_b(target, 1),
0b010 => Mnemonic::RCL_b(target, 1),
0b011 => Mnemonic::RCR_b(target, 1),
0b100 => Mnemonic::SHL_b(target, 1),
0b101 => Mnemonic::SHR_b(target, 1),
0b110 => Mnemonic::SAR_b(target, 1),
0b111 => Mnemonic::SAR_b(target, 1),
_ => panic!("Illegal Group 2 mnemonic"),
0b000 => Ok(Mnemonic::ROL_b(target, 1)),
0b001 => Ok(Mnemonic::ROR_b(target, 1)),
0b010 => Ok(Mnemonic::RCL_b(target, 1)),
0b011 => Ok(Mnemonic::RCR_b(target, 1)),
0b100 => Ok(Mnemonic::SHL_b(target, 1)),
0b101 => Ok(Mnemonic::SHR_b(target, 1)),
0b110 => Ok(Mnemonic::SAR_b(target, 1)),
0b111 => Ok(Mnemonic::SAR_b(target, 1)),
_ => return Err(DisasmError::IllegalGroupMnemonic(2, reg)),
}
}
@@ -296,37 +331,42 @@ impl Disassembler {
/// Group 2 only has a single operand, the other one is either a constant
/// 1 (not present in the binary) or the CL register.
/// This function assumes the operand to be CL register.
pub fn modrm_reg_to_grp2_cl(reg: u8, target: ModRmTarget) -> Mnemonic {
pub fn modrm_reg_to_grp2_cl(reg: u8, target: ModRmTarget) -> Result<Mnemonic, DisasmError> {
match reg {
0b000 => Mnemonic::ROL_fromReg(target, Register::CL),
0b001 => Mnemonic::ROR_fromReg(target, Register::CL),
0b010 => Mnemonic::RCL_fromReg(target, Register::CL),
0b011 => Mnemonic::RCR_fromReg(target, Register::CL),
0b100 => Mnemonic::SHL_fromReg(target, Register::CL),
0b101 => Mnemonic::SHR_fromReg(target, Register::CL),
0b110 => Mnemonic::SAR_fromReg(target, Register::CL),
0b111 => Mnemonic::SAR_fromReg(target, Register::CL),
_ => panic!("Illegal Group 2 mnemonic"),
0b000 => Ok(Mnemonic::ROL_fromReg(target, Register::CL)),
0b001 => Ok(Mnemonic::ROR_fromReg(target, Register::CL)),
0b010 => Ok(Mnemonic::RCL_fromReg(target, Register::CL)),
0b011 => Ok(Mnemonic::RCR_fromReg(target, Register::CL)),
0b100 => Ok(Mnemonic::SHL_fromReg(target, Register::CL)),
0b101 => Ok(Mnemonic::SHR_fromReg(target, Register::CL)),
0b110 => Ok(Mnemonic::SAR_fromReg(target, Register::CL)),
0b111 => Ok(Mnemonic::SAR_fromReg(target, Register::CL)),
_ => return Err(DisasmError::IllegalGroupMnemonic(2, reg)),
}
}
/// Match the modrm reg bits to the GPR3a/b mnemonics.
/// Group 3 only has a single operand, which is the ModRmTarget selected
/// by modrm bits.
pub fn modrm_reg_to_grp3(&mut self, reg: u8, target: ModRmTarget, width: Operand) -> Mnemonic {
pub fn modrm_reg_to_grp3(
&mut self,
reg: u8,
target: ModRmTarget,
width: Operand,
) -> Result<Mnemonic, DisasmError> {
match reg {
0b000 => match width {
Operand::Byte(_) => Mnemonic::TEST_Ib(target, self.parse_byte()),
Operand::Word(_) => Mnemonic::TEST_Iv(target, self.parse_word()),
Operand::Byte(_) => Ok(Mnemonic::TEST_Ib(target, self.parse_byte()?)),
Operand::Word(_) => Ok(Mnemonic::TEST_Iv(target, self.parse_word()?)),
},
// 0b001 => // unused
0b010 => Mnemonic::NOT(target),
0b011 => Mnemonic::NEG(target),
0b100 => Mnemonic::MUL(target),
0b101 => Mnemonic::IMUL(target),
0b110 => Mnemonic::DIV(target),
0b111 => Mnemonic::IDIV(target),
_ => panic!("Illegal Group 3 mnemonic"),
0b010 => Ok(Mnemonic::NOT(target)),
0b011 => Ok(Mnemonic::NEG(target)),
0b100 => Ok(Mnemonic::MUL(target)),
0b101 => Ok(Mnemonic::IMUL(target)),
0b110 => Ok(Mnemonic::DIV(target)),
0b111 => Ok(Mnemonic::IDIV(target)),
_ => Err(DisasmError::IllegalGroupMnemonic(3, reg)),
}
}
@@ -334,7 +374,7 @@ impl Disassembler {
/// An Mp is a ModRM byte with the `reg` bits ignored and an additional
/// 2 words parsed for a `Pointer` type.
pub fn modrm_mp(&mut self) -> Result<(ModRmTarget, Pointer), DisasmError> {
let (target, _) = self.parse_modrm_byte(Operand::Byte(0));
let (target, _) = self.parse_modrm_byte(Operand::Byte(0))?;
let ptr = Pointer::new(self)?;
Ok((target, ptr))
}
@@ -362,8 +402,8 @@ impl Disassembler {
0x01 => modrmv!(self, ADD_FromReg),
0x02 => modrmb!(self, ADD_ToReg),
0x03 => modrmv!(self, ADD_ToReg),
0x04 => Mnemonic::ADD_ALIb(self.parse_byte()),
0x05 => Mnemonic::ADD_AXIv(self.parse_word()),
0x04 => Mnemonic::ADD_ALIb(self.parse_byte()?),
0x05 => Mnemonic::ADD_AXIv(self.parse_word()?),
0x06 => Mnemonic::PUSH_S(SegmentRegister::ES),
0x07 => Mnemonic::POP_S(SegmentRegister::ES),
@@ -372,8 +412,8 @@ impl Disassembler {
0x09 => modrmv!(self, OR_FromReg),
0x0A => modrmb!(self, OR_ToReg),
0x0B => modrmv!(self, OR_ToReg),
0x0C => Mnemonic::OR_ALIb(self.parse_byte()),
0x0D => Mnemonic::OR_AXIv(self.parse_word()),
0x0C => Mnemonic::OR_ALIb(self.parse_byte()?),
0x0D => Mnemonic::OR_AXIv(self.parse_word()?),
0x0E => Mnemonic::PUSH_S(SegmentRegister::CS),
@@ -383,8 +423,8 @@ impl Disassembler {
0x11 => modrmv!(self, ADC_FromReg),
0x12 => modrmb!(self, ADC_ToReg),
0x13 => modrmv!(self, ADC_ToReg),
0x14 => Mnemonic::ADC_ALIb(self.parse_byte()),
0x15 => Mnemonic::ADC_AXIv(self.parse_word()),
0x14 => Mnemonic::ADC_ALIb(self.parse_byte()?),
0x15 => Mnemonic::ADC_AXIv(self.parse_word()?),
0x16 => Mnemonic::PUSH_S(SegmentRegister::SS),
0x17 => Mnemonic::POP_S(SegmentRegister::SS),
@@ -393,8 +433,8 @@ impl Disassembler {
0x19 => modrmv!(self, SBB_FromReg),
0x1A => modrmb!(self, SBB_ToReg),
0x1B => modrmv!(self, SBB_ToReg),
0x1C => Mnemonic::SBB_ALIb(self.parse_byte()),
0x1D => Mnemonic::SBB_AXIv(self.parse_word()),
0x1C => Mnemonic::SBB_ALIb(self.parse_byte()?),
0x1D => Mnemonic::SBB_AXIv(self.parse_word()?),
0x1E => Mnemonic::PUSH_S(SegmentRegister::DS),
0x1F => Mnemonic::POP_S(SegmentRegister::DS),
@@ -403,8 +443,8 @@ impl Disassembler {
0x21 => modrmv!(self, AND_FromReg),
0x22 => modrmb!(self, AND_ToReg),
0x23 => modrmv!(self, AND_ToReg),
0x24 => Mnemonic::AND_ALIb(self.parse_byte()),
0x25 => Mnemonic::AND_AXIv(self.parse_word()),
0x24 => Mnemonic::AND_ALIb(self.parse_byte()?),
0x25 => Mnemonic::AND_AXIv(self.parse_word()?),
0x26 => Mnemonic::OVERRIDE(SegmentRegister::ES),
0x27 => Mnemonic::DAA,
@@ -413,8 +453,8 @@ impl Disassembler {
0x29 => modrmv!(self, SUB_FromReg),
0x2A => modrmb!(self, SUB_ToReg),
0x2B => modrmv!(self, SUB_ToReg),
0x2C => Mnemonic::SUB_ALIb(self.parse_byte()),
0x2D => Mnemonic::SUB_AXIv(self.parse_word()),
0x2C => Mnemonic::SUB_ALIb(self.parse_byte()?),
0x2D => Mnemonic::SUB_AXIv(self.parse_word()?),
0x2E => Mnemonic::OVERRIDE(SegmentRegister::CS),
0x2F => Mnemonic::DAS,
@@ -423,8 +463,8 @@ impl Disassembler {
0x31 => modrmv!(self, XOR_FromReg),
0x32 => modrmb!(self, XOR_ToReg),
0x33 => modrmv!(self, XOR_ToReg),
0x34 => Mnemonic::XOR_ALIb(self.parse_byte()),
0x35 => Mnemonic::XOR_AXIv(self.parse_word()),
0x34 => Mnemonic::XOR_ALIb(self.parse_byte()?),
0x35 => Mnemonic::XOR_AXIv(self.parse_word()?),
0x36 => Mnemonic::OVERRIDE(SegmentRegister::SS),
0x37 => Mnemonic::AAA,
@@ -433,8 +473,8 @@ impl Disassembler {
0x39 => modrmv!(self, CMP_FromReg),
0x3A => modrmb!(self, CMP_ToReg),
0x3B => modrmv!(self, CMP_ToReg),
0x3C => Mnemonic::CMP_ALIb(self.parse_byte()),
0x3D => Mnemonic::CMP_AXIv(self.parse_word()),
0x3C => Mnemonic::CMP_ALIb(self.parse_byte()?),
0x3D => Mnemonic::CMP_AXIv(self.parse_word()?),
0x3E => Mnemonic::OVERRIDE(SegmentRegister::DS),
0x3F => Mnemonic::AAS,
@@ -477,45 +517,45 @@ impl Disassembler {
0x60..=0x6F => return Err(DisasmError::OpcodeUndefined(opcode)),
0x70 => Mnemonic::JO(self.parse_j_byte()),
0x71 => Mnemonic::JNO(self.parse_j_byte()),
0x72 => Mnemonic::JB(self.parse_j_byte()),
0x73 => Mnemonic::JNB(self.parse_j_byte()),
0x74 => Mnemonic::JZ(self.parse_j_byte()),
0x75 => Mnemonic::JNZ(self.parse_j_byte()),
0x76 => Mnemonic::JBE(self.parse_j_byte()),
0x77 => Mnemonic::JA(self.parse_j_byte()),
0x78 => Mnemonic::JS(self.parse_j_byte()),
0x79 => Mnemonic::JNS(self.parse_j_byte()),
0x7A => Mnemonic::JPE(self.parse_j_byte()),
0x7B => Mnemonic::JPO(self.parse_j_byte()),
0x7C => Mnemonic::JL(self.parse_j_byte()),
0x7D => Mnemonic::JGE(self.parse_j_byte()),
0x7E => Mnemonic::JLE(self.parse_j_byte()),
0x7F => Mnemonic::JG(self.parse_j_byte()),
0x70 => Mnemonic::JO(self.parse_j_byte()?),
0x71 => Mnemonic::JNO(self.parse_j_byte()?),
0x72 => Mnemonic::JB(self.parse_j_byte()?),
0x73 => Mnemonic::JNB(self.parse_j_byte()?),
0x74 => Mnemonic::JZ(self.parse_j_byte()?),
0x75 => Mnemonic::JNZ(self.parse_j_byte()?),
0x76 => Mnemonic::JBE(self.parse_j_byte()?),
0x77 => Mnemonic::JA(self.parse_j_byte()?),
0x78 => Mnemonic::JS(self.parse_j_byte()?),
0x79 => Mnemonic::JNS(self.parse_j_byte()?),
0x7A => Mnemonic::JPE(self.parse_j_byte()?),
0x7B => Mnemonic::JPO(self.parse_j_byte()?),
0x7C => Mnemonic::JL(self.parse_j_byte()?),
0x7D => Mnemonic::JGE(self.parse_j_byte()?),
0x7E => Mnemonic::JLE(self.parse_j_byte()?),
0x7F => Mnemonic::JG(self.parse_j_byte()?),
// Group 1
0x80 => {
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
let imm = self.parse_byte();
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0))?;
let imm = self.parse_byte()?;
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))?
}
0x81 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
let imm = self.parse_word();
Self::modrm_reg_to_grp1(reg, target, Operand::Word(imm))
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
let imm = self.parse_word()?;
Self::modrm_reg_to_grp1(reg, target, Operand::Word(imm))?
}
0x82 => {
// same as 0x80
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
let imm = self.parse_byte();
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0))?;
let imm = self.parse_byte()?;
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))?
}
0x83 => {
// byte extended version
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
let imm = self.parse_byte();
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
let imm = self.parse_byte()?;
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))?
}
0x84 => modrmb!(self, TEST),
@@ -534,7 +574,7 @@ impl Disassembler {
0x8D => modrmv!(self, LEA),
0x8F => {
let target = self.parse_modrm_byte(Operand::Word(0)).0;
let target = self.parse_modrm_byte(Operand::Word(0))?.0;
let mem = match target {
ModRmTarget::Memory(idx) => idx,
_ => panic!("POP_M instruction given a register to pop into"),
@@ -554,16 +594,7 @@ impl Disassembler {
0x98 => Mnemonic::CBW,
0x99 => Mnemonic::CWD,
0x9A => Mnemonic::CALL_p(Pointer {
raw: DWord::from_le_bytes([
self.text[self.offset],
self.text[self.offset + 1],
self.text[self.offset + 2],
self.text[self.offset + 3],
]),
segment: self.parse_word(),
offset: self.parse_word(),
}),
0x9A => Mnemonic::CALL_p(Pointer::new(self)?),
0x9B => Mnemonic::WAIT,
@@ -572,18 +603,18 @@ impl Disassembler {
0x9E => Mnemonic::SAHF,
0x9F => Mnemonic::LAHF,
0xA0 => Mnemonic::MOV_AL0b(self.parse_byte()),
0xA1 => Mnemonic::MOV_AX0v(self.parse_word()),
0xA2 => Mnemonic::MOV_0bAL(self.parse_byte()),
0xA3 => Mnemonic::MOV_0vAX(self.parse_word()),
0xA0 => Mnemonic::MOV_AL0b(self.parse_byte()?),
0xA1 => Mnemonic::MOV_AX0v(self.parse_word()?),
0xA2 => Mnemonic::MOV_0bAL(self.parse_byte()?),
0xA3 => Mnemonic::MOV_0vAX(self.parse_word()?),
0xA4 => Mnemonic::MOVSB,
0xA5 => Mnemonic::MOVSW,
0xA6 => Mnemonic::CMPSB,
0xA7 => Mnemonic::CMPSW,
0xA8 => Mnemonic::TEST_ALIb(self.parse_byte()),
0xA9 => Mnemonic::TEST_AXIv(self.parse_word()),
0xA8 => Mnemonic::TEST_ALIb(self.parse_byte()?),
0xA9 => Mnemonic::TEST_AXIv(self.parse_word()?),
0xAA => Mnemonic::STOSB,
0xAB => Mnemonic::STOSW,
@@ -592,26 +623,26 @@ impl Disassembler {
0xAE => Mnemonic::SCASB,
0xAF => Mnemonic::SCASW,
0xB0 => Mnemonic::MOV_ALIb(self.parse_byte()),
0xB1 => Mnemonic::MOV_CLIb(self.parse_byte()),
0xB2 => Mnemonic::MOV_DLIb(self.parse_byte()),
0xB3 => Mnemonic::MOV_BLIb(self.parse_byte()),
0xB4 => Mnemonic::MOV_AHIb(self.parse_byte()),
0xB5 => Mnemonic::MOV_CHIb(self.parse_byte()),
0xB6 => Mnemonic::MOV_DHIb(self.parse_byte()),
0xB7 => Mnemonic::MOV_BHIb(self.parse_byte()),
0xB8 => Mnemonic::MOV_AXIv(self.parse_word()),
0xB9 => Mnemonic::MOV_CXIv(self.parse_word()),
0xBA => Mnemonic::MOV_DXIv(self.parse_word()),
0xBB => Mnemonic::MOV_BXIv(self.parse_word()),
0xBC => Mnemonic::MOV_SPIv(self.parse_word()),
0xBD => Mnemonic::MOV_BPIv(self.parse_word()),
0xBE => Mnemonic::MOV_SIIv(self.parse_word()),
0xBF => Mnemonic::MOV_DIIv(self.parse_word()),
0xB0 => Mnemonic::MOV_ALIb(self.parse_byte()?),
0xB1 => Mnemonic::MOV_CLIb(self.parse_byte()?),
0xB2 => Mnemonic::MOV_DLIb(self.parse_byte()?),
0xB3 => Mnemonic::MOV_BLIb(self.parse_byte()?),
0xB4 => Mnemonic::MOV_AHIb(self.parse_byte()?),
0xB5 => Mnemonic::MOV_CHIb(self.parse_byte()?),
0xB6 => Mnemonic::MOV_DHIb(self.parse_byte()?),
0xB7 => Mnemonic::MOV_BHIb(self.parse_byte()?),
0xB8 => Mnemonic::MOV_AXIv(self.parse_word()?),
0xB9 => Mnemonic::MOV_CXIv(self.parse_word()?),
0xBA => Mnemonic::MOV_DXIv(self.parse_word()?),
0xBB => Mnemonic::MOV_BXIv(self.parse_word()?),
0xBC => Mnemonic::MOV_SPIv(self.parse_word()?),
0xBD => Mnemonic::MOV_BPIv(self.parse_word()?),
0xBE => Mnemonic::MOV_SIIv(self.parse_word()?),
0xBF => Mnemonic::MOV_DIIv(self.parse_word()?),
0xC0..=0xC1 => return Err(DisasmError::OpcodeUndefined(opcode)),
0xC2 => Mnemonic::RET_Iw(self.parse_word()),
0xC2 => Mnemonic::RET_Iw(self.parse_word()?),
0xC3 => Mnemonic::RET,
0xC4 => {
@@ -624,45 +655,45 @@ impl Disassembler {
}
0xC6 => {
let (target, _) = self.parse_modrm_byte(Operand::Byte(0));
Mnemonic::MOV_Ib(target, self.parse_byte())
let (target, _) = self.parse_modrm_byte(Operand::Byte(0))?;
Mnemonic::MOV_Ib(target, self.parse_byte()?)
}
0xC7 => {
let (target, _) = self.parse_modrm_byte(Operand::Word(0));
Mnemonic::MOV_Iv(target, self.parse_word())
let (target, _) = self.parse_modrm_byte(Operand::Word(0))?;
Mnemonic::MOV_Iv(target, self.parse_word()?)
}
0xC8..=0xC9 => return Err(DisasmError::OpcodeUndefined(opcode)),
0xCA => Mnemonic::RETF_Iw(self.parse_word()),
0xCA => Mnemonic::RETF_Iw(self.parse_word()?),
0xCB => Mnemonic::RETF,
0xCC => Mnemonic::INT(3),
0xCD => Mnemonic::INT(self.parse_byte()),
0xCD => Mnemonic::INT(self.parse_byte()?),
0xCE => Mnemonic::INTO,
0xCF => Mnemonic::IRET,
// Group 2
0xD0 => {
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
Self::modrm_reg_to_grp2_1(reg, target)
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0))?;
Self::modrm_reg_to_grp2_1(reg, target)?
}
0xD1 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
Self::modrm_reg_to_grp2_1(reg, target)
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
Self::modrm_reg_to_grp2_1(reg, target)?
}
0xD2 => {
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
Self::modrm_reg_to_grp2_cl(reg, target)
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0))?;
Self::modrm_reg_to_grp2_cl(reg, target)?
}
0xD3 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
Self::modrm_reg_to_grp2_cl(reg, target)
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
Self::modrm_reg_to_grp2_cl(reg, target)?
}
0xD4 => Mnemonic::AAM(self.parse_byte()),
0xD5 => Mnemonic::AAD(self.parse_byte()),
0xD4 => Mnemonic::AAM(self.parse_byte()?),
0xD5 => Mnemonic::AAD(self.parse_byte()?),
0xD6 => return Err(DisasmError::OpcodeUndefined(opcode)),
@@ -670,21 +701,21 @@ impl Disassembler {
0xD8..=0xDF => return Err(DisasmError::OpcodeUndefined(opcode)),
0xE0 => Mnemonic::LOOPNZ(self.parse_j_byte()),
0xE1 => Mnemonic::LOOPZ(self.parse_j_byte()),
0xE2 => Mnemonic::LOOP(self.parse_j_byte()),
0xE3 => Mnemonic::JCXZ(self.parse_j_byte()),
0xE0 => Mnemonic::LOOPNZ(self.parse_j_byte()?),
0xE1 => Mnemonic::LOOPZ(self.parse_j_byte()?),
0xE2 => Mnemonic::LOOP(self.parse_j_byte()?),
0xE3 => Mnemonic::JCXZ(self.parse_j_byte()?),
0xE4 => Mnemonic::IN_AL(self.parse_byte()),
0xE5 => Mnemonic::IN_AX(self.parse_byte()),
0xE6 => Mnemonic::OUT_AL(self.parse_byte()),
0xE7 => Mnemonic::OUT_AX(self.parse_byte()),
0xE4 => Mnemonic::IN_AL(self.parse_byte()?),
0xE5 => Mnemonic::IN_AX(self.parse_byte()?),
0xE6 => Mnemonic::OUT_AL(self.parse_byte()?),
0xE7 => Mnemonic::OUT_AX(self.parse_byte()?),
0xE8 => Mnemonic::CALL_v(self.parse_j_word()),
0xE8 => Mnemonic::CALL_v(self.parse_j_word()?),
0xE9 => Mnemonic::JMP_v(self.parse_j_word()),
0xE9 => Mnemonic::JMP_v(self.parse_j_word()?),
0xEA => Mnemonic::JMP_p(Pointer::new(self)?),
0xEB => Mnemonic::JMP_b(self.parse_j_byte()),
0xEB => Mnemonic::JMP_b(self.parse_j_byte()?),
0xEC => Mnemonic::IN_ALDX,
0xED => Mnemonic::IN_AXDX,
@@ -703,12 +734,12 @@ impl Disassembler {
// Group 3
0xF6 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
self.modrm_reg_to_grp3(reg, target, Operand::Byte(0))
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
self.modrm_reg_to_grp3(reg, target, Operand::Byte(0))?
}
0xF7 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
self.modrm_reg_to_grp3(reg, target, Operand::Word(0))
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
self.modrm_reg_to_grp3(reg, target, Operand::Word(0))?
}
0xF8 => Mnemonic::CLC,
@@ -719,15 +750,15 @@ impl Disassembler {
0xFD => Mnemonic::STD,
0xFE => {
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0))?;
match reg {
0b0 => Mnemonic::INC_Mod(target),
0b1 => Mnemonic::DEC_Mod(target),
_ => panic!("Illegal Group 4 mnemonic"),
_ => return Err(DisasmError::IllegalGroupMnemonic(4, reg)),
}
}
0xFF => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
let (target, reg) = self.parse_modrm_byte(Operand::Word(0))?;
match reg {
0b000 => Mnemonic::INC_Mod(target),
0b001 => Mnemonic::DEC_Mod(target),
@@ -737,7 +768,7 @@ impl Disassembler {
0b101 => Mnemonic::JMP_Mp(target, Pointer::new(self)?),
0b110 => Mnemonic::PUSH_Mod(target),
// 0b111 => unused
_ => panic!("Illegal Group 5 mnemonic"),
_ => return Err(DisasmError::IllegalGroupMnemonic(5, reg)),
}
}

View File

@@ -4,8 +4,8 @@
/// Generate a Mnemonic for an 8-bit Register from a ModRM byte.
macro_rules! modrmb {
($self:ident, $variant:ident) => {{
let (target, reg) = $self.parse_modrm_byte(Operand::Byte(0));
Mnemonic::$variant(target, Register::by_id(Operand::Byte(reg)))
let (target, reg) = $self.parse_modrm_byte(Operand::Byte(0))?;
Mnemonic::$variant(target, Register::by_id(Operand::Byte(reg))?)
}};
}
@@ -13,8 +13,8 @@ macro_rules! modrmb {
/// Generate a Mnemonic for a 16-bit Register from a ModRM byte.
macro_rules! modrmv {
($self:ident, $variant:ident) => {{
let (target, reg) = $self.parse_modrm_byte(Operand::Word(0));
Mnemonic::$variant(target, Register::by_id(Operand::Word(reg.into())))
let (target, reg) = $self.parse_modrm_byte(Operand::Word(0))?;
Mnemonic::$variant(target, Register::by_id(Operand::Word(reg.into()))?)
}};
}
@@ -22,7 +22,7 @@ macro_rules! modrmv {
/// Generate a Mnemonic for a 16-bit Segment Register from a ModRM byte.
macro_rules! modrms {
($self:ident, $variant:ident) => {{
let (target, reg) = $self.parse_modrm_byte(Operand::Word(0));
Mnemonic::$variant(target, SegmentRegister::by_id(reg))
let (target, reg) = $self.parse_modrm_byte(Operand::Word(0))?;
Mnemonic::$variant(target, SegmentRegister::by_id(reg)?)
}};
}

View File

@@ -141,27 +141,31 @@ pub struct Pointer {
impl Pointer {
pub fn new(disasm: &mut Disassembler) -> Result<Self, DisasmError> {
log::debug!(
"Seeking 4 bytes ahead of current text offset... ({} + 4)",
disasm.offset
);
let byte0 = disasm
.text
.get(disasm.offset)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset))?;
.ok_or(DisasmError::ReadBeyondTextSection(disasm.clone()))?;
let byte1 = disasm
.text
.get(disasm.offset + 1)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset + 1))?;
.ok_or(DisasmError::ReadBeyondTextSection(disasm.clone()))?;
let byte2 = disasm
.text
.get(disasm.offset + 2)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset + 2))?;
.ok_or(DisasmError::ReadBeyondTextSection(disasm.clone()))?;
let byte3 = disasm
.text
.get(disasm.offset + 3)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset + 3))?;
.ok_or(DisasmError::ReadBeyondTextSection(disasm.clone()))?;
Ok(Pointer {
raw: DWord::from_le_bytes([*byte0, *byte1, *byte2, *byte3]),
segment: disasm.parse_word(),
offset: disasm.parse_word(),
segment: disasm.parse_word()?,
offset: disasm.parse_word()?,
})
}
}

View File

@@ -1,6 +1,6 @@
//! Internal abstraction of all 8086 registers for disassembly.
use crate::operands::Operand;
use crate::{disasm::DisasmError, operands::Operand};
use core::fmt;
#[derive(Debug, Clone)]
@@ -36,29 +36,29 @@ pub type RegisterId = u8;
#[allow(dead_code)]
impl Register {
/// Find the register corresponding to the 8086 bytecode ID
pub fn by_id(id: Operand) -> Self {
pub fn by_id(id: Operand) -> Result<Self, DisasmError> {
match id {
Operand::Byte(b) => match b {
0b000 => Self::AL,
0b001 => Self::CL,
0b010 => Self::DL,
0b011 => Self::BL,
0b100 => Self::AH,
0b101 => Self::CH,
0b110 => Self::DH,
0b111 => Self::BH,
_ => panic!("Invalid 8bit register ID encountered"),
0b000 => Ok(Self::AL),
0b001 => Ok(Self::CL),
0b010 => Ok(Self::DL),
0b011 => Ok(Self::BL),
0b100 => Ok(Self::AH),
0b101 => Ok(Self::CH),
0b110 => Ok(Self::DH),
0b111 => Ok(Self::BH),
_ => Err(DisasmError::UnknownRegister(b as usize)),
},
Operand::Word(w) => match w {
0b000 => Self::AX,
0b001 => Self::CX,
0b010 => Self::DX,
0b011 => Self::BX,
0b100 => Self::SP,
0b101 => Self::BP,
0b110 => Self::SI,
0b111 => Self::DI,
_ => panic!("Invalid 16bit register ID encountered"),
0b000 => Ok(Self::AX),
0b001 => Ok(Self::CX),
0b010 => Ok(Self::DX),
0b011 => Ok(Self::BX),
0b100 => Ok(Self::SP),
0b101 => Ok(Self::BP),
0b110 => Ok(Self::SI),
0b111 => Ok(Self::DI),
_ => Err(DisasmError::UnknownRegister(w as usize)),
},
}
}
@@ -100,13 +100,13 @@ pub enum SegmentRegister {
#[allow(dead_code)]
impl SegmentRegister {
/// Find the SRegister corresponding to the 8086 bytecode ID
pub fn by_id(id: u8) -> Self {
pub fn by_id(id: u8) -> Result<Self, DisasmError> {
match id {
0x00 => Self::ES,
0x01 => Self::CS,
0x10 => Self::SS,
0x11 => Self::DS,
_ => panic!("Invalid segment register ID encountered"),
0x00 => Ok(Self::ES),
0x01 => Ok(Self::CS),
0x10 => Ok(Self::SS),
0x11 => Ok(Self::DS),
_ => Err(DisasmError::UnknownRegister(id as usize)),
}
}
}