1use std::ffi::c_void;
14use std::ffi::CString;
15use std::io;
16use std::mem::size_of_val;
17use std::os::fd::AsFd;
18use std::os::fd::AsRawFd;
19use std::os::fd::BorrowedFd;
20use std::os::fd::FromRawFd;
21use std::os::fd::OwnedFd;
22use std::os::raw::c_char;
23use std::ptr;
24use std::time::Duration;
25
26use crate::util;
27use crate::MapType;
28use crate::ProgramAttachType;
29use crate::ProgramType;
30use crate::Result;
31
32macro_rules! gen_info_impl {
33 ($(#[$attr:meta])*
35 $name:ident, $info_ty:ty, $uapi_info_ty:ty, $next_id:expr, $fd_by_id:expr) => {
36 $(#[$attr])*
37 #[derive(Default, Debug)]
38 pub struct $name {
39 cur_id: u32,
40 }
41
42 impl $name {
43 fn next_valid_fd(&mut self) -> Option<OwnedFd> {
45 loop {
46 if unsafe { $next_id(self.cur_id, &mut self.cur_id) } != 0 {
47 return None;
48 }
49
50 let fd = unsafe { $fd_by_id(self.cur_id) };
51 if fd < 0 {
52 let err = io::Error::last_os_error();
53 if err.kind() == io::ErrorKind::NotFound {
54 continue;
55 }
56
57 return None;
58 }
59
60 return Some(unsafe { OwnedFd::from_raw_fd(fd)});
61 }
62 }
63 }
64
65 impl Iterator for $name {
66 type Item = $info_ty;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 let fd = self.next_valid_fd()?;
70
71 let mut item: $uapi_info_ty = unsafe { std::mem::zeroed() };
77 let item_ptr: *mut $uapi_info_ty = &mut item;
78 let mut len = size_of_val(&item) as u32;
79
80 let ret = unsafe { libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len) };
81 let parsed_uapi = if ret != 0 {
82 None
83 } else {
84 <$info_ty>::from_uapi(fd.as_fd(), item)
85 };
86
87 parsed_uapi
88 }
89 }
90 };
91}
92
93#[derive(Clone, Debug)]
95pub struct LineInfo {
96 pub insn_off: u32,
98 pub file_name_off: u32,
100 pub line_off: u32,
102 pub line_num: u32,
104 pub line_col: u32,
106}
107
108impl From<&libbpf_sys::bpf_line_info> for LineInfo {
109 fn from(item: &libbpf_sys::bpf_line_info) -> Self {
110 LineInfo {
111 insn_off: item.insn_off,
112 file_name_off: item.file_name_off,
113 line_off: item.line_off,
114 line_num: item.line_col >> 10,
115 line_col: item.line_col & 0x3ff,
116 }
117 }
118}
119
120#[derive(Debug, Clone, Default)]
122#[repr(C)]
123pub struct Tag(pub [u8; 8]);
124
125#[derive(Debug, Clone)]
127#[allow(missing_docs)]
129pub struct ProgramInfo {
130 pub name: CString,
131 pub ty: ProgramType,
132 pub tag: Tag,
133 pub id: u32,
134 pub jited_prog_insns: Vec<u8>,
135 pub xlated_prog_insns: Vec<u8>,
136 pub load_time: Duration,
138 pub created_by_uid: u32,
139 pub map_ids: Vec<u32>,
140 pub ifindex: u32,
141 pub gpl_compatible: bool,
142 pub netns_dev: u64,
143 pub netns_ino: u64,
144 pub jited_ksyms: Vec<*const c_void>,
145 pub jited_func_lens: Vec<u32>,
146 pub btf_id: u32,
147 pub func_info_rec_size: u32,
148 pub func_info: Vec<libbpf_sys::bpf_func_info>,
149 pub line_info: Vec<LineInfo>,
150 pub jited_line_info: Vec<*const c_void>,
151 pub line_info_rec_size: u32,
152 pub jited_line_info_rec_size: u32,
153 pub prog_tags: Vec<Tag>,
154 pub run_time_ns: u64,
155 pub run_cnt: u64,
156 pub recursion_misses: u64,
158}
159
160#[derive(Default, Debug)]
162pub struct ProgInfoIter {
163 cur_id: u32,
164 opts: ProgInfoQueryOptions,
165}
166
167#[derive(Clone, Default, Debug)]
169pub struct ProgInfoQueryOptions {
170 include_xlated_prog_insns: bool,
172 include_jited_prog_insns: bool,
174 include_map_ids: bool,
176 include_line_info: bool,
178 include_func_info: bool,
180 include_jited_line_info: bool,
182 include_jited_func_lens: bool,
184 include_prog_tags: bool,
186 include_jited_ksyms: bool,
188}
189
190impl ProgInfoIter {
191 pub fn with_query_opts(opts: ProgInfoQueryOptions) -> Self {
193 Self {
194 opts,
195 ..Self::default()
196 }
197 }
198}
199
200impl ProgInfoQueryOptions {
201 pub fn include_xlated_prog_insns(mut self, v: bool) -> Self {
203 self.include_xlated_prog_insns = v;
204 self
205 }
206
207 pub fn include_jited_prog_insns(mut self, v: bool) -> Self {
209 self.include_jited_prog_insns = v;
210 self
211 }
212
213 pub fn include_map_ids(mut self, v: bool) -> Self {
215 self.include_map_ids = v;
216 self
217 }
218
219 pub fn include_line_info(mut self, v: bool) -> Self {
221 self.include_line_info = v;
222 self
223 }
224
225 pub fn include_func_info(mut self, v: bool) -> Self {
227 self.include_func_info = v;
228 self
229 }
230
231 pub fn include_jited_line_info(mut self, v: bool) -> Self {
233 self.include_jited_line_info = v;
234 self
235 }
236
237 pub fn include_jited_func_lens(mut self, v: bool) -> Self {
239 self.include_jited_func_lens = v;
240 self
241 }
242
243 pub fn include_prog_tags(mut self, v: bool) -> Self {
245 self.include_prog_tags = v;
246 self
247 }
248
249 pub fn include_jited_ksyms(mut self, v: bool) -> Self {
251 self.include_jited_ksyms = v;
252 self
253 }
254
255 pub fn include_all(self) -> Self {
257 Self {
258 include_xlated_prog_insns: true,
259 include_jited_prog_insns: true,
260 include_map_ids: true,
261 include_line_info: true,
262 include_func_info: true,
263 include_jited_line_info: true,
264 include_jited_func_lens: true,
265 include_prog_tags: true,
266 include_jited_ksyms: true,
267 }
268 }
269}
270
271impl ProgramInfo {
272 fn load_from_fd(fd: BorrowedFd<'_>, opts: &ProgInfoQueryOptions) -> Result<Self> {
273 let mut item = libbpf_sys::bpf_prog_info::default();
274
275 let mut xlated_prog_insns: Vec<u8> = Vec::new();
276 let mut jited_prog_insns: Vec<u8> = Vec::new();
277 let mut map_ids: Vec<u32> = Vec::new();
278 let mut jited_line_info: Vec<*const c_void> = Vec::new();
279 let mut line_info: Vec<libbpf_sys::bpf_line_info> = Vec::new();
280 let mut func_info: Vec<libbpf_sys::bpf_func_info> = Vec::new();
281 let mut jited_func_lens: Vec<u32> = Vec::new();
282 let mut prog_tags: Vec<Tag> = Vec::new();
283 let mut jited_ksyms: Vec<*const c_void> = Vec::new();
284
285 let item_ptr: *mut libbpf_sys::bpf_prog_info = &mut item;
286 let mut len = size_of_val(&item) as u32;
287
288 let ret = unsafe {
289 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
290 };
291 util::parse_ret(ret)?;
292
293 let name = util::c_char_slice_to_cstr(&item.name).unwrap();
295 let ty = ProgramType::from(item.type_);
296
297 if opts.include_xlated_prog_insns {
298 xlated_prog_insns.resize(item.xlated_prog_len as usize, 0u8);
299 item.xlated_prog_insns = xlated_prog_insns.as_mut_ptr() as *mut c_void as u64;
300 } else {
301 item.xlated_prog_len = 0;
302 }
303
304 if opts.include_jited_prog_insns {
305 jited_prog_insns.resize(item.jited_prog_len as usize, 0u8);
306 item.jited_prog_insns = jited_prog_insns.as_mut_ptr() as *mut c_void as u64;
307 } else {
308 item.jited_prog_len = 0;
309 }
310
311 if opts.include_map_ids {
312 map_ids.resize(item.nr_map_ids as usize, 0u32);
313 item.map_ids = map_ids.as_mut_ptr() as *mut c_void as u64;
314 } else {
315 item.nr_map_ids = 0;
316 }
317
318 if opts.include_line_info {
319 line_info.resize(
320 item.nr_line_info as usize,
321 libbpf_sys::bpf_line_info::default(),
322 );
323 item.line_info = line_info.as_mut_ptr() as *mut c_void as u64;
324 } else {
325 item.nr_line_info = 0;
326 }
327
328 if opts.include_func_info {
329 func_info.resize(
330 item.nr_func_info as usize,
331 libbpf_sys::bpf_func_info::default(),
332 );
333 item.func_info = func_info.as_mut_ptr() as *mut c_void as u64;
334 } else {
335 item.nr_func_info = 0;
336 }
337
338 if opts.include_jited_line_info {
339 jited_line_info.resize(item.nr_jited_line_info as usize, ptr::null());
340 item.jited_line_info = jited_line_info.as_mut_ptr() as *mut c_void as u64;
341 } else {
342 item.nr_jited_line_info = 0;
343 }
344
345 if opts.include_jited_func_lens {
346 jited_func_lens.resize(item.nr_jited_func_lens as usize, 0);
347 item.jited_func_lens = jited_func_lens.as_mut_ptr() as *mut c_void as u64;
348 } else {
349 item.nr_jited_func_lens = 0;
350 }
351
352 if opts.include_prog_tags {
353 prog_tags.resize(item.nr_prog_tags as usize, Tag::default());
354 item.prog_tags = prog_tags.as_mut_ptr() as *mut c_void as u64;
355 } else {
356 item.nr_prog_tags = 0;
357 }
358
359 if opts.include_jited_ksyms {
360 jited_ksyms.resize(item.nr_jited_ksyms as usize, ptr::null());
361 item.jited_ksyms = jited_ksyms.as_mut_ptr() as *mut c_void as u64;
362 } else {
363 item.nr_jited_ksyms = 0;
364 }
365
366 let ret = unsafe {
367 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
368 };
369 util::parse_ret(ret)?;
370
371 Ok(ProgramInfo {
372 name: name.to_owned(),
373 ty,
374 tag: Tag(item.tag),
375 id: item.id,
376 jited_prog_insns,
377 xlated_prog_insns,
378 load_time: Duration::from_nanos(item.load_time),
379 created_by_uid: item.created_by_uid,
380 map_ids,
381 ifindex: item.ifindex,
382 gpl_compatible: item._bitfield_1.get_bit(0),
383 netns_dev: item.netns_dev,
384 netns_ino: item.netns_ino,
385 jited_ksyms,
386 jited_func_lens,
387 btf_id: item.btf_id,
388 func_info_rec_size: item.func_info_rec_size,
389 func_info,
390 line_info: line_info.iter().map(|li| li.into()).collect(),
391 jited_line_info,
392 line_info_rec_size: item.line_info_rec_size,
393 jited_line_info_rec_size: item.jited_line_info_rec_size,
394 prog_tags,
395 run_time_ns: item.run_time_ns,
396 run_cnt: item.run_cnt,
397 recursion_misses: item.recursion_misses,
398 })
399 }
400}
401
402impl ProgInfoIter {
403 fn next_valid_fd(&mut self) -> Option<OwnedFd> {
404 loop {
405 if unsafe { libbpf_sys::bpf_prog_get_next_id(self.cur_id, &mut self.cur_id) } != 0 {
406 return None;
407 }
408
409 let fd = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(self.cur_id) };
410 if fd < 0 {
411 let err = io::Error::last_os_error();
412 if err.kind() == io::ErrorKind::NotFound {
413 continue;
414 }
415 return None;
416 }
417
418 return Some(unsafe { OwnedFd::from_raw_fd(fd) });
419 }
420 }
421}
422
423impl Iterator for ProgInfoIter {
424 type Item = ProgramInfo;
425
426 fn next(&mut self) -> Option<Self::Item> {
427 let fd = self.next_valid_fd()?;
428
429 let prog = ProgramInfo::load_from_fd(fd.as_fd(), &self.opts);
430
431 match prog {
432 Ok(p) => Some(p),
433 Err(_err) => None,
435 }
436 }
437}
438
439#[derive(Debug, Clone)]
441#[allow(missing_docs)]
443pub struct MapInfo {
444 pub name: CString,
445 pub ty: MapType,
446 pub id: u32,
447 pub key_size: u32,
448 pub value_size: u32,
449 pub max_entries: u32,
450 pub map_flags: u32,
451 pub ifindex: u32,
452 pub btf_vmlinux_value_type_id: u32,
453 pub netns_dev: u64,
454 pub netns_ino: u64,
455 pub btf_id: u32,
456 pub btf_key_type_id: u32,
457 pub btf_value_type_id: u32,
458}
459
460impl MapInfo {
461 fn from_uapi(_fd: BorrowedFd<'_>, s: libbpf_sys::bpf_map_info) -> Option<Self> {
462 let name = util::c_char_slice_to_cstr(&s.name).unwrap();
464 let ty = MapType::from(s.type_);
465
466 Some(Self {
467 name: name.to_owned(),
468 ty,
469 id: s.id,
470 key_size: s.key_size,
471 value_size: s.value_size,
472 max_entries: s.max_entries,
473 map_flags: s.map_flags,
474 ifindex: s.ifindex,
475 btf_vmlinux_value_type_id: s.btf_vmlinux_value_type_id,
476 netns_dev: s.netns_dev,
477 netns_ino: s.netns_ino,
478 btf_id: s.btf_id,
479 btf_key_type_id: s.btf_key_type_id,
480 btf_value_type_id: s.btf_value_type_id,
481 })
482 }
483}
484
485gen_info_impl!(
486 MapInfoIter,
488 MapInfo,
489 libbpf_sys::bpf_map_info,
490 libbpf_sys::bpf_map_get_next_id,
491 libbpf_sys::bpf_map_get_fd_by_id
492);
493
494#[derive(Debug, Clone)]
496pub struct BtfInfo {
497 pub name: CString,
499 pub btf: Vec<u8>,
501 pub id: u32,
503}
504
505impl BtfInfo {
506 fn load_from_fd(fd: BorrowedFd<'_>) -> Result<Self> {
507 let mut item = libbpf_sys::bpf_btf_info::default();
508 let mut btf: Vec<u8> = Vec::new();
509 let mut name: Vec<u8> = Vec::new();
510
511 let item_ptr: *mut libbpf_sys::bpf_btf_info = &mut item;
512 let mut len = size_of_val(&item) as u32;
513
514 let ret = unsafe {
515 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
516 };
517 util::parse_ret(ret)?;
518
519 item.name_len += 1;
522 name.resize(item.name_len as usize, 0u8);
523 item.name = name.as_mut_ptr() as *mut c_void as u64;
524
525 btf.resize(item.btf_size as usize, 0u8);
526 item.btf = btf.as_mut_ptr() as *mut c_void as u64;
527
528 let ret = unsafe {
529 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr as *mut c_void, &mut len)
530 };
531 util::parse_ret(ret)?;
532
533 Ok(BtfInfo {
534 name: CString::from_vec_with_nul(name).unwrap(),
538 btf,
539 id: item.id,
540 })
541 }
542}
543
544#[derive(Debug, Default)]
545pub struct BtfInfoIter {
548 cur_id: u32,
549}
550
551impl BtfInfoIter {
552 fn next_valid_fd(&mut self) -> Option<OwnedFd> {
554 loop {
555 if unsafe { libbpf_sys::bpf_btf_get_next_id(self.cur_id, &mut self.cur_id) } != 0 {
556 return None;
557 }
558
559 let fd = unsafe { libbpf_sys::bpf_btf_get_fd_by_id(self.cur_id) };
560 if fd < 0 {
561 let err = io::Error::last_os_error();
562 if err.kind() == io::ErrorKind::NotFound {
563 continue;
564 }
565 return None;
566 }
567
568 return Some(unsafe { OwnedFd::from_raw_fd(fd) });
569 }
570 }
571}
572
573impl Iterator for BtfInfoIter {
574 type Item = BtfInfo;
575
576 fn next(&mut self) -> Option<Self::Item> {
577 let fd = self.next_valid_fd()?;
578
579 let info = BtfInfo::load_from_fd(fd.as_fd());
580
581 match info {
582 Ok(i) => Some(i),
583 Err(_err) => None,
585 }
586 }
587}
588
589#[derive(Debug, Clone)]
590#[allow(missing_docs)]
592pub struct RawTracepointLinkInfo {
593 pub name: String,
594}
595
596#[derive(Debug, Clone)]
597#[allow(missing_docs)]
599pub struct TracingLinkInfo {
600 pub attach_type: ProgramAttachType,
601}
602
603#[derive(Debug, Clone)]
604#[allow(missing_docs)]
606pub struct CgroupLinkInfo {
607 pub cgroup_id: u64,
608 pub attach_type: ProgramAttachType,
609}
610
611#[derive(Debug, Clone)]
612#[allow(missing_docs)]
614pub struct NetNsLinkInfo {
615 pub ino: u32,
616 pub attach_type: ProgramAttachType,
617}
618
619#[derive(Debug, Clone)]
620#[allow(missing_docs)]
622pub enum LinkTypeInfo {
623 RawTracepoint(RawTracepointLinkInfo),
624 Tracing(TracingLinkInfo),
625 Cgroup(CgroupLinkInfo),
626 Iter,
627 NetNs(NetNsLinkInfo),
628 Unknown,
629}
630
631#[derive(Debug, Clone)]
633#[allow(missing_docs)]
635pub struct LinkInfo {
636 pub info: LinkTypeInfo,
637 pub id: u32,
638 pub prog_id: u32,
639}
640
641impl LinkInfo {
642 fn from_uapi(fd: BorrowedFd<'_>, mut s: libbpf_sys::bpf_link_info) -> Option<Self> {
643 let type_info = match s.type_ {
644 libbpf_sys::BPF_LINK_TYPE_RAW_TRACEPOINT => {
645 let mut buf = [0; 256];
646 s.__bindgen_anon_1.raw_tracepoint.tp_name = buf.as_mut_ptr() as u64;
647 s.__bindgen_anon_1.raw_tracepoint.tp_name_len = buf.len() as u32;
648 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
649 let mut len = size_of_val(&s) as u32;
650
651 let ret = unsafe {
652 libbpf_sys::bpf_obj_get_info_by_fd(
653 fd.as_raw_fd(),
654 item_ptr as *mut c_void,
655 &mut len,
656 )
657 };
658 if ret != 0 {
659 return None;
660 }
661
662 LinkTypeInfo::RawTracepoint(RawTracepointLinkInfo {
663 name: util::c_ptr_to_string(
664 unsafe { s.__bindgen_anon_1.raw_tracepoint.tp_name } as *const c_char,
665 )
666 .unwrap_or_else(|_| "?".to_string()),
667 })
668 }
669 libbpf_sys::BPF_LINK_TYPE_TRACING => LinkTypeInfo::Tracing(TracingLinkInfo {
670 attach_type: ProgramAttachType::from(unsafe {
671 s.__bindgen_anon_1.tracing.attach_type
672 }),
673 }),
674 libbpf_sys::BPF_LINK_TYPE_CGROUP => LinkTypeInfo::Cgroup(CgroupLinkInfo {
675 cgroup_id: unsafe { s.__bindgen_anon_1.cgroup.cgroup_id },
676 attach_type: ProgramAttachType::from(unsafe {
677 s.__bindgen_anon_1.cgroup.attach_type
678 }),
679 }),
680 libbpf_sys::BPF_LINK_TYPE_ITER => LinkTypeInfo::Iter,
681 libbpf_sys::BPF_LINK_TYPE_NETNS => LinkTypeInfo::NetNs(NetNsLinkInfo {
682 ino: unsafe { s.__bindgen_anon_1.netns.netns_ino },
683 attach_type: ProgramAttachType::from(unsafe {
684 s.__bindgen_anon_1.netns.attach_type
685 }),
686 }),
687 _ => LinkTypeInfo::Unknown,
688 };
689
690 Some(Self {
691 info: type_info,
692 id: s.id,
693 prog_id: s.prog_id,
694 })
695 }
696}
697
698gen_info_impl!(
699 LinkInfoIter,
701 LinkInfo,
702 libbpf_sys::bpf_link_info,
703 libbpf_sys::bpf_link_get_next_id,
704 libbpf_sys::bpf_link_get_fd_by_id
705);