Skip to content

Commit ed1e496

Browse files
d-e-s-odanielocfb
authored andcommitted
Rework error evaluation
This change starts a rework of the way we check for potential errors reported from libbpf functions. Instead of relying on the weird create_bpf_entity_checked() helper which works on a closure, introduce validate_bpf_ret(). Having an explicit call means that we can contextualize errors. So on top of getting rid of various hard-to-parse (for humans) closures and potentially nested error mapping, we will report better error chains. As a first step, get rid of usage of create_bpf_entity_checked_opt() from btf/mod.rs. Signed-off-by: Daniel Müller <[email protected]>
1 parent 9a5e061 commit ed1e496

File tree

2 files changed

+36
-11
lines changed

2 files changed

+36
-11
lines changed

libbpf-rs/src/btf/mod.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ use std::ptr;
3838
use std::ptr::NonNull;
3939

4040
use crate::util::create_bpf_entity_checked;
41-
use crate::util::create_bpf_entity_checked_opt;
4241
use crate::util::parse_ret_i32;
42+
use crate::util::validate_bpf_ret;
4343
use crate::AsRawLibbpf;
4444
use crate::Error;
45+
use crate::ErrorExt as _;
4546
use crate::Result;
4647

4748
use self::types::Composite;
@@ -230,17 +231,22 @@ impl<'btf> Btf<'btf> {
230231
}
231232

232233
fn from_bpf_object_raw(obj: *const libbpf_sys::bpf_object) -> Result<Option<Self>> {
233-
create_bpf_entity_checked_opt(|| unsafe {
234+
let ptr = unsafe {
234235
// SAFETY: the obj pointer is valid since it's behind a reference.
235236
libbpf_sys::bpf_object__btf(obj)
236-
})
237-
.map(|opt| {
238-
opt.map(|ptr| Self {
239-
ptr,
240-
drop_policy: DropPolicy::Nothing,
241-
_marker: PhantomData,
242-
})
243-
})
237+
};
238+
// Contrary to general `libbpf` contract, `bpf_object__btf` may
239+
// return `NULL` without setting `errno`.
240+
if ptr.is_null() {
241+
return Ok(None)
242+
}
243+
let ptr = validate_bpf_ret(ptr).context("failed to create BTF from BPF object")?;
244+
let slf = Self {
245+
ptr,
246+
drop_policy: DropPolicy::Nothing,
247+
_marker: PhantomData,
248+
};
249+
Ok(Some(slf))
244250
}
245251

246252
/// From raw bytes coming from an object file.

libbpf-rs/src/util.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ pub fn parse_ret_i32(ret: i32) -> Result<i32> {
7676
parse_ret(ret).map(|()| ret)
7777
}
7878

79+
80+
/// Check the returned pointer of a `libbpf` call, extracting any
81+
/// reported errors and converting them.
82+
pub fn validate_bpf_ret<T>(ptr: *mut T) -> Result<NonNull<T>> {
83+
// SAFETY: `libbpf_get_error` is always safe to call.
84+
match unsafe { libbpf_sys::libbpf_get_error(ptr as *const _) } {
85+
0 => {
86+
debug_assert!(!ptr.is_null());
87+
// SAFETY: libbpf guarantees that if NULL is returned an
88+
// error it set, so we will always end up with a
89+
// valid pointer when `libbpf_get_error` returned 0.
90+
let ptr = unsafe { NonNull::new_unchecked(ptr) };
91+
Ok(ptr)
92+
}
93+
err => Err(Error::from_raw_os_error(-err as i32)),
94+
}
95+
}
96+
97+
7998
pub fn create_bpf_entity_checked<B: 'static, F: FnOnce() -> *mut B>(f: F) -> Result<NonNull<B>> {
8099
create_bpf_entity_checked_opt(f).and_then(|ptr| {
81100
ptr.ok_or_else(|| {
@@ -95,7 +114,7 @@ pub fn create_bpf_entity_checked<B: 'static, F: FnOnce() -> *mut B>(f: F) -> Res
95114
})
96115
}
97116

98-
pub fn create_bpf_entity_checked_opt<B: 'static, F: FnOnce() -> *mut B>(
117+
fn create_bpf_entity_checked_opt<B: 'static, F: FnOnce() -> *mut B>(
99118
f: F,
100119
) -> Result<Option<NonNull<B>>> {
101120
let ptr = f();

0 commit comments

Comments
 (0)