1use {
10 crate::{elf::ElfError, memory_region::AccessType, verifier::VerifierError},
11 std::error::Error,
12};
13
14#[derive(Debug, thiserror::Error)]
16#[repr(u64)] pub enum EbpfError {
18 #[error("ELF error: {0}")]
20 ElfError(#[from] ElfError),
21 #[error("function #{0} was already registered")]
23 FunctionAlreadyRegistered(usize),
24 #[error("exceeded max BPF to BPF call depth")]
26 CallDepthExceeded,
27 #[error("attempted to exit root call frame")]
29 ExitRootCallFrame,
30 #[error("divide by zero at BPF instruction")]
32 DivideByZero,
33 #[error("division overflow at BPF instruction")]
35 DivideOverflow,
36 #[error("attempted to execute past the end of the text segment at BPF instruction")]
38 ExecutionOverrun,
39 #[error("callx attempted to call outside of the text segment")]
41 CallOutsideTextSegment,
42 #[error("exceeded CUs meter at BPF instruction")]
44 ExceededMaxInstructions,
45 #[error("program has not been JIT-compiled")]
47 JitNotCompiled,
48 #[error("Invalid memory region at index {0}")]
50 InvalidMemoryRegion(usize),
51 #[error("Access violation in {3} section at address {1:#x} of size {2:?}")]
53 AccessViolation(AccessType, u64, u64, &'static str),
54 #[error("Access violation in stack frame {3} at address {1:#x} of size {2:?}")]
56 StackAccessViolation(AccessType, u64, u64, i64),
57 #[error("invalid BPF instruction")]
59 InvalidInstruction,
60 #[error("unsupported BPF instruction")]
62 UnsupportedInstruction,
63 #[error("Compilation exhausted text segment at BPF instruction {0}")]
65 ExhaustedTextSegment(usize),
66 #[error("Libc calling {0} {1:?} returned error code {2}")]
68 LibcInvocationFailed(&'static str, Vec<String>, i32),
69 #[error("Verifier error: {0}")]
71 VerifierError(#[from] VerifierError),
72 #[error("Syscall error: {0}")]
74 SyscallError(Box<dyn Error>),
75}
76
77#[derive(Debug)]
79#[repr(C, u64)]
80pub enum StableResult<T, E> {
81 Ok(T),
83 Err(E),
85}
86
87impl<T: std::fmt::Debug, E: std::fmt::Debug> StableResult<T, E> {
88 pub fn is_ok(&self) -> bool {
90 match self {
91 Self::Ok(_) => true,
92 Self::Err(_) => false,
93 }
94 }
95
96 pub fn is_err(&self) -> bool {
98 match self {
99 Self::Ok(_) => false,
100 Self::Err(_) => true,
101 }
102 }
103
104 pub fn unwrap(self) -> T {
106 match self {
107 Self::Ok(value) => value,
108 Self::Err(error) => panic!("unwrap {:?}", error),
109 }
110 }
111
112 pub fn unwrap_err(self) -> E {
114 match self {
115 Self::Ok(value) => panic!("unwrap_err {:?}", value),
116 Self::Err(error) => error,
117 }
118 }
119
120 pub fn map<U, O: FnOnce(T) -> U>(self, op: O) -> StableResult<U, E> {
122 match self {
123 Self::Ok(value) => StableResult::<U, E>::Ok(op(value)),
124 Self::Err(error) => StableResult::<U, E>::Err(error),
125 }
126 }
127
128 pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> StableResult<T, F> {
130 match self {
131 Self::Ok(value) => StableResult::<T, F>::Ok(value),
132 Self::Err(error) => StableResult::<T, F>::Err(op(error)),
133 }
134 }
135
136 #[cfg_attr(
137 any(
138 not(feature = "jit"),
139 target_os = "windows",
140 not(target_arch = "x86_64")
141 ),
142 allow(dead_code)
143 )]
144 pub(crate) fn discriminant(&self) -> u64 {
145 unsafe { *std::ptr::addr_of!(*self).cast::<u64>() }
146 }
147}
148
149impl<T, E> From<StableResult<T, E>> for Result<T, E> {
150 fn from(result: StableResult<T, E>) -> Self {
151 match result {
152 StableResult::Ok(value) => Ok(value),
153 StableResult::Err(value) => Err(value),
154 }
155 }
156}
157
158impl<T, E> From<Result<T, E>> for StableResult<T, E> {
159 fn from(result: Result<T, E>) -> Self {
160 match result {
161 Ok(value) => Self::Ok(value),
162 Err(value) => Self::Err(value),
163 }
164 }
165}
166
167pub type ProgramResult = StableResult<u64, EbpfError>;
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_program_result_is_stable() {
176 let ok = ProgramResult::Ok(42);
177 assert_eq!(ok.discriminant(), 0);
178 let err = ProgramResult::Err(EbpfError::JitNotCompiled);
179 assert_eq!(err.discriminant(), 1);
180 }
181}