btf_rs/
btf.rs

1#![allow(dead_code)]
2
3use std::{
4    convert::AsRef,
5    fs::File,
6    io::{BufReader, Cursor, Read},
7    path::Path,
8    sync::Arc,
9};
10
11use anyhow::{bail, Result};
12
13use crate::cbtf;
14use crate::obj::BtfObj;
15
16/// Main representation of a parsed BTF object. Provides helpers to resolve
17/// types and their associated names.
18pub struct Btf {
19    obj: Arc<BtfObj>,
20    base: Option<Arc<BtfObj>>,
21}
22
23impl Btf {
24    /// Parse a stand-alone BTF object file and construct a Rust representation for later
25    /// use. Trying to open split BTF files using this function will fail. For split BTF
26    /// files use `Btf::from_split_file()`.
27    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Btf> {
28        Ok(Btf {
29            obj: Arc::new(BtfObj::from_reader(
30                &mut BufReader::new(File::open(path)?),
31                None,
32            )?),
33            base: None,
34        })
35    }
36
37    /// Parse a split BTF object file and construct a Rust representation for later
38    /// use. A base Btf object must be provided.
39    pub fn from_split_file<P: AsRef<Path>>(path: P, base: &Btf) -> Result<Btf> {
40        if !path.as_ref().is_file() {
41            bail!("Invalid BTF file {}", path.as_ref().display());
42        }
43
44        Ok(Btf {
45            obj: Arc::new(BtfObj::from_reader(
46                &mut BufReader::new(File::open(path)?),
47                Some(base.obj.clone()),
48            )?),
49            base: Some(base.obj.clone()),
50        })
51    }
52
53    /// Performs the same actions as from_file(), but fed with a byte slice.
54    pub fn from_bytes(bytes: &[u8]) -> Result<Btf> {
55        Ok(Btf {
56            obj: Arc::new(BtfObj::from_reader(&mut Cursor::new(bytes), None)?),
57            base: None,
58        })
59    }
60
61    /// Performs the same actions as from_split_file(), but fed with a byte slice.
62    pub fn from_split_bytes(bytes: &[u8], base: &Btf) -> Result<Btf> {
63        let base = base.obj.clone();
64        Ok(Btf {
65            obj: Arc::new(BtfObj::from_reader(
66                &mut Cursor::new(bytes),
67                Some(base.clone()),
68            )?),
69            base: Some(base),
70        })
71    }
72
73    /// Find a list of BTF ids using their name as a key.
74    pub fn resolve_ids_by_name(&self, name: &str) -> Result<Vec<u32>> {
75        let mut ids = Vec::new();
76
77        if let Some(base) = &self.base {
78            if let Ok(mut ids_base) = base.resolve_ids_by_name(name) {
79                ids.append(&mut ids_base);
80            }
81        }
82        if let Ok(mut ids_obj) = self.obj.resolve_ids_by_name(name) {
83            ids.append(&mut ids_obj);
84        }
85
86        if ids.is_empty() {
87            bail!("No id linked to name {name}");
88        }
89        Ok(ids)
90    }
91
92    /// Find a BTF type using its id as a key.
93    pub fn resolve_type_by_id(&self, id: u32) -> Result<Type> {
94        match &self.base {
95            Some(base) => base
96                .resolve_type_by_id(id)
97                .or_else(|_| self.obj.resolve_type_by_id(id)),
98            None => self.obj.resolve_type_by_id(id),
99        }
100    }
101
102    /// Find a list of BTF types using their name as a key.
103    pub fn resolve_types_by_name(&self, name: &str) -> Result<Vec<Type>> {
104        let mut types = Vec::new();
105
106        if let Some(base) = &self.base {
107            if let Ok(mut types_base) = base.resolve_types_by_name(name) {
108                types.append(&mut types_base);
109            }
110        }
111        if let Ok(mut types_obj) = self.obj.resolve_types_by_name(name) {
112            types.append(&mut types_obj);
113        }
114
115        if types.is_empty() {
116            // Keep "id" and not "type" below to be consitent with
117            // BtfObj::resolve_types_by_name.
118            bail!("No id linked to name {name}");
119        }
120        Ok(types)
121    }
122
123    /// Resolve a name referenced by a Type which is defined in the current BTF
124    /// object.
125    pub fn resolve_name<T: BtfType + ?Sized>(&self, r#type: &T) -> Result<String> {
126        match &self.base {
127            Some(base) => base
128                .resolve_name(r#type)
129                .or_else(|_| self.obj.resolve_name(r#type)),
130            None => self.obj.resolve_name(r#type),
131        }
132    }
133
134    /// Types can have a reference to another one, e.g. `Ptr -> Int`. This
135    /// helper resolve a Type referenced in an other one. It is the main helper
136    /// to traverse the Type tree.
137    pub fn resolve_chained_type<T: BtfType + ?Sized>(&self, r#type: &T) -> Result<Type> {
138        self.resolve_type_by_id(r#type.get_type_id()?)
139    }
140
141    /// This helper returns an iterator that allow to resolve a Type
142    /// referenced in another one all the way down to the chain.
143    /// The helper makes use of `Btf::resolve_chained_type()`.
144    pub fn type_iter<'a, T: BtfType + ?Sized>(&'a self, r#type: &'a T) -> TypeIter {
145        let ty = self.resolve_chained_type(r#type).ok();
146        TypeIter {
147            btf: self,
148            r#type: ty,
149        }
150    }
151}
152
153/// Iterator type returned by `Btf::type_iter()`.
154pub struct TypeIter<'a> {
155    btf: &'a Btf,
156    r#type: Option<Type>,
157}
158
159/// Iterator for `Btf::TypeIter`.
160impl<'a> Iterator for TypeIter<'a> {
161    type Item = Type;
162
163    fn next(&mut self) -> Option<Self::Item> {
164        match self.r#type.clone() {
165            None => None,
166            Some(ty) => {
167                self.r#type = match ty.as_btf_type() {
168                    Some(x) => self.btf.resolve_chained_type(x).ok(),
169                    // We might have encountered Void or other
170                    // non-BtfType types.
171                    None => None,
172                };
173                Some(ty)
174            }
175        }
176    }
177}
178
179/// Rust representation of BTF types. Each type then contains its own specific
180/// data and provides helpers to access it.
181#[derive(Clone, Debug)]
182pub enum Type {
183    Void,
184    Int(Int),
185    Ptr(Ptr),
186    Array(Array),
187    Struct(Struct),
188    Union(Union),
189    Enum(Enum),
190    Fwd(Fwd),
191    Typedef(Typedef),
192    Volatile(Volatile),
193    Const(Const),
194    Restrict(Restrict),
195    Func(Func),
196    FuncProto(FuncProto),
197    Var(Var),
198    Datasec(Datasec),
199    Float(Float),
200    DeclTag(DeclTag),
201    TypeTag(TypeTag),
202    Enum64(Enum64),
203}
204
205impl Type {
206    pub fn name(&self) -> &'static str {
207        match &self {
208            Type::Void => "void",
209            Type::Int(_) => "int",
210            Type::Ptr(_) => "ptr",
211            Type::Array(_) => "array",
212            Type::Struct(_) => "struct",
213            Type::Union(_) => "union",
214            Type::Enum(_) => "enum",
215            Type::Fwd(_) => "fwd",
216            Type::Typedef(_) => "typedef",
217            Type::Volatile(_) => "volatile",
218            Type::Const(_) => "const",
219            Type::Restrict(_) => "restrict",
220            Type::Func(_) => "func",
221            Type::FuncProto(_) => "func-proto",
222            Type::Var(_) => "var",
223            Type::Datasec(_) => "datasec",
224            Type::Float(_) => "float",
225            Type::DeclTag(_) => "decl-tag",
226            Type::TypeTag(_) => "type-tag",
227            Type::Enum64(_) => "enum64",
228        }
229    }
230
231    pub fn as_btf_type(&self) -> Option<&dyn BtfType> {
232        match self {
233            Type::Int(i) => Some(i),
234            Type::Ptr(p) => Some(p),
235            Type::Array(a) => Some(a),
236            Type::Struct(s) => Some(s),
237            Type::Union(u) => Some(u),
238            Type::Enum(e) => Some(e),
239            Type::Fwd(f) => Some(f),
240            Type::Typedef(td) => Some(td),
241            Type::Volatile(v) => Some(v),
242            Type::Const(c) => Some(c),
243            Type::Restrict(r) => Some(r),
244            Type::Func(fu) => Some(fu),
245            Type::Var(v) => Some(v),
246            Type::Datasec(ds) => Some(ds),
247            Type::Float(f) => Some(f),
248            Type::DeclTag(dt) => Some(dt),
249            Type::TypeTag(tt) => Some(tt),
250            Type::Enum64(e64) => Some(e64),
251            _ => None,
252        }
253    }
254}
255
256pub trait BtfType {
257    fn get_name_offset(&self) -> Result<u32> {
258        bail!("No name offset in type");
259    }
260
261    fn get_type_id(&self) -> Result<u32> {
262        bail!("No type offset in type");
263    }
264}
265
266/// Rust representation for BTF type `BTF_KIND_INT`.
267#[derive(Clone, Debug)]
268pub struct Int {
269    btf_type: cbtf::btf_type,
270    btf_int: cbtf::btf_int,
271}
272
273impl Int {
274    pub(super) fn from_reader<R: Read>(
275        reader: &mut R,
276        endianness: &cbtf::Endianness,
277        btf_type: cbtf::btf_type,
278    ) -> Result<Int> {
279        Ok(Int {
280            btf_type,
281            btf_int: cbtf::btf_int::from_reader(reader, endianness)?,
282        })
283    }
284
285    pub fn is_signed(&self) -> bool {
286        self.btf_int.encoding() & cbtf::BTF_INT_SIGNED == cbtf::BTF_INT_SIGNED
287    }
288
289    pub fn is_char(&self) -> bool {
290        self.btf_int.encoding() & cbtf::BTF_INT_CHAR == cbtf::BTF_INT_CHAR
291    }
292
293    pub fn is_bool(&self) -> bool {
294        self.btf_int.encoding() & cbtf::BTF_INT_BOOL == cbtf::BTF_INT_BOOL
295    }
296
297    pub fn size(&self) -> usize {
298        self.btf_type.size()
299    }
300}
301
302impl BtfType for Int {
303    fn get_name_offset(&self) -> Result<u32> {
304        Ok(self.btf_type.name_off)
305    }
306}
307
308/// Rust representation for BTF type `BTF_KIND_PTR`.
309#[derive(Clone, Debug)]
310pub struct Ptr {
311    btf_type: cbtf::btf_type,
312}
313
314impl Ptr {
315    pub(super) fn new(btf_type: cbtf::btf_type) -> Ptr {
316        Ptr { btf_type }
317    }
318}
319
320impl BtfType for Ptr {
321    fn get_type_id(&self) -> Result<u32> {
322        Ok(self.btf_type.r#type())
323    }
324}
325
326/// Rust representation for BTF type `BTF_KIND_ARRAY`.
327#[derive(Clone, Debug)]
328pub struct Array {
329    btf_type: cbtf::btf_type,
330    btf_array: cbtf::btf_array,
331}
332
333#[allow(clippy::len_without_is_empty)]
334impl Array {
335    pub(super) fn from_reader<R: Read>(
336        reader: &mut R,
337        endianness: &cbtf::Endianness,
338        btf_type: cbtf::btf_type,
339    ) -> Result<Array> {
340        Ok(Array {
341            btf_type,
342            btf_array: cbtf::btf_array::from_reader(reader, endianness)?,
343        })
344    }
345
346    pub fn len(&self) -> usize {
347        self.btf_array.nelems as usize
348    }
349}
350
351impl BtfType for Array {
352    fn get_type_id(&self) -> Result<u32> {
353        Ok(self.btf_array.r#type)
354    }
355}
356
357/// Rust representation for BTF type `BTF_KIND_STRUCT`.
358#[derive(Clone, Debug)]
359pub struct Struct {
360    btf_type: cbtf::btf_type,
361    pub members: Vec<Member>,
362}
363
364impl Struct {
365    pub(super) fn from_reader<R: Read>(
366        reader: &mut R,
367        endianness: &cbtf::Endianness,
368        btf_type: cbtf::btf_type,
369    ) -> Result<Struct> {
370        let mut members = Vec::new();
371
372        for _ in 0..btf_type.vlen() {
373            members.push(Member::from_reader(
374                reader,
375                endianness,
376                btf_type.kind_flag(),
377            )?);
378        }
379
380        Ok(Struct { btf_type, members })
381    }
382
383    pub fn size(&self) -> usize {
384        self.btf_type.size()
385    }
386}
387
388impl BtfType for Struct {
389    fn get_name_offset(&self) -> Result<u32> {
390        Ok(self.btf_type.name_off)
391    }
392}
393
394/// Rust representation for BTF type `BTF_KIND_UNION`.
395pub type Union = Struct;
396
397/// Represents a [`Struct`] member.
398#[derive(Clone, Debug)]
399pub struct Member {
400    kind_flag: u32,
401    btf_member: cbtf::btf_member,
402}
403
404impl Member {
405    pub(super) fn from_reader<R: Read>(
406        reader: &mut R,
407        endianness: &cbtf::Endianness,
408        kind_flag: u32,
409    ) -> Result<Member> {
410        Ok(Member {
411            kind_flag,
412            btf_member: cbtf::btf_member::from_reader(reader, endianness)?,
413        })
414    }
415
416    pub fn bit_offset(&self) -> u32 {
417        match self.kind_flag {
418            1 => self.btf_member.offset & 0xffffff,
419            _ => self.btf_member.offset,
420        }
421    }
422
423    pub fn bitfield_size(&self) -> Option<u32> {
424        match self.kind_flag {
425            1 => Some(self.btf_member.offset >> 24),
426            _ => None,
427        }
428    }
429}
430
431impl BtfType for Member {
432    fn get_name_offset(&self) -> Result<u32> {
433        Ok(self.btf_member.name_off)
434    }
435
436    fn get_type_id(&self) -> Result<u32> {
437        Ok(self.btf_member.r#type)
438    }
439}
440
441/// Rust representation for BTF type `BTF_KIND_ENUM`.
442#[derive(Clone, Debug)]
443pub struct Enum {
444    btf_type: cbtf::btf_type,
445    pub members: Vec<EnumMember>,
446}
447
448#[allow(clippy::len_without_is_empty)]
449impl Enum {
450    pub(super) fn from_reader<R: Read>(
451        reader: &mut R,
452        endianness: &cbtf::Endianness,
453        btf_type: cbtf::btf_type,
454    ) -> Result<Enum> {
455        let mut members = Vec::new();
456
457        for _ in 0..btf_type.vlen() {
458            members.push(EnumMember::from_reader(reader, endianness)?);
459        }
460
461        Ok(Enum { btf_type, members })
462    }
463
464    pub fn is_signed(&self) -> bool {
465        self.btf_type.kind_flag() == 1
466    }
467
468    pub fn len(&self) -> usize {
469        self.btf_type.vlen() as usize
470    }
471
472    pub fn size(&self) -> usize {
473        self.btf_type.size()
474    }
475}
476
477impl BtfType for Enum {
478    fn get_name_offset(&self) -> Result<u32> {
479        Ok(self.btf_type.name_off)
480    }
481}
482
483/// Represents an [`Enum`] member.
484#[derive(Clone, Debug)]
485pub struct EnumMember {
486    btf_enum: cbtf::btf_enum,
487}
488
489impl EnumMember {
490    pub(super) fn from_reader<R: Read>(
491        reader: &mut R,
492        endianness: &cbtf::Endianness,
493    ) -> Result<EnumMember> {
494        Ok(EnumMember {
495            btf_enum: cbtf::btf_enum::from_reader(reader, endianness)?,
496        })
497    }
498
499    pub fn val(&self) -> u32 {
500        self.btf_enum.val
501    }
502}
503
504impl BtfType for EnumMember {
505    fn get_name_offset(&self) -> Result<u32> {
506        Ok(self.btf_enum.name_off)
507    }
508}
509
510/// Rust representation for BTF type `BTF_KIND_FWD`.
511#[derive(Clone, Debug)]
512pub struct Fwd {
513    btf_type: cbtf::btf_type,
514}
515
516impl Fwd {
517    pub(super) fn new(btf_type: cbtf::btf_type) -> Fwd {
518        Fwd { btf_type }
519    }
520
521    /// Tests if the forward declaration is for a struct type.
522    pub fn is_struct(&self) -> bool {
523        self.btf_type.kind_flag() == 0
524    }
525
526    /// Tests if the forward declaration is for a union type.
527    pub fn is_union(&self) -> bool {
528        self.btf_type.kind_flag() == 1
529    }
530}
531
532impl BtfType for Fwd {
533    fn get_name_offset(&self) -> Result<u32> {
534        Ok(self.btf_type.name_off)
535    }
536}
537
538/// Rust representation for BTF type `BTF_KIND_TYPEDEF`.
539#[derive(Clone, Debug)]
540pub struct Typedef {
541    btf_type: cbtf::btf_type,
542}
543
544impl Typedef {
545    pub(super) fn new(btf_type: cbtf::btf_type) -> Typedef {
546        Typedef { btf_type }
547    }
548}
549
550impl BtfType for Typedef {
551    fn get_name_offset(&self) -> Result<u32> {
552        Ok(self.btf_type.name_off)
553    }
554
555    fn get_type_id(&self) -> Result<u32> {
556        Ok(self.btf_type.r#type())
557    }
558}
559
560/// Rust representation for BTF type `BTF_KIND_TYPE_TAG`.
561pub type TypeTag = Typedef;
562
563/// Rust representation for BTF type `BTF_KIND_VOLATILE`.
564#[derive(Clone, Debug)]
565pub struct Volatile {
566    btf_type: cbtf::btf_type,
567}
568
569impl Volatile {
570    pub(super) fn new(btf_type: cbtf::btf_type) -> Volatile {
571        Volatile { btf_type }
572    }
573}
574
575impl BtfType for Volatile {
576    fn get_type_id(&self) -> Result<u32> {
577        Ok(self.btf_type.r#type())
578    }
579}
580
581/// Rust representation for BTF type `BTF_KIND_CONST`.
582pub type Const = Volatile;
583
584/// Rust representation for BTF type `BTF_KIND_RESTRICT`.
585pub type Restrict = Volatile;
586
587/// Rust representation for BTF type `BTF_KIND_FUNC`.
588#[derive(Clone, Debug)]
589pub struct Func {
590    btf_type: cbtf::btf_type,
591}
592
593impl Func {
594    pub(super) fn new(btf_type: cbtf::btf_type) -> Func {
595        Func { btf_type }
596    }
597
598    pub fn is_static(&self) -> bool {
599        self.btf_type.vlen() == cbtf::BTF_FUNC_STATIC
600    }
601
602    pub fn is_global(&self) -> bool {
603        self.btf_type.vlen() == cbtf::BTF_FUNC_GLOBAL
604    }
605
606    pub fn is_extern(&self) -> bool {
607        self.btf_type.vlen() == cbtf::BTF_FUNC_EXTERN
608    }
609}
610
611impl BtfType for Func {
612    fn get_name_offset(&self) -> Result<u32> {
613        Ok(self.btf_type.name_off)
614    }
615
616    fn get_type_id(&self) -> Result<u32> {
617        Ok(self.btf_type.r#type())
618    }
619}
620
621/// Rust representation for BTF type `BTF_KIND_FUNC_PROTO`.
622#[derive(Clone, Debug)]
623pub struct FuncProto {
624    btf_type: cbtf::btf_type,
625    pub parameters: Vec<Parameter>,
626}
627
628impl FuncProto {
629    pub(super) fn from_reader<R: Read>(
630        reader: &mut R,
631        endianness: &cbtf::Endianness,
632        btf_type: cbtf::btf_type,
633    ) -> Result<FuncProto> {
634        let mut parameters = Vec::new();
635
636        for _ in 0..btf_type.vlen() {
637            parameters.push(Parameter::from_reader(reader, endianness)?);
638        }
639
640        Ok(FuncProto {
641            btf_type,
642            parameters,
643        })
644    }
645
646    pub fn return_type_id(&self) -> u32 {
647        self.btf_type.r#type()
648    }
649}
650
651/// Represents a [`FuncProto`] parameter.
652#[derive(Clone, Debug)]
653pub struct Parameter {
654    btf_param: cbtf::btf_param,
655}
656
657impl Parameter {
658    pub(super) fn from_reader<R: Read>(
659        reader: &mut R,
660        endianness: &cbtf::Endianness,
661    ) -> Result<Parameter> {
662        Ok(Parameter {
663            btf_param: cbtf::btf_param::from_reader(reader, endianness)?,
664        })
665    }
666
667    pub fn is_variadic(&self) -> bool {
668        self.btf_param.name_off == 0 && self.btf_param.r#type == 0
669    }
670}
671
672impl BtfType for Parameter {
673    fn get_name_offset(&self) -> Result<u32> {
674        Ok(self.btf_param.name_off)
675    }
676
677    fn get_type_id(&self) -> Result<u32> {
678        Ok(self.btf_param.r#type)
679    }
680}
681
682/// Rust representation for BTF type `BTF_KIND_VAR`.
683#[derive(Clone, Debug)]
684pub struct Var {
685    btf_type: cbtf::btf_type,
686    btf_var: cbtf::btf_var,
687}
688
689impl Var {
690    pub(super) fn from_reader<R: Read>(
691        reader: &mut R,
692        endianness: &cbtf::Endianness,
693        btf_type: cbtf::btf_type,
694    ) -> Result<Var> {
695        Ok(Var {
696            btf_type,
697            btf_var: cbtf::btf_var::from_reader(reader, endianness)?,
698        })
699    }
700
701    pub fn is_static(&self) -> bool {
702        self.btf_var.linkage == 0
703    }
704
705    pub fn is_global(&self) -> bool {
706        self.btf_var.linkage == 1
707    }
708}
709
710impl BtfType for Var {
711    fn get_name_offset(&self) -> Result<u32> {
712        Ok(self.btf_type.name_off)
713    }
714
715    fn get_type_id(&self) -> Result<u32> {
716        Ok(self.btf_type.r#type())
717    }
718}
719
720/// Rust representation for BTF type `BTF_KIND_DATASEC`.
721#[derive(Clone, Debug)]
722pub struct Datasec {
723    btf_type: cbtf::btf_type,
724    pub variables: Vec<VarSecinfo>,
725}
726
727impl Datasec {
728    pub(super) fn from_reader<R: Read>(
729        reader: &mut R,
730        endianness: &cbtf::Endianness,
731        btf_type: cbtf::btf_type,
732    ) -> Result<Datasec> {
733        let mut variables = Vec::new();
734
735        for _ in 0..btf_type.vlen() {
736            variables.push(VarSecinfo::from_reader(reader, endianness)?);
737        }
738
739        Ok(Datasec {
740            btf_type,
741            variables,
742        })
743    }
744}
745
746impl BtfType for Datasec {
747    fn get_name_offset(&self) -> Result<u32> {
748        Ok(self.btf_type.name_off)
749    }
750}
751
752/// Represents a [`Datasec`] variable.
753#[derive(Clone, Debug)]
754pub struct VarSecinfo {
755    btf_var_secinfo: cbtf::btf_var_secinfo,
756}
757
758impl VarSecinfo {
759    pub(super) fn from_reader<R: Read>(
760        reader: &mut R,
761        endianness: &cbtf::Endianness,
762    ) -> Result<VarSecinfo> {
763        Ok(VarSecinfo {
764            btf_var_secinfo: cbtf::btf_var_secinfo::from_reader(reader, endianness)?,
765        })
766    }
767
768    pub fn offset(&self) -> u32 {
769        self.btf_var_secinfo.offset
770    }
771
772    pub fn size(&self) -> usize {
773        self.btf_var_secinfo.size as usize
774    }
775}
776
777impl BtfType for VarSecinfo {
778    fn get_type_id(&self) -> Result<u32> {
779        Ok(self.btf_var_secinfo.r#type)
780    }
781}
782
783/// Rust representation for BTF type `BTF_KIND_FLOAT`.
784#[derive(Clone, Debug)]
785pub struct Float {
786    btf_type: cbtf::btf_type,
787}
788
789impl Float {
790    pub(super) fn new(btf_type: cbtf::btf_type) -> Float {
791        Float { btf_type }
792    }
793
794    pub fn size(&self) -> usize {
795        self.btf_type.size()
796    }
797}
798
799impl BtfType for Float {
800    fn get_name_offset(&self) -> Result<u32> {
801        Ok(self.btf_type.name_off)
802    }
803}
804
805/// Rust representation for BTF type `BTF_KIND_DECL_TAG`.
806#[derive(Clone, Debug)]
807pub struct DeclTag {
808    btf_type: cbtf::btf_type,
809    btf_decl_tag: cbtf::btf_decl_tag,
810}
811
812impl DeclTag {
813    pub(super) fn from_reader<R: Read>(
814        reader: &mut R,
815        endianness: &cbtf::Endianness,
816        btf_type: cbtf::btf_type,
817    ) -> Result<DeclTag> {
818        Ok(DeclTag {
819            btf_type,
820            btf_decl_tag: cbtf::btf_decl_tag::from_reader(reader, endianness)?,
821        })
822    }
823
824    pub fn component_index(&self) -> Option<u32> {
825        let component_idx = self.btf_decl_tag.component_idx;
826        match component_idx {
827            x if x < 0 => None,
828            x => Some(x as u32),
829        }
830    }
831}
832
833impl BtfType for DeclTag {
834    fn get_name_offset(&self) -> Result<u32> {
835        Ok(self.btf_type.name_off)
836    }
837
838    fn get_type_id(&self) -> Result<u32> {
839        Ok(self.btf_type.r#type())
840    }
841}
842
843/// Rust representation for BTF type `BTF_KIND_ENUM64`.
844#[derive(Clone, Debug)]
845pub struct Enum64 {
846    btf_type: cbtf::btf_type,
847    pub members: Vec<Enum64Member>,
848}
849
850#[allow(clippy::len_without_is_empty)]
851impl Enum64 {
852    pub(super) fn from_reader<R: Read>(
853        reader: &mut R,
854        endianness: &cbtf::Endianness,
855        btf_type: cbtf::btf_type,
856    ) -> Result<Enum64> {
857        let mut members = Vec::new();
858
859        for _ in 0..btf_type.vlen() {
860            members.push(Enum64Member::from_reader(reader, endianness)?);
861        }
862
863        Ok(Enum64 { btf_type, members })
864    }
865
866    pub fn is_signed(&self) -> bool {
867        self.btf_type.kind_flag() == 1
868    }
869
870    pub fn len(&self) -> usize {
871        self.btf_type.vlen() as usize
872    }
873
874    pub fn size(&self) -> usize {
875        self.btf_type.size()
876    }
877}
878
879impl BtfType for Enum64 {
880    fn get_name_offset(&self) -> Result<u32> {
881        Ok(self.btf_type.name_off)
882    }
883}
884
885/// Represents an [`Enum64`] member.
886#[derive(Clone, Debug)]
887pub struct Enum64Member {
888    btf_enum64: cbtf::btf_enum64,
889}
890
891impl Enum64Member {
892    pub(super) fn from_reader<R: Read>(
893        reader: &mut R,
894        endianness: &cbtf::Endianness,
895    ) -> Result<Enum64Member> {
896        Ok(Enum64Member {
897            btf_enum64: cbtf::btf_enum64::from_reader(reader, endianness)?,
898        })
899    }
900
901    pub fn val(&self) -> u64 {
902        (self.btf_enum64.val_hi32 as u64) << 32 | self.btf_enum64.val_lo32 as u64
903    }
904}
905
906impl BtfType for Enum64Member {
907    fn get_name_offset(&self) -> Result<u32> {
908        Ok(self.btf_enum64.name_off)
909    }
910}