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.
bddisasm/bindings/rsbddisasm/bddisasm/src/decode_error.rs

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