1use std::ffi::c_void;
14use std::ffi::CStr;
15use std::ffi::OsStr;
16use std::ffi::OsString;
17use std::io;
18use std::mem::size_of_val;
19use std::mem::zeroed;
20use std::os::fd::AsFd;
21use std::os::fd::AsRawFd;
22use std::os::fd::BorrowedFd;
23use std::os::fd::FromRawFd;
24use std::os::fd::OwnedFd;
25use std::os::raw::c_char;
26use std::os::unix::ffi::OsStrExt;
27use std::path::PathBuf;
28use std::ptr;
29use std::time::Duration;
30
31use crate::util;
32use crate::CgroupIterOrder;
33use crate::MapType;
34use crate::ProgramAttachType;
35use crate::ProgramType;
36use crate::Result;
37
38fn cstr_to_os_string(s: &CStr) -> OsString {
40 OsStr::from_bytes(s.to_bytes()).to_owned()
41}
42
43macro_rules! gen_info_impl {
44 ($(#[$attr:meta])*
46 $name:ident, $info_ty:ty, $uapi_info_ty:ty, $next_id:expr, $fd_by_id:expr) => {
47 $(#[$attr])*
48 #[derive(Default, Debug)]
49 pub struct $name {
50 cur_id: u32,
51 }
52
53 impl $name {
54 fn next_valid_fd(&mut self) -> Option<OwnedFd> {
56 loop {
57 if unsafe { $next_id(self.cur_id, &mut self.cur_id) } != 0 {
58 return None;
59 }
60
61 let fd = unsafe { $fd_by_id(self.cur_id) };
62 if fd < 0 {
63 let err = io::Error::last_os_error();
64 if err.kind() == io::ErrorKind::NotFound {
65 continue;
66 }
67
68 return None;
69 }
70
71 return Some(unsafe { OwnedFd::from_raw_fd(fd)});
72 }
73 }
74 }
75
76 impl Iterator for $name {
77 type Item = $info_ty;
78
79 fn next(&mut self) -> Option<Self::Item> {
80 let fd = self.next_valid_fd()?;
81
82 let mut item: $uapi_info_ty = unsafe { std::mem::zeroed() };
88 let item_ptr: *mut $uapi_info_ty = &mut item;
89 let mut len = size_of_val(&item) as u32;
90
91 let ret = unsafe { libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast(), &mut len) };
92 let parsed_uapi = if ret != 0 {
93 None
94 } else {
95 <$info_ty>::from_uapi(fd.as_fd(), item)
96 };
97
98 parsed_uapi
99 }
100 }
101 };
102}
103
104#[derive(Clone, Debug)]
106pub struct LineInfo {
107 pub insn_off: u32,
109 pub file_name_off: u32,
111 pub line_off: u32,
113 pub line_num: u32,
115 pub line_col: u32,
117}
118
119impl From<&libbpf_sys::bpf_line_info> for LineInfo {
120 fn from(item: &libbpf_sys::bpf_line_info) -> Self {
121 Self {
122 insn_off: item.insn_off,
123 file_name_off: item.file_name_off,
124 line_off: item.line_off,
125 line_num: item.line_col >> 10,
126 line_col: item.line_col & 0x3ff,
127 }
128 }
129}
130
131#[derive(Debug, Clone, Default)]
133#[repr(C)]
134pub struct Tag(pub [u8; 8]);
135
136#[derive(Debug, Clone)]
138pub struct ProgramInfo {
139 pub name: OsString,
141 pub ty: ProgramType,
143 pub tag: Tag,
146 pub id: u32,
148 pub jited_prog_insns: Vec<u8>,
150 pub xlated_prog_insns: Vec<u8>,
152 pub load_time: Duration,
154 pub created_by_uid: u32,
156 pub map_ids: Vec<u32>,
158 pub ifindex: u32,
160 pub gpl_compatible: bool,
162 pub netns_dev: u64,
164 pub netns_ino: u64,
166 pub jited_ksyms: Vec<*const c_void>,
168 pub jited_func_lens: Vec<u32>,
170 pub btf_id: u32,
172 pub func_info_rec_size: u32,
174 pub func_info: Vec<libbpf_sys::bpf_func_info>,
176 pub line_info: Vec<LineInfo>,
178 pub jited_line_info: Vec<*const c_void>,
180 pub line_info_rec_size: u32,
182 pub jited_line_info_rec_size: u32,
184 pub prog_tags: Vec<Tag>,
186 pub run_time_ns: u64,
188 pub run_cnt: u64,
190 pub recursion_misses: u64,
192 pub verified_insns: u32,
194 #[doc(hidden)]
196 pub _non_exhaustive: (),
197}
198
199#[derive(Default, Debug)]
201pub struct ProgInfoIter {
202 cur_id: u32,
203 opts: ProgInfoQueryOptions,
204}
205
206#[derive(Clone, Default, Debug)]
208pub struct ProgInfoQueryOptions {
209 include_xlated_prog_insns: bool,
211 include_jited_prog_insns: bool,
213 include_map_ids: bool,
215 include_line_info: bool,
217 include_func_info: bool,
219 include_jited_line_info: bool,
221 include_jited_func_lens: bool,
223 include_prog_tags: bool,
225 include_jited_ksyms: bool,
227}
228
229impl ProgInfoIter {
230 pub fn with_query_opts(opts: ProgInfoQueryOptions) -> Self {
232 Self {
233 opts,
234 ..Self::default()
235 }
236 }
237}
238
239impl ProgInfoQueryOptions {
240 pub fn include_xlated_prog_insns(mut self, v: bool) -> Self {
242 self.include_xlated_prog_insns = v;
243 self
244 }
245
246 pub fn include_jited_prog_insns(mut self, v: bool) -> Self {
248 self.include_jited_prog_insns = v;
249 self
250 }
251
252 pub fn include_map_ids(mut self, v: bool) -> Self {
254 self.include_map_ids = v;
255 self
256 }
257
258 pub fn include_line_info(mut self, v: bool) -> Self {
260 self.include_line_info = v;
261 self
262 }
263
264 pub fn include_func_info(mut self, v: bool) -> Self {
266 self.include_func_info = v;
267 self
268 }
269
270 pub fn include_jited_line_info(mut self, v: bool) -> Self {
272 self.include_jited_line_info = v;
273 self
274 }
275
276 pub fn include_jited_func_lens(mut self, v: bool) -> Self {
278 self.include_jited_func_lens = v;
279 self
280 }
281
282 pub fn include_prog_tags(mut self, v: bool) -> Self {
284 self.include_prog_tags = v;
285 self
286 }
287
288 pub fn include_jited_ksyms(mut self, v: bool) -> Self {
290 self.include_jited_ksyms = v;
291 self
292 }
293
294 pub fn include_all(self) -> Self {
296 Self {
297 include_xlated_prog_insns: true,
298 include_jited_prog_insns: true,
299 include_map_ids: true,
300 include_line_info: true,
301 include_func_info: true,
302 include_jited_line_info: true,
303 include_jited_func_lens: true,
304 include_prog_tags: true,
305 include_jited_ksyms: true,
306 }
307 }
308}
309
310impl ProgramInfo {
311 fn load_from_fd(fd: BorrowedFd<'_>, opts: &ProgInfoQueryOptions) -> Result<Self> {
312 let mut item = libbpf_sys::bpf_prog_info::default();
313
314 let mut xlated_prog_insns: Vec<u8> = Vec::new();
315 let mut jited_prog_insns: Vec<u8> = Vec::new();
316 let mut map_ids: Vec<u32> = Vec::new();
317 let mut jited_line_info: Vec<*const c_void> = Vec::new();
318 let mut line_info: Vec<libbpf_sys::bpf_line_info> = Vec::new();
319 let mut func_info: Vec<libbpf_sys::bpf_func_info> = Vec::new();
320 let mut jited_func_lens: Vec<u32> = Vec::new();
321 let mut prog_tags: Vec<Tag> = Vec::new();
322 let mut jited_ksyms: Vec<*const c_void> = Vec::new();
323
324 let item_ptr: *mut libbpf_sys::bpf_prog_info = &mut item;
325 let mut len = size_of_val(&item) as u32;
326
327 let ret = unsafe {
328 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast::<c_void>(), &mut len)
329 };
330 util::parse_ret(ret)?;
331
332 let name = util::c_char_slice_to_cstr(&item.name).unwrap();
334 let ty = ProgramType::from(item.type_);
335
336 if opts.include_xlated_prog_insns {
337 xlated_prog_insns.resize(item.xlated_prog_len as usize, 0u8);
338 item.xlated_prog_insns = xlated_prog_insns.as_mut_ptr().cast::<c_void>() as u64;
339 } else {
340 item.xlated_prog_len = 0;
341 }
342
343 if opts.include_jited_prog_insns {
344 jited_prog_insns.resize(item.jited_prog_len as usize, 0u8);
345 item.jited_prog_insns = jited_prog_insns.as_mut_ptr().cast::<c_void>() as u64;
346 } else {
347 item.jited_prog_len = 0;
348 }
349
350 if opts.include_map_ids {
351 map_ids.resize(item.nr_map_ids as usize, 0u32);
352 item.map_ids = map_ids.as_mut_ptr().cast::<c_void>() as u64;
353 } else {
354 item.nr_map_ids = 0;
355 }
356
357 if opts.include_line_info {
358 line_info.resize(
359 item.nr_line_info as usize,
360 libbpf_sys::bpf_line_info::default(),
361 );
362 item.line_info = line_info.as_mut_ptr().cast::<c_void>() as u64;
363 } else {
364 item.nr_line_info = 0;
365 }
366
367 if opts.include_func_info {
368 func_info.resize(
369 item.nr_func_info as usize,
370 libbpf_sys::bpf_func_info::default(),
371 );
372 item.func_info = func_info.as_mut_ptr().cast::<c_void>() as u64;
373 } else {
374 item.nr_func_info = 0;
375 }
376
377 if opts.include_jited_line_info {
378 jited_line_info.resize(item.nr_jited_line_info as usize, ptr::null());
379 item.jited_line_info = jited_line_info.as_mut_ptr().cast::<c_void>() as u64;
380 } else {
381 item.nr_jited_line_info = 0;
382 }
383
384 if opts.include_jited_func_lens {
385 jited_func_lens.resize(item.nr_jited_func_lens as usize, 0);
386 item.jited_func_lens = jited_func_lens.as_mut_ptr().cast::<c_void>() as u64;
387 } else {
388 item.nr_jited_func_lens = 0;
389 }
390
391 if opts.include_prog_tags {
392 prog_tags.resize(item.nr_prog_tags as usize, Tag::default());
393 item.prog_tags = prog_tags.as_mut_ptr().cast::<c_void>() as u64;
394 } else {
395 item.nr_prog_tags = 0;
396 }
397
398 if opts.include_jited_ksyms {
399 jited_ksyms.resize(item.nr_jited_ksyms as usize, ptr::null());
400 item.jited_ksyms = jited_ksyms.as_mut_ptr().cast::<c_void>() as u64;
401 } else {
402 item.nr_jited_ksyms = 0;
403 }
404
405 let ret = unsafe {
406 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast::<c_void>(), &mut len)
407 };
408 util::parse_ret(ret)?;
409
410 Ok(Self {
411 name: cstr_to_os_string(name),
412 ty,
413 tag: Tag(item.tag),
414 id: item.id,
415 jited_prog_insns,
416 xlated_prog_insns,
417 load_time: Duration::from_nanos(item.load_time),
418 created_by_uid: item.created_by_uid,
419 map_ids,
420 ifindex: item.ifindex,
421 gpl_compatible: item._bitfield_1.get_bit(0),
422 netns_dev: item.netns_dev,
423 netns_ino: item.netns_ino,
424 jited_ksyms,
425 jited_func_lens,
426 btf_id: item.btf_id,
427 func_info_rec_size: item.func_info_rec_size,
428 func_info,
429 line_info: line_info.iter().map(Into::into).collect(),
430 jited_line_info,
431 line_info_rec_size: item.line_info_rec_size,
432 jited_line_info_rec_size: item.jited_line_info_rec_size,
433 prog_tags,
434 run_time_ns: item.run_time_ns,
435 run_cnt: item.run_cnt,
436 recursion_misses: item.recursion_misses,
437 verified_insns: item.verified_insns,
438 _non_exhaustive: (),
439 })
440 }
441}
442
443impl ProgInfoIter {
444 fn next_valid_fd(&mut self) -> Option<OwnedFd> {
445 loop {
446 if unsafe { libbpf_sys::bpf_prog_get_next_id(self.cur_id, &mut self.cur_id) } != 0 {
447 return None;
448 }
449
450 let fd = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(self.cur_id) };
451 if fd < 0 {
452 let err = io::Error::last_os_error();
453 if err.kind() == io::ErrorKind::NotFound {
454 continue;
455 }
456 return None;
457 }
458
459 return Some(unsafe { OwnedFd::from_raw_fd(fd) });
460 }
461 }
462}
463
464impl Iterator for ProgInfoIter {
465 type Item = ProgramInfo;
466
467 fn next(&mut self) -> Option<Self::Item> {
468 let fd = self.next_valid_fd()?;
469 let prog = ProgramInfo::load_from_fd(fd.as_fd(), &self.opts);
470 prog.ok()
471 }
472}
473
474#[derive(Debug, Clone)]
476pub struct MapInfo {
477 pub name: OsString,
479 pub ty: MapType,
481 pub id: u32,
483 pub key_size: u32,
485 pub value_size: u32,
487 pub max_entries: u32,
489 pub map_flags: u32,
491 pub ifindex: u32,
494 pub btf_vmlinux_value_type_id: u32,
496 pub netns_dev: u64,
498 pub netns_ino: u64,
500 pub btf_id: u32,
503 pub btf_key_type_id: u32,
505 pub btf_value_type_id: u32,
507}
508
509impl MapInfo {
510 fn from_uapi(_fd: BorrowedFd<'_>, s: libbpf_sys::bpf_map_info) -> Option<Self> {
511 let name = util::c_char_slice_to_cstr(&s.name).unwrap();
513 let ty = MapType::from(s.type_);
514
515 Some(Self {
516 name: cstr_to_os_string(name),
517 ty,
518 id: s.id,
519 key_size: s.key_size,
520 value_size: s.value_size,
521 max_entries: s.max_entries,
522 map_flags: s.map_flags,
523 ifindex: s.ifindex,
524 btf_vmlinux_value_type_id: s.btf_vmlinux_value_type_id,
525 netns_dev: s.netns_dev,
526 netns_ino: s.netns_ino,
527 btf_id: s.btf_id,
528 btf_key_type_id: s.btf_key_type_id,
529 btf_value_type_id: s.btf_value_type_id,
530 })
531 }
532}
533
534gen_info_impl!(
535 MapInfoIter,
537 MapInfo,
538 libbpf_sys::bpf_map_info,
539 libbpf_sys::bpf_map_get_next_id,
540 libbpf_sys::bpf_map_get_fd_by_id
541);
542
543#[derive(Debug, Clone)]
545pub struct BtfInfo {
546 pub name: OsString,
548 pub btf: Vec<u8>,
550 pub id: u32,
552}
553
554impl BtfInfo {
555 fn load_from_fd(fd: BorrowedFd<'_>) -> Result<Self> {
556 let mut item = libbpf_sys::bpf_btf_info::default();
557 let mut btf: Vec<u8> = Vec::new();
558 let mut name: Vec<u8> = Vec::new();
559
560 let item_ptr: *mut libbpf_sys::bpf_btf_info = &mut item;
561 let mut len = size_of_val(&item) as u32;
562
563 let ret = unsafe {
564 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast::<c_void>(), &mut len)
565 };
566 util::parse_ret(ret)?;
567
568 item.name_len += 1;
571 name.resize(item.name_len as usize, 0u8);
572 item.name = name.as_mut_ptr().cast::<c_void>() as u64;
573
574 btf.resize(item.btf_size as usize, 0u8);
575 item.btf = btf.as_mut_ptr().cast::<c_void>() as u64;
576
577 let ret = unsafe {
578 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast::<c_void>(), &mut len)
579 };
580 util::parse_ret(ret)?;
581
582 Ok(Self {
583 name: cstr_to_os_string(CStr::from_bytes_with_nul(&name).unwrap()),
587 btf,
588 id: item.id,
589 })
590 }
591}
592
593#[derive(Debug, Default)]
594pub struct BtfInfoIter {
597 cur_id: u32,
598}
599
600impl BtfInfoIter {
601 fn next_valid_fd(&mut self) -> Option<OwnedFd> {
603 loop {
604 if unsafe { libbpf_sys::bpf_btf_get_next_id(self.cur_id, &mut self.cur_id) } != 0 {
605 return None;
606 }
607
608 let fd = unsafe { libbpf_sys::bpf_btf_get_fd_by_id(self.cur_id) };
609 if fd < 0 {
610 let err = io::Error::last_os_error();
611 if err.kind() == io::ErrorKind::NotFound {
612 continue;
613 }
614 return None;
615 }
616
617 return Some(unsafe { OwnedFd::from_raw_fd(fd) });
618 }
619 }
620}
621
622impl Iterator for BtfInfoIter {
623 type Item = BtfInfo;
624
625 fn next(&mut self) -> Option<Self::Item> {
626 let fd = self.next_valid_fd()?;
627 let info = BtfInfo::load_from_fd(fd.as_fd());
628 info.ok()
629 }
630}
631
632#[derive(Debug, Clone)]
634pub struct RawTracepointLinkInfo {
635 pub name: String,
637 #[doc(hidden)]
639 pub _non_exhaustive: (),
640}
641
642#[derive(Debug, Clone)]
644pub struct TracingLinkInfo {
645 pub attach_type: ProgramAttachType,
647 pub target_obj_id: u32,
650 pub target_btf_id: u32,
652 #[doc(hidden)]
654 pub _non_exhaustive: (),
655}
656
657#[derive(Debug, Clone)]
659pub struct CgroupLinkInfo {
660 pub cgroup_id: u64,
662 pub attach_type: ProgramAttachType,
664 #[doc(hidden)]
666 pub _non_exhaustive: (),
667}
668
669#[derive(Debug, Clone)]
671pub struct IterLinkInfo {
672 pub target_name: OsString,
674 pub iter_type: IterType,
676 #[doc(hidden)]
678 pub _non_exhaustive: (),
679}
680
681#[derive(Debug, Clone)]
683pub enum IterType {
684 Map {
686 map_id: u32,
688 },
689 Cgroup {
691 cgroup_id: u64,
693 order: CgroupIterOrder,
695 },
696 Task {
698 tid: u32,
700 pid: u32,
702 },
703 Unknown,
708}
709
710#[derive(Debug, Clone)]
712pub struct NetNsLinkInfo {
713 pub ino: u32,
715 pub attach_type: ProgramAttachType,
717 #[doc(hidden)]
719 pub _non_exhaustive: (),
720}
721
722#[derive(Debug, Clone)]
724pub struct NetfilterLinkInfo {
725 pub protocol_family: u32,
727 pub hooknum: u32,
729 pub priority: i32,
731 pub flags: u32,
733 #[doc(hidden)]
735 pub _non_exhaustive: (),
736}
737
738#[derive(Debug, Clone)]
740pub struct XdpLinkInfo {
741 pub ifindex: u32,
743 #[doc(hidden)]
745 pub _non_exhaustive: (),
746}
747
748#[derive(Debug, Clone)]
750pub struct SockMapLinkInfo {
751 pub map_id: u32,
753 pub attach_type: ProgramAttachType,
755 #[doc(hidden)]
757 pub _non_exhaustive: (),
758}
759
760#[derive(Debug, Clone)]
762pub struct NetkitLinkInfo {
763 pub ifindex: u32,
765 pub attach_type: ProgramAttachType,
767 #[doc(hidden)]
769 pub _non_exhaustive: (),
770}
771
772#[derive(Debug, Clone)]
774pub struct TcxLinkInfo {
775 pub ifindex: u32,
777 pub attach_type: ProgramAttachType,
779 #[doc(hidden)]
781 pub _non_exhaustive: (),
782}
783
784#[derive(Debug, Clone)]
786pub struct StructOpsLinkInfo {
787 pub map_id: u32,
789 #[doc(hidden)]
791 pub _non_exhaustive: (),
792}
793
794#[derive(Debug, Clone)]
796pub struct KprobeMultiLinkInfo {
797 pub count: u32,
799 pub flags: u32,
801 pub missed: u64,
803 pub addrs: Vec<u64>,
805 pub cookies: Vec<u64>,
807 #[doc(hidden)]
809 pub _non_exhaustive: (),
810}
811
812#[derive(Debug, Clone)]
814pub struct UprobeMultiLinkInfo {
815 pub path_size: u32,
817 pub path: Option<PathBuf>,
819 pub count: u32,
821 pub flags: u32,
823 pub pid: u32,
825 pub offsets: Vec<u64>,
827 pub ref_ctr_offsets: Vec<u64>,
829 pub cookies: Vec<u64>,
831 #[doc(hidden)]
833 pub _non_exhaustive: (),
834}
835
836#[derive(Debug, Clone)]
838pub struct PerfEventLinkInfo {
839 pub event_type: PerfEventType,
841 #[doc(hidden)]
843 pub _non_exhaustive: (),
844}
845
846#[derive(Debug, Clone)]
848pub enum PerfEventType {
849 Tracepoint {
851 name: Option<OsString>,
853 cookie: u64,
855 },
856 Kprobe {
858 func_name: Option<OsString>,
860 is_retprobe: bool,
862 addr: u64,
864 offset: u32,
866 missed: u64,
868 cookie: u64,
870 },
871 Uprobe {
873 file_name: Option<OsString>,
875 is_retprobe: bool,
877 offset: u32,
879 cookie: u64,
881 ref_ctr_offset: u64,
883 },
884 Event {
886 config: u64,
888 event_type: u32,
890 cookie: u64,
892 },
893 Unknown(u32),
895}
896
897#[derive(Debug, Clone)]
900pub enum LinkTypeInfo {
901 RawTracepoint(RawTracepointLinkInfo),
905 Tracing(TracingLinkInfo),
907 Cgroup(CgroupLinkInfo),
911 Iter(IterLinkInfo),
913 NetNs(NetNsLinkInfo),
915 Xdp(XdpLinkInfo),
920 StructOps(StructOpsLinkInfo),
925 Netfilter(NetfilterLinkInfo),
927 KprobeMulti(KprobeMultiLinkInfo),
929 UprobeMulti(UprobeMultiLinkInfo),
931 Tcx(TcxLinkInfo),
933 Netkit(NetkitLinkInfo),
935 SockMap(SockMapLinkInfo),
937 PerfEvent(PerfEventLinkInfo),
942 Unknown,
944}
945
946#[derive(Debug, Clone)]
948pub struct LinkInfo {
949 pub info: LinkTypeInfo,
951 pub id: u32,
953 pub prog_id: u32,
955}
956
957impl LinkInfo {
958 pub fn from_fd(fd: BorrowedFd<'_>) -> Result<Self> {
960 let mut link_info: libbpf_sys::bpf_link_info = unsafe { zeroed() };
962 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut link_info;
963 let mut len = size_of_val(&link_info) as u32;
964
965 let ret = unsafe {
966 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast::<c_void>(), &mut len)
967 };
968 util::parse_ret(ret)?;
969
970 Self::from_uapi(fd, link_info)
971 .ok_or_else(|| crate::Error::with_invalid_data("failed to parse link info"))
972 }
973
974 fn from_uapi(fd: BorrowedFd<'_>, mut s: libbpf_sys::bpf_link_info) -> Option<Self> {
975 let type_info = match s.type_ {
976 libbpf_sys::BPF_LINK_TYPE_RAW_TRACEPOINT => {
977 let mut buf = [0u8; 256];
978 s.__bindgen_anon_1.raw_tracepoint.tp_name = buf.as_mut_ptr() as u64;
979 s.__bindgen_anon_1.raw_tracepoint.tp_name_len = buf.len() as u32;
980 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
981 let mut len = size_of_val(&s) as u32;
982
983 let ret = unsafe {
984 libbpf_sys::bpf_obj_get_info_by_fd(
985 fd.as_raw_fd(),
986 item_ptr.cast::<c_void>(),
987 &mut len,
988 )
989 };
990 if ret != 0 {
991 return None;
992 }
993
994 LinkTypeInfo::RawTracepoint(RawTracepointLinkInfo {
995 name: util::c_ptr_to_string(
996 unsafe { s.__bindgen_anon_1.raw_tracepoint.tp_name } as *const c_char,
997 )
998 .unwrap_or_else(|_| "?".to_string()),
999 _non_exhaustive: (),
1000 })
1001 }
1002 libbpf_sys::BPF_LINK_TYPE_TRACING => LinkTypeInfo::Tracing(TracingLinkInfo {
1003 attach_type: ProgramAttachType::from(unsafe {
1004 s.__bindgen_anon_1.tracing.attach_type
1005 }),
1006 target_obj_id: unsafe { s.__bindgen_anon_1.tracing.target_obj_id },
1007 target_btf_id: unsafe { s.__bindgen_anon_1.tracing.target_btf_id },
1008 _non_exhaustive: (),
1009 }),
1010 libbpf_sys::BPF_LINK_TYPE_CGROUP => LinkTypeInfo::Cgroup(CgroupLinkInfo {
1011 cgroup_id: unsafe { s.__bindgen_anon_1.cgroup.cgroup_id },
1012 attach_type: ProgramAttachType::from(unsafe {
1013 s.__bindgen_anon_1.cgroup.attach_type
1014 }),
1015 _non_exhaustive: (),
1016 }),
1017 libbpf_sys::BPF_LINK_TYPE_ITER => {
1018 let mut buf = [0u8; 256];
1019 s.__bindgen_anon_1.iter.target_name = buf.as_mut_ptr() as u64;
1020 s.__bindgen_anon_1.iter.target_name_len = buf.len() as u32;
1021 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
1022 let mut len = size_of_val(&s) as u32;
1023
1024 let ret = unsafe {
1025 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast(), &mut len)
1026 };
1027 if ret != 0 {
1028 return None;
1029 }
1030
1031 let iter_info = unsafe { s.__bindgen_anon_1.iter };
1032 let target_name = unsafe {
1036 cstr_to_os_string(CStr::from_ptr(iter_info.target_name as *const c_char))
1037 };
1038
1039 let iter_type = match target_name.as_bytes() {
1040 b"bpf_map_elem" | b"bpf_sk_storage_map" => IterType::Map {
1041 map_id: unsafe { iter_info.__bindgen_anon_1.map.map_id },
1042 },
1043 b"cgroup" => {
1044 let order = match unsafe { iter_info.__bindgen_anon_2.cgroup.order } {
1045 libbpf_sys::BPF_CGROUP_ITER_SELF_ONLY => CgroupIterOrder::SelfOnly,
1046 libbpf_sys::BPF_CGROUP_ITER_DESCENDANTS_PRE => {
1047 CgroupIterOrder::DescendantsPre
1048 }
1049 libbpf_sys::BPF_CGROUP_ITER_DESCENDANTS_POST => {
1050 CgroupIterOrder::DescendantsPost
1051 }
1052 libbpf_sys::BPF_CGROUP_ITER_ANCESTORS_UP => {
1053 CgroupIterOrder::AncestorsUp
1054 }
1055 _ => CgroupIterOrder::Default,
1056 };
1057 IterType::Cgroup {
1058 cgroup_id: unsafe { iter_info.__bindgen_anon_2.cgroup.cgroup_id },
1059 order,
1060 }
1061 }
1062 b"task" | b"task_file" | b"task_vma" => IterType::Task {
1063 tid: unsafe { iter_info.__bindgen_anon_2.task.tid },
1064 pid: unsafe { iter_info.__bindgen_anon_2.task.pid },
1065 },
1066 _ => IterType::Unknown,
1067 };
1068
1069 LinkTypeInfo::Iter(IterLinkInfo {
1070 target_name,
1071 iter_type,
1072 _non_exhaustive: (),
1073 })
1074 }
1075 libbpf_sys::BPF_LINK_TYPE_NETNS => LinkTypeInfo::NetNs(NetNsLinkInfo {
1076 ino: unsafe { s.__bindgen_anon_1.netns.netns_ino },
1077 attach_type: ProgramAttachType::from(unsafe {
1078 s.__bindgen_anon_1.netns.attach_type
1079 }),
1080 _non_exhaustive: (),
1081 }),
1082 libbpf_sys::BPF_LINK_TYPE_NETFILTER => LinkTypeInfo::Netfilter(NetfilterLinkInfo {
1083 protocol_family: unsafe { s.__bindgen_anon_1.netfilter.pf },
1084 hooknum: unsafe { s.__bindgen_anon_1.netfilter.hooknum },
1085 priority: unsafe { s.__bindgen_anon_1.netfilter.priority },
1086 flags: unsafe { s.__bindgen_anon_1.netfilter.flags },
1087 _non_exhaustive: (),
1088 }),
1089 libbpf_sys::BPF_LINK_TYPE_XDP => LinkTypeInfo::Xdp(XdpLinkInfo {
1090 ifindex: unsafe { s.__bindgen_anon_1.xdp.ifindex },
1091 _non_exhaustive: (),
1092 }),
1093 libbpf_sys::BPF_LINK_TYPE_NETKIT => LinkTypeInfo::Netkit(NetkitLinkInfo {
1094 ifindex: unsafe { s.__bindgen_anon_1.netkit.ifindex },
1095 attach_type: ProgramAttachType::from(unsafe {
1096 s.__bindgen_anon_1.netkit.attach_type
1097 }),
1098 _non_exhaustive: (),
1099 }),
1100 libbpf_sys::BPF_LINK_TYPE_TCX => LinkTypeInfo::Tcx(TcxLinkInfo {
1101 ifindex: unsafe { s.__bindgen_anon_1.tcx.ifindex },
1102 attach_type: ProgramAttachType::from(unsafe { s.__bindgen_anon_1.tcx.attach_type }),
1103 _non_exhaustive: (),
1104 }),
1105 libbpf_sys::BPF_LINK_TYPE_STRUCT_OPS => LinkTypeInfo::StructOps(StructOpsLinkInfo {
1106 map_id: unsafe { s.__bindgen_anon_1.struct_ops.map_id },
1107 _non_exhaustive: (),
1108 }),
1109 libbpf_sys::BPF_LINK_TYPE_KPROBE_MULTI => {
1110 let count = unsafe { s.__bindgen_anon_1.kprobe_multi.count } as usize;
1111 let mut addrs = vec![0; count];
1112 let mut cookies = vec![0; count];
1113
1114 s.__bindgen_anon_1.kprobe_multi.addrs = addrs.as_mut_ptr() as u64;
1115 s.__bindgen_anon_1.kprobe_multi.cookies = cookies.as_mut_ptr() as u64;
1116 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
1117 let mut len = size_of_val(&s) as u32;
1118 let ret = unsafe {
1119 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast(), &mut len)
1120 };
1121 if ret != 0 {
1122 return None;
1123 }
1124
1125 LinkTypeInfo::KprobeMulti(KprobeMultiLinkInfo {
1126 count: unsafe { s.__bindgen_anon_1.kprobe_multi.count },
1127 flags: unsafe { s.__bindgen_anon_1.kprobe_multi.flags },
1128 missed: unsafe { s.__bindgen_anon_1.kprobe_multi.missed },
1129 addrs,
1130 cookies,
1131 _non_exhaustive: (),
1132 })
1133 }
1134 libbpf_sys::BPF_LINK_TYPE_UPROBE_MULTI => {
1135 let mut buf = [0u8; libc::PATH_MAX as usize];
1136 let count = unsafe { s.__bindgen_anon_1.uprobe_multi.count } as usize;
1137 let mut offsets = vec![0; count];
1138 let mut ref_ctr_offsets = vec![0; count];
1139 let mut cookies = vec![0; count];
1140
1141 s.__bindgen_anon_1.uprobe_multi.path = buf.as_mut_ptr() as u64;
1142 s.__bindgen_anon_1.uprobe_multi.path_size = buf.len() as u32;
1143 s.__bindgen_anon_1.uprobe_multi.offsets = offsets.as_mut_ptr() as u64;
1144 s.__bindgen_anon_1.uprobe_multi.ref_ctr_offsets =
1145 ref_ctr_offsets.as_mut_ptr() as u64;
1146 s.__bindgen_anon_1.uprobe_multi.cookies = cookies.as_mut_ptr() as u64;
1147 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
1148 let mut len = size_of_val(&s) as u32;
1149 let ret = unsafe {
1150 libbpf_sys::bpf_obj_get_info_by_fd(fd.as_raw_fd(), item_ptr.cast(), &mut len)
1151 };
1152 if ret != 0 {
1153 return None;
1154 }
1155
1156 let path_size = unsafe { s.__bindgen_anon_1.uprobe_multi.path_size };
1157 let path = if path_size != 0 {
1158 let path_ptr = unsafe { s.__bindgen_anon_1.uprobe_multi.path } as *const c_char;
1159 let c_str = unsafe { CStr::from_ptr(path_ptr) };
1160 Some(PathBuf::from(OsStr::from_bytes(c_str.to_bytes())))
1161 } else {
1162 None
1163 };
1164
1165 LinkTypeInfo::UprobeMulti(UprobeMultiLinkInfo {
1166 path_size,
1167 path,
1168 count: unsafe { s.__bindgen_anon_1.uprobe_multi.count },
1169 flags: unsafe { s.__bindgen_anon_1.uprobe_multi.flags },
1170 pid: unsafe { s.__bindgen_anon_1.uprobe_multi.pid },
1171 offsets,
1172 ref_ctr_offsets,
1173 cookies,
1174 _non_exhaustive: (),
1175 })
1176 }
1177 libbpf_sys::BPF_LINK_TYPE_SOCKMAP => LinkTypeInfo::SockMap(SockMapLinkInfo {
1178 map_id: unsafe { s.__bindgen_anon_1.sockmap.map_id },
1179 attach_type: ProgramAttachType::from(unsafe {
1180 s.__bindgen_anon_1.sockmap.attach_type
1181 }),
1182 _non_exhaustive: (),
1183 }),
1184 libbpf_sys::BPF_LINK_TYPE_PERF_EVENT => {
1185 let bpf_perf_event_type = unsafe { s.__bindgen_anon_1.perf_event.type_ };
1187
1188 let mut buf = [0u8; libc::PATH_MAX as usize];
1194 let call_get_info_again = match bpf_perf_event_type {
1195 libbpf_sys::BPF_PERF_EVENT_TRACEPOINT => {
1196 s.__bindgen_anon_1
1197 .perf_event
1198 .__bindgen_anon_1
1199 .tracepoint
1200 .tp_name = buf.as_mut_ptr() as u64;
1201 s.__bindgen_anon_1
1202 .perf_event
1203 .__bindgen_anon_1
1204 .tracepoint
1205 .name_len = buf.len() as u32;
1206 true
1207 }
1208 libbpf_sys::BPF_PERF_EVENT_KPROBE | libbpf_sys::BPF_PERF_EVENT_KRETPROBE => {
1209 s.__bindgen_anon_1
1210 .perf_event
1211 .__bindgen_anon_1
1212 .kprobe
1213 .func_name = buf.as_mut_ptr() as u64;
1214 s.__bindgen_anon_1
1215 .perf_event
1216 .__bindgen_anon_1
1217 .kprobe
1218 .name_len = buf.len() as u32;
1219 true
1220 }
1221 libbpf_sys::BPF_PERF_EVENT_UPROBE | libbpf_sys::BPF_PERF_EVENT_URETPROBE => {
1222 let uprobe =
1224 unsafe { &mut s.__bindgen_anon_1.perf_event.__bindgen_anon_1.uprobe };
1225 uprobe.file_name = buf.as_mut_ptr() as u64;
1226 uprobe.name_len = buf.len() as u32;
1227 true
1228 }
1229 _ => false,
1230 };
1231
1232 if call_get_info_again {
1233 let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
1234 let mut len = size_of_val(&s) as u32;
1235 let ret = unsafe {
1236 libbpf_sys::bpf_obj_get_info_by_fd(
1237 fd.as_raw_fd(),
1238 item_ptr.cast::<c_void>(),
1239 &mut len,
1240 )
1241 };
1242 if ret != 0 {
1243 return None;
1244 }
1245 }
1246
1247 let event_type = match bpf_perf_event_type {
1248 libbpf_sys::BPF_PERF_EVENT_TRACEPOINT => {
1249 let tp_name = unsafe {
1250 s.__bindgen_anon_1
1251 .perf_event
1252 .__bindgen_anon_1
1253 .tracepoint
1254 .tp_name
1255 };
1256 let cookie = unsafe {
1257 s.__bindgen_anon_1
1258 .perf_event
1259 .__bindgen_anon_1
1260 .tracepoint
1261 .cookie
1262 };
1263 let name = (tp_name != 0).then(|| unsafe {
1264 cstr_to_os_string(CStr::from_ptr(tp_name as *const c_char))
1265 });
1266
1267 PerfEventType::Tracepoint { name, cookie }
1268 }
1269 libbpf_sys::BPF_PERF_EVENT_KPROBE | libbpf_sys::BPF_PERF_EVENT_KRETPROBE => {
1270 let func_name = unsafe {
1271 s.__bindgen_anon_1
1272 .perf_event
1273 .__bindgen_anon_1
1274 .kprobe
1275 .func_name
1276 };
1277 let addr =
1278 unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.addr };
1279 let offset =
1280 unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.offset };
1281 let missed =
1282 unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.missed };
1283 let cookie =
1284 unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.cookie };
1285 let func_name = (func_name != 0).then(|| unsafe {
1286 cstr_to_os_string(CStr::from_ptr(func_name as *const c_char))
1287 });
1288
1289 let is_retprobe =
1290 bpf_perf_event_type == libbpf_sys::BPF_PERF_EVENT_KRETPROBE;
1291 PerfEventType::Kprobe {
1292 func_name,
1293 is_retprobe,
1294 addr,
1295 offset,
1296 missed,
1297 cookie,
1298 }
1299 }
1300 libbpf_sys::BPF_PERF_EVENT_UPROBE | libbpf_sys::BPF_PERF_EVENT_URETPROBE => {
1301 let uprobe =
1303 unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.uprobe };
1304 let file_name = (uprobe.file_name != 0).then(|| unsafe {
1306 cstr_to_os_string(CStr::from_ptr(uprobe.file_name as *const c_char))
1307 });
1308
1309 PerfEventType::Uprobe {
1310 file_name,
1311 is_retprobe: bpf_perf_event_type
1312 == libbpf_sys::BPF_PERF_EVENT_URETPROBE,
1313 offset: uprobe.offset,
1314 cookie: uprobe.cookie,
1315 ref_ctr_offset: uprobe.ref_ctr_offset,
1316 }
1317 }
1318 libbpf_sys::BPF_PERF_EVENT_EVENT => {
1319 let event = unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.event };
1321
1322 PerfEventType::Event {
1323 config: event.config,
1324 event_type: event.type_,
1325 cookie: event.cookie,
1326 }
1327 }
1328 ty => PerfEventType::Unknown(ty),
1329 };
1330
1331 LinkTypeInfo::PerfEvent(PerfEventLinkInfo {
1332 event_type,
1333 _non_exhaustive: (),
1334 })
1335 }
1336 _ => LinkTypeInfo::Unknown,
1337 };
1338
1339 Some(Self {
1340 info: type_info,
1341 id: s.id,
1342 prog_id: s.prog_id,
1343 })
1344 }
1345}
1346
1347gen_info_impl!(
1348 LinkInfoIter,
1350 LinkInfo,
1351 libbpf_sys::bpf_link_info,
1352 libbpf_sys::bpf_link_get_next_id,
1353 libbpf_sys::bpf_link_get_fd_by_id
1354);