Skip to main content

libbpf_rs/
query.rs

1//! Query the host about BPF
2//!
3//! For example, to list the name of every bpf program running on the system:
4//! ```
5//! use libbpf_rs::query::ProgInfoIter;
6//!
7//! let mut iter = ProgInfoIter::default();
8//! for prog in iter {
9//!     println!("{}", prog.name.to_string_lossy());
10//! }
11//! ```
12
13use 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
38/// Convert a [`CStr`] into an owned [`OsString`].
39fn cstr_to_os_string(s: &CStr) -> OsString {
40    OsStr::from_bytes(s.to_bytes()).to_owned()
41}
42
43macro_rules! gen_info_impl {
44    // This magic here allows us to embed doc comments into macro expansions
45    ($(#[$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            // Returns Some(next_valid_fd), None on none left
55            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                // We need to use std::mem::zeroed() instead of just using
83                // ::default() because padding bytes need to be zero as well.
84                // Old kernels which know about fewer fields than we do will
85                // check to make sure every byte past what they know is zero
86                // and will return E2BIG otherwise.
87                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/// BTF Line information.
105#[derive(Clone, Debug)]
106pub struct LineInfo {
107    /// Offset of instruction in vector.
108    pub insn_off: u32,
109    /// File name offset.
110    pub file_name_off: u32,
111    /// Line offset in debug info.
112    pub line_off: u32,
113    /// Line number.
114    pub line_num: u32,
115    /// Line column number.
116    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/// Bpf identifier tag.
132#[derive(Debug, Clone, Default)]
133#[repr(C)]
134pub struct Tag(pub [u8; 8]);
135
136/// Information about a BPF program. Maps to `struct bpf_prog_info` in kernel uapi.
137#[derive(Debug, Clone)]
138pub struct ProgramInfo {
139    /// A user-defined name for the BPF program.
140    pub name: OsString,
141    /// The type of the program.
142    pub ty: ProgramType,
143    /// An 8-byte hash (`BPF_TAG_SIZE`) computed from the program's
144    /// contents; used to detect changes in the program code.
145    pub tag: Tag,
146    /// A unique identifier for the program instance.
147    pub id: u32,
148    /// JIT-compiled instructions.
149    pub jited_prog_insns: Vec<u8>,
150    /// Translated BPF instructions in an intermediate representation.
151    pub xlated_prog_insns: Vec<u8>,
152    /// Time (since system boot) at which the program was loaded.
153    pub load_time: Duration,
154    /// UID of the user who loaded the program.
155    pub created_by_uid: u32,
156    /// Array of map IDs associated with this program.
157    pub map_ids: Vec<u32>,
158    /// Network interface index if the program is attached to a specific device.
159    pub ifindex: u32,
160    /// Whether the program is GPL compatible.
161    pub gpl_compatible: bool,
162    /// Device ID of the network namespace that the program is associated with.
163    pub netns_dev: u64,
164    /// Inode number of the network namespace associated with the program.
165    pub netns_ino: u64,
166    /// Number of kernel symbols in the JITed code (if available).
167    pub jited_ksyms: Vec<*const c_void>,
168    /// Number of function length records available for the JITed code.
169    pub jited_func_lens: Vec<u32>,
170    /// Identifier of the associated BTF (BPF Type Format) data.
171    pub btf_id: u32,
172    /// Size (in bytes) of each record in the function info array.
173    pub func_info_rec_size: u32,
174    /// Array of function info records for this program.
175    pub func_info: Vec<libbpf_sys::bpf_func_info>,
176    /// Array of line info records mapping BPF instructions to source code lines.
177    pub line_info: Vec<LineInfo>,
178    /// Line info records for the JIT-compiled code.
179    pub jited_line_info: Vec<*const c_void>,
180    /// Size (in bytes) of each line info record.
181    pub line_info_rec_size: u32,
182    /// Size (in bytes) of each record in the JITed line info array.
183    pub jited_line_info_rec_size: u32,
184    /// Array of program tags.
185    pub prog_tags: Vec<Tag>,
186    /// Total accumulated run time (in nanoseconds) for the program's execution.
187    pub run_time_ns: u64,
188    /// Total number of times the program has been executed.
189    pub run_cnt: u64,
190    /// Skipped BPF executions due to recursion or concurrent execution prevention.
191    pub recursion_misses: u64,
192    /// Number of instructions that were verified by the verifier.
193    pub verified_insns: u32,
194    /// The struct is non-exhaustive and open to extension.
195    #[doc(hidden)]
196    pub _non_exhaustive: (),
197}
198
199/// An iterator for the information of loaded bpf programs.
200#[derive(Default, Debug)]
201pub struct ProgInfoIter {
202    cur_id: u32,
203    opts: ProgInfoQueryOptions,
204}
205
206/// Options to query the program info currently loaded.
207#[derive(Clone, Default, Debug)]
208pub struct ProgInfoQueryOptions {
209    /// Include the vector of bpf instructions in the result.
210    include_xlated_prog_insns: bool,
211    /// Include the vector of jited instructions in the result.
212    include_jited_prog_insns: bool,
213    /// Include the ids of maps associated with the program.
214    include_map_ids: bool,
215    /// Include source line information corresponding to xlated code.
216    include_line_info: bool,
217    /// Include function type information corresponding to xlated code.
218    include_func_info: bool,
219    /// Include source line information corresponding to jited code.
220    include_jited_line_info: bool,
221    /// Include function type information corresponding to jited code.
222    include_jited_func_lens: bool,
223    /// Include program tags.
224    include_prog_tags: bool,
225    /// Include the jited kernel symbols.
226    include_jited_ksyms: bool,
227}
228
229impl ProgInfoIter {
230    /// Generate an iter from more specific query options.
231    pub fn with_query_opts(opts: ProgInfoQueryOptions) -> Self {
232        Self {
233            opts,
234            ..Self::default()
235        }
236    }
237}
238
239impl ProgInfoQueryOptions {
240    /// Include the vector of jited bpf instructions in the result.
241    pub fn include_xlated_prog_insns(mut self, v: bool) -> Self {
242        self.include_xlated_prog_insns = v;
243        self
244    }
245
246    /// Include the vector of jited instructions in the result.
247    pub fn include_jited_prog_insns(mut self, v: bool) -> Self {
248        self.include_jited_prog_insns = v;
249        self
250    }
251
252    /// Include the ids of maps associated with the program.
253    pub fn include_map_ids(mut self, v: bool) -> Self {
254        self.include_map_ids = v;
255        self
256    }
257
258    /// Include source line information corresponding to xlated code.
259    pub fn include_line_info(mut self, v: bool) -> Self {
260        self.include_line_info = v;
261        self
262    }
263
264    /// Include function type information corresponding to xlated code.
265    pub fn include_func_info(mut self, v: bool) -> Self {
266        self.include_func_info = v;
267        self
268    }
269
270    /// Include source line information corresponding to jited code.
271    pub fn include_jited_line_info(mut self, v: bool) -> Self {
272        self.include_jited_line_info = v;
273        self
274    }
275
276    /// Include function type information corresponding to jited code.
277    pub fn include_jited_func_lens(mut self, v: bool) -> Self {
278        self.include_jited_func_lens = v;
279        self
280    }
281
282    /// Include program tags.
283    pub fn include_prog_tags(mut self, v: bool) -> Self {
284        self.include_prog_tags = v;
285        self
286    }
287
288    /// Include the jited kernel symbols.
289    pub fn include_jited_ksyms(mut self, v: bool) -> Self {
290        self.include_jited_ksyms = v;
291        self
292    }
293
294    /// Include everything there is in the query results.
295    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        // SANITY: `libbpf` should guarantee NUL termination.
333        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/// Information about a BPF map. Maps to `struct bpf_map_info` in kernel uapi.
475#[derive(Debug, Clone)]
476pub struct MapInfo {
477    /// A user-defined name for the BPF Map.
478    pub name: OsString,
479    /// The BPF map type.
480    pub ty: MapType,
481    /// A unique identifier for this map instance.
482    pub id: u32,
483    /// Size (in bytes) of the keys stored in the map.
484    pub key_size: u32,
485    /// Size (in bytes) of the values stored in the map.
486    pub value_size: u32,
487    /// Maximum number of entries that the map can hold.
488    pub max_entries: u32,
489    /// Map flags indicating specific properties (e.g., `BPF_F_NO_PREALLOC`).
490    pub map_flags: u32,
491    /// Network interface index if the map is associated with a specific device. Otherwise, this
492    /// may be zero.
493    pub ifindex: u32,
494    /// BTF (BPF Type Format) type ID for the value type as defined in the vmlinux BTF data.
495    pub btf_vmlinux_value_type_id: u32,
496    /// Device identifier of the network namespace.
497    pub netns_dev: u64,
498    /// Inode number of the network namespace.
499    pub netns_ino: u64,
500    /// BTF ID referencing the BTF data for this map. This helps to verify the correctness of the
501    /// map's data structure as per BTF metadata.
502    pub btf_id: u32,
503    /// BTF type ID for the key type.
504    pub btf_key_type_id: u32,
505    /// BTF type ID for the value type.
506    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        // SANITY: `libbpf` should guarantee NUL termination.
512        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    /// Iterator that returns [`MapInfo`]s.
536    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/// Information about BPF type format.
544#[derive(Debug, Clone)]
545pub struct BtfInfo {
546    /// The name associated with this btf information in the kernel.
547    pub name: OsString,
548    /// The raw btf bytes from the kernel.
549    pub btf: Vec<u8>,
550    /// The btf id associated with this btf information in the kernel.
551    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        // The API gives you the ascii string length while expecting
569        // you to give it back space for a nul-terminator
570        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            // SANITY: Our buffer contained space for a NUL byte and we set its
584            //         contents to 0. Barring a `libbpf` bug a NUL byte will be
585            //         present.
586            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)]
594/// An iterator for the btf type information of modules and programs
595/// in the kernel
596pub struct BtfInfoIter {
597    cur_id: u32,
598}
599
600impl BtfInfoIter {
601    // Returns Some(next_valid_fd), None on none left
602    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/// Information about a raw tracepoint.
633#[derive(Debug, Clone)]
634pub struct RawTracepointLinkInfo {
635    /// The name of the raw tracepoint.
636    pub name: String,
637    /// The struct is non-exhaustive and open to extension.
638    #[doc(hidden)]
639    pub _non_exhaustive: (),
640}
641
642/// Information about a tracing link
643#[derive(Debug, Clone)]
644pub struct TracingLinkInfo {
645    /// Attach type of the tracing link.
646    pub attach_type: ProgramAttachType,
647    /// Target object ID (`prog_id` for [`ProgramType::Ext`], otherwise
648    /// BTF object id).
649    pub target_obj_id: u32,
650    /// BTF type id inside the target object.
651    pub target_btf_id: u32,
652    /// The struct is non-exhaustive and open to extension.
653    #[doc(hidden)]
654    pub _non_exhaustive: (),
655}
656
657/// Information about a cgroup link
658#[derive(Debug, Clone)]
659pub struct CgroupLinkInfo {
660    /// Identifier of the target cgroup.
661    pub cgroup_id: u64,
662    /// Attachment type for cgroup-based programs.
663    pub attach_type: ProgramAttachType,
664    /// The struct is non-exhaustive and open to extension.
665    #[doc(hidden)]
666    pub _non_exhaustive: (),
667}
668
669/// Information about a BPF iterator link.
670#[derive(Debug, Clone)]
671pub struct IterLinkInfo {
672    /// The `bpf_iter__*` target name.
673    pub target_name: OsString,
674    /// Specific BPF iterator information.
675    pub iter_type: IterType,
676    /// The struct is non-exhaustive and open to extension.
677    #[doc(hidden)]
678    pub _non_exhaustive: (),
679}
680
681/// Specific BPF iterator types with decoded information.
682#[derive(Debug, Clone)]
683pub enum IterType {
684    /// A map type iterator.
685    Map {
686        /// The ID of the map being iterated.
687        map_id: u32,
688    },
689    /// A cgroup type iterator.
690    Cgroup {
691        /// The cgroup ID of where the iterator starts.
692        cgroup_id: u64,
693        /// The order in how the iterator traverses.
694        order: CgroupIterOrder,
695    },
696    /// A task type iterator.
697    Task {
698        /// Specific thread that is iterated over.
699        tid: u32,
700        /// Specific process that is iterated over.
701        pid: u32,
702    },
703    /// An unknown or unsupported iterator type.
704    ///
705    /// The [`target_name`](IterLinkInfo::target_name) can still be used to
706    /// identify the iterator.
707    Unknown,
708}
709
710/// Information about a network namespace link.
711#[derive(Debug, Clone)]
712pub struct NetNsLinkInfo {
713    /// Inode number of the network namespace.
714    pub ino: u32,
715    /// Attachment type for network namespace programs.
716    pub attach_type: ProgramAttachType,
717    /// The struct is non-exhaustive and open to extension.
718    #[doc(hidden)]
719    pub _non_exhaustive: (),
720}
721
722/// Information about a BPF netfilter link.
723#[derive(Debug, Clone)]
724pub struct NetfilterLinkInfo {
725    /// Protocol family of the netfilter hook.
726    pub protocol_family: u32,
727    /// Netfilter hook number.
728    pub hooknum: u32,
729    /// Priority of the netfilter link.
730    pub priority: i32,
731    /// Flags used for the netfilter link.
732    pub flags: u32,
733    /// The struct is non-exhaustive and open to extension.
734    #[doc(hidden)]
735    pub _non_exhaustive: (),
736}
737
738/// Information about a XDP link.
739#[derive(Debug, Clone)]
740pub struct XdpLinkInfo {
741    /// Interface index to which the XDP link is attached.
742    pub ifindex: u32,
743    /// The struct is non-exhaustive and open to extension.
744    #[doc(hidden)]
745    pub _non_exhaustive: (),
746}
747
748/// Information about a BPF sockmap link.
749#[derive(Debug, Clone)]
750pub struct SockMapLinkInfo {
751    /// The ID of the BPF sockmap.
752    pub map_id: u32,
753    /// The type of program attached to the sockmap.
754    pub attach_type: ProgramAttachType,
755    /// The struct is non-exhaustive and open to extension.
756    #[doc(hidden)]
757    pub _non_exhaustive: (),
758}
759
760/// Information about a BPF netkit link.
761#[derive(Debug, Clone)]
762pub struct NetkitLinkInfo {
763    /// Interface index to which the netkit link is attached.
764    pub ifindex: u32,
765    /// Type of program attached to the netkit link.
766    pub attach_type: ProgramAttachType,
767    /// The struct is non-exhaustive and open to extension.
768    #[doc(hidden)]
769    pub _non_exhaustive: (),
770}
771
772/// Information about a BPF tc link.
773#[derive(Debug, Clone)]
774pub struct TcxLinkInfo {
775    /// Interface index to which the tc link is attached.
776    pub ifindex: u32,
777    /// Type of program attached to the tc link.
778    pub attach_type: ProgramAttachType,
779    /// The struct is non-exhaustive and open to extension.
780    #[doc(hidden)]
781    pub _non_exhaustive: (),
782}
783
784/// Information about a BPF `struct_ops` link.
785#[derive(Debug, Clone)]
786pub struct StructOpsLinkInfo {
787    /// The ID of the BPF map to which the `struct_ops` link is attached.
788    pub map_id: u32,
789    /// The struct is non-exhaustive and open to extension.
790    #[doc(hidden)]
791    pub _non_exhaustive: (),
792}
793
794/// Information about a multi-kprobe link.
795#[derive(Debug, Clone)]
796pub struct KprobeMultiLinkInfo {
797    /// Count of kprobe targets.
798    pub count: u32,
799    /// Flags for the link.
800    pub flags: u32,
801    /// Missed probes count.
802    pub missed: u64,
803    /// Addresses of the probe.
804    pub addrs: Vec<u64>,
805    /// Cookies corresponding to the attach addresses.
806    pub cookies: Vec<u64>,
807    /// The struct is non-exhaustive and open to extension.
808    #[doc(hidden)]
809    pub _non_exhaustive: (),
810}
811
812/// Information about a multi-uprobe link.
813#[derive(Debug, Clone)]
814pub struct UprobeMultiLinkInfo {
815    /// Size of the path.
816    pub path_size: u32,
817    /// The absolute file path of the binary being probed.
818    pub path: Option<PathBuf>,
819    /// Count of uprobe targets.
820    pub count: u32,
821    /// Flags for the link.
822    pub flags: u32,
823    /// PID to which the uprobe is attached.
824    pub pid: u32,
825    /// Offsets from the binary.
826    pub offsets: Vec<u64>,
827    /// Offsets of kernel reference counted USDT semaphore.
828    pub ref_ctr_offsets: Vec<u64>,
829    /// Cookies corresponding to the attach addresses.
830    pub cookies: Vec<u64>,
831    /// The struct is non-exhaustive and open to extension.
832    #[doc(hidden)]
833    pub _non_exhaustive: (),
834}
835
836/// Information about a perf event link.
837#[derive(Debug, Clone)]
838pub struct PerfEventLinkInfo {
839    /// The specific type of perf event with decoded information.
840    pub event_type: PerfEventType,
841    /// The struct is non-exhaustive and open to extension.
842    #[doc(hidden)]
843    pub _non_exhaustive: (),
844}
845
846/// Specific types of perf events with decoded information.
847#[derive(Debug, Clone)]
848pub enum PerfEventType {
849    /// A tracepoint event.
850    Tracepoint {
851        /// The tracepoint name.
852        name: Option<OsString>,
853        /// Attach cookie value for this link.
854        cookie: u64,
855    },
856    /// A kprobe event (includes both kprobe and kretprobe).
857    Kprobe {
858        /// The function being probed.
859        func_name: Option<OsString>,
860        /// Whether this is a return probe (kretprobe).
861        is_retprobe: bool,
862        /// Address of the probe.
863        addr: u64,
864        /// Offset from the function.
865        offset: u32,
866        /// Number of missed events.
867        missed: u64,
868        /// Cookie value for the kprobe.
869        cookie: u64,
870    },
871    /// A uprobe event (includes both uprobe and uretprobe).
872    Uprobe {
873        /// The absolute file path of the binary being probed.
874        file_name: Option<OsString>,
875        /// Whether this is a return probe (uretprobe).
876        is_retprobe: bool,
877        /// Offset from the binary.
878        offset: u32,
879        /// Cookie value for the uprobe.
880        cookie: u64,
881        /// Offset of kernel reference counted USDT semaphore.
882        ref_ctr_offset: u64,
883    },
884    /// A perf event.
885    Event {
886        /// The specific event of the perf event type.
887        config: u64,
888        /// The perf event type.
889        event_type: u32,
890        /// Cookie value for the perf event program.
891        cookie: u64,
892    },
893    /// An unknown or unsupported perf event type.
894    Unknown(u32),
895}
896
897/// Information about BPF link types. Maps to the anonymous union in `struct bpf_link_info` in
898/// kernel uapi.
899#[derive(Debug, Clone)]
900pub enum LinkTypeInfo {
901    /// Link type for raw tracepoints.
902    ///
903    /// Contains information about the BPF program directly to a raw tracepoint.
904    RawTracepoint(RawTracepointLinkInfo),
905    /// Tracing link type.
906    Tracing(TracingLinkInfo),
907    /// Link type for cgroup programs.
908    ///
909    /// Contains information about the cgroups and its attachment type.
910    Cgroup(CgroupLinkInfo),
911    /// Iterator link type.
912    Iter(IterLinkInfo),
913    /// Network namespace link type.
914    NetNs(NetNsLinkInfo),
915    /// Link type for XDP programs.
916    ///
917    /// Contains information about the XDP link, such as the interface index
918    /// to which the XDP link is attached.
919    Xdp(XdpLinkInfo),
920    /// Link type for `struct_ops` programs.
921    ///
922    /// Contains information about the BPF map to which the `struct_ops` link is
923    /// attached.
924    StructOps(StructOpsLinkInfo),
925    /// Link type for netfilter programs.
926    Netfilter(NetfilterLinkInfo),
927    /// Link type for kprobe-multi links.
928    KprobeMulti(KprobeMultiLinkInfo),
929    /// Link type for multi-uprobe links.
930    UprobeMulti(UprobeMultiLinkInfo),
931    /// Link type for TC programs.
932    Tcx(TcxLinkInfo),
933    /// Link type for netkit programs.
934    Netkit(NetkitLinkInfo),
935    /// Link type for sockmap programs.
936    SockMap(SockMapLinkInfo),
937    /// Link type for perf-event programs.
938    ///
939    /// Contains information about the perf event configuration including type and config
940    /// which can be used to identify tracepoints, kprobes, uprobes, etc.
941    PerfEvent(PerfEventLinkInfo),
942    /// Unknown link type.
943    Unknown,
944}
945
946/// Information about a BPF link. Maps to `struct bpf_link_info` in kernel uapi.
947#[derive(Debug, Clone)]
948pub struct LinkInfo {
949    /// Information about the BPF link type.
950    pub info: LinkTypeInfo,
951    /// Unique identifier of the BPF link.
952    pub id: u32,
953    /// ID of the BPF program attached via this link.
954    pub prog_id: u32,
955}
956
957impl LinkInfo {
958    /// Create a `LinkInfo` object from a fd.
959    pub fn from_fd(fd: BorrowedFd<'_>) -> Result<Self> {
960        // See comment in gen_info_impl!() for why we use std::mem::zeroed()
961        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                // On a successful call the kernel always reports the target name
1033                // (its length is `strlen(target) + 1`) and copies it into `buf`,
1034                // so it is guaranteed to be present here.
1035                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                // Get the BPF perf event type (BPF_PERF_EVENT_*) from the link info.
1186                let bpf_perf_event_type = unsafe { s.__bindgen_anon_1.perf_event.type_ };
1187
1188                // Handle two-phase call for perf event string data if needed (this mimics the
1189                // behavior of bpftool):
1190                // For tracepoints, kprobes, and uprobes, we need to pass in a buffer to get the
1191                // name. So we initialize the struct with a buffer pointer, and call
1192                // `bpf_obj_get_info_by_fd` again to populate the name.
1193                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                        // SAFETY: This field is valid to access in `bpf_link_info`.
1223                        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                        // SAFETY: This field is valid to access in `bpf_link_info`.
1302                        let uprobe =
1303                            unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.uprobe };
1304                        // SAFETY: `file_name_ptr` is a valid nul terminated string pointer.
1305                        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                        // SAFETY: This field is valid to access in `bpf_link_info`.
1320                        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    /// Iterator that returns [`LinkInfo`]s.
1349    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);