1use std::num::NonZeroI32;
6use std::prelude::v1::*;
7use std::{fmt, result, str};
8
9use log::{debug, error, info, trace, warn};
10
11use crate::cglue::IntError;
12
13#[cfg(feature = "std")]
14use std::error;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
17pub struct Error(pub ErrorOrigin, pub ErrorKind);
18
19impl Error {
20 pub fn as_str(&self) -> &'static str {
22 self.1.to_str()
23 }
24
25 pub fn into_str(self) -> &'static str {
27 self.as_str()
28 }
29
30 pub fn log_error(self, err: impl std::fmt::Display) -> Self {
31 error!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
32 self
33 }
34
35 pub fn log_warn(self, err: impl std::fmt::Display) -> Self {
36 warn!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
37 self
38 }
39
40 pub fn log_info(self, err: impl std::fmt::Display) -> Self {
41 info!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
42 self
43 }
44
45 pub fn log_debug(self, err: impl std::fmt::Display) -> Self {
46 debug!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
47 self
48 }
49
50 pub fn log_trace(self, err: impl std::fmt::Display) -> Self {
51 trace!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
52 self
53 }
54}
55
56impl IntError for Error {
57 fn into_int_err(self) -> NonZeroI32 {
58 let origin = ((self.0 as i32 + 1) & 0xFFFi32) << 4;
59 let kind = ((self.1 as i32 + 1) & 0xFFFi32) << 16;
60 NonZeroI32::new(-(1 + origin + kind)).unwrap()
61 }
62
63 fn from_int_err(err: NonZeroI32) -> Self {
64 let origin = ((-err.get() - 1) >> 4i32) & 0xFFFi32;
65 let kind = ((-err.get() - 1) >> 16i32) & 0xFFFi32;
66
67 let error_origin = if origin > 0 && origin <= ErrorOrigin::Other as i32 + 1 {
68 unsafe { std::mem::transmute::<u16, ErrorOrigin>(origin as u16 - 1) }
69 } else {
70 ErrorOrigin::Other
71 };
72
73 let error_kind = if kind > 0 && kind <= ErrorKind::Unknown as i32 + 1 {
74 unsafe { std::mem::transmute::<u16, ErrorKind>(kind as u16 - 1) }
75 } else {
76 ErrorKind::Unknown
77 };
78
79 Self(error_origin, error_kind)
80 }
81}
82
83impl fmt::Display for Error {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 write!(f, "{}: {}", self.0.to_str(), self.1.to_str())
86 }
87}
88
89#[cfg(feature = "std")]
90impl error::Error for Error {
91 fn description(&self) -> &str {
92 self.as_str()
93 }
94}
95
96impl<T> From<PartialError<T>> for Error {
98 fn from(err: PartialError<T>) -> Self {
99 match err {
100 PartialError::Error(e) => e,
101 _ => Error(ErrorOrigin::Memory, ErrorKind::PartialData),
102 }
103 }
104}
105
106impl From<ErrorOrigin> for Error {
107 fn from(origin: ErrorOrigin) -> Self {
108 Error(origin, ErrorKind::Unknown)
109 }
110}
111
112impl From<ErrorKind> for Error {
113 fn from(kind: ErrorKind) -> Self {
114 Error(ErrorOrigin::Other, kind)
115 }
116}
117
118#[repr(u16)]
119#[non_exhaustive]
120#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
121pub enum ErrorOrigin {
122 Pointer,
123
124 Args,
125 ArgsValidator,
126
127 Memory,
128 Mmu,
129 MemoryMap,
130
131 PhysicalMemory,
132 VirtualTranslate,
133 Cache,
134 TlbCache,
135 PageCache,
136 VirtualMemory,
137
138 Inventory,
139 Connector,
140 OsLayer,
141 Ffi,
142
143 Other,
144}
145
146impl ErrorOrigin {
147 pub fn to_str(self) -> &'static str {
149 match self {
150 ErrorOrigin::Pointer => "pointer",
151
152 ErrorOrigin::Args => "args",
153 ErrorOrigin::ArgsValidator => "args validator",
154
155 ErrorOrigin::Memory => "memory",
156 ErrorOrigin::Mmu => "mmu",
157 ErrorOrigin::MemoryMap => "memory map",
158
159 ErrorOrigin::PhysicalMemory => "physical memory",
160 ErrorOrigin::VirtualTranslate => "virtual translate",
161 ErrorOrigin::Cache => "cache",
162 ErrorOrigin::TlbCache => "tlb cache",
163 ErrorOrigin::PageCache => "page cache",
164 ErrorOrigin::VirtualMemory => "virtual memory",
165
166 ErrorOrigin::Inventory => "inventory",
167 ErrorOrigin::Connector => "connector",
168 ErrorOrigin::OsLayer => "oslayer",
169 ErrorOrigin::Ffi => "ffi",
170
171 ErrorOrigin::Other => "other",
172 }
173 }
174}
175
176#[repr(u16)]
177#[non_exhaustive]
178#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
179pub enum ErrorKind {
180 Uninitialized,
181 NotSupported,
182 NotImplemented,
183 Configuration,
184 Offset,
185 Http,
186
187 ArgNotExists,
188 ArgValidation,
189 RequiredArgNotFound,
190
191 InvalidArgument,
192
193 PartialData,
194
195 NotFound,
196 OutOfBounds,
197 OutOfMemoryRange,
198 Encoding,
199
200 InvalidPath,
201 ReadOnly,
202 UnableToReadDir,
203 UnableToReadDirEntry,
204 UnableToReadFile,
205 UnableToCreateDirectory,
206 UnableToWriteFile,
207 UnableToSeekFile,
208
209 UnableToMapFile,
210 MemoryMapOutOfRange,
211 UnableToReadMemory,
212
213 InvalidArchitecture,
214 InvalidMemorySize,
215 InvalidMemorySizeUnit,
216
217 UnableToLoadLibrary,
218 InvalidExeFile,
219 MemflowExportsNotFound,
220 VersionMismatch,
221 AlreadyExists,
222 PluginNotFound,
223 TargetNotFound,
224 InvalidAbi,
225 UnsupportedOptionalFeature,
226
227 ProcessNotFound,
228 InvalidProcessInfo,
229 ModuleNotFound,
230 ExportNotFound,
231 ImportNotFound,
232 SectionNotFound,
233
234 Unknown,
235}
236
237impl ErrorKind {
238 pub fn to_str(self) -> &'static str {
240 match self {
241 ErrorKind::Uninitialized => "unitialized",
242 ErrorKind::NotSupported => "not supported",
243 ErrorKind::NotImplemented => "not implemented",
244 ErrorKind::Configuration => "configuration error",
245 ErrorKind::Offset => "offset error",
246 ErrorKind::Http => "http error",
247
248 ErrorKind::ArgNotExists => "the given argument does not exist",
249 ErrorKind::ArgValidation => "the argument could not be validated",
250 ErrorKind::RequiredArgNotFound => "required argument is not set",
251
252 ErrorKind::InvalidArgument => "invalid argument passed",
253
254 ErrorKind::PartialData => "partial data",
255
256 ErrorKind::NotFound => "not found",
257 ErrorKind::OutOfBounds => "out of bounds",
258 ErrorKind::OutOfMemoryRange => "out of memory range",
259 ErrorKind::Encoding => "encoding error",
260
261 ErrorKind::InvalidPath => "invalid path",
262 ErrorKind::ReadOnly => "trying to write to a read only resource",
263 ErrorKind::UnableToReadDir => "unable to read directory",
264 ErrorKind::UnableToReadDirEntry => "unable to read directory entry",
265 ErrorKind::UnableToReadFile => "unable to read file",
266 ErrorKind::UnableToCreateDirectory => "unable to create directory",
267 ErrorKind::UnableToWriteFile => "unable to write file",
268 ErrorKind::UnableToSeekFile => "unable to seek file",
269
270 ErrorKind::UnableToMapFile => "unable to map file",
271 ErrorKind::MemoryMapOutOfRange => "memory map is out of range",
272 ErrorKind::UnableToReadMemory => "unable to read memory",
273
274 ErrorKind::InvalidArchitecture => "invalid architecture",
275 ErrorKind::InvalidMemorySize => "invalid memory size",
276 ErrorKind::InvalidMemorySizeUnit => "invalid memory size units (or none)",
277
278 ErrorKind::UnableToLoadLibrary => "unable to load library",
279 ErrorKind::InvalidExeFile => "file is not a valid executable file",
280 ErrorKind::MemflowExportsNotFound => "file does not contain any memflow exports",
281 ErrorKind::VersionMismatch => "version mismatch",
282 ErrorKind::AlreadyExists => "already exists",
283 ErrorKind::PluginNotFound => "plugin not found",
284 ErrorKind::TargetNotFound => "specified (connector) target could not be found",
285 ErrorKind::InvalidAbi => "invalid plugin ABI",
286 ErrorKind::UnsupportedOptionalFeature => "unsupported optional feature",
287
288 ErrorKind::ProcessNotFound => "process not found",
289 ErrorKind::InvalidProcessInfo => "invalid process info",
290 ErrorKind::ModuleNotFound => "module not found",
291 ErrorKind::ExportNotFound => "export not found",
292 ErrorKind::ImportNotFound => "import not found",
293 ErrorKind::SectionNotFound => "section not found",
294
295 ErrorKind::Unknown => "unknown error",
296 }
297 }
298}
299
300#[derive(Clone, Eq, PartialEq, Hash)]
302pub enum PartialError<T> {
303 Error(Error),
307 PartialVirtualRead(T),
312 PartialVirtualWrite(T),
317}
318
319impl<T> From<Error> for PartialError<T> {
321 fn from(err: Error) -> Self {
322 PartialError::Error(err)
323 }
324}
325
326impl<T> PartialError<T> {
327 pub fn as_str(&self) -> &'static str {
329 match self {
330 PartialError::Error(e) => e.as_str(),
331 PartialError::PartialVirtualRead(_) => "partial virtual read",
332 PartialError::PartialVirtualWrite(_) => "partial virtual write",
333 }
334 }
335
336 pub fn into_str(self) -> &'static str {
338 self.as_str()
339 }
340}
341
342impl IntError for PartialError<()> {
343 fn into_int_err(self) -> NonZeroI32 {
344 match self {
345 PartialError::Error(err) => err.into_int_err(),
346 PartialError::PartialVirtualRead(_) => NonZeroI32::new(-2).unwrap(),
347 PartialError::PartialVirtualWrite(_) => NonZeroI32::new(-3).unwrap(),
348 }
349 }
350
351 fn from_int_err(err: NonZeroI32) -> Self {
352 let errc = (-err.get()) & 0xFi32;
353 match errc {
354 1 => PartialError::Error(Error::from_int_err(err)),
355 2 => PartialError::PartialVirtualRead(()),
356 3 => PartialError::PartialVirtualWrite(()),
357 _ => PartialError::Error(Error(ErrorOrigin::Ffi, ErrorKind::Unknown)),
358 }
359 }
360}
361
362impl<T> fmt::Debug for PartialError<T> {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 f.write_str(&self.to_string())
367 }
368}
369
370impl<T> fmt::Display for PartialError<T> {
371 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372 match self {
373 PartialError::Error(e) => f.write_str(e.as_str()),
374 _ => f.write_str(self.as_str()),
375 }
376 }
377}
378
379#[cfg(feature = "std")]
380impl<T: fmt::Debug> error::Error for PartialError<T> {
381 fn description(&self) -> &str {
382 self.as_str()
383 }
384}
385
386pub type Result<T> = result::Result<T, Error>;
388
389pub type PartialResult<T> = result::Result<T, PartialError<T>>;
391
392pub trait PartialResultExt<T> {
394 fn data(self) -> Result<T>;
397
398 fn data_part(self) -> Result<T>;
402
403 fn map_data<U, F: FnOnce(T) -> U>(self, func: F) -> PartialResult<U>;
407}
408
409impl<T> PartialResultExt<T> for PartialResult<T> {
410 fn data(self) -> Result<T> {
411 match self {
412 Ok(data) => Ok(data),
413 Err(_) => Err(Error(ErrorOrigin::Memory, ErrorKind::PartialData)),
414 }
415 }
416
417 fn data_part(self) -> Result<T> {
418 match self {
419 Ok(data) => Ok(data),
420 Err(PartialError::PartialVirtualRead(data)) => Ok(data),
421 Err(PartialError::PartialVirtualWrite(data)) => Ok(data),
422 Err(PartialError::Error(e)) => Err(e),
423 }
424 }
425
426 fn map_data<U, F: FnOnce(T) -> U>(self, func: F) -> PartialResult<U> {
427 match self {
428 Ok(data) => Ok(func(data)),
429 Err(PartialError::Error(e)) => Err(PartialError::Error(e)),
430 Err(PartialError::PartialVirtualRead(data)) => Ok(func(data)),
431 Err(PartialError::PartialVirtualWrite(data)) => Ok(func(data)),
432 }
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439 use crate::cglue::result::{
440 from_int_result, from_int_result_empty, into_int_out_result, into_int_result, IntError,
441 };
442 use std::mem::MaybeUninit;
443 use std::num::NonZeroI32;
444
445 #[test]
446 pub fn error_from_i32_invalid() {
447 let mut err = Error::from_int_err(NonZeroI32::new(i32::MIN + 1).unwrap());
448 assert_eq!(err.0, ErrorOrigin::Other);
449 assert_eq!(err.1, ErrorKind::Unknown);
450
451 err = Error::from_int_err(NonZeroI32::new(-1).unwrap());
452 assert_eq!(err.0, ErrorOrigin::Other);
453 assert_eq!(err.1, ErrorKind::Unknown);
454
455 err = Error::from_int_err(NonZeroI32::new(-2).unwrap());
456 assert_eq!(err.0, ErrorOrigin::Other);
457 assert_eq!(err.1, ErrorKind::Unknown);
458
459 err = Error::from_int_err(NonZeroI32::new(-3).unwrap());
460 assert_eq!(err.0, ErrorOrigin::Other);
461 assert_eq!(err.1, ErrorKind::Unknown);
462 }
463
464 #[test]
465 pub fn part_error_from_i32_invalid() {
466 let mut result: PartialResult<()> = from_int_result_empty(-1);
467 assert!(result.is_err());
468 assert_eq!(
469 result.err().unwrap(),
470 PartialError::Error(Error(ErrorOrigin::Other, ErrorKind::Unknown))
471 );
472
473 result = from_int_result_empty(-2);
474 assert!(result.is_err());
475 assert_eq!(result.err().unwrap(), PartialError::PartialVirtualRead(()));
476
477 result = from_int_result_empty(-3);
478 assert!(result.is_err());
479 assert_eq!(result.err().unwrap(), PartialError::PartialVirtualWrite(()));
480
481 result = from_int_result_empty(-4);
482 assert!(result.is_err());
483 assert_eq!(
484 result.err().unwrap(),
485 PartialError::Error(Error(ErrorOrigin::Ffi, ErrorKind::Unknown))
486 );
487 }
488
489 #[test]
490 pub fn error_to_from_i32() {
491 let err = Error::from_int_err(
492 Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile).into_int_err(),
493 );
494 assert_eq!(err.0, ErrorOrigin::Other);
495 assert_eq!(err.1, ErrorKind::InvalidExeFile);
496 }
497
498 #[test]
499 pub fn result_ok_void_ffi() {
500 let r: Result<()> = Ok(());
501 let result: Result<()> = from_int_result_empty(into_int_result(r));
502 assert!(result.is_ok());
503 }
504
505 #[test]
506 pub fn result_ok_value_ffi() {
507 let r: Result<i32> = Ok(1234i32);
508 let mut out = MaybeUninit::<i32>::uninit();
509 let result: Result<i32> = unsafe { from_int_result(into_int_out_result(r, &mut out), out) };
510 assert!(result.is_ok());
511 assert_eq!(result.unwrap(), 1234i32);
512 }
513
514 #[test]
515 pub fn result_error_void_ffi() {
516 let r: Result<i32> = Err(Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile));
517 let result: Result<()> = from_int_result_empty(into_int_result(r));
518 assert!(result.is_err());
519 assert_eq!(result.err().unwrap().0, ErrorOrigin::Other);
520 assert_eq!(result.err().unwrap().1, ErrorKind::InvalidExeFile);
521 }
522
523 #[test]
524 pub fn result_error_value_ffi() {
525 let r: Result<i32> = Err(Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile));
526 let mut out = MaybeUninit::<i32>::uninit();
527 let result: Result<i32> = unsafe { from_int_result(into_int_out_result(r, &mut out), out) };
528 assert!(result.is_err());
529 assert_eq!(result.err().unwrap().0, ErrorOrigin::Other);
530 assert_eq!(result.err().unwrap().1, ErrorKind::InvalidExeFile);
531 }
532
533 #[test]
534 pub fn part_result_ok_void_ffi() {
535 let r: PartialResult<()> = Ok(());
536 let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
537 assert!(result.is_ok());
538 }
539
540 #[test]
541 pub fn part_result_error_void_ffi() {
542 let r: PartialResult<()> = Err(PartialError::Error(Error(
543 ErrorOrigin::Other,
544 ErrorKind::InvalidExeFile,
545 )));
546 let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
547 assert!(result.is_err());
548 assert_eq!(
549 result.err().unwrap(),
550 PartialError::Error(Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile))
551 );
552 }
553
554 #[test]
555 pub fn part_result_part_error_read_ffi() {
556 let r: PartialResult<()> = Err(PartialError::PartialVirtualRead(()));
557 let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
558 assert!(result.is_err());
559 assert_eq!(result.err().unwrap(), PartialError::PartialVirtualRead(()));
560 }
561
562 #[test]
563 pub fn part_result_part_error_write_ffi() {
564 let r: PartialResult<()> = Err(PartialError::PartialVirtualWrite(()));
565 let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
566 assert!(result.is_err());
567 assert_eq!(result.err().unwrap(), PartialError::PartialVirtualWrite(()));
568 }
569}