solana_sbpf/
error.rs

1// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
2//
3// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
4// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
5// copied, modified, or distributed except according to those terms.
6
7//! This module contains error and result types
8
9use {
10    crate::{elf::ElfError, memory_region::AccessType, verifier::VerifierError},
11    std::error::Error,
12};
13
14/// Error definitions
15#[derive(Debug, thiserror::Error)]
16#[repr(u64)] // discriminant size, used in emit_exception_kind in JIT
17pub enum EbpfError {
18    /// ELF error
19    #[error("ELF error: {0}")]
20    ElfError(#[from] ElfError),
21    /// Function was already registered
22    #[error("function #{0} was already registered")]
23    FunctionAlreadyRegistered(usize),
24    /// Exceeded max BPF to BPF call depth
25    #[error("exceeded max BPF to BPF call depth")]
26    CallDepthExceeded,
27    /// Attempt to exit from root call frame
28    #[error("attempted to exit root call frame")]
29    ExitRootCallFrame,
30    /// Divide by zero"
31    #[error("divide by zero at BPF instruction")]
32    DivideByZero,
33    /// Divide overflow
34    #[error("division overflow at BPF instruction")]
35    DivideOverflow,
36    /// Exceeded max instructions allowed
37    #[error("attempted to execute past the end of the text segment at BPF instruction")]
38    ExecutionOverrun,
39    /// Attempt to call to an address outside the text segment
40    #[error("callx attempted to call outside of the text segment")]
41    CallOutsideTextSegment,
42    /// Exceeded max instructions allowed
43    #[error("exceeded CUs meter at BPF instruction")]
44    ExceededMaxInstructions,
45    /// Program has not been JIT-compiled
46    #[error("program has not been JIT-compiled")]
47    JitNotCompiled,
48    /// Invalid virtual address
49    #[error("invalid virtual address {0:x?}")]
50    InvalidVirtualAddress(u64),
51    /// Memory region index or virtual address space is invalid
52    #[error("Invalid memory region at index {0}")]
53    InvalidMemoryRegion(usize),
54    /// Access violation (general)
55    #[error("Access violation in {3} section at address {1:#x} of size {2:?}")]
56    AccessViolation(AccessType, u64, u64, &'static str),
57    /// Access violation (stack specific)
58    #[error("Access violation in stack frame {3} at address {1:#x} of size {2:?}")]
59    StackAccessViolation(AccessType, u64, u64, i64),
60    /// Invalid instruction
61    #[error("invalid BPF instruction")]
62    InvalidInstruction,
63    /// Unsupported instruction
64    #[error("unsupported BPF instruction")]
65    UnsupportedInstruction,
66    /// Compilation is too big to fit
67    #[error("Compilation exhausted text segment at BPF instruction {0}")]
68    ExhaustedTextSegment(usize),
69    /// Libc function call returned an error
70    #[error("Libc calling {0} {1:?} returned error code {2}")]
71    LibcInvocationFailed(&'static str, Vec<String>, i32),
72    /// Verifier error
73    #[error("Verifier error: {0}")]
74    VerifierError(#[from] VerifierError),
75    /// Syscall error
76    #[error("Syscall error: {0}")]
77    SyscallError(Box<dyn Error>),
78}
79
80/// Same as `Result` but provides a stable memory layout
81#[derive(Debug)]
82#[repr(C, u64)]
83pub enum StableResult<T, E> {
84    /// Success
85    Ok(T),
86    /// Failure
87    Err(E),
88}
89
90impl<T: std::fmt::Debug, E: std::fmt::Debug> StableResult<T, E> {
91    /// `true` if `Ok`
92    pub fn is_ok(&self) -> bool {
93        match self {
94            Self::Ok(_) => true,
95            Self::Err(_) => false,
96        }
97    }
98
99    /// `true` if `Err`
100    pub fn is_err(&self) -> bool {
101        match self {
102            Self::Ok(_) => false,
103            Self::Err(_) => true,
104        }
105    }
106
107    /// Returns the inner value if `Ok`, panics otherwise
108    pub fn unwrap(self) -> T {
109        match self {
110            Self::Ok(value) => value,
111            Self::Err(error) => panic!("unwrap {:?}", error),
112        }
113    }
114
115    /// Returns the inner error if `Err`, panics otherwise
116    pub fn unwrap_err(self) -> E {
117        match self {
118            Self::Ok(value) => panic!("unwrap_err {:?}", value),
119            Self::Err(error) => error,
120        }
121    }
122
123    /// Maps ok values, leaving error values untouched
124    pub fn map<U, O: FnOnce(T) -> U>(self, op: O) -> StableResult<U, E> {
125        match self {
126            Self::Ok(value) => StableResult::<U, E>::Ok(op(value)),
127            Self::Err(error) => StableResult::<U, E>::Err(error),
128        }
129    }
130
131    /// Maps error values, leaving ok values untouched
132    pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> StableResult<T, F> {
133        match self {
134            Self::Ok(value) => StableResult::<T, F>::Ok(value),
135            Self::Err(error) => StableResult::<T, F>::Err(op(error)),
136        }
137    }
138
139    #[cfg_attr(
140        any(
141            not(feature = "jit"),
142            target_os = "windows",
143            not(target_arch = "x86_64")
144        ),
145        allow(dead_code)
146    )]
147    pub(crate) fn discriminant(&self) -> u64 {
148        unsafe { *std::ptr::addr_of!(*self).cast::<u64>() }
149    }
150}
151
152impl<T, E> From<StableResult<T, E>> for Result<T, E> {
153    fn from(result: StableResult<T, E>) -> Self {
154        match result {
155            StableResult::Ok(value) => Ok(value),
156            StableResult::Err(value) => Err(value),
157        }
158    }
159}
160
161impl<T, E> From<Result<T, E>> for StableResult<T, E> {
162    fn from(result: Result<T, E>) -> Self {
163        match result {
164            Ok(value) => Self::Ok(value),
165            Err(value) => Self::Err(value),
166        }
167    }
168}
169
170/// Return value of programs and syscalls
171pub type ProgramResult = StableResult<u64, EbpfError>;
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn test_program_result_is_stable() {
179        let ok = ProgramResult::Ok(42);
180        assert_eq!(ok.discriminant(), 0);
181        let err = ProgramResult::Err(EbpfError::JitNotCompiled);
182        assert_eq!(err.discriminant(), 1);
183    }
184}