use core::{fmt, result};
pub type Result<T = ()> = result::Result<T, Status>;
pub const ZYAN_MODULE_ZYCORE: usize = 0x1;
pub const ZYAN_MODULE_ZYDIS: usize = 0x2;
pub const ZYAN_MODULE_USER: usize = 0x3FF;
pub const ZYAN_MODULE_ZYDIS_RS: usize = ZYAN_MODULE_USER + 0x42;
macro_rules! make_status {
($error:expr, $module:expr, $code:expr) => {
((($error & 1) << 31) | (($module & 0x7FF) << 20) | ($code & 0xFFFFF)) as u32
};
}
#[repr(u32)]
#[non_exhaustive]
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Status {
Success = make_status!(0, ZYAN_MODULE_ZYCORE, 0x00),
Failed = make_status!(1, ZYAN_MODULE_ZYCORE, 0x01),
True = make_status!(0, ZYAN_MODULE_ZYCORE, 0x02),
False = make_status!(0, ZYAN_MODULE_ZYCORE, 0x03),
InvalidArgument = make_status!(1, ZYAN_MODULE_ZYCORE, 0x04),
InvalidOperation = make_status!(1, ZYAN_MODULE_ZYCORE, 0x05),
NotFound = make_status!(1, ZYAN_MODULE_ZYCORE, 0x06),
OutOfRange = make_status!(1, ZYAN_MODULE_ZYCORE, 0x07),
InsufficientBufferSize = make_status!(1, ZYAN_MODULE_ZYCORE, 0x08),
NotEnoughMemory = make_status!(1, ZYAN_MODULE_ZYCORE, 0x09),
BadSystemCall = make_status!(1, ZYAN_MODULE_ZYCORE, 0x0A),
NoMoreData = make_status!(1, ZYAN_MODULE_ZYDIS, 0x00),
DecodingError = make_status!(1, ZYAN_MODULE_ZYDIS, 0x01),
InstructionTooLong = make_status!(1, ZYAN_MODULE_ZYDIS, 0x02),
BadRegister = make_status!(1, ZYAN_MODULE_ZYDIS, 0x03),
IllegalLock = make_status!(1, ZYAN_MODULE_ZYDIS, 0x04),
IllegalLegacyPfx = make_status!(1, ZYAN_MODULE_ZYDIS, 0x05),
IllegalRex = make_status!(1, ZYAN_MODULE_ZYDIS, 0x06),
InvalidMap = make_status!(1, ZYAN_MODULE_ZYDIS, 0x07),
MalformedEvex = make_status!(1, ZYAN_MODULE_ZYDIS, 0x08),
MalformedMvex = make_status!(1, ZYAN_MODULE_ZYDIS, 0x09),
InvalidMask = make_status!(1, ZYAN_MODULE_ZYDIS, 0x0A),
SkipToken = make_status!(0, ZYAN_MODULE_ZYDIS, 0x0B),
ImpossibleInstruction = make_status!(1, ZYAN_MODULE_ZYDIS, 0x0C),
User = make_status!(1, ZYAN_MODULE_ZYDIS_RS, 0x00),
NotUTF8 = make_status!(1, ZYAN_MODULE_ZYDIS_RS, 0x01),
FormatterError = make_status!(1, ZYAN_MODULE_ZYDIS_RS, 0x02),
}
impl Status {
pub fn code(self) -> usize {
(self as usize) & 0xFFFFF
}
pub fn module(self) -> usize {
(self as usize >> 20) & 0x7FF
}
pub fn is_error(self) -> bool {
(self as usize >> 31) == 1
}
pub fn description(self) -> &'static str {
match self {
Status::Success => "no error",
Status::Failed => "A operation failed.",
Status::InvalidArgument => "An invalid parameter was passed to a function.",
Status::InvalidOperation => "An attempt was made to perform an invalid operation.",
Status::InsufficientBufferSize => {
"A buffer passed to a function was too small to complete the requested operation."
}
Status::OutOfRange => "An index was out of bounds.",
Status::NotFound => "The requested entity was not found.",
Status::NotEnoughMemory => "Insufficient memory to perform the operation.",
Status::BadSystemCall => "An error occurred during a system call.",
Status::NoMoreData => {
"An attempt was made to read data from an input data-source that has no more data \
available."
}
Status::DecodingError => {
"An general error occured while decoding the current instruction. The instruction \
might be undfined."
}
Status::InstructionTooLong => {
"The instruction exceeded the maximum length of 15 bytes."
}
Status::BadRegister => "The instruction encoded an invalid register.",
Status::IllegalLock => {
"A lock-prefix (F0) was found while decoding an instruction that does not support \
locking."
}
Status::IllegalLegacyPfx => {
"A legacy-prefix (F2, F3, 66) was found while decoding a XOP/VEX/EVEX/MVEX \
instruction."
}
Status::IllegalRex => {
"A rex-prefix was found while decoding a XOP/VEX/EVEX/MVEX instruction."
}
Status::InvalidMap => {
"An invalid opcode-map value was found while decoding a XOP/VEX/EVEX/MVEX-prefix."
}
Status::MalformedEvex => "An error occured while decoding the EVEX-prefix.",
Status::MalformedMvex => "An error occured while decoding the MVEX-prefix.",
Status::InvalidMask => {
"An invalid write-mask was specified for an EVEX/MVEX instruction."
}
Status::True | Status::False => "true/false not an error",
Status::SkipToken => "skip this token",
Status::User => "user error",
Status::NotUTF8 => "invalid utf8 data was passed to rust",
Status::ImpossibleInstruction => "requested impossible instruction",
_ => "unknown error",
}
}
pub fn as_result(self) -> Result {
if self.is_error() {
Err(self)
} else {
Ok(())
}
}
}
impl From<Status> for Result {
fn from(x: Status) -> Self {
x.as_result()
}
}
impl fmt::Debug for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
impl fmt::Display for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[cfg(feature = "std")]
impl std::error::Error for Status {
fn description(&self) -> &str {
Self::description(*self)
}
fn cause(&self) -> Option<&dyn std::error::Error> {
None
}
}
macro_rules! check_string {
($expression:expr) => {{
use core::ffi::CStr;
match $expression {
x if x.is_null() => None,
x => Some(CStr::from_ptr(x).to_str().unwrap()),
}
}};
}