1use core::ffi::c_void;
2use std::cell::OnceCell;
3use std::ffi::CStr;
4use std::ffi::CString;
5use std::ffi::OsStr;
6use std::mem;
7use std::os::unix::ffi::OsStrExt as _;
8use std::path::Path;
9use std::ptr;
10use std::ptr::NonNull;
11
12use crate::map::map_fd;
13use crate::set_print;
14use crate::util;
15use crate::util::validate_bpf_ret;
16use crate::Btf;
17use crate::ErrorExt as _;
18use crate::Map;
19use crate::MapMut;
20use crate::OpenMap;
21use crate::OpenMapMut;
22use crate::OpenProgram;
23use crate::OpenProgramMut;
24use crate::PrintLevel;
25use crate::Program;
26use crate::ProgramMut;
27use crate::Result;
28
29
30#[derive(Debug)]
32#[doc(alias = "bpf_object__next_map")]
33pub struct MapIter<'obj> {
34 obj: &'obj libbpf_sys::bpf_object,
35 last: *mut libbpf_sys::bpf_map,
36}
37
38impl<'obj> MapIter<'obj> {
39 pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
41 Self {
42 obj,
43 last: ptr::null_mut(),
44 }
45 }
46}
47
48impl Iterator for MapIter<'_> {
49 type Item = NonNull<libbpf_sys::bpf_map>;
50
51 fn next(&mut self) -> Option<Self::Item> {
52 self.last = unsafe { libbpf_sys::bpf_object__next_map(self.obj, self.last) };
53 NonNull::new(self.last)
54 }
55}
56
57
58#[derive(Debug)]
60#[doc(alias = "bpf_object__next_program")]
61pub struct ProgIter<'obj> {
62 obj: &'obj libbpf_sys::bpf_object,
63 last: *mut libbpf_sys::bpf_program,
64}
65
66impl<'obj> ProgIter<'obj> {
67 pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
69 Self {
70 obj,
71 last: ptr::null_mut(),
72 }
73 }
74}
75
76impl Iterator for ProgIter<'_> {
77 type Item = NonNull<libbpf_sys::bpf_program>;
78
79 fn next(&mut self) -> Option<Self::Item> {
80 self.last = unsafe { libbpf_sys::bpf_object__next_program(self.obj, self.last) };
81 NonNull::new(self.last)
82 }
83}
84
85
86pub trait AsRawLibbpf {
92 type LibbpfType;
94
95 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType>;
104}
105
106#[derive(Debug)]
108#[doc(alias = "bpf_object_open_opts")]
109pub struct ObjectBuilder {
110 name: Option<CString>,
111 pin_root_path: Option<CString>,
112 btf_custom_path: Option<CString>,
113
114 opts: OnceCell<libbpf_sys::bpf_object_open_opts>,
115}
116
117impl Default for ObjectBuilder {
118 fn default() -> Self {
119 Self {
120 name: None,
121 pin_root_path: None,
122 btf_custom_path: None,
123 opts: OnceCell::new(),
124 }
125 }
126}
127
128impl PartialEq for ObjectBuilder {
129 fn eq(&self, other: &Self) -> bool {
130 let Self {
131 name,
132 pin_root_path,
133 btf_custom_path,
134 opts,
135 } = self;
136
137 opts.get().is_none()
141 && other.opts.get().is_none()
142 && name == &other.name
143 && pin_root_path == &other.pin_root_path
144 && btf_custom_path == &other.btf_custom_path
145 }
146}
147
148impl ObjectBuilder {
149 fn opts(&self) -> &libbpf_sys::bpf_object_open_opts {
150 self.opts.get_or_init(|| libbpf_sys::bpf_object_open_opts {
151 sz: mem::size_of::<libbpf_sys::bpf_object_open_opts>() as libbpf_sys::size_t,
152 ..Default::default()
153 })
154 }
155
156 fn opts_mut(&mut self) -> &mut libbpf_sys::bpf_object_open_opts {
157 let _opts = self.opts();
158 self.opts.get_mut().unwrap()
160 }
161
162 pub fn name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self> {
164 self.name = Some(util::str_to_cstring(name.as_ref())?);
165 self.opts_mut().object_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr());
166 Ok(self)
167 }
168
169 pub fn pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
173 self.pin_root_path = Some(util::path_to_cstring(path)?);
174 self.opts_mut().pin_root_path = self
175 .pin_root_path
176 .as_ref()
177 .map_or(ptr::null(), |p| p.as_ptr());
178 Ok(self)
179 }
180
181 pub fn btf_custom_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
186 self.btf_custom_path = Some(util::path_to_cstring(path)?);
187 self.opts_mut().btf_custom_path = self
188 .btf_custom_path
189 .as_ref()
190 .map_or(ptr::null(), |p| p.as_ptr());
191 Ok(self)
192 }
193
194 pub fn relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self {
196 self.opts_mut().relaxed_maps = relaxed_maps;
197 self
198 }
199
200 pub fn debug(&mut self, dbg: bool) -> &mut Self {
205 if dbg {
206 set_print(Some((PrintLevel::Debug, |_, s| print!("{s}"))));
207 } else {
208 set_print(None);
209 }
210 self
211 }
212
213 #[doc(alias = "bpf_object__open_file")]
215 pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject> {
216 let path = path.as_ref();
217 let path_c = util::path_to_cstring(path)?;
218 let path_ptr = path_c.as_ptr();
219 let opts_ptr = self.as_libbpf_object().as_ptr();
220
221 let ptr = unsafe { libbpf_sys::bpf_object__open_file(path_ptr, opts_ptr) };
222 let ptr = validate_bpf_ret(ptr)
223 .with_context(|| format!("failed to open object from `{}`", path.display()))?;
224
225 let obj = unsafe { OpenObject::from_ptr(ptr) };
226 Ok(obj)
227 }
228
229 #[doc(alias = "bpf_object__open_mem")]
231 pub fn open_memory(&mut self, mem: &[u8]) -> Result<OpenObject> {
232 let opts_ptr = self.as_libbpf_object().as_ptr();
233 let ptr = unsafe {
234 libbpf_sys::bpf_object__open_mem(
235 mem.as_ptr().cast::<c_void>(),
236 mem.len() as libbpf_sys::size_t,
237 opts_ptr,
238 )
239 };
240 let ptr = validate_bpf_ret(ptr).context("failed to open object from memory")?;
241 let obj = unsafe { OpenObject::from_ptr(ptr) };
242 Ok(obj)
243 }
244}
245
246impl AsRawLibbpf for ObjectBuilder {
247 type LibbpfType = libbpf_sys::bpf_object_open_opts;
248
249 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
251 unsafe { NonNull::new_unchecked(ptr::from_ref(self.opts()).cast_mut()) }
253 }
254}
255
256
257#[derive(Debug)]
261#[repr(transparent)]
262#[doc(alias = "bpf_object")]
263pub struct OpenObject {
264 ptr: NonNull<libbpf_sys::bpf_object>,
265}
266
267impl OpenObject {
268 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
279 Self { ptr }
280 }
281
282 pub fn take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object> {
284 let ptr = {
285 let Self { ptr } = &mut self;
286 *ptr
287 };
288 mem::forget(self);
290 ptr
291 }
292
293 #[doc(alias = "bpf_object__name")]
295 pub fn name(&self) -> Option<&OsStr> {
296 let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
298 let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr.cast()) };
300 if err != 0 {
301 return None
302 }
303 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
304 let str = OsStr::from_bytes(name_c_str.to_bytes());
305 Some(str)
306 }
307
308 pub fn maps(&self) -> impl Iterator<Item = OpenMap<'_>> {
310 MapIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { OpenMap::new(ptr.as_ref()) })
311 }
312
313 pub fn maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>> {
315 MapIter::new(unsafe { self.ptr.as_ref() })
316 .map(|mut ptr| unsafe { OpenMapMut::new_mut(ptr.as_mut()) })
317 }
318
319 pub fn progs(&self) -> impl Iterator<Item = OpenProgram<'_>> {
321 ProgIter::new(unsafe { self.ptr.as_ref() })
322 .map(|ptr| unsafe { OpenProgram::new(ptr.as_ref()) })
323 }
324
325 pub fn progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>> {
327 ProgIter::new(unsafe { self.ptr.as_ref() })
328 .map(|mut ptr| unsafe { OpenProgramMut::new_mut(ptr.as_mut()) })
329 }
330
331 #[doc(alias = "bpf_object__load")]
333 pub fn load(self) -> Result<Object> {
334 let ret = unsafe { libbpf_sys::bpf_object__load(self.ptr.as_ptr()) };
335 let () = util::parse_ret(ret)?;
336
337 let obj = unsafe { Object::from_ptr(self.take_ptr()) };
338
339 Ok(obj)
340 }
341}
342
343unsafe impl Send for OpenObject {}
345unsafe impl Sync for OpenObject {}
347
348impl AsRawLibbpf for OpenObject {
349 type LibbpfType = libbpf_sys::bpf_object;
350
351 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
353 self.ptr
354 }
355}
356
357impl Drop for OpenObject {
358 #[doc(alias = "bpf_object__close")]
359 fn drop(&mut self) {
360 unsafe {
362 libbpf_sys::bpf_object__close(self.ptr.as_ptr());
363 }
364 }
365}
366
367
368#[derive(Debug)]
378#[repr(transparent)]
379#[doc(alias = "bpf_object")]
380pub struct Object {
381 ptr: NonNull<libbpf_sys::bpf_object>,
382}
383
384impl Object {
385 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
394 Self { ptr }
395 }
396
397 #[doc(alias = "bpf_object__name")]
399 pub fn name(&self) -> Option<&OsStr> {
400 let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
402 let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr.cast()) };
404 if err != 0 {
405 return None
406 }
407 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
408 let str = OsStr::from_bytes(name_c_str.to_bytes());
409 Some(str)
410 }
411
412 #[doc(alias = "bpf_object__btf")]
414 pub fn btf(&self) -> Result<Option<Btf<'_>>> {
415 Btf::from_bpf_object(unsafe { &*self.ptr.as_ptr() })
416 }
417
418 pub fn maps(&self) -> impl Iterator<Item = Map<'_>> {
420 MapIter::new(unsafe { self.ptr.as_ref() })
421 .filter(|ptr| map_fd(*ptr).is_some())
422 .map(|ptr| unsafe { Map::new(ptr.as_ref()) })
423 }
424
425 pub fn maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>> {
427 MapIter::new(unsafe { self.ptr.as_ref() })
428 .filter(|ptr| map_fd(*ptr).is_some())
429 .map(|mut ptr| unsafe { MapMut::new_mut(ptr.as_mut()) })
430 }
431
432 pub fn progs(&self) -> impl Iterator<Item = Program<'_>> {
434 ProgIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { Program::new(ptr.as_ref()) })
435 }
436
437 pub fn progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>> {
439 ProgIter::new(unsafe { self.ptr.as_ref() })
440 .map(|mut ptr| unsafe { ProgramMut::new_mut(ptr.as_mut()) })
441 }
442}
443
444unsafe impl Send for Object {}
446unsafe impl Sync for Object {}
448
449impl AsRawLibbpf for Object {
450 type LibbpfType = libbpf_sys::bpf_object;
451
452 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
454 self.ptr
455 }
456}
457
458impl Drop for Object {
459 #[doc(alias = "bpf_object__close")]
460 fn drop(&mut self) {
461 unsafe {
462 libbpf_sys::bpf_object__close(self.ptr.as_ptr());
463 }
464 }
465}