You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
11 KiB
257 lines
11 KiB
/*
|
|
* Copyright (c) 2021 Bitdefender
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
//! Errors that can be encountered when decoding an instruction or when trying to get details about a decoded
|
|
//! instruction.
|
|
//!
|
|
//! # Notes
|
|
//!
|
|
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [DecodeError](DecodeError) enum.
|
|
//! However, some of these are unlikely to be encountered when using this crate (for example,
|
|
//! [BufferOverflow](DecodeError::BufferOverflow)) which indicates that a buffer passed to the `bddisasm` C library is
|
|
//! not large enough.
|
|
//!
|
|
//! Other errors, such as [UnknownStatus](DecodeError::UnknownStatus) or
|
|
//! [UnknownInstruction](DecodeError::UnknownInstruction) are used to indicate that this crate is out of sync with
|
|
//! `bddisasm-sys`, which also should never happen.
|
|
|
|
extern crate bddisasm_sys as ffi;
|
|
|
|
use std::error::Error;
|
|
use std::fmt;
|
|
|
|
/// Holds all the possible errors that can be encountered by the decoder.
|
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
|
pub enum DecodeError {
|
|
/// The underlying bddisasm status is not known. The inner value holds the status as it was returned by bddisasm.
|
|
///
|
|
/// This usually means that this library is out of sync with bddisasm-sys and is not aware that a new error status
|
|
/// was added.
|
|
UnknownStatus(u32),
|
|
|
|
/// The instruction class returned by bddisasm is not known. The inner value holds the instruction class as it was
|
|
/// returned by bddisasm.
|
|
///
|
|
/// This usually means that this library is out of sync with bddisasm-sys and is not aware that a new instruction
|
|
/// class was added.
|
|
UnknownInstruction(u32),
|
|
|
|
/// The provided input buffer is too small and does not contain a valid instruction.
|
|
BufferTooSmall,
|
|
|
|
/// Invalid encoding/instruction.
|
|
InvalidEncoding,
|
|
|
|
/// Instruction exceeds the maximum 15 bytes.
|
|
InstructionTooLong,
|
|
|
|
/// Invalid prefix sequence is present.
|
|
InvalidPrefixSequence,
|
|
|
|
/// The instruction uses an invalid register.
|
|
InvalidRegisterInInstruction,
|
|
|
|
/// XOP is present, but also a legacy prefix.
|
|
XopWithPrefix,
|
|
|
|
/// VEX is present, but also a legacy prefix.
|
|
VexWithPrefix,
|
|
|
|
/// EVEX is present, but also a legacy prefix.
|
|
EvexWithPrefix,
|
|
|
|
/// Invalid encoding/instruction.
|
|
InvalidEncodingInMode,
|
|
|
|
/// Invalid usage of LOCK.
|
|
BadLockPrefix,
|
|
|
|
/// An attempt to load the CS register.
|
|
CsLoad,
|
|
|
|
/// 0x66 prefix is not accepted.
|
|
Prefix66NotAccepted,
|
|
|
|
/// 16 bit addressing mode not supported.
|
|
AddressingNotSupported16Bit,
|
|
|
|
/// RIP-relative addressing not supported.
|
|
RipRelAddressingNotSupported,
|
|
|
|
/// Instruction uses VSIB, but SIB is not present.
|
|
VsibWithoutSib,
|
|
|
|
/// VSIB addressing, same vector reg used more than once.
|
|
InvalidVsibRegs,
|
|
|
|
/// VEX.VVVV field must be zero.
|
|
VexVvvvMustBeZero,
|
|
|
|
/// Masking is not supported.
|
|
MaskNotSupported,
|
|
|
|
/// Masking is mandatory.
|
|
MaskRequired,
|
|
|
|
/// Embedded rounding/SAE not supported.
|
|
ErSaeNotSupported,
|
|
|
|
/// Zeroing not supported.
|
|
ZeroingNotSupported,
|
|
|
|
/// Zeroing on memory.
|
|
ZeroingOnMemory,
|
|
|
|
/// Zeroing without masking.
|
|
ZeroingNoMask,
|
|
|
|
/// Broadcast not supported.
|
|
BroadcastNotSupported,
|
|
|
|
/// EVEX.V' field must be one (negated 0).
|
|
BadEvexVPrime,
|
|
|
|
/// EVEX.L'L field is invalid for the instruction.
|
|
BadEvexLl,
|
|
|
|
/// Instruction uses SIBMEM, but SIB is not present.
|
|
SibmemWithoutSib,
|
|
|
|
/// Tile registers are not unique.
|
|
InvalidTileRegs,
|
|
|
|
/// Destination register is not unique (used as src).
|
|
InvalidDestRegs,
|
|
|
|
/// An invalid parameter was provided.
|
|
InvalidParameter,
|
|
|
|
/// The INSTRUX contains unexpected values.
|
|
InvalidInstrux,
|
|
|
|
/// Not enough space is available.
|
|
BufferOverflow,
|
|
|
|
/// Internal library error.
|
|
InternalError,
|
|
}
|
|
|
|
impl fmt::Display for DecodeError {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
DecodeError::UnknownStatus(value) => write!(f, "unknown status: {:#x}", value),
|
|
DecodeError::UnknownInstruction(value) => {
|
|
write!(f, "unknown instruction: {:#x}", value)
|
|
}
|
|
DecodeError::BufferTooSmall => write!(f, "the provided input buffer is too small"),
|
|
DecodeError::InvalidEncoding => write!(f, "invalid encoding/instruction"),
|
|
DecodeError::InstructionTooLong => {
|
|
write!(f, "instruction exceeds the maximum 15 bytes")
|
|
}
|
|
DecodeError::InvalidPrefixSequence => write!(f, "invalid prefix sequence is present"),
|
|
DecodeError::InvalidRegisterInInstruction => {
|
|
write!(f, "the instruction uses an invalid register")
|
|
}
|
|
DecodeError::XopWithPrefix => write!(f, "XOP is present, but also a legacy prefix"),
|
|
DecodeError::VexWithPrefix => write!(f, "VEX is present, but also a legacy prefix"),
|
|
DecodeError::EvexWithPrefix => write!(f, "EVEX is present, but also a legacy prefix"),
|
|
DecodeError::InvalidEncodingInMode => write!(f, "invalid encoding/instruction"),
|
|
DecodeError::BadLockPrefix => write!(f, "invalid usage of LOCK"),
|
|
DecodeError::CsLoad => write!(f, "an attempt to load the CS register"),
|
|
DecodeError::Prefix66NotAccepted => write!(f, "0x66 prefix is not accepted"),
|
|
DecodeError::AddressingNotSupported16Bit => {
|
|
write!(f, "16 bit addressing mode not supported")
|
|
}
|
|
DecodeError::RipRelAddressingNotSupported => {
|
|
write!(f, "RIP-relative addressing not supported")
|
|
}
|
|
DecodeError::VsibWithoutSib => {
|
|
write!(f, "instruction uses VSIB, but SIB is not present")
|
|
}
|
|
DecodeError::InvalidVsibRegs => {
|
|
write!(
|
|
f,
|
|
"VSIB addressing with the same vector register used more than once"
|
|
)
|
|
}
|
|
DecodeError::VexVvvvMustBeZero => write!(f, "VEX.VVVV field must be zero"),
|
|
DecodeError::MaskNotSupported => write!(f, "masking is not supported"),
|
|
DecodeError::MaskRequired => write!(f, "masking is mandatory"),
|
|
DecodeError::ErSaeNotSupported => write!(f, "embedded rounding/SAE not supported"),
|
|
DecodeError::ZeroingNotSupported => write!(f, "zeroing not supported"),
|
|
DecodeError::ZeroingOnMemory => write!(f, "zeroing on memory"),
|
|
DecodeError::ZeroingNoMask => write!(f, "zeroing without masking"),
|
|
DecodeError::BroadcastNotSupported => write!(f, "broadcast not supported"),
|
|
DecodeError::BadEvexVPrime => write!(f, "EVEX.V' field must be one (negated 0)"),
|
|
DecodeError::BadEvexLl => write!(f, "EVEX.L'L field is invalid for the instruction"),
|
|
DecodeError::SibmemWithoutSib => {
|
|
write!(f, "instruction uses SIBMEM, but SIB is not present")
|
|
}
|
|
DecodeError::InvalidTileRegs => write!(f, "tile registers are not unique"),
|
|
DecodeError::InvalidDestRegs => {
|
|
write!(f, "destination register is not unique (used as src)")
|
|
}
|
|
DecodeError::InvalidParameter => write!(f, "an invalid parameter was provided"),
|
|
DecodeError::InvalidInstrux => {
|
|
write!(f, "the INSTRUX structure contains unexpected values")
|
|
}
|
|
DecodeError::BufferOverflow => {
|
|
write!(f, "not enough space is available to format instruction")
|
|
}
|
|
DecodeError::InternalError => write!(f, "internal error"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Error for DecodeError {}
|
|
|
|
pub(crate) fn status_to_error(status: ffi::NDSTATUS) -> Result<(), DecodeError> {
|
|
if status == ffi::ND_STATUS_SUCCESS || status == ffi::ND_STATUS_HINT_OPERAND_NOT_USED {
|
|
Ok(())
|
|
} else {
|
|
match status {
|
|
ffi::ND_STATUS_BUFFER_TOO_SMALL => Err(DecodeError::BufferTooSmall),
|
|
ffi::ND_STATUS_INVALID_ENCODING => Err(DecodeError::InvalidEncoding),
|
|
ffi::ND_STATUS_INSTRUCTION_TOO_LONG => Err(DecodeError::InstructionTooLong),
|
|
ffi::ND_STATUS_INVALID_PREFIX_SEQUENCE => Err(DecodeError::InvalidPrefixSequence),
|
|
ffi::ND_STATUS_INVALID_REGISTER_IN_INSTRUCTION => {
|
|
Err(DecodeError::InvalidRegisterInInstruction)
|
|
}
|
|
ffi::ND_STATUS_XOP_WITH_PREFIX => Err(DecodeError::XopWithPrefix),
|
|
ffi::ND_STATUS_VEX_WITH_PREFIX => Err(DecodeError::VexWithPrefix),
|
|
ffi::ND_STATUS_EVEX_WITH_PREFIX => Err(DecodeError::EvexWithPrefix),
|
|
ffi::ND_STATUS_INVALID_ENCODING_IN_MODE => Err(DecodeError::InvalidEncodingInMode),
|
|
ffi::ND_STATUS_BAD_LOCK_PREFIX => Err(DecodeError::BadLockPrefix),
|
|
ffi::ND_STATUS_CS_LOAD => Err(DecodeError::CsLoad),
|
|
ffi::ND_STATUS_66_NOT_ACCEPTED => Err(DecodeError::Prefix66NotAccepted),
|
|
ffi::ND_STATUS_16_BIT_ADDRESSING_NOT_SUPPORTED => {
|
|
Err(DecodeError::AddressingNotSupported16Bit)
|
|
}
|
|
ffi::ND_STATUS_RIP_REL_ADDRESSING_NOT_SUPPORTED => {
|
|
Err(DecodeError::RipRelAddressingNotSupported)
|
|
}
|
|
ffi::ND_STATUS_VSIB_WITHOUT_SIB => Err(DecodeError::VsibWithoutSib),
|
|
ffi::ND_STATUS_INVALID_VSIB_REGS => Err(DecodeError::InvalidVsibRegs),
|
|
ffi::ND_STATUS_VEX_VVVV_MUST_BE_ZERO => Err(DecodeError::VexVvvvMustBeZero),
|
|
ffi::ND_STATUS_MASK_NOT_SUPPORTED => Err(DecodeError::MaskNotSupported),
|
|
ffi::ND_STATUS_MASK_REQUIRED => Err(DecodeError::MaskRequired),
|
|
ffi::ND_STATUS_ER_SAE_NOT_SUPPORTED => Err(DecodeError::ErSaeNotSupported),
|
|
ffi::ND_STATUS_ZEROING_NOT_SUPPORTED => Err(DecodeError::ZeroingNotSupported),
|
|
ffi::ND_STATUS_ZEROING_ON_MEMORY => Err(DecodeError::ZeroingOnMemory),
|
|
ffi::ND_STATUS_ZEROING_NO_MASK => Err(DecodeError::ZeroingNoMask),
|
|
ffi::ND_STATUS_BROADCAST_NOT_SUPPORTED => Err(DecodeError::BroadcastNotSupported),
|
|
ffi::ND_STATUS_BAD_EVEX_V_PRIME => Err(DecodeError::BadEvexVPrime),
|
|
ffi::ND_STATUS_BAD_EVEX_LL => Err(DecodeError::BadEvexLl),
|
|
ffi::ND_STATUS_SIBMEM_WITHOUT_SIB => Err(DecodeError::SibmemWithoutSib),
|
|
ffi::ND_STATUS_INVALID_TILE_REGS => Err(DecodeError::InvalidTileRegs),
|
|
ffi::ND_STATUS_INVALID_DEST_REGS => Err(DecodeError::InvalidDestRegs),
|
|
ffi::ND_STATUS_INVALID_PARAMETER => Err(DecodeError::InvalidParameter),
|
|
ffi::ND_STATUS_INVALID_INSTRUX => Err(DecodeError::InvalidInstrux),
|
|
ffi::ND_STATUS_BUFFER_OVERFLOW => Err(DecodeError::BufferOverflow),
|
|
ffi::ND_STATUS_INTERNAL_ERROR => Err(DecodeError::InternalError),
|
|
_ => Err(DecodeError::UnknownStatus(status)),
|
|
}
|
|
}
|
|
}
|