bpf_script/formats/
btf.rs

1use crate::error::{Error, Result};
2use crate::types::{Array, BaseType, Field, Float, Integer, Struct, Type, TypeDatabase};
3
4use btf::{
5    Array as BtfArray, Btf, Float as BtfFloat, Integer as BtfInteger, Struct as BtfStruct,
6    Type as BtfType,
7};
8
9use std::collections::HashMap;
10
11impl TypeDatabase {
12    /// Adds a void type.
13    ///
14    /// # Arguments
15    ///
16    /// * `name` - The optional name of the type.
17    /// * `num_refs` - The reference count on the type.
18    fn add_btf_void(&mut self, name: Option<&str>, num_refs: u32) -> Result<usize> {
19        let new_type = Type {
20            base_type: BaseType::Void,
21            num_refs,
22        };
23
24        self.add_type(name, &new_type)
25    }
26
27    /// Adds a BTF integer type.
28    ///
29    /// # Arguments
30    ///
31    /// * `name` - The optional name of the type.
32    /// * `integer` - The BTF integer to add.
33    /// * `num_refs` - The reference count on the type.
34    fn add_btf_integer(
35        &mut self,
36        name: Option<&str>,
37        integer: &BtfInteger,
38        num_refs: u32,
39    ) -> Result<usize> {
40        let base_type = BaseType::Integer(Integer {
41            used_bits: integer.used_bits,
42            bits: integer.bits,
43            is_signed: integer.is_signed,
44        });
45
46        let new_type = Type {
47            base_type,
48            num_refs,
49        };
50
51        self.add_type(name, &new_type)
52    }
53
54    /// Adds a BTF float type.
55    ///
56    /// # Arguments
57    ///
58    /// * `name` - The optional name of the type.
59    /// * `float` - The BTF float to add.
60    /// * `num_refs` - The reference count on the type.
61    fn add_btf_float(
62        &mut self,
63        name: Option<&str>,
64        float: &BtfFloat,
65        num_refs: u32,
66    ) -> Result<usize> {
67        let base_type = BaseType::Float(Float { bits: float.bits });
68
69        let new_type = Type {
70            base_type,
71            num_refs,
72        };
73
74        self.add_type(name, &new_type)
75    }
76
77    /// Adds a BTF array type.
78    ///
79    /// # Arguments
80    ///
81    /// * `name` - The optional name of the type.
82    /// * `array` - The BTF array to add.
83    /// * `num_refs` - The reference count on the type.
84    fn add_btf_array(
85        &mut self,
86        name: Option<&str>,
87        array: &BtfArray,
88        num_refs: u32,
89    ) -> Result<usize> {
90        let btf_id_name = format!(".btf.{}", array.elem_type_id);
91        let element_type_id = self
92            .get_type_id_by_name(&btf_id_name)
93            .ok_or(Error::NoConversion)?;
94        let base_type = BaseType::Array(Array::create(self, element_type_id, array.num_elements)?);
95        let new_type = Type {
96            base_type,
97            num_refs,
98        };
99        self.add_type(name, &new_type)
100    }
101
102    /// Adds a BTF struct type.
103    ///
104    /// # Arguments
105    ///
106    /// * `name` - The optional name of the type.
107    /// * `structure` - The BTF struct to add.
108    /// * `num_refs` - The reference count on the type.
109    fn add_btf_struct(
110        &mut self,
111        name: Option<&str>,
112        structure: &BtfStruct,
113        num_refs: u32,
114    ) -> Result<usize> {
115        let mut size = 0;
116        let mut fields = HashMap::with_capacity(structure.members.len());
117        for (i, member) in structure.members.iter().enumerate() {
118            let btf_id_name = format!(".btf.{}", member.type_id);
119            let type_id = self
120                .get_type_id_by_name(&btf_id_name)
121                .ok_or(Error::NoConversion)?;
122            let field = Field {
123                offset: member.offset,
124                type_id,
125            };
126
127            let field_type = self
128                .get_type_by_name(&btf_id_name)
129                .ok_or(Error::NoConversion)?;
130            let field_size = (member.offset + field_type.get_size() * 8) / 8;
131            if field_size > size {
132                size = field_size;
133            }
134
135            if let Some(member_name) = &member.name {
136                fields.insert(member_name.to_string(), field);
137            } else {
138                let member_name = format!("{}", i);
139                fields.insert(member_name, field);
140            }
141        }
142
143        let base_type = BaseType::Struct(Struct { size, fields });
144        let new_type = Type {
145            base_type,
146            num_refs,
147        };
148        self.add_type(name, &new_type)
149    }
150
151    /// Adds a BTF type to the database.
152    ///
153    /// # Arguments
154    ///
155    /// * `name` - The optional name of the type.
156    /// * `btf_type` - The BTF type.
157    /// * `num_refs` - The reference count on the type.
158    fn add_btf_type(
159        &mut self,
160        name: Option<&str>,
161        btf_type: &BtfType,
162        num_refs: u32,
163    ) -> Result<usize> {
164        match btf_type {
165            BtfType::Integer(integer) => self.add_btf_integer(name, integer, num_refs),
166            BtfType::Float(float) => self.add_btf_float(name, float, num_refs),
167            BtfType::Array(array) => self.add_btf_array(name, array, num_refs),
168            BtfType::Struct(structure) => self.add_btf_struct(name, structure, num_refs),
169            _ => self.add_btf_void(name, num_refs),
170        }
171    }
172
173    /// Adds a parsed list of BTF types to this type database.
174    ///
175    /// # Arguments
176    ///
177    /// * `name` - The optional name of the type.
178    /// * `btf` - The BTF types.
179    ///
180    /// # Example
181    /// ```
182    /// use bpf_script::types::TypeDatabase;
183    /// use btf::Btf;
184    ///
185    /// let btf = Btf::from_file("/sys/kernel/btf/vmlinux").expect("Failed to parse vmlinux btf");
186    /// let mut database = TypeDatabase::default();
187    ///
188    /// database
189    ///     .add_btf_types(&btf)
190    ///     .expect("failed to add btf types");
191    /// database
192    ///     .get_type_by_name("task_struct")
193    ///     .expect("Couldn't find task_struct");
194    /// ```
195    pub fn add_btf_types(&mut self, btf: &Btf) -> Result<()> {
196        // Types can forward reference, add placeholder for each.
197        for i in 0..btf.get_types().len() {
198            let btf_id_name = format!(".btf.{}", i);
199            self.add_btf_void(Some(&btf_id_name), 0)?;
200        }
201
202        for (i, btf_type) in btf.get_types().iter().enumerate() {
203            let btf_id_name = format!(".btf.{}", i);
204            self.add_btf_type(Some(&btf_id_name), &btf_type.base_type, btf_type.num_refs)?;
205            self.add_btf_type(
206                btf_type.name.as_deref(),
207                &btf_type.base_type,
208                btf_type.num_refs,
209            )?;
210        }
211
212        Ok(())
213    }
214}