Skip to main content

dll_syringe/
error.rs

1use std::{
2    fmt::{self, Display},
3    io,
4};
5
6use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError};
7use thiserror::Error;
8use winapi::um::{
9    minwinbase::{
10        EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT,
11        EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND,
12        EXCEPTION_FLT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT,
13        EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK,
14        EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, EXCEPTION_ILLEGAL_INSTRUCTION,
15        EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_INVALID_DISPOSITION,
16        EXCEPTION_INVALID_HANDLE, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION,
17        EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, EXCEPTION_STACK_OVERFLOW,
18    },
19    winnt::STATUS_UNWIND_CONSOLIDATE,
20};
21
22#[cfg(feature = "syringe")]
23use winapi::shared::winerror::ERROR_PARTIAL_COPY;
24
25#[derive(Debug, Error)]
26/// Error enum representing either a windows api error or a nul error from an invalid interior nul.
27pub enum IoOrNulError {
28    /// Variant representing an illegal interior nul value.
29    #[error("interior nul found")]
30    Nul(#[from] widestring::error::ContainsNul<u16>),
31    /// Variant representing an windows api error.
32    #[error("io error: {}", _0)]
33    Io(#[from] io::Error),
34}
35
36/// Error enum for errors during a call to [`ProcessModule::get_local_procedure_address`].
37///
38/// [`ProcessModule::get_local_procedure_address`]: crate::process::ProcessModule::get_local_procedure_address
39#[derive(Debug, Error)]
40pub enum GetLocalProcedureAddressError {
41    /// Variant representing an illegal interior nul value.
42    #[error("interior nul found")]
43    Nul(#[from] std::ffi::NulError),
44    /// Variant representing an windows api error.
45    #[error("io error: {}", _0)]
46    Io(#[from] io::Error),
47    /// Variant representing an unsupported target process.
48    #[error("unsupported remote target process")]
49    UnsupportedRemoteTarget,
50}
51
52#[derive(
53    Debug, TryFromPrimitive, IntoPrimitive, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash,
54)]
55#[repr(u32)]
56/// Codes for unhandled windows exceptions from [msdn](https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode).
57pub enum ExceptionCode {
58    /// The thread attempts to read from or write to a virtual address for which it does not have access.
59    AccessViolation = EXCEPTION_ACCESS_VIOLATION,
60    /// The thread attempts to access an array element that is out of bounds, and the underlying hardware supports bounds checking.
61    ArrayBoundsExceeded = EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
62    /// A breakpoint is encountered.
63    Breakpoint = EXCEPTION_BREAKPOINT,
64    /// The thread attempts to read or write data that is misaligned on hardware that does not provide alignment.
65    /// For example, 16-bit values must be aligned on 2-byte boundaries, 32-bit values on 4-byte boundaries, and so on.
66    DatatypeMisalignment = EXCEPTION_DATATYPE_MISALIGNMENT,
67    /// One of the operands in a floating point operation is denormal.
68    /// A denormal value is one that is too small to represent as a standard floating point value.
69    FltDenormalOperand = EXCEPTION_FLT_DENORMAL_OPERAND,
70    /// The thread attempts to divide a floating point value by a floating point divisor of 0 (zero).
71    FltDivideByZero = EXCEPTION_FLT_DIVIDE_BY_ZERO,
72    /// The result of a floating point operation cannot be represented exactly as a decimal fraction.
73    FltInexactResult = EXCEPTION_FLT_INEXACT_RESULT,
74    /// A floating point exception that is not included in this list.
75    FltInvalidOperation = EXCEPTION_FLT_INVALID_OPERATION,
76    /// The exponent of a floating point operation is greater than the magnitude allowed by the corresponding type.
77    FltOverflow = EXCEPTION_FLT_OVERFLOW,
78    /// The stack has overflowed or underflowed, because of a floating point operation.
79    FltStackCheck = EXCEPTION_FLT_STACK_CHECK,
80    /// The exponent of a floating point operation is less than the magnitude allowed by the corresponding type.
81    FltUnderflow = EXCEPTION_FLT_UNDERFLOW,
82    /// The thread accessed memory allocated with the PAGE_GUARD modifier.
83    GuardPage = EXCEPTION_GUARD_PAGE,
84    /// The thread tries to execute an invalid instruction.
85    IllegalInstruction = EXCEPTION_ILLEGAL_INSTRUCTION,
86    /// The thread tries to access a page that is not present, and the system is unable to load the page.
87    /// For example, this exception might occur if a network connection is lost while running a program over a network.
88    InPageError = EXCEPTION_IN_PAGE_ERROR,
89    /// The thread attempts to divide an integer value by an integer divisor of 0 (zero).
90    IntegerDivideByZero = EXCEPTION_INT_DIVIDE_BY_ZERO,
91    /// The result of an integer operation creates a value that is too large to be held by the destination register.
92    /// In some cases, this will result in a carry out of the most significant bit of the result.
93    /// Some operations do not set the carry flag.
94    IntegerOverflow = EXCEPTION_INT_OVERFLOW,
95    /// An exception handler returns an invalid disposition to the exception dispatcher.
96    /// Programmers using a high-level language such as C should never encounter this exception.
97    InvalidDisposition = EXCEPTION_INVALID_DISPOSITION,
98    /// The thread used a handle to a kernel object that was invalid (probably because it had been closed.)
99    InvalidHandle = EXCEPTION_INVALID_HANDLE,
100    /// The thread attempts to continue execution after a non-continuable exception occurs.
101    NoncontinuableException = EXCEPTION_NONCONTINUABLE_EXCEPTION,
102    /// The thread attempts to execute an instruction with an operation that is not allowed in the current computer mode.
103    PrivilegedInstruction = EXCEPTION_PRIV_INSTRUCTION,
104    /// A trace trap or other single instruction mechanism signals that one instruction is executed.
105    SingleStep = EXCEPTION_SINGLE_STEP,
106    /// The thread uses up its stack.
107    StackOverflow = EXCEPTION_STACK_OVERFLOW,
108    /// A frame consolidation has been executed.
109    UnwindConsolidate = STATUS_UNWIND_CONSOLIDATE,
110}
111
112impl ExceptionCode {
113    /// Try to interpret the given code as a windows exception code.
114    pub fn try_from_code(code: u32) -> Result<Self, TryFromPrimitiveError<Self>> {
115        Self::try_from_primitive(code)
116    }
117    /// Returns the underlying windows exception code.
118    #[must_use]
119    pub fn code(self) -> u32 {
120        self.into()
121    }
122}
123
124impl Display for ExceptionCode {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        // These error messages were collected using https://stackoverflow.com/a/43961146/6304917 and https://stackoverflow.com/a/7915329/6304917
127        // They are hardcoded as they are unlikely appear very often and would require a lot of extra code
128        // Additionally, the messages returned from the methods above are sometimes unusable and inconsitently formatted.
129
130        match *self {
131            Self::AccessViolation => write!(f, "Invalid access to memory location."),
132            Self::ArrayBoundsExceeded => write!(f, "Array bounds exceeded."),
133            Self::Breakpoint => write!(f, "A breakpoint has been reached."),
134            Self::DatatypeMisalignment => write!(f, "A datatype misalignment was detected in a load or store instruction."),
135            Self::FltDenormalOperand => write!(f, "Floating-point denormal operand."),
136            Self::FltDivideByZero => write!(f, "Floating-point division by zero."),
137            Self::FltInexactResult => write!(f, "Floating-point inexact result."),
138            Self::FltInvalidOperation => write!(f, "Floating-point invalid operation."),
139            Self::FltOverflow => write!(f, "Floating-point overflow."),
140            Self::FltStackCheck => write!(f, "Floating-point stack check."),
141            Self::FltUnderflow => write!(f, "Floating-point underflow."),
142            Self::GuardPage => write!(f, "A page of memory that marks the end of a data structure, such as a stack or an array, has been accessed."),
143            Self::IllegalInstruction => write!(f, "An attempt was made to execute an illegal instruction."),
144            Self::InPageError => write!(f, "Error performing inpage operation."),
145            Self::IntegerDivideByZero => write!(f, "Integer division by zero."),
146            Self::IntegerOverflow => write!(f, "Integer overflow."),
147            Self::InvalidDisposition => write!(f, "An invalid exception disposition was returned by an exception handler."),
148            Self::InvalidHandle => write!(f, "The handle is invalid."),
149            Self::NoncontinuableException => write!(f, "Windows cannot continue from this exception."),
150            Self::PrivilegedInstruction => write!(f, "Privileged instruction."),
151            Self::SingleStep => write!(f, "A single step or trace operation has just been completed."),
152            Self::StackOverflow => write!(f, "Recursion too deep; the stack overflowed."),
153            Self::UnwindConsolidate => write!(f, "A frame consolidation has been executed."),
154        }
155    }
156}
157
158#[derive(Debug, Error)]
159/// An error representing either an unhandled exception or an io error.
160pub enum ExceptionOrIoError {
161    /// Variant representing an io error.
162    #[error("remote io error: {}", _0)]
163    Io(io::Error),
164    /// Variant representing an unhandled exception.
165    #[error("remote exception: {}", _0)]
166    Exception(ExceptionCode),
167}
168
169/// Error enum for errors during [`Syringe::load_inject_help_data_for_process`](crate::Syringe::load_inject_help_data_for_process).
170#[derive(Debug, Error)]
171#[cfg(feature = "syringe")]
172#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "syringe")))]
173pub(crate) enum LoadInjectHelpDataError {
174    /// Variant representing an io error.
175    #[error("io error: {}", _0)]
176    Io(io::Error),
177    /// Variant representing an unsupported target process.
178    #[error("unsupported target process")]
179    UnsupportedTarget,
180    /// Variant representing an inaccessible target process.
181    /// This can occur if it crashed or was terminated.
182    #[error("inaccessible target process")]
183    ProcessInaccessible,
184    /// Variant representing an error while loading an pe file.
185    #[cfg(target_arch = "x86_64")]
186    #[cfg(feature = "into-x86-from-x64")]
187    #[error("failed to load pe file: {}", _0)]
188    Goblin(#[from] goblin::error::Error),
189}
190
191#[cfg(feature = "syringe")]
192impl From<io::Error> for LoadInjectHelpDataError {
193    fn from(err: io::Error) -> Self {
194        if err.raw_os_error() == Some(ERROR_PARTIAL_COPY as _)
195            || err.kind() == io::ErrorKind::PermissionDenied
196        {
197            Self::ProcessInaccessible
198        } else {
199            Self::Io(err)
200        }
201    }
202}
203
204/// Error enum for errors during [`Syringe::inject`](crate::Syringe::inject).
205#[derive(Debug, Error)]
206#[cfg(feature = "syringe")]
207#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "syringe")))]
208pub enum InjectError {
209    /// Variant representing an illegal interior nul value in the module path.
210    #[error("module path contains illegal interior nul")]
211    IllegalPath(#[from] widestring::error::ContainsNul<u16>),
212    /// Variant representing an io error.
213    #[error("io error: {}", _0)]
214    Io(io::Error),
215    /// Variant representing an unsupported target process.
216    #[error("unsupported target process")]
217    UnsupportedTarget,
218    /// Variant representing an io error inside the target process.
219    #[error("remote io error: {}", _0)]
220    RemoteIo(io::Error),
221    /// Variant representing an unhandled exception inside the target process.
222    #[error("remote exception: {}", _0)]
223    RemoteException(ExceptionCode),
224    /// Variant representing an inaccessible target process.
225    /// This can occur if it crashed or was terminated.
226    #[error("inaccessible target process")]
227    ProcessInaccessible,
228    /// Variant representing an incompatible payload module compiled for a different target than the target process.
229    #[error("mismatch between target and payload architecture")]
230    ArchitectureMismatch,
231    /// Variant representing an error while loading an pe file.
232    #[cfg(target_arch = "x86_64")]
233    #[cfg(feature = "into-x86-from-x64")]
234    #[error("failed to load pe file: {}", _0)]
235    Goblin(#[from] goblin::error::Error),
236}
237
238#[cfg(feature = "syringe")]
239impl From<io::Error> for InjectError {
240    fn from(err: io::Error) -> Self {
241        if err.raw_os_error() == Some(ERROR_PARTIAL_COPY as _)
242            || err.kind() == io::ErrorKind::PermissionDenied
243        {
244            Self::ProcessInaccessible
245        } else {
246            Self::Io(err)
247        }
248    }
249}
250
251#[cfg(feature = "syringe")]
252impl From<ExceptionCode> for InjectError {
253    fn from(err: ExceptionCode) -> Self {
254        Self::RemoteException(err)
255    }
256}
257
258#[cfg(feature = "syringe")]
259impl From<IoOrNulError> for InjectError {
260    fn from(err: IoOrNulError) -> Self {
261        match err {
262            IoOrNulError::Nul(e) => e.into(),
263            IoOrNulError::Io(e) => e.into(),
264        }
265    }
266}
267
268#[cfg(feature = "syringe")]
269impl From<ExceptionOrIoError> for InjectError {
270    fn from(err: ExceptionOrIoError) -> Self {
271        match err {
272            ExceptionOrIoError::Io(e) => Self::RemoteIo(e),
273            ExceptionOrIoError::Exception(e) => Self::RemoteException(e),
274        }
275    }
276}
277
278#[cfg(feature = "syringe")]
279impl From<LoadInjectHelpDataError> for InjectError {
280    fn from(err: LoadInjectHelpDataError) -> Self {
281        match err {
282            LoadInjectHelpDataError::Io(e) => Self::Io(e),
283            LoadInjectHelpDataError::UnsupportedTarget => Self::UnsupportedTarget,
284            LoadInjectHelpDataError::ProcessInaccessible => Self::ProcessInaccessible,
285            #[cfg(target_arch = "x86_64")]
286            #[cfg(feature = "into-x86-from-x64")]
287            LoadInjectHelpDataError::Goblin(e) => Self::Goblin(e),
288        }
289    }
290}
291
292/// Error enum for errors during [`Syringe::eject`](crate::Syringe::eject).
293#[derive(Debug, Error)]
294#[cfg(feature = "syringe")]
295#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "syringe")))]
296pub enum EjectError {
297    /// Variant representing an io error.
298    #[error("io error: {}", _0)]
299    Io(io::Error),
300    /// Variant representing an unsupported target process.
301    #[error("unsupported target process")]
302    UnsupportedTarget,
303    /// Variant representing an io error inside the target process.
304    #[error("remote io error: {}", _0)]
305    RemoteIo(io::Error),
306    /// Variant representing an unhandled exception inside the target process.
307    #[error("remote exception: {}", _0)]
308    RemoteException(ExceptionCode),
309    /// Variant representing an inaccessible target process.
310    /// This can occur if it crashed or was terminated.
311    #[error("inaccessible target process")]
312    ProcessInaccessible,
313    /// Variant representing an inaccessible target module.
314    /// This can occur if the target module was ejected or unloaded.
315    #[error("inaccessible target module")]
316    ModuleInaccessible,
317    /// Variant representing an error while loading an pe file.
318    #[cfg(target_arch = "x86_64")]
319    #[cfg(feature = "into-x86-from-x64")]
320    #[error("failed to load pe file: {}", _0)]
321    Goblin(#[from] goblin::error::Error),
322}
323
324#[cfg(feature = "syringe")]
325impl From<LoadInjectHelpDataError> for EjectError {
326    fn from(err: LoadInjectHelpDataError) -> Self {
327        match err {
328            LoadInjectHelpDataError::Io(e) => Self::Io(e),
329            LoadInjectHelpDataError::UnsupportedTarget => Self::UnsupportedTarget,
330            LoadInjectHelpDataError::ProcessInaccessible => Self::ProcessInaccessible,
331            #[cfg(target_arch = "x86_64")]
332            #[cfg(feature = "into-x86-from-x64")]
333            LoadInjectHelpDataError::Goblin(e) => Self::Goblin(e),
334        }
335    }
336}
337
338#[cfg(feature = "syringe")]
339impl From<io::Error> for EjectError {
340    fn from(err: io::Error) -> Self {
341        if err.raw_os_error() == Some(ERROR_PARTIAL_COPY as _)
342            || err.kind() == io::ErrorKind::PermissionDenied
343        {
344            Self::ProcessInaccessible
345        } else {
346            Self::Io(err)
347        }
348    }
349}
350
351#[cfg(feature = "syringe")]
352impl From<ExceptionCode> for EjectError {
353    fn from(err: ExceptionCode) -> Self {
354        Self::RemoteException(err)
355    }
356}
357
358#[cfg(feature = "syringe")]
359impl From<ExceptionOrIoError> for EjectError {
360    fn from(err: ExceptionOrIoError) -> Self {
361        match err {
362            ExceptionOrIoError::Io(e) => Self::RemoteIo(e),
363            ExceptionOrIoError::Exception(e) => Self::RemoteException(e),
364        }
365    }
366}
367
368/// Error enum for errors during procedure loading.
369#[derive(Debug, Error)]
370#[cfg(feature = "syringe")]
371#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "syringe")))]
372pub enum LoadProcedureError {
373    /// Variant representing an io error.
374    #[error("io error: {}", _0)]
375    Io(io::Error),
376    /// Variant representing an unsupported target process.
377    #[error("unsupported target process")]
378    UnsupportedTarget,
379    /// Variant representing an io error inside the target process.
380    #[error("remote io error: {}", _0)]
381    RemoteIo(io::Error),
382    /// Variant representing an unhandled exception inside the target process.
383    #[error("remote exception: {}", _0)]
384    RemoteException(ExceptionCode),
385    /// Variant representing an inaccessible target process.
386    /// This can occur if it crashed or was terminated.
387    #[error("inaccessible target process")]
388    ProcessInaccessible,
389    /// Variant representing an inaccessible target module.
390    /// This can occur if the target module was ejected or unloaded.
391    #[error("inaccessible target module")]
392    ModuleInaccessible,
393    /// Variant representing an error while loading an pe file.
394    #[cfg(target_arch = "x86_64")]
395    #[cfg(feature = "into-x86-from-x64")]
396    #[error("failed to load pe file: {}", _0)]
397    Goblin(#[from] goblin::error::Error),
398}
399
400#[cfg(feature = "syringe")]
401impl From<LoadInjectHelpDataError> for LoadProcedureError {
402    fn from(err: LoadInjectHelpDataError) -> Self {
403        match err {
404            LoadInjectHelpDataError::Io(e) => Self::Io(e),
405            LoadInjectHelpDataError::UnsupportedTarget => Self::UnsupportedTarget,
406            LoadInjectHelpDataError::ProcessInaccessible => Self::ProcessInaccessible,
407            #[cfg(target_arch = "x86_64")]
408            #[cfg(feature = "into-x86-from-x64")]
409            LoadInjectHelpDataError::Goblin(e) => Self::Goblin(e),
410        }
411    }
412}
413
414#[cfg(feature = "syringe")]
415impl From<io::Error> for LoadProcedureError {
416    fn from(err: io::Error) -> Self {
417        if err.raw_os_error() == Some(ERROR_PARTIAL_COPY as _)
418            || err.kind() == io::ErrorKind::PermissionDenied
419        {
420            Self::ProcessInaccessible
421        } else {
422            Self::Io(err)
423        }
424    }
425}
426
427#[cfg(feature = "syringe")]
428impl From<ExceptionCode> for LoadProcedureError {
429    fn from(err: ExceptionCode) -> Self {
430        Self::RemoteException(err)
431    }
432}
433
434#[cfg(feature = "syringe")]
435impl From<ExceptionOrIoError> for LoadProcedureError {
436    fn from(err: ExceptionOrIoError) -> Self {
437        match err {
438            ExceptionOrIoError::Io(e) => Self::RemoteIo(e),
439            ExceptionOrIoError::Exception(e) => Self::RemoteException(e),
440        }
441    }
442}
443
444/// Error enum encompassing all errors during [`Syringe`](crate::Syringe) operations.
445#[derive(Debug, Error)]
446#[cfg(feature = "syringe")]
447#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "syringe")))]
448pub enum SyringeError {
449    /// Variant representing an illegal interior nul value in the module path.
450    #[error("module path contains illegal interior nul")]
451    IllegalPath(#[from] widestring::error::ContainsNul<u16>),
452    /// Variant representing an io error.
453    #[error("io error: {}", _0)]
454    Io(io::Error),
455    /// Variant representing an unsupported target process.
456    #[error("unsupported target process")]
457    UnsupportedTarget,
458    /// Variant representing an io error inside the target process.
459    #[error("remote io error: {}", _0)]
460    RemoteIo(io::Error),
461    /// Variant representing an unhandled exception inside the target process.
462    #[error("remote exception: {}", _0)]
463    RemoteException(ExceptionCode),
464    /// Variant representing an inaccessible target process.
465    /// This can occur if it crashed or was terminated.
466    #[error("inaccessible target process")]
467    ProcessInaccessible,
468    /// Variant representing an incompatible payload module compiled for a different target than the target process.
469    #[error("mismatch between target and payload architecture")]
470    ArchitectureMismatch,
471    /// Variant representing an inaccessible target module.
472    /// This can occur if the target module was ejected or unloaded.
473    #[error("inaccessible target module")]
474    ModuleInaccessible,
475    /// Variant representing an error while serializing or deserializing.
476    #[cfg(feature = "rpc-payload")]
477    #[error("serde error: {}", _0)]
478    Serde(crate::rpc::SerdeError),
479    /// Variant representing an error or panic inside a remote payload procedure.
480    #[cfg(feature = "rpc-payload")]
481    #[error("remote payload error: {}", _0)]
482    RemotePayloadProcedure(String),
483    /// Variant representing an error while loading an pe file.
484    #[cfg(target_arch = "x86_64")]
485    #[cfg(feature = "into-x86-from-x64")]
486    #[error("failed to load pe file: {}", _0)]
487    Goblin(#[from] goblin::error::Error),
488}
489
490#[cfg(feature = "syringe")]
491impl From<io::Error> for SyringeError {
492    fn from(err: io::Error) -> Self {
493        if err.raw_os_error() == Some(ERROR_PARTIAL_COPY as _)
494            || err.kind() == io::ErrorKind::PermissionDenied
495        {
496            Self::ProcessInaccessible
497        } else {
498            Self::Io(err)
499        }
500    }
501}
502
503#[cfg(feature = "syringe")]
504impl From<ExceptionCode> for SyringeError {
505    fn from(err: ExceptionCode) -> Self {
506        Self::RemoteException(err)
507    }
508}
509
510#[cfg(feature = "syringe")]
511impl From<IoOrNulError> for SyringeError {
512    fn from(err: IoOrNulError) -> Self {
513        match err {
514            IoOrNulError::Nul(e) => e.into(),
515            IoOrNulError::Io(e) => e.into(),
516        }
517    }
518}
519
520#[cfg(feature = "syringe")]
521impl From<ExceptionOrIoError> for SyringeError {
522    fn from(err: ExceptionOrIoError) -> Self {
523        match err {
524            ExceptionOrIoError::Io(e) => Self::RemoteIo(e),
525            ExceptionOrIoError::Exception(e) => Self::RemoteException(e),
526        }
527    }
528}
529
530#[cfg(feature = "syringe")]
531impl From<InjectError> for SyringeError {
532    fn from(err: InjectError) -> Self {
533        match err {
534            InjectError::IllegalPath(e) => Self::IllegalPath(e),
535            InjectError::Io(e) => Self::Io(e),
536            InjectError::UnsupportedTarget => Self::UnsupportedTarget,
537            InjectError::RemoteIo(e) => Self::RemoteIo(e),
538            InjectError::RemoteException(e) => Self::RemoteException(e),
539            InjectError::ProcessInaccessible => Self::ProcessInaccessible,
540            InjectError::ArchitectureMismatch => Self::ArchitectureMismatch,
541            #[cfg(target_arch = "x86_64")]
542            #[cfg(feature = "into-x86-from-x64")]
543            InjectError::Goblin(e) => Self::Goblin(e),
544        }
545    }
546}
547
548#[cfg(feature = "syringe")]
549impl From<EjectError> for SyringeError {
550    fn from(err: EjectError) -> Self {
551        match err {
552            EjectError::Io(e) => Self::Io(e),
553            EjectError::UnsupportedTarget => Self::UnsupportedTarget,
554            EjectError::RemoteIo(e) => Self::RemoteIo(e),
555            EjectError::RemoteException(e) => Self::RemoteException(e),
556            EjectError::ProcessInaccessible => Self::ProcessInaccessible,
557            EjectError::ModuleInaccessible => Self::ModuleInaccessible,
558            #[cfg(target_arch = "x86_64")]
559            #[cfg(feature = "into-x86-from-x64")]
560            EjectError::Goblin(e) => Self::Goblin(e),
561        }
562    }
563}
564
565#[cfg(feature = "rpc-core")]
566impl From<LoadProcedureError> for SyringeError {
567    fn from(err: LoadProcedureError) -> Self {
568        match err {
569            LoadProcedureError::Io(e) => Self::Io(e),
570            LoadProcedureError::UnsupportedTarget => Self::UnsupportedTarget,
571            LoadProcedureError::RemoteIo(e) => Self::RemoteIo(e),
572            LoadProcedureError::RemoteException(e) => Self::RemoteException(e),
573            LoadProcedureError::ProcessInaccessible => Self::ProcessInaccessible,
574            LoadProcedureError::ModuleInaccessible => Self::ModuleInaccessible,
575            #[cfg(target_arch = "x86_64")]
576            #[cfg(feature = "into-x86-from-x64")]
577            LoadProcedureError::Goblin(e) => Self::Goblin(e),
578        }
579    }
580}
581
582#[cfg(feature = "rpc-core")]
583#[cfg_attr(all(feature = "rpc-core", not(feature = "rpc-raw")), doc(hidden))]
584impl From<crate::rpc::RawRpcError> for SyringeError {
585    fn from(err: crate::rpc::RawRpcError) -> Self {
586        match err {
587            crate::rpc::RawRpcError::Io(err) => Self::Io(err),
588            crate::rpc::RawRpcError::RemoteException(code) => Self::RemoteException(code),
589            crate::rpc::RawRpcError::ProcessInaccessible => Self::ProcessInaccessible,
590            crate::rpc::RawRpcError::ModuleInaccessible => Self::ModuleInaccessible,
591        }
592    }
593}
594
595#[cfg(feature = "rpc-payload")]
596#[cfg_attr(all(feature = "rpc-core", not(feature = "rpc-raw")), doc(hidden))]
597impl From<crate::rpc::PayloadRpcError> for SyringeError {
598    fn from(err: crate::rpc::PayloadRpcError) -> Self {
599        match err {
600            crate::rpc::PayloadRpcError::Io(e) => Self::Io(e),
601            crate::rpc::PayloadRpcError::RemoteException(e) => Self::RemoteException(e),
602            crate::rpc::PayloadRpcError::ProcessInaccessible => Self::ProcessInaccessible,
603            crate::rpc::PayloadRpcError::ModuleInaccessible => Self::ModuleInaccessible,
604            crate::rpc::PayloadRpcError::RemoteProcedure(e) => Self::RemotePayloadProcedure(e),
605            crate::rpc::PayloadRpcError::Serde(e) => Self::Serde(e),
606        }
607    }
608}
609
610/// Error enum encompassing all errors during syringe operations in a nested format.
611#[derive(Debug, Error)]
612#[cfg(feature = "syringe")]
613#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "syringe")))]
614pub enum SyringeOperationError {
615    /// Variant representing an error while injecting a module.
616    #[error("inject error: {}", _0)]
617    Inject(#[from] InjectError),
618    /// Variant representing an error while ejecting a module.
619    #[error("eject error: {}", _0)]
620    Eject(#[from] EjectError),
621    /// Variant representing an error while using payload rpc.
622    #[cfg(feature = "rpc-payload")]
623    #[error("payload rpc error: {}", _0)]
624    PayloadProcedureCall(#[from] crate::rpc::PayloadRpcError),
625    /// Variant representing an error while using raw rpc.
626    #[cfg(feature = "rpc-raw")]
627    #[error("raw rpc error: {}", _0)]
628    RawProcedureCall(#[from] crate::rpc::RawRpcError),
629    /// Variant representing an error while using rpc.
630    #[cfg(feature = "rpc-core")]
631    #[error("procedure load error: {}", _0)]
632    ProcedureLoad(#[from] LoadProcedureError),
633}