use thiserror::Error;
#[derive(Debug, Error)]
pub enum EbpfError {
#[cfg(target_os = "linux")]
#[error("failed to load eBPF object: {0}")]
Load(#[from] aya::EbpfError),
#[cfg(target_os = "linux")]
#[error("eBPF map operation failed: {0}")]
Map(#[from] aya::maps::MapError),
#[cfg(target_os = "linux")]
#[error("eBPF program operation failed: {0}")]
Program(#[from] aya::programs::ProgramError),
#[error("failed to attach probe to `{symbol}`: {source}")]
Attach {
symbol: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync + 'static>,
},
#[error("ring buffer event size mismatch: expected {expected}, got {got}")]
EventSize {
expected: usize,
got: usize,
},
#[error("eBPF map `{name}` not found in object")]
MapNotFound {
name: String,
},
#[error("eBPF program `{name}` not found in object")]
ProgramNotFound {
name: String,
},
#[error("permission denied: {detail}")]
PermissionDenied {
detail: String,
},
#[error("could not find OpenSSL library for pid {pid:?}")]
OpenSslNotFound {
pid: Option<i32>,
},
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("eBPF program load failed: {0}")]
ProgramLoad(String),
#[error("kprobe attach failed: {0}")]
ProbeAttach(String),
#[error("BPF map update failed: {0}")]
MapUpdate(String),
#[error("event parse failed: {0}")]
EventParse(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_program_load() {
let err = EbpfError::ProgramLoad("missing privileges".into());
assert_eq!(err.to_string(), "eBPF program load failed: missing privileges");
}
#[test]
fn display_probe_attach() {
let err = EbpfError::ProbeAttach("sys_openat not found".into());
assert_eq!(err.to_string(), "kprobe attach failed: sys_openat not found");
}
#[test]
fn display_map_update() {
let err = EbpfError::MapUpdate("map full".into());
assert_eq!(err.to_string(), "BPF map update failed: map full");
}
#[test]
fn display_event_parse() {
let err = EbpfError::EventParse("truncated buffer".into());
assert_eq!(err.to_string(), "event parse failed: truncated buffer");
}
#[test]
fn display_map_not_found() {
let err = EbpfError::MapNotFound {
name: "PID_FILTER".into(),
};
assert_eq!(err.to_string(), "eBPF map `PID_FILTER` not found in object");
}
#[test]
fn display_program_not_found() {
let err = EbpfError::ProgramNotFound {
name: "ssl_write".into(),
};
assert_eq!(err.to_string(), "eBPF program `ssl_write` not found in object");
}
#[test]
fn display_permission_denied() {
let err = EbpfError::PermissionDenied {
detail: "requires CAP_BPF".into(),
};
assert_eq!(err.to_string(), "permission denied: requires CAP_BPF");
}
#[test]
fn display_openssl_not_found() {
let err = EbpfError::OpenSslNotFound { pid: Some(1234) };
assert_eq!(err.to_string(), "could not find OpenSSL library for pid Some(1234)");
}
#[test]
fn implements_std_error() {
let err = EbpfError::ProgramLoad("test".into());
let _: &dyn std::error::Error = &err;
}
}