Skip to main content

libbpf_rs/
linker.rs

1use std::path::Path;
2use std::ptr::null_mut;
3use std::ptr::NonNull;
4
5use crate::util::path_to_cstring;
6use crate::util::validate_bpf_ret;
7use crate::AsRawLibbpf;
8use crate::Error;
9use crate::ErrorExt as _;
10use crate::Result;
11
12/// A type used for linking multiple BPF object files into a single one.
13///
14/// Please refer to
15/// <https://lwn.net/ml/bpf/20210310040431.916483-6-andrii@kernel.org/> for
16/// additional details.
17#[derive(Debug)]
18#[doc(alias = "bpf_linker")]
19pub struct Linker {
20    /// The `libbpf` linker object.
21    linker: NonNull<libbpf_sys::bpf_linker>,
22}
23
24impl Linker {
25    /// Instantiate a `Linker` object.
26    #[doc(alias = "bpf_linker__new")]
27    pub fn new<P>(output: P) -> Result<Self>
28    where
29        P: AsRef<Path>,
30    {
31        let output = path_to_cstring(output)?;
32        let opts = null_mut();
33        // SAFETY: `output` is a valid pointer and `opts` is accepted as NULL.
34        let ptr = unsafe { libbpf_sys::bpf_linker__new(output.as_ptr(), opts) };
35        let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
36        let slf = Self { linker: ptr };
37        Ok(slf)
38    }
39
40    /// Add a file to the set of files to link.
41    #[doc(alias = "bpf_linker__add_file")]
42    pub fn add_file<P>(&mut self, file: P) -> Result<()>
43    where
44        P: AsRef<Path>,
45    {
46        let file = path_to_cstring(file)?;
47        let opts = null_mut();
48        // SAFETY: `linker` and `file` are a valid pointers.
49        let err =
50            unsafe { libbpf_sys::bpf_linker__add_file(self.linker.as_ptr(), file.as_ptr(), opts) };
51        if err != 0 {
52            Err(Error::from_raw_os_error(err)).context("bpf_linker__add_file failed")
53        } else {
54            Ok(())
55        }
56    }
57
58    /// Add a buffer to the set of objects to link.
59    #[doc(alias = "bpf_linker__add_buf")]
60    pub fn add_buf(&mut self, buf: &[u8]) -> Result<()> {
61        let opts = null_mut();
62        // SAFETY: `linker` and `buf` are valid pointers.
63        let err = unsafe {
64            libbpf_sys::bpf_linker__add_buf(
65                self.linker.as_ptr(),
66                buf.as_ptr().cast_mut().cast(),
67                buf.len() as _,
68                opts,
69            )
70        };
71        if err != 0 {
72            Err(Error::from_raw_os_error(err)).context("bpf_linker__add_buf failed")
73        } else {
74            Ok(())
75        }
76    }
77
78    /// Link all BPF object files [added](Self::add_file) to this object into
79    /// a single one.
80    #[doc(alias = "bpf_linker__finalize")]
81    pub fn link(&self) -> Result<()> {
82        // SAFETY: `linker` is a valid pointer.
83        let err = unsafe { libbpf_sys::bpf_linker__finalize(self.linker.as_ptr()) };
84        if err != 0 {
85            return Err(Error::from_raw_os_error(err)).context("bpf_linker__finalize failed");
86        }
87        Ok(())
88    }
89}
90
91impl AsRawLibbpf for Linker {
92    type LibbpfType = libbpf_sys::bpf_linker;
93
94    /// Retrieve the underlying [`libbpf_sys::bpf_linker`].
95    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
96        self.linker
97    }
98}
99
100// SAFETY: `bpf_linker` can be sent to a different thread.
101unsafe impl Send for Linker {}
102
103impl Drop for Linker {
104    #[doc(alias = "bpf_linker__free")]
105    fn drop(&mut self) {
106        // SAFETY: `linker` is a valid pointer returned by `bpf_linker__new`.
107        unsafe { libbpf_sys::bpf_linker__free(self.linker.as_ptr()) }
108    }
109}
110
111#[cfg(test)]
112mod test {
113    use super::*;
114
115    /// Check that `Linker` is `Send`.
116    #[test]
117    fn linker_is_send() {
118        fn test<T>()
119        where
120            T: Send,
121        {
122        }
123
124        test::<Linker>();
125    }
126}