btf_rs/
cbtf.rs

1//! Parsing logic for the C representation of the BTF data. See,
2//! <https://www.kernel.org/doc/html/latest/bpf/btf.html>
3//!
4//! Please use a packed C representation so mem::size_of can be used.
5
6#![allow(non_camel_case_types, dead_code)]
7
8use std::io::Read;
9
10use anyhow::{bail, Result};
11use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
12
13pub(super) enum Endianness {
14    Little,
15    Big,
16}
17
18impl Endianness {
19    fn u16_from_reader<R: Read>(&self, reader: &mut R) -> Result<u16, std::io::Error> {
20        match &self {
21            Endianness::Little => reader.read_u16::<LittleEndian>(),
22            Endianness::Big => reader.read_u16::<BigEndian>(),
23        }
24    }
25
26    fn u32_from_reader<R: Read>(&self, reader: &mut R) -> Result<u32, std::io::Error> {
27        match &self {
28            Endianness::Little => reader.read_u32::<LittleEndian>(),
29            Endianness::Big => reader.read_u32::<BigEndian>(),
30        }
31    }
32
33    fn i32_from_reader<R: Read>(&self, reader: &mut R) -> Result<i32, std::io::Error> {
34        match &self {
35            Endianness::Little => reader.read_i32::<LittleEndian>(),
36            Endianness::Big => reader.read_i32::<BigEndian>(),
37        }
38    }
39}
40
41#[derive(Clone, Copy, Debug)]
42#[repr(C, packed)]
43pub(super) struct btf_header {
44    pub(super) magic: u16,
45    pub(super) version: u8,
46    pub(super) flags: u8,
47    pub(super) hdr_len: u32,
48    pub(super) type_off: u32,
49    pub(super) type_len: u32,
50    pub(super) str_off: u32,
51    pub(super) str_len: u32,
52}
53
54impl btf_header {
55    pub(super) fn from_reader<R: Read>(reader: &mut R) -> Result<(btf_header, Endianness)> {
56        let magic = reader.read_u16::<LittleEndian>()?;
57        #[allow(clippy::mixed_case_hex_literals)]
58        let endianness = match magic {
59            0xeB9F => Endianness::Little,
60            0x9FeB => Endianness::Big,
61            magic => bail!("Invalid BTF magic: {:#x}", magic),
62        };
63
64        Ok((
65            btf_header {
66                magic,
67                version: reader.read_u8()?,
68                flags: reader.read_u8()?,
69                hdr_len: endianness.u32_from_reader(reader)?,
70                type_off: endianness.u32_from_reader(reader)?,
71                type_len: endianness.u32_from_reader(reader)?,
72                str_off: endianness.u32_from_reader(reader)?,
73                str_len: endianness.u32_from_reader(reader)?,
74            },
75            endianness,
76        ))
77    }
78}
79
80#[derive(Clone, Copy, Debug)]
81#[repr(C, packed)]
82pub(super) struct btf_type {
83    pub(super) name_off: u32,
84    // bits 0-15:  vlen
85    // bits 16-23: unused
86    // bits 24-28: kind
87    // bits 39-30: unused
88    // bit  31:    kind_flag
89    info: u32,
90    // union {
91    //         _u32 size;
92    //         _u32 type;
93    // };
94    size_type: u32,
95}
96
97impl btf_type {
98    pub(super) fn from_reader<R: Read>(
99        reader: &mut R,
100        endianness: &Endianness,
101    ) -> Result<btf_type> {
102        Ok(btf_type {
103            name_off: endianness.u32_from_reader(reader)?,
104            info: endianness.u32_from_reader(reader)?,
105            size_type: endianness.u32_from_reader(reader)?,
106        })
107    }
108
109    pub(super) fn vlen(&self) -> u32 {
110        self.info & 0xffff
111    }
112
113    pub(super) fn kind(&self) -> u32 {
114        (self.info >> 24) & 0x1f
115    }
116
117    pub(super) fn kind_flag(&self) -> u32 {
118        (self.info >> 31) & 0x1
119    }
120
121    pub(super) fn size(&self) -> usize {
122        self.size_type as usize
123    }
124
125    pub(super) fn r#type(&self) -> u32 {
126        self.size_type
127    }
128}
129
130#[derive(Clone, Copy, Debug)]
131#[repr(C, packed)]
132pub(super) struct btf_int {
133    data: u32,
134}
135
136impl btf_int {
137    pub(super) fn from_reader<R: Read>(reader: &mut R, endianness: &Endianness) -> Result<btf_int> {
138        Ok(btf_int {
139            data: endianness.u32_from_reader(reader)?,
140        })
141    }
142
143    pub(super) fn encoding(&self) -> u32 {
144        (self.data & 0x0f000000) >> 24
145    }
146
147    pub(super) fn offset(&self) -> u32 {
148        (self.data & 0x00ff0000) >> 16
149    }
150
151    pub(super) fn bits(&self) -> u32 {
152        self.data & 0x000000ff
153    }
154}
155
156pub(super) const BTF_INT_SIGNED: u32 = 1 << 0;
157pub(super) const BTF_INT_CHAR: u32 = 1 << 1;
158pub(super) const BTF_INT_BOOL: u32 = 1 << 2;
159
160#[derive(Clone, Copy, Debug)]
161#[repr(C, packed)]
162pub(super) struct btf_array {
163    pub(super) r#type: u32,
164    pub(super) index_type: u32,
165    pub(super) nelems: u32,
166}
167
168impl btf_array {
169    pub(super) fn from_reader<R: Read>(
170        reader: &mut R,
171        endianness: &Endianness,
172    ) -> Result<btf_array> {
173        Ok(btf_array {
174            r#type: endianness.u32_from_reader(reader)?,
175            index_type: endianness.u32_from_reader(reader)?,
176            nelems: endianness.u32_from_reader(reader)?,
177        })
178    }
179}
180
181#[derive(Clone, Copy, Debug)]
182#[repr(C, packed)]
183pub(super) struct btf_member {
184    pub(super) name_off: u32,
185    pub(super) r#type: u32,
186    pub(super) offset: u32,
187}
188
189impl btf_member {
190    pub(super) fn from_reader<R: Read>(
191        reader: &mut R,
192        endianness: &Endianness,
193    ) -> Result<btf_member> {
194        Ok(btf_member {
195            name_off: endianness.u32_from_reader(reader)?,
196            r#type: endianness.u32_from_reader(reader)?,
197            offset: endianness.u32_from_reader(reader)?,
198        })
199    }
200}
201
202#[derive(Clone, Copy, Debug)]
203#[repr(C, packed)]
204pub(super) struct btf_enum {
205    pub(super) name_off: u32,
206    pub(super) val: u32,
207}
208
209impl btf_enum {
210    pub(super) fn from_reader<R: Read>(
211        reader: &mut R,
212        endianness: &Endianness,
213    ) -> Result<btf_enum> {
214        Ok(btf_enum {
215            name_off: endianness.u32_from_reader(reader)?,
216            val: endianness.u32_from_reader(reader)?,
217        })
218    }
219}
220
221pub(super) const BTF_FUNC_STATIC: u32 = 0;
222pub(super) const BTF_FUNC_GLOBAL: u32 = 1;
223pub(super) const BTF_FUNC_EXTERN: u32 = 2;
224
225#[derive(Clone, Copy, Debug)]
226#[repr(C, packed)]
227pub(super) struct btf_param {
228    pub(super) name_off: u32,
229    pub(super) r#type: u32,
230}
231
232impl btf_param {
233    pub(super) fn from_reader<R: Read>(
234        reader: &mut R,
235        endianness: &Endianness,
236    ) -> Result<btf_param> {
237        Ok(btf_param {
238            name_off: endianness.u32_from_reader(reader)?,
239            r#type: endianness.u32_from_reader(reader)?,
240        })
241    }
242}
243
244#[derive(Clone, Copy, Debug)]
245#[repr(C, packed)]
246pub(super) struct btf_var {
247    pub(super) linkage: u32,
248}
249
250impl btf_var {
251    pub(super) fn from_reader<R: Read>(reader: &mut R, endianness: &Endianness) -> Result<btf_var> {
252        Ok(btf_var {
253            linkage: endianness.u32_from_reader(reader)?,
254        })
255    }
256}
257
258#[derive(Clone, Copy, Debug)]
259#[repr(C, packed)]
260pub(super) struct btf_var_secinfo {
261    pub(super) r#type: u32,
262    pub(super) offset: u32,
263    pub(super) size: u32,
264}
265
266impl btf_var_secinfo {
267    pub(super) fn from_reader<R: Read>(
268        reader: &mut R,
269        endianness: &Endianness,
270    ) -> Result<btf_var_secinfo> {
271        Ok(btf_var_secinfo {
272            r#type: endianness.u32_from_reader(reader)?,
273            offset: endianness.u32_from_reader(reader)?,
274            size: endianness.u32_from_reader(reader)?,
275        })
276    }
277}
278
279#[derive(Clone, Copy, Debug)]
280#[repr(C, packed)]
281pub(super) struct btf_decl_tag {
282    pub(super) component_idx: i32,
283}
284
285impl btf_decl_tag {
286    pub(super) fn from_reader<R: Read>(
287        reader: &mut R,
288        endianness: &Endianness,
289    ) -> Result<btf_decl_tag> {
290        Ok(btf_decl_tag {
291            component_idx: endianness.i32_from_reader(reader)?,
292        })
293    }
294}
295
296#[derive(Clone, Copy, Debug)]
297#[repr(C, packed)]
298pub(super) struct btf_enum64 {
299    pub(super) name_off: u32,
300    pub(super) val_lo32: u32,
301    pub(super) val_hi32: u32,
302}
303
304impl btf_enum64 {
305    pub(super) fn from_reader<R: Read>(
306        reader: &mut R,
307        endianness: &Endianness,
308    ) -> Result<btf_enum64> {
309        Ok(btf_enum64 {
310            name_off: endianness.u32_from_reader(reader)?,
311            val_lo32: endianness.u32_from_reader(reader)?,
312            val_hi32: endianness.u32_from_reader(reader)?,
313        })
314    }
315}