Skip to main content

zydis_rs/
error.rs

1//! Error types for zydis-rs
2//!
3//! This module provides comprehensive error handling for the zydis-rs library,
4//! including detailed error types for decoding and encoding operations.
5//!
6//! ## Error Categories
7//!
8//! - **Decode Errors**: Errors that occur during instruction decoding
9//! - **Encode Errors**: Errors that occur during instruction encoding
10//! - **General Errors**: Other errors like invalid mode, buffer issues, etc.
11//!
12//! ## Error Recovery
13//!
14//! The decoder supports partial recovery from errors. When decoding fails,
15//! the error includes context information that can be used to:
16//! - Skip invalid bytes and continue decoding
17//! - Report detailed error messages to users
18//! - Implement custom error handling logic
19
20use core::fmt;
21
22/// Result type alias for zydis-rs operations
23pub type Result<T> = core::result::Result<T, Error>;
24
25/// Main error type
26#[derive(Debug, Clone, PartialEq, Eq)]
27#[non_exhaustive]
28pub enum Error {
29    /// Invalid machine mode
30    InvalidMachineMode,
31
32    /// Invalid stack width
33    InvalidStackWidth,
34
35    /// Failed to decode instruction
36    DecodeFailed(DecodeError),
37
38    /// Encoding failed
39    EncodeFailed(EncodeError),
40
41    /// Incomplete instruction (need more bytes)
42    IncompleteInstruction {
43        /// How many more bytes are needed
44        needed: usize,
45    },
46
47    /// Not enough bytes to decode
48    InsufficientBytes,
49
50    /// Instruction exceeds maximum length (15 bytes)
51    InstructionTooLong,
52
53    /// Invalid instruction encoding
54    InvalidEncoding,
55
56    /// Buffer too small
57    BufferTooSmall,
58
59    /// Invalid operand
60    InvalidOperand,
61
62    /// Feature not implemented yet
63    NotYetImplemented(&'static str),
64
65    /// Undefined or reserved instruction
66    UndefinedInstruction {
67        /// The opcode byte that caused the error
68        opcode: u8,
69        /// Optional description of why it's undefined
70        reason: UndefinedReason,
71    },
72
73    /// Invalid prefix combination
74    InvalidPrefixCombination {
75        /// The conflicting prefixes
76        prefixes: &'static str,
77    },
78
79    /// EVEX encoding error (AVX-512 specific)
80    EvexEncodingError {
81        /// Specific EVEX error type
82        kind: EvexErrorKind,
83    },
84
85    /// Instruction not supported in current mode
86    ModeNotSupported {
87        /// The machine mode
88        mode: &'static str,
89        /// The instruction or feature
90        feature: &'static str,
91    },
92}
93
94/// Reasons why an instruction is undefined
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum UndefinedReason {
97    /// Opcode is reserved for future use
98    Reserved,
99    /// Opcode was never defined
100    NeverDefined,
101    /// Opcode was valid on older CPUs but removed
102    Removed,
103    /// Invalid in current decoding mode
104    ModeInvalid,
105    /// Invalid prefix for this instruction
106    InvalidPrefix,
107}
108
109/// EVEX-specific error kinds for AVX-512
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum EvexErrorKind {
112    /// Invalid mask register (must be k0-k7)
113    InvalidMaskRegister,
114    /// Zeroing mode requires non-zero mask
115    ZeroingWithoutMask,
116    /// Invalid rounding mode encoding
117    InvalidRoundingMode,
118    /// SAE not supported for this instruction
119    SaeNotSupported,
120    /// Broadcast not valid for this operand type
121    InvalidBroadcast,
122    /// Vector length not supported for this instruction
123    InvalidVectorLength,
124    /// Embedded rounding requires register operand
125    EmbeddedRoundingRequiresReg,
126}
127
128impl fmt::Display for Error {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        match self {
131            Error::InvalidMachineMode => write!(f, "invalid machine mode"),
132            Error::InvalidStackWidth => write!(f, "invalid stack width"),
133            Error::DecodeFailed(e) => write!(f, "decode failed: {}", e),
134            Error::EncodeFailed(e) => write!(f, "encode failed: {}", e),
135            Error::IncompleteInstruction { needed } => {
136                write!(f, "incomplete instruction, need {} more bytes", needed)
137            }
138            Error::InsufficientBytes => write!(f, "insufficient bytes to decode instruction"),
139            Error::InstructionTooLong => {
140                write!(f, "instruction exceeds maximum length of 15 bytes")
141            }
142            Error::InvalidEncoding => write!(f, "invalid instruction encoding"),
143            Error::BufferTooSmall => write!(f, "buffer too small"),
144            Error::InvalidOperand => write!(f, "invalid operand"),
145            Error::NotYetImplemented(msg) => write!(f, "not yet implemented: {}", msg),
146            Error::UndefinedInstruction { opcode, reason } => {
147                let reason_str = match reason {
148                    UndefinedReason::Reserved => "reserved opcode",
149                    UndefinedReason::NeverDefined => "undefined opcode",
150                    UndefinedReason::Removed => "removed opcode",
151                    UndefinedReason::ModeInvalid => "invalid in current mode",
152                    UndefinedReason::InvalidPrefix => "invalid prefix combination",
153                };
154                write!(
155                    f,
156                    "undefined instruction: opcode 0x{:02X} ({})",
157                    opcode, reason_str
158                )
159            }
160            Error::InvalidPrefixCombination { prefixes } => {
161                write!(f, "invalid prefix combination: {}", prefixes)
162            }
163            Error::EvexEncodingError { kind } => {
164                let kind_str = match kind {
165                    EvexErrorKind::InvalidMaskRegister => "invalid mask register (must be k0-k7)",
166                    EvexErrorKind::ZeroingWithoutMask => "zeroing mode requires non-zero mask",
167                    EvexErrorKind::InvalidRoundingMode => "invalid rounding mode encoding",
168                    EvexErrorKind::SaeNotSupported => "SAE not supported for this instruction",
169                    EvexErrorKind::InvalidBroadcast => "broadcast not valid for this operand",
170                    EvexErrorKind::InvalidVectorLength => "vector length not supported",
171                    EvexErrorKind::EmbeddedRoundingRequiresReg => {
172                        "embedded rounding requires register operand"
173                    }
174                };
175                write!(f, "EVEX encoding error: {}", kind_str)
176            }
177            Error::ModeNotSupported { mode, feature } => {
178                write!(f, "{} not supported in {} mode", feature, mode)
179            }
180        }
181    }
182}
183
184#[cfg(feature = "std")]
185impl std::error::Error for Error {}
186
187/// Specific decode errors
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub enum DecodeError {
190    /// No more data to decode
191    NoMoreData,
192
193    /// Invalid opcode
194    InvalidOpcode,
195
196    /// Invalid ModRM byte
197    InvalidModRM,
198
199    /// Invalid SIB byte
200    InvalidSIB,
201
202    /// Invalid displacement
203    InvalidDisplacement,
204
205    /// Invalid immediate value
206    InvalidImmediate,
207
208    /// Invalid prefix combination
209    InvalidPrefix,
210
211    /// Internal error (should not happen)
212    InternalError,
213
214    /// Undefined opcode (valid encoding but undefined instruction)
215    UndefinedOpcode,
216
217    /// Reserved opcode (reserved for future use)
218    ReservedOpcode,
219
220    /// VEX prefix error
221    VexError,
222
223    /// EVEX prefix error (AVX-512)
224    EvexError,
225
226    /// XOP prefix error
227    XopError,
228
229    /// 3DNow! instruction error
230    ThreeDNowError,
231
232    /// Lock prefix used with non-lockable instruction
233    InvalidLockPrefix,
234
235    /// REP/REPE prefix used incorrectly
236    InvalidRepPrefix,
237
238    /// REX prefix in 16/32-bit mode
239    RexInLegacyMode,
240
241    /// Instruction too long (exceeds 15 bytes)
242    TooLong,
243
244    /// Invalid register encoding
245    InvalidRegister,
246
247    /// Missing mandatory ModRM byte
248    MissingModRM,
249
250    /// Missing mandatory SIB byte
251    MissingSIB,
252}
253
254impl fmt::Display for DecodeError {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        match self {
257            DecodeError::NoMoreData => write!(f, "no more data to decode"),
258            DecodeError::InvalidOpcode => write!(f, "invalid opcode"),
259            DecodeError::InvalidModRM => write!(f, "invalid ModRM byte"),
260            DecodeError::InvalidSIB => write!(f, "invalid SIB byte"),
261            DecodeError::InvalidDisplacement => write!(f, "invalid displacement"),
262            DecodeError::InvalidImmediate => write!(f, "invalid immediate value"),
263            DecodeError::InvalidPrefix => write!(f, "invalid prefix combination"),
264            DecodeError::InternalError => write!(f, "internal decoder error"),
265            DecodeError::UndefinedOpcode => write!(f, "undefined opcode"),
266            DecodeError::ReservedOpcode => write!(f, "reserved opcode"),
267            DecodeError::VexError => write!(f, "VEX prefix error"),
268            DecodeError::EvexError => write!(f, "EVEX prefix error"),
269            DecodeError::XopError => write!(f, "XOP prefix error"),
270            DecodeError::ThreeDNowError => write!(f, "3DNow! instruction error"),
271            DecodeError::InvalidLockPrefix => write!(f, "invalid LOCK prefix"),
272            DecodeError::InvalidRepPrefix => write!(f, "invalid REP/REPE prefix"),
273            DecodeError::RexInLegacyMode => write!(f, "REX prefix in legacy mode"),
274            DecodeError::TooLong => write!(f, "instruction exceeds 15 bytes"),
275            DecodeError::InvalidRegister => write!(f, "invalid register encoding"),
276            DecodeError::MissingModRM => write!(f, "missing mandatory ModRM byte"),
277            DecodeError::MissingSIB => write!(f, "missing mandatory SIB byte"),
278        }
279    }
280}
281
282#[cfg(feature = "std")]
283impl std::error::Error for DecodeError {}
284
285/// Specific encode errors
286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
287pub enum EncodeError {
288    /// Invalid instruction for encoding
289    InvalidInstruction,
290
291    /// Invalid mnemonic
292    InvalidMnemonic,
293
294    /// Invalid operand combination
295    InvalidOperandCombination,
296
297    /// Unsupported instruction in current mode
298    UnsupportedInMode,
299
300    /// Register encoding error
301    RegisterError,
302
303    /// Immediate value out of range
304    ImmediateOutOfRange,
305
306    /// Displacement out of range
307    DisplacementOutOfRange,
308
309    /// Internal error (should not happen)
310    InternalError,
311
312    /// AVX-512 mask register error
313    MaskRegisterError,
314
315    /// AVX-512 zeroing mode error
316    ZeroingModeError,
317
318    /// AVX-512 rounding mode error
319    RoundingModeError,
320
321    /// AVX-512 SAE error
322    SaeError,
323
324    /// AVX-512 broadcast error
325    BroadcastError,
326
327    /// VEX encoding not possible (need EVEX)
328    VexNotPossible,
329
330    /// EVEX encoding required
331    EvexRequired,
332
333    /// Memory operand required but register provided
334    MemoryOperandRequired,
335
336    /// Register operand required but memory provided
337    RegisterOperandRequired,
338
339    /// Invalid scale factor (must be 1, 2, 4, or 8)
340    InvalidScaleFactor,
341
342    /// RSP cannot be used as index register
343    RspAsIndexRegister,
344
345    /// RBP/R13 as base requires displacement
346    BaseRequiresDisplacement,
347
348    /// Instruction not encodable
349    NotEncodable,
350}
351
352impl fmt::Display for EncodeError {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        match self {
355            EncodeError::InvalidInstruction => write!(f, "invalid instruction for encoding"),
356            EncodeError::InvalidMnemonic => write!(f, "invalid mnemonic"),
357            EncodeError::InvalidOperandCombination => write!(f, "invalid operand combination"),
358            EncodeError::UnsupportedInMode => {
359                write!(f, "unsupported instruction in current machine mode")
360            }
361            EncodeError::RegisterError => write!(f, "register encoding error"),
362            EncodeError::ImmediateOutOfRange => write!(f, "immediate value out of range"),
363            EncodeError::DisplacementOutOfRange => write!(f, "displacement out of range"),
364            EncodeError::InternalError => write!(f, "internal encoder error"),
365            EncodeError::MaskRegisterError => write!(f, "AVX-512 mask register error"),
366            EncodeError::ZeroingModeError => write!(f, "AVX-512 zeroing mode error"),
367            EncodeError::RoundingModeError => write!(f, "AVX-512 rounding mode error"),
368            EncodeError::SaeError => write!(f, "AVX-512 SAE error"),
369            EncodeError::BroadcastError => write!(f, "AVX-512 broadcast error"),
370            EncodeError::VexNotPossible => write!(f, "VEX encoding not possible (EVEX required)"),
371            EncodeError::EvexRequired => write!(f, "EVEX encoding required"),
372            EncodeError::MemoryOperandRequired => write!(f, "memory operand required"),
373            EncodeError::RegisterOperandRequired => write!(f, "register operand required"),
374            EncodeError::InvalidScaleFactor => {
375                write!(f, "invalid scale factor (must be 1, 2, 4, or 8)")
376            }
377            EncodeError::RspAsIndexRegister => write!(f, "RSP cannot be used as index register"),
378            EncodeError::BaseRequiresDisplacement => {
379                write!(f, "RBP/R13 as base requires displacement")
380            }
381            EncodeError::NotEncodable => write!(f, "instruction not encodable"),
382        }
383    }
384}
385
386#[cfg(feature = "std")]
387impl std::error::Error for EncodeError {}