Skip to main content

btf_rs/
btf.rs

1//! Main object of the `btf-rs` crate, providing a way to parse BTF data and
2//! helpers to query the information it describes.
3
4use std::{
5    convert::AsRef,
6    fs::File,
7    io::{BufReader, Cursor, Read},
8    path::Path,
9    sync::Arc,
10};
11
12use fallible_iterator::FallibleIterator;
13use memmap2::MmapOptions;
14
15use crate::{cbtf, section::BtfSection, Error, Result};
16
17/// Backend used by the [`Btf`] object to store and access the underlying BTF
18/// information.
19#[non_exhaustive]
20pub enum Backend {
21    /// Parse the BTF data during initialization and then store the result. This
22    /// provides faster API calls at the cost of a slower initialization and
23    /// larger memory footprint.
24    Cache,
25    /// Mmap the BTF data without parsing all of it. This provides a smaller
26    /// memory footprint and faster initialization at the cost of slower API
27    /// calls.
28    Mmap,
29}
30
31/// Main representation of parsed BTF data. Provides helpers to resolve types
32/// and their associated names.
33pub struct Btf {
34    obj: Arc<BtfSection>,
35    base: Option<Arc<BtfSection>>,
36}
37
38impl Btf {
39    /// Parse a stand-alone BTF section from a file and construct a Rust
40    /// representation for later use. By default [`Backend::Cache`] is used.
41    ///
42    /// Trying to open split BTF files using this function will fail. For split
43    /// BTF files use [`Btf::from_split_file`].
44    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
45        Self::from_file_with_backend(&path, Backend::Cache)
46    }
47
48    /// Same as [`Btf::from_file`] but forcing a given [`Backend`] to be used.
49    /// This allows selecting the desired behavior and balance, but can fail if
50    /// a given [`Backend`] isn't supported by the underlying system.
51    pub fn from_file_with_backend<P: AsRef<Path>>(path: P, backend: Backend) -> Result<Self> {
52        Ok(Btf {
53            obj: Arc::new(match backend {
54                Backend::Cache => {
55                    BtfSection::from_reader(&mut BufReader::new(File::open(path)?), None)?
56                }
57                Backend::Mmap => BtfSection::from_mmap(
58                    unsafe { MmapOptions::new().map_copy_read_only(&File::open(path)?)? },
59                    None,
60                )?,
61            }),
62            base: None,
63        })
64    }
65
66    /// Parse a split BTF section from a file and construct a Rust
67    /// representation for later use. A base [`Btf`] containing the base section
68    /// must be provided.
69    pub fn from_split_file<P: AsRef<Path>>(path: P, base: &Btf) -> Result<Btf> {
70        if base.base.is_some() {
71            return Err(Error::OpNotSupp("Provided base is a split BTF".to_string()));
72        }
73
74        Ok(Btf {
75            obj: Arc::new(BtfSection::from_reader(
76                &mut BufReader::new(File::open(path)?),
77                Some(base.obj.clone()),
78            )?),
79            base: Some(base.obj.clone()),
80        })
81    }
82
83    /// Perform the same actions as [`Btf::from_file`], but fed with a byte
84    /// slice.
85    pub fn from_bytes(bytes: &[u8]) -> Result<Btf> {
86        Ok(Btf {
87            obj: Arc::new(BtfSection::from_reader(&mut Cursor::new(bytes), None)?),
88            base: None,
89        })
90    }
91
92    /// Performs the same actions as [`Btf::from_split_file`], but fed with a
93    /// byte slice.
94    pub fn from_split_bytes(bytes: &[u8], base: &Btf) -> Result<Btf> {
95        if base.base.is_some() {
96            return Err(Error::OpNotSupp("Provided base is a split BTF".to_string()));
97        }
98
99        let base = base.obj.clone();
100        Ok(Btf {
101            obj: Arc::new(BtfSection::from_reader(
102                &mut Cursor::new(bytes),
103                Some(base.clone()),
104            )?),
105            base: Some(base),
106        })
107    }
108
109    /// Returns a reference the base BTF section. For non-split `Btf` the base
110    /// BTF section holds the full BTF representation. Base BTF sections are
111    /// standalone representations (no reference to external BTF sections).
112    pub fn base(&self) -> &BtfSection {
113        match &self.base {
114            Some(base) => base,
115            None => &self.obj,
116        }
117    }
118
119    /// Returns a reference to the split BTF section, if any. A split BTF
120    /// section is not a standalone representation (it uses references to a base
121    /// BTF section).
122    pub fn split(&self) -> Option<&BtfSection> {
123        self.base.as_ref()?;
124        Some(&self.obj)
125    }
126
127    /// Find a list of BTF ids with a given name.
128    ///
129    /// Using an empty name (`""`) resolves anonymous ids.
130    pub fn resolve_ids_by_name(&self, name: &str) -> Result<Vec<u32>> {
131        let mut ids = self.obj.resolve_ids_by_name(name)?;
132
133        if let Some(base) = &self.base {
134            ids.append(&mut base.resolve_ids_by_name(name)?);
135        }
136
137        Ok(ids)
138    }
139
140    /// Find a list of BTF ids whose names match a regex.
141    ///
142    /// If the regex matches the empty name (`""`), e.g. `"^$"`, the result will
143    /// contain anonymous ids.
144    #[cfg(feature = "regex")]
145    pub fn resolve_ids_by_regex(&self, re: &regex::Regex) -> Result<Vec<u32>> {
146        let mut ids = self.obj.resolve_ids_by_regex(re)?;
147
148        if let Some(base) = &self.base {
149            ids.append(&mut base.resolve_ids_by_regex(re)?);
150        }
151
152        Ok(ids)
153    }
154
155    /// Find a BTF type with a given id.
156    pub fn resolve_type_by_id(&self, id: u32) -> Result<Type> {
157        if let Some(base) = &self.base {
158            if let Ok(r#type) = base.resolve_type_by_id(id) {
159                return Ok(r#type);
160            }
161        }
162
163        self.obj.resolve_type_by_id(id)
164    }
165
166    /// Find a list of BTF types with a given name.
167    ///
168    /// Using an empty name (`""`) resolves anonymous types.
169    pub fn resolve_types_by_name(&self, name: &str) -> Result<Vec<Type>> {
170        let mut types = self.obj.resolve_types_by_name(name)?;
171
172        if let Some(base) = &self.base {
173            types.append(&mut base.resolve_types_by_name(name)?);
174        }
175
176        Ok(types)
177    }
178
179    /// Find a list of BTF types whose names match a regex.
180    ///
181    /// If the regex matches the empty name (`""`), e.g. `"^$"`, the result will
182    /// contain anonymous types.
183    #[cfg(feature = "regex")]
184    pub fn resolve_types_by_regex(&self, re: &regex::Regex) -> Result<Vec<Type>> {
185        let mut types = self.obj.resolve_types_by_regex(re)?;
186
187        if let Some(base) = &self.base {
188            types.append(&mut base.resolve_types_by_regex(re)?);
189        }
190
191        Ok(types)
192    }
193
194    /// Resolve a name referenced by a Type which is defined in the current
195    /// [`Btf`] object.
196    pub fn resolve_name(&self, r#type: &dyn BtfType) -> Result<String> {
197        match &self.base {
198            Some(base) => base
199                .resolve_name(r#type)
200                .or_else(|_| self.obj.resolve_name(r#type)),
201            None => self.obj.resolve_name(r#type),
202        }
203    }
204
205    /// Return an iterator over all types defined in the current BTF object.
206    pub fn type_iter(&self) -> TypeIter<'_> {
207        TypeIter::new(&self.obj, self.base.as_ref().map(|s| s.as_ref()))
208    }
209
210    /// Types can have a reference to another one, e.g. `Ptr -> Int`. This
211    /// helper resolve a Type referenced in an other one. It is the main helper
212    /// to traverse the Type tree.
213    pub fn resolve_chained_type<T: BtfType + ?Sized>(&self, r#type: &T) -> Result<Type> {
214        let id = r#type
215            .get_type_id()
216            .ok_or(Error::OpNotSupp("No chained type in type".to_string()))?;
217        self.resolve_type_by_id(id)
218    }
219
220    /// This helper returns an iterator that allow to resolve a Type
221    /// referenced in another one all the way down to the chain.
222    /// The helper makes use of [`Btf::resolve_chained_type`].
223    pub fn chained_type_iter<T: BtfType + ?Sized>(&self, r#type: &T) -> ChainedTypeIter<'_> {
224        ChainedTypeIter {
225            btf: self,
226            r#type: self.resolve_chained_type(r#type).ok(),
227        }
228    }
229}
230
231/// Iterator over BTF types.
232pub struct TypeIter<'a> {
233    pub(crate) section: &'a BtfSection,
234    pub(crate) next_section: Option<&'a BtfSection>,
235    cursor: u32,
236    end: u32,
237}
238
239impl<'a> TypeIter<'a> {
240    pub(crate) fn new(section: &'a BtfSection, next_section: Option<&'a BtfSection>) -> Self {
241        let (start, end) = section.type_id_range();
242
243        TypeIter {
244            section,
245            next_section,
246            cursor: start,
247            end,
248        }
249    }
250}
251
252impl FallibleIterator for TypeIter<'_> {
253    type Item = Type;
254    type Error = Error;
255
256    fn next(&mut self) -> Result<Option<Self::Item>> {
257        // Go to the next section if needed.
258        if self.cursor > self.end {
259            self.section = match self.next_section.take() {
260                Some(section) => section,
261                None => return Ok(None),
262            };
263
264            (self.cursor, self.end) = self.section.type_id_range();
265        }
266
267        let r#type = self.section.resolve_type_by_id(self.cursor)?;
268        self.cursor += 1;
269
270        Ok(Some(r#type))
271    }
272}
273
274/// Iterator over chained types (types referencing other types in a chain).
275pub struct ChainedTypeIter<'a> {
276    btf: &'a Btf,
277    r#type: Option<Type>,
278}
279
280impl Iterator for ChainedTypeIter<'_> {
281    type Item = Type;
282
283    fn next(&mut self) -> Option<Self::Item> {
284        match self.r#type.clone() {
285            None => None,
286            Some(ty) => {
287                self.r#type = match ty.as_btf_type() {
288                    Some(x) => self.btf.resolve_chained_type(x).ok(),
289                    // We might have encountered Void or other
290                    // non-BtfType types.
291                    None => None,
292                };
293                Some(ty)
294            }
295        }
296    }
297}
298
299/// Rust representation of BTF types. Each type then contains its own specific
300/// data and provides helpers to access it.
301#[non_exhaustive]
302#[derive(Clone, Debug, Eq, PartialEq)]
303pub enum Type {
304    Void,
305    Int(Int),
306    Ptr(Ptr),
307    Array(Array),
308    Struct(Struct),
309    Union(Union),
310    Enum(Enum),
311    Fwd(Fwd),
312    Typedef(Typedef),
313    Volatile(Volatile),
314    Const(Const),
315    Restrict(Restrict),
316    Func(Func),
317    FuncProto(FuncProto),
318    Var(Var),
319    Datasec(Datasec),
320    Float(Float),
321    DeclTag(DeclTag),
322    TypeTag(TypeTag),
323    Enum64(Enum64),
324}
325
326impl Type {
327    // Creates a new Type reading a BTF definition from a reader.
328    pub(super) fn from_reader<R: Read>(
329        reader: &mut R,
330        endianness: &cbtf::Endianness,
331        bt: cbtf::btf_type,
332    ) -> Result<Self> {
333        // Each BTF type needs specific handling to parse its type-specific header.
334        use cbtf::BtfKind;
335        Ok(match BtfKind::from_id(bt.kind())? {
336            BtfKind::Int => Type::Int(Int::from_reader(reader, endianness, bt)?),
337            BtfKind::Ptr => Type::Ptr(Ptr::new(bt)),
338            BtfKind::Array => Type::Array(Array::from_reader(reader, endianness, bt)?),
339            BtfKind::Struct => Type::Struct(Struct::from_reader(reader, endianness, bt)?),
340            BtfKind::Union => Type::Union(Struct::from_reader(reader, endianness, bt)?),
341            BtfKind::Enum => Type::Enum(Enum::from_reader(reader, endianness, bt)?),
342            BtfKind::Fwd => Type::Fwd(Fwd::new(bt)),
343            BtfKind::Typedef => Type::Typedef(Typedef::new(bt)),
344            BtfKind::Volatile => Type::Volatile(Volatile::new(bt)),
345            BtfKind::Const => Type::Const(Volatile::new(bt)),
346            BtfKind::Restrict => Type::Restrict(Volatile::new(bt)),
347            BtfKind::Func => Type::Func(Func::new(bt)),
348            BtfKind::FuncProto => Type::FuncProto(FuncProto::from_reader(reader, endianness, bt)?),
349            BtfKind::Var => Type::Var(Var::from_reader(reader, endianness, bt)?),
350            BtfKind::Datasec => Type::Datasec(Datasec::from_reader(reader, endianness, bt)?),
351            BtfKind::Float => Type::Float(Float::new(bt)),
352            BtfKind::DeclTag => Type::DeclTag(DeclTag::from_reader(reader, endianness, bt)?),
353            BtfKind::TypeTag => Type::TypeTag(TypeTag::new(bt)),
354            BtfKind::Enum64 => Type::Enum64(Enum64::from_reader(reader, endianness, bt)?),
355        })
356    }
357
358    // Creates a new Type reading a BTF definition from bytes.
359    pub(crate) fn from_bytes(
360        buf: &[u8],
361        endianness: &cbtf::Endianness,
362        bt: cbtf::btf_type,
363    ) -> Result<Self> {
364        Self::from_reader(&mut Cursor::new(buf), endianness, bt)
365    }
366
367    /// Returns an `str` representation of the [`Type`].
368    pub fn name(&self) -> &'static str {
369        match &self {
370            Type::Void => "void",
371            Type::Int(_) => "int",
372            Type::Ptr(_) => "ptr",
373            Type::Array(_) => "array",
374            Type::Struct(_) => "struct",
375            Type::Union(_) => "union",
376            Type::Enum(_) => "enum",
377            Type::Fwd(_) => "fwd",
378            Type::Typedef(_) => "typedef",
379            Type::Volatile(_) => "volatile",
380            Type::Const(_) => "const",
381            Type::Restrict(_) => "restrict",
382            Type::Func(_) => "func",
383            Type::FuncProto(_) => "func-proto",
384            Type::Var(_) => "var",
385            Type::Datasec(_) => "datasec",
386            Type::Float(_) => "float",
387            Type::DeclTag(_) => "decl-tag",
388            Type::TypeTag(_) => "type-tag",
389            Type::Enum64(_) => "enum64",
390        }
391    }
392
393    pub fn as_btf_type(&self) -> Option<&dyn BtfType> {
394        match self {
395            Type::Int(i) => Some(i),
396            Type::Ptr(p) => Some(p),
397            Type::Array(a) => Some(a),
398            Type::Struct(s) => Some(s),
399            Type::Union(u) => Some(u),
400            Type::Enum(e) => Some(e),
401            Type::Fwd(f) => Some(f),
402            Type::Typedef(td) => Some(td),
403            Type::Volatile(v) => Some(v),
404            Type::Const(c) => Some(c),
405            Type::Restrict(r) => Some(r),
406            Type::Func(fu) => Some(fu),
407            Type::Var(v) => Some(v),
408            Type::Datasec(ds) => Some(ds),
409            Type::Float(f) => Some(f),
410            Type::DeclTag(dt) => Some(dt),
411            Type::TypeTag(tt) => Some(tt),
412            Type::Enum64(e64) => Some(e64),
413            _ => None,
414        }
415    }
416}
417
418/// Helpers common to all BTF types. Ease the use of types.
419pub trait BtfType {
420    /// Returns the offset of the string associated with the type, if any.
421    fn get_name_offset(&self) -> Option<u32> {
422        None
423    }
424
425    /// Returns the type id associated with the current type, if any.
426    fn get_type_id(&self) -> Option<u32> {
427        None
428    }
429}
430
431/// Rust representation for BTF type `BTF_KIND_INT`.
432#[derive(Clone, Debug, Eq, PartialEq)]
433pub struct Int {
434    btf_type: cbtf::btf_type,
435    btf_int: cbtf::btf_int,
436}
437
438impl Int {
439    fn from_reader<R: Read>(
440        reader: &mut R,
441        endianness: &cbtf::Endianness,
442        btf_type: cbtf::btf_type,
443    ) -> Result<Int> {
444        Ok(Int {
445            btf_type,
446            btf_int: cbtf::btf_int::from_reader(reader, endianness)?,
447        })
448    }
449
450    pub fn is_signed(&self) -> bool {
451        self.btf_int.encoding() & cbtf::BTF_INT_SIGNED == cbtf::BTF_INT_SIGNED
452    }
453
454    pub fn is_char(&self) -> bool {
455        self.btf_int.encoding() & cbtf::BTF_INT_CHAR == cbtf::BTF_INT_CHAR
456    }
457
458    pub fn is_bool(&self) -> bool {
459        self.btf_int.encoding() & cbtf::BTF_INT_BOOL == cbtf::BTF_INT_BOOL
460    }
461
462    pub fn size(&self) -> usize {
463        self.btf_type.size().expect("int should have a size")
464    }
465}
466
467impl BtfType for Int {
468    fn get_name_offset(&self) -> Option<u32> {
469        self.btf_type.name_offset()
470    }
471}
472
473/// Rust representation for BTF type `BTF_KIND_PTR`.
474#[derive(Clone, Debug, Eq, PartialEq)]
475pub struct Ptr {
476    btf_type: cbtf::btf_type,
477}
478
479impl Ptr {
480    fn new(btf_type: cbtf::btf_type) -> Ptr {
481        Ptr { btf_type }
482    }
483}
484
485impl BtfType for Ptr {
486    fn get_type_id(&self) -> Option<u32> {
487        self.btf_type.r#type()
488    }
489}
490
491/// Rust representation for BTF type `BTF_KIND_ARRAY`.
492#[derive(Clone, Debug, Eq, PartialEq)]
493pub struct Array {
494    btf_type: cbtf::btf_type,
495    btf_array: cbtf::btf_array,
496}
497
498#[allow(clippy::len_without_is_empty)]
499impl Array {
500    fn from_reader<R: Read>(
501        reader: &mut R,
502        endianness: &cbtf::Endianness,
503        btf_type: cbtf::btf_type,
504    ) -> Result<Array> {
505        Ok(Array {
506            btf_type,
507            btf_array: cbtf::btf_array::from_reader(reader, endianness)?,
508        })
509    }
510
511    /// Number of elements in the `Array`.
512    pub fn len(&self) -> usize {
513        self.btf_array.nelems as usize
514    }
515}
516
517impl BtfType for Array {
518    fn get_type_id(&self) -> Option<u32> {
519        Some(self.btf_array.r#type)
520    }
521}
522
523/// Rust representation for BTF type `BTF_KIND_STRUCT`.
524#[derive(Clone, Debug, Eq, PartialEq)]
525pub struct Struct {
526    btf_type: cbtf::btf_type,
527    /// The members information. Use `.len()` to count them.
528    pub members: Vec<Member>,
529}
530
531impl Struct {
532    fn from_reader<R: Read>(
533        reader: &mut R,
534        endianness: &cbtf::Endianness,
535        btf_type: cbtf::btf_type,
536    ) -> Result<Struct> {
537        let mut members = Vec::new();
538
539        for _ in 0..btf_type.vlen() {
540            members.push(Member::from_reader(
541                reader,
542                endianness,
543                btf_type.kind_flag(),
544            )?);
545        }
546
547        Ok(Struct { btf_type, members })
548    }
549
550    pub fn size(&self) -> usize {
551        self.btf_type
552            .size()
553            .expect("struct and union should have a size")
554    }
555}
556
557impl BtfType for Struct {
558    fn get_name_offset(&self) -> Option<u32> {
559        self.btf_type.name_offset()
560    }
561}
562
563/// Rust representation for BTF type `BTF_KIND_UNION`.
564pub type Union = Struct;
565
566/// Represents a [`Struct`] member.
567#[derive(Clone, Debug, Eq, PartialEq)]
568pub struct Member {
569    kind_flag: u32,
570    btf_member: cbtf::btf_member,
571}
572
573impl Member {
574    fn from_reader<R: Read>(
575        reader: &mut R,
576        endianness: &cbtf::Endianness,
577        kind_flag: u32,
578    ) -> Result<Member> {
579        Ok(Member {
580            kind_flag,
581            btf_member: cbtf::btf_member::from_reader(reader, endianness)?,
582        })
583    }
584
585    pub fn bit_offset(&self) -> u32 {
586        match self.kind_flag {
587            1 => self.btf_member.offset & 0xffffff,
588            _ => self.btf_member.offset,
589        }
590    }
591
592    pub fn bitfield_size(&self) -> Option<u32> {
593        match self.kind_flag {
594            1 => Some(self.btf_member.offset >> 24),
595            _ => None,
596        }
597    }
598}
599
600impl BtfType for Member {
601    fn get_name_offset(&self) -> Option<u32> {
602        Some(self.btf_member.name_off)
603    }
604
605    fn get_type_id(&self) -> Option<u32> {
606        Some(self.btf_member.r#type)
607    }
608}
609
610/// Rust representation for BTF type `BTF_KIND_ENUM`.
611#[derive(Clone, Debug, Eq, PartialEq)]
612pub struct Enum {
613    btf_type: cbtf::btf_type,
614    /// The enum members information. Use `.len()` to count them.
615    pub members: Vec<EnumMember>,
616}
617
618#[allow(clippy::len_without_is_empty)]
619impl Enum {
620    fn from_reader<R: Read>(
621        reader: &mut R,
622        endianness: &cbtf::Endianness,
623        btf_type: cbtf::btf_type,
624    ) -> Result<Enum> {
625        let mut members = Vec::new();
626
627        for _ in 0..btf_type.vlen() {
628            members.push(EnumMember::from_reader(reader, endianness)?);
629        }
630
631        Ok(Enum { btf_type, members })
632    }
633
634    pub fn is_signed(&self) -> bool {
635        self.btf_type.kind_flag() == 1
636    }
637
638    pub fn size(&self) -> usize {
639        self.btf_type.size().expect("enum should have a size")
640    }
641}
642
643impl BtfType for Enum {
644    fn get_name_offset(&self) -> Option<u32> {
645        self.btf_type.name_offset()
646    }
647}
648
649/// Represents an [`Enum`] member.
650#[derive(Clone, Debug, Eq, PartialEq)]
651pub struct EnumMember {
652    btf_enum: cbtf::btf_enum,
653}
654
655impl EnumMember {
656    fn from_reader<R: Read>(reader: &mut R, endianness: &cbtf::Endianness) -> Result<EnumMember> {
657        Ok(EnumMember {
658            btf_enum: cbtf::btf_enum::from_reader(reader, endianness)?,
659        })
660    }
661
662    pub fn val(&self) -> u32 {
663        self.btf_enum.val
664    }
665}
666
667impl BtfType for EnumMember {
668    fn get_name_offset(&self) -> Option<u32> {
669        Some(self.btf_enum.name_off)
670    }
671}
672
673/// Rust representation for BTF type `BTF_KIND_FWD`.
674#[derive(Clone, Debug, Eq, PartialEq)]
675pub struct Fwd {
676    btf_type: cbtf::btf_type,
677}
678
679impl Fwd {
680    fn new(btf_type: cbtf::btf_type) -> Fwd {
681        Fwd { btf_type }
682    }
683
684    /// Tests if the forward declaration is for a struct type.
685    pub fn is_struct(&self) -> bool {
686        self.btf_type.kind_flag() == 0
687    }
688
689    /// Tests if the forward declaration is for a union type.
690    pub fn is_union(&self) -> bool {
691        self.btf_type.kind_flag() == 1
692    }
693}
694
695impl BtfType for Fwd {
696    fn get_name_offset(&self) -> Option<u32> {
697        self.btf_type.name_offset()
698    }
699}
700
701/// Rust representation for BTF type `BTF_KIND_TYPEDEF`.
702#[derive(Clone, Debug, Eq, PartialEq)]
703pub struct Typedef {
704    btf_type: cbtf::btf_type,
705}
706
707impl Typedef {
708    fn new(btf_type: cbtf::btf_type) -> Typedef {
709        Typedef { btf_type }
710    }
711}
712
713impl BtfType for Typedef {
714    fn get_name_offset(&self) -> Option<u32> {
715        self.btf_type.name_offset()
716    }
717
718    fn get_type_id(&self) -> Option<u32> {
719        self.btf_type.r#type()
720    }
721}
722
723/// Rust representation for BTF type `BTF_KIND_VOLATILE`.
724#[derive(Clone, Debug, Eq, PartialEq)]
725pub struct Volatile {
726    btf_type: cbtf::btf_type,
727}
728
729impl Volatile {
730    fn new(btf_type: cbtf::btf_type) -> Volatile {
731        Volatile { btf_type }
732    }
733}
734
735impl BtfType for Volatile {
736    fn get_type_id(&self) -> Option<u32> {
737        self.btf_type.r#type()
738    }
739}
740
741/// Rust representation for BTF type `BTF_KIND_CONST`.
742pub type Const = Volatile;
743
744/// Rust representation for BTF type `BTF_KIND_RESTRICT`.
745pub type Restrict = Volatile;
746
747/// Rust representation for BTF type `BTF_KIND_FUNC`.
748#[derive(Clone, Debug, Eq, PartialEq)]
749pub struct Func {
750    btf_type: cbtf::btf_type,
751}
752
753impl Func {
754    fn new(btf_type: cbtf::btf_type) -> Func {
755        Func { btf_type }
756    }
757
758    pub fn is_static(&self) -> bool {
759        self.btf_type.vlen() == cbtf::BTF_FUNC_STATIC
760    }
761
762    pub fn is_global(&self) -> bool {
763        self.btf_type.vlen() == cbtf::BTF_FUNC_GLOBAL
764    }
765
766    pub fn is_extern(&self) -> bool {
767        self.btf_type.vlen() == cbtf::BTF_FUNC_EXTERN
768    }
769}
770
771impl BtfType for Func {
772    fn get_name_offset(&self) -> Option<u32> {
773        self.btf_type.name_offset()
774    }
775
776    fn get_type_id(&self) -> Option<u32> {
777        self.btf_type.r#type()
778    }
779}
780
781/// Rust representation for BTF type `BTF_KIND_FUNC_PROTO`.
782#[derive(Clone, Debug, Eq, PartialEq)]
783pub struct FuncProto {
784    btf_type: cbtf::btf_type,
785    pub parameters: Vec<Parameter>,
786}
787
788impl FuncProto {
789    fn from_reader<R: Read>(
790        reader: &mut R,
791        endianness: &cbtf::Endianness,
792        btf_type: cbtf::btf_type,
793    ) -> Result<FuncProto> {
794        let mut parameters = Vec::new();
795
796        for _ in 0..btf_type.vlen() {
797            parameters.push(Parameter::from_reader(reader, endianness)?);
798        }
799
800        Ok(FuncProto {
801            btf_type,
802            parameters,
803        })
804    }
805
806    pub fn return_type_id(&self) -> u32 {
807        self.btf_type
808            .r#type()
809            .expect("func proto should have a type")
810    }
811}
812
813/// Represents a [`FuncProto`] parameter.
814#[derive(Clone, Debug, Eq, PartialEq)]
815pub struct Parameter {
816    btf_param: cbtf::btf_param,
817}
818
819impl Parameter {
820    fn from_reader<R: Read>(reader: &mut R, endianness: &cbtf::Endianness) -> Result<Parameter> {
821        Ok(Parameter {
822            btf_param: cbtf::btf_param::from_reader(reader, endianness)?,
823        })
824    }
825
826    pub fn is_variadic(&self) -> bool {
827        self.btf_param.name_off == 0 && self.btf_param.r#type == 0
828    }
829}
830
831impl BtfType for Parameter {
832    fn get_name_offset(&self) -> Option<u32> {
833        Some(self.btf_param.name_off)
834    }
835
836    fn get_type_id(&self) -> Option<u32> {
837        Some(self.btf_param.r#type)
838    }
839}
840
841/// Rust representation for BTF type `BTF_KIND_VAR`.
842#[derive(Clone, Debug, Eq, PartialEq)]
843pub struct Var {
844    btf_type: cbtf::btf_type,
845    btf_var: cbtf::btf_var,
846}
847
848impl Var {
849    fn from_reader<R: Read>(
850        reader: &mut R,
851        endianness: &cbtf::Endianness,
852        btf_type: cbtf::btf_type,
853    ) -> Result<Var> {
854        Ok(Var {
855            btf_type,
856            btf_var: cbtf::btf_var::from_reader(reader, endianness)?,
857        })
858    }
859
860    pub fn is_static(&self) -> bool {
861        self.btf_var.linkage == cbtf::BTF_VAR_STATIC
862    }
863
864    pub fn is_global(&self) -> bool {
865        self.btf_var.linkage == cbtf::BTF_VAR_GLOBAL_ALLOCATED
866    }
867
868    pub fn is_extern(&self) -> bool {
869        self.btf_var.linkage == cbtf::BTF_VAR_GLOBAL_EXTERN
870    }
871}
872
873impl BtfType for Var {
874    fn get_name_offset(&self) -> Option<u32> {
875        self.btf_type.name_offset()
876    }
877
878    fn get_type_id(&self) -> Option<u32> {
879        self.btf_type.r#type()
880    }
881}
882
883/// Rust representation for BTF type `BTF_KIND_DATASEC`.
884#[derive(Clone, Debug, Eq, PartialEq)]
885pub struct Datasec {
886    btf_type: cbtf::btf_type,
887    pub variables: Vec<VarSecinfo>,
888}
889
890impl Datasec {
891    fn from_reader<R: Read>(
892        reader: &mut R,
893        endianness: &cbtf::Endianness,
894        btf_type: cbtf::btf_type,
895    ) -> Result<Datasec> {
896        let mut variables = Vec::new();
897
898        for _ in 0..btf_type.vlen() {
899            variables.push(VarSecinfo::from_reader(reader, endianness)?);
900        }
901
902        Ok(Datasec {
903            btf_type,
904            variables,
905        })
906    }
907
908    pub fn size(&self) -> usize {
909        self.btf_type.size().expect("datasec should have a size")
910    }
911}
912
913impl BtfType for Datasec {
914    fn get_name_offset(&self) -> Option<u32> {
915        self.btf_type.name_offset()
916    }
917}
918
919/// Represents a [`Datasec`] variable.
920#[derive(Clone, Debug, Eq, PartialEq)]
921pub struct VarSecinfo {
922    btf_var_secinfo: cbtf::btf_var_secinfo,
923}
924
925impl VarSecinfo {
926    fn from_reader<R: Read>(reader: &mut R, endianness: &cbtf::Endianness) -> Result<VarSecinfo> {
927        Ok(VarSecinfo {
928            btf_var_secinfo: cbtf::btf_var_secinfo::from_reader(reader, endianness)?,
929        })
930    }
931
932    pub fn offset(&self) -> u32 {
933        self.btf_var_secinfo.offset
934    }
935
936    pub fn size(&self) -> usize {
937        self.btf_var_secinfo.size as usize
938    }
939}
940
941impl BtfType for VarSecinfo {
942    fn get_type_id(&self) -> Option<u32> {
943        Some(self.btf_var_secinfo.r#type)
944    }
945}
946
947/// Rust representation for BTF type `BTF_KIND_FLOAT`.
948#[derive(Clone, Debug, Eq, PartialEq)]
949pub struct Float {
950    btf_type: cbtf::btf_type,
951}
952
953impl Float {
954    fn new(btf_type: cbtf::btf_type) -> Float {
955        Float { btf_type }
956    }
957
958    pub fn size(&self) -> usize {
959        self.btf_type.size().expect("float should have a size")
960    }
961}
962
963impl BtfType for Float {
964    fn get_name_offset(&self) -> Option<u32> {
965        self.btf_type.name_offset()
966    }
967}
968
969/// Rust representation for BTF type `BTF_KIND_DECL_TAG`.
970#[derive(Clone, Debug, Eq, PartialEq)]
971pub struct DeclTag {
972    btf_type: cbtf::btf_type,
973    btf_decl_tag: cbtf::btf_decl_tag,
974}
975
976impl DeclTag {
977    fn from_reader<R: Read>(
978        reader: &mut R,
979        endianness: &cbtf::Endianness,
980        btf_type: cbtf::btf_type,
981    ) -> Result<DeclTag> {
982        Ok(DeclTag {
983            btf_type,
984            btf_decl_tag: cbtf::btf_decl_tag::from_reader(reader, endianness)?,
985        })
986    }
987
988    pub fn component_index(&self) -> Option<u32> {
989        let component_idx = self.btf_decl_tag.component_idx;
990        match component_idx {
991            x if x < 0 => None,
992            x => Some(x as u32),
993        }
994    }
995
996    pub fn is_attribute(&self) -> bool {
997        self.btf_type.kind_flag() == 1
998    }
999}
1000
1001impl BtfType for DeclTag {
1002    fn get_name_offset(&self) -> Option<u32> {
1003        self.btf_type.name_offset()
1004    }
1005
1006    fn get_type_id(&self) -> Option<u32> {
1007        self.btf_type.r#type()
1008    }
1009}
1010
1011/// Rust representation for BTF type `BTF_KIND_TYPE_TAG`.
1012#[derive(Clone, Debug, Eq, PartialEq)]
1013pub struct TypeTag {
1014    btf_type: cbtf::btf_type,
1015}
1016
1017impl TypeTag {
1018    fn new(btf_type: cbtf::btf_type) -> TypeTag {
1019        TypeTag { btf_type }
1020    }
1021
1022    pub fn is_attribute(&self) -> bool {
1023        self.btf_type.kind_flag() == 1
1024    }
1025}
1026
1027impl BtfType for TypeTag {
1028    fn get_name_offset(&self) -> Option<u32> {
1029        self.btf_type.name_offset()
1030    }
1031
1032    fn get_type_id(&self) -> Option<u32> {
1033        self.btf_type.r#type()
1034    }
1035}
1036
1037/// Rust representation for BTF type `BTF_KIND_ENUM64`.
1038#[derive(Clone, Debug, Eq, PartialEq)]
1039pub struct Enum64 {
1040    btf_type: cbtf::btf_type,
1041    /// The enum members information. Use `.len()` to count them.
1042    pub members: Vec<Enum64Member>,
1043}
1044
1045#[allow(clippy::len_without_is_empty)]
1046impl Enum64 {
1047    fn from_reader<R: Read>(
1048        reader: &mut R,
1049        endianness: &cbtf::Endianness,
1050        btf_type: cbtf::btf_type,
1051    ) -> Result<Enum64> {
1052        let mut members = Vec::new();
1053
1054        for _ in 0..btf_type.vlen() {
1055            members.push(Enum64Member::from_reader(reader, endianness)?);
1056        }
1057
1058        Ok(Enum64 { btf_type, members })
1059    }
1060
1061    pub fn is_signed(&self) -> bool {
1062        self.btf_type.kind_flag() == 1
1063    }
1064
1065    pub fn size(&self) -> usize {
1066        self.btf_type.size().expect("enum64 should have a size")
1067    }
1068}
1069
1070impl BtfType for Enum64 {
1071    fn get_name_offset(&self) -> Option<u32> {
1072        self.btf_type.name_offset()
1073    }
1074}
1075
1076/// Represents an [`Enum64`] member.
1077#[derive(Clone, Debug, Eq, PartialEq)]
1078pub struct Enum64Member {
1079    btf_enum64: cbtf::btf_enum64,
1080}
1081
1082impl Enum64Member {
1083    fn from_reader<R: Read>(reader: &mut R, endianness: &cbtf::Endianness) -> Result<Enum64Member> {
1084        Ok(Enum64Member {
1085            btf_enum64: cbtf::btf_enum64::from_reader(reader, endianness)?,
1086        })
1087    }
1088
1089    pub fn val(&self) -> u64 {
1090        ((self.btf_enum64.val_hi32 as u64) << 32) | self.btf_enum64.val_lo32 as u64
1091    }
1092}
1093
1094impl BtfType for Enum64Member {
1095    fn get_name_offset(&self) -> Option<u32> {
1096        Some(self.btf_enum64.name_off)
1097    }
1098}