Skip to main content

aya_obj/btf/
types.rs

1#![expect(clippy::unused_self, reason = "these APIs are horrible")]
2#![expect(missing_docs, reason = "TODO")]
3
4use std::{fmt::Display, ptr, string::ToString as _};
5
6use object::Endianness;
7
8use crate::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH};
9
10#[derive(Clone, Debug)]
11pub enum BtfType {
12    Unknown,
13    Fwd(Fwd),
14    Const(Const),
15    Volatile(Volatile),
16    Restrict(Restrict),
17    Ptr(Ptr),
18    Typedef(Typedef),
19    Func(Func),
20    Int(Int),
21    Float(Float),
22    Enum(Enum),
23    Array(Array),
24    Struct(Struct),
25    Union(Union),
26    FuncProto(FuncProto),
27    Var(Var),
28    DataSec(DataSec),
29    DeclTag(DeclTag),
30    TypeTag(TypeTag),
31    Enum64(Enum64),
32}
33
34#[repr(C)]
35#[derive(Clone, Debug)]
36pub struct Fwd {
37    pub(crate) name_offset: u32,
38    info: u32,
39    _unused: u32,
40}
41
42impl Fwd {
43    pub(crate) fn to_bytes(&self) -> Vec<u8> {
44        bytes_of::<Self>(self).to_vec()
45    }
46
47    pub(crate) const fn kind(&self) -> BtfKind {
48        BtfKind::Fwd
49    }
50
51    pub(crate) const fn type_info_size(&self) -> usize {
52        size_of::<Self>()
53    }
54}
55
56#[repr(C)]
57#[derive(Clone, Debug)]
58pub struct Const {
59    pub(crate) name_offset: u32,
60    info: u32,
61    pub(crate) btf_type: u32,
62}
63
64impl Const {
65    pub(crate) fn to_bytes(&self) -> Vec<u8> {
66        bytes_of::<Self>(self).to_vec()
67    }
68
69    pub(crate) const fn kind(&self) -> BtfKind {
70        BtfKind::Const
71    }
72
73    pub(crate) const fn type_info_size(&self) -> usize {
74        size_of::<Self>()
75    }
76
77    pub(crate) const fn new(btf_type: u32) -> Self {
78        let info = (BtfKind::Const as u32) << 24;
79        Self {
80            name_offset: 0,
81            info,
82            btf_type,
83        }
84    }
85}
86
87#[repr(C)]
88#[derive(Clone, Debug)]
89pub struct Volatile {
90    pub(crate) name_offset: u32,
91    info: u32,
92    pub(crate) btf_type: u32,
93}
94
95impl Volatile {
96    pub(crate) fn to_bytes(&self) -> Vec<u8> {
97        bytes_of::<Self>(self).to_vec()
98    }
99
100    pub(crate) const fn kind(&self) -> BtfKind {
101        BtfKind::Volatile
102    }
103
104    pub(crate) const fn type_info_size(&self) -> usize {
105        size_of::<Self>()
106    }
107}
108
109#[derive(Clone, Debug)]
110pub struct Restrict {
111    pub(crate) name_offset: u32,
112    _info: u32,
113    pub(crate) btf_type: u32,
114}
115
116impl Restrict {
117    pub(crate) fn to_bytes(&self) -> Vec<u8> {
118        bytes_of::<Self>(self).to_vec()
119    }
120
121    pub(crate) const fn kind(&self) -> BtfKind {
122        BtfKind::Restrict
123    }
124
125    pub(crate) const fn type_info_size(&self) -> usize {
126        size_of::<Self>()
127    }
128}
129
130#[repr(C)]
131#[derive(Clone, Debug)]
132pub struct Ptr {
133    pub(crate) name_offset: u32,
134    info: u32,
135    pub(crate) btf_type: u32,
136}
137
138impl Ptr {
139    pub(crate) fn to_bytes(&self) -> Vec<u8> {
140        bytes_of::<Self>(self).to_vec()
141    }
142
143    pub(crate) const fn kind(&self) -> BtfKind {
144        BtfKind::Ptr
145    }
146
147    pub(crate) const fn type_info_size(&self) -> usize {
148        size_of::<Self>()
149    }
150
151    pub const fn new(name_offset: u32, btf_type: u32) -> Self {
152        let info = (BtfKind::Ptr as u32) << 24;
153        Self {
154            name_offset,
155            info,
156            btf_type,
157        }
158    }
159}
160
161#[repr(C)]
162#[derive(Clone, Debug)]
163pub struct Typedef {
164    pub(crate) name_offset: u32,
165    info: u32,
166    pub(crate) btf_type: u32,
167}
168
169impl Typedef {
170    pub(crate) fn to_bytes(&self) -> Vec<u8> {
171        bytes_of::<Self>(self).to_vec()
172    }
173
174    pub(crate) const fn kind(&self) -> BtfKind {
175        BtfKind::Typedef
176    }
177
178    pub(crate) const fn type_info_size(&self) -> usize {
179        size_of::<Self>()
180    }
181
182    pub(crate) const fn new(name_offset: u32, btf_type: u32) -> Self {
183        let info = (BtfKind::Typedef as u32) << 24;
184        Self {
185            name_offset,
186            info,
187            btf_type,
188        }
189    }
190}
191
192#[repr(C)]
193#[derive(Clone, Debug)]
194pub struct Float {
195    pub(crate) name_offset: u32,
196    info: u32,
197    pub(crate) size: u32,
198}
199
200impl Float {
201    pub(crate) fn to_bytes(&self) -> Vec<u8> {
202        bytes_of::<Self>(self).to_vec()
203    }
204
205    pub(crate) const fn kind(&self) -> BtfKind {
206        BtfKind::Float
207    }
208    pub(crate) const fn type_info_size(&self) -> usize {
209        size_of::<Self>()
210    }
211
212    pub const fn new(name_offset: u32, size: u32) -> Self {
213        let info = (BtfKind::Float as u32) << 24;
214        Self {
215            name_offset,
216            info,
217            size,
218        }
219    }
220}
221
222#[repr(C)]
223#[derive(Clone, Debug)]
224pub struct Func {
225    pub(crate) name_offset: u32,
226    info: u32,
227    pub(crate) btf_type: u32,
228}
229
230#[repr(u32)]
231#[derive(Clone, Debug, PartialEq, Eq)]
232pub enum FuncLinkage {
233    Static = 0,
234    Global = 1,
235    Extern = 2,
236    Unknown,
237}
238
239impl From<u32> for FuncLinkage {
240    fn from(v: u32) -> Self {
241        match v {
242            0 => Self::Static,
243            1 => Self::Global,
244            2 => Self::Extern,
245            _ => Self::Unknown,
246        }
247    }
248}
249
250impl Func {
251    pub(crate) fn to_bytes(&self) -> Vec<u8> {
252        bytes_of::<Self>(self).to_vec()
253    }
254
255    pub(crate) const fn kind(&self) -> BtfKind {
256        BtfKind::Func
257    }
258    pub(crate) const fn type_info_size(&self) -> usize {
259        size_of::<Self>()
260    }
261
262    pub const fn new(name_offset: u32, proto: u32, linkage: FuncLinkage) -> Self {
263        let mut info = (BtfKind::Func as u32) << 24;
264        info |= (linkage as u32) & 0xFFFF;
265        Self {
266            name_offset,
267            info,
268            btf_type: proto,
269        }
270    }
271
272    pub(crate) fn linkage(&self) -> FuncLinkage {
273        (self.info & 0xFFFF).into()
274    }
275
276    pub(crate) const fn set_linkage(&mut self, linkage: FuncLinkage) {
277        self.info = (self.info & 0xFFFF0000) | (linkage as u32) & 0xFFFF;
278    }
279}
280
281#[repr(C)]
282#[derive(Clone, Debug)]
283pub struct TypeTag {
284    pub(crate) name_offset: u32,
285    info: u32,
286    pub(crate) btf_type: u32,
287}
288
289impl TypeTag {
290    pub(crate) fn to_bytes(&self) -> Vec<u8> {
291        bytes_of::<Self>(self).to_vec()
292    }
293
294    pub(crate) const fn kind(&self) -> BtfKind {
295        BtfKind::TypeTag
296    }
297
298    pub(crate) const fn type_info_size(&self) -> usize {
299        size_of::<Self>()
300    }
301
302    pub const fn new(name_offset: u32, btf_type: u32) -> Self {
303        let info = (BtfKind::TypeTag as u32) << 24;
304        Self {
305            name_offset,
306            info,
307            btf_type,
308        }
309    }
310}
311
312#[repr(u32)]
313#[derive(Clone, Debug, Eq, PartialEq)]
314pub enum IntEncoding {
315    None,
316    Signed = 1,
317    Char = 2,
318    Bool = 4,
319    Unknown,
320}
321
322impl From<u32> for IntEncoding {
323    fn from(v: u32) -> Self {
324        match v {
325            0 => Self::None,
326            1 => Self::Signed,
327            2 => Self::Char,
328            4 => Self::Bool,
329            _ => Self::Unknown,
330        }
331    }
332}
333
334#[repr(C)]
335#[derive(Clone, Debug)]
336pub struct Int {
337    pub(crate) name_offset: u32,
338    info: u32,
339    pub(crate) size: u32,
340    pub(crate) data: u32,
341}
342
343impl Int {
344    pub(crate) fn to_bytes(&self) -> Vec<u8> {
345        let Self {
346            name_offset,
347            info,
348            size,
349            data,
350        } = self;
351        [
352            bytes_of::<u32>(name_offset),
353            bytes_of::<u32>(info),
354            bytes_of::<u32>(size),
355            bytes_of::<u32>(data),
356        ]
357        .concat()
358    }
359
360    pub(crate) const fn kind(&self) -> BtfKind {
361        BtfKind::Int
362    }
363    pub(crate) const fn type_info_size(&self) -> usize {
364        size_of::<Self>()
365    }
366
367    pub const fn new(name_offset: u32, size: u32, encoding: IntEncoding, offset: u32) -> Self {
368        let info = (BtfKind::Int as u32) << 24;
369        let mut data = 0u32;
370        data |= (encoding as u32 & 0x0f) << 24;
371        data |= (offset & 0xff) << 16;
372        data |= (size * 8) & 0xff;
373        Self {
374            name_offset,
375            info,
376            size,
377            data,
378        }
379    }
380
381    pub(crate) fn encoding(&self) -> IntEncoding {
382        ((self.data & 0x0f000000) >> 24).into()
383    }
384
385    pub(crate) const fn offset(&self) -> u32 {
386        (self.data & 0x00ff0000) >> 16
387    }
388
389    // TODO: Remove directive this when this crate is pub
390    #[cfg(test)]
391    pub(crate) const fn bits(&self) -> u32 {
392        self.data & 0x000000ff
393    }
394}
395
396#[repr(C)]
397#[derive(Debug, Clone)]
398pub struct BtfEnum {
399    pub name_offset: u32,
400    pub value: u32,
401}
402
403impl BtfEnum {
404    pub const fn new(name_offset: u32, value: u32) -> Self {
405        Self { name_offset, value }
406    }
407}
408
409#[repr(C)]
410#[derive(Clone, Debug)]
411pub struct Enum {
412    pub(crate) name_offset: u32,
413    info: u32,
414    pub(crate) size: u32,
415    pub(crate) variants: Vec<BtfEnum>,
416}
417
418impl Enum {
419    pub(crate) fn to_bytes(&self) -> Vec<u8> {
420        let Self {
421            name_offset,
422            info,
423            size,
424            variants,
425        } = self;
426        [
427            bytes_of::<u32>(name_offset),
428            bytes_of::<u32>(info),
429            bytes_of::<u32>(size),
430        ]
431        .into_iter()
432        .chain(variants.iter().flat_map(|BtfEnum { name_offset, value }| {
433            [bytes_of::<u32>(name_offset), bytes_of::<u32>(value)]
434        }))
435        .flatten()
436        .copied()
437        .collect()
438    }
439
440    pub(crate) const fn kind(&self) -> BtfKind {
441        BtfKind::Enum
442    }
443
444    pub(crate) const fn type_info_size(&self) -> usize {
445        size_of::<Fwd>() + size_of::<BtfEnum>() * self.variants.len()
446    }
447
448    pub const fn new(name_offset: u32, signed: bool, variants: Vec<BtfEnum>) -> Self {
449        let mut info = (BtfKind::Enum as u32) << 24;
450        info |= (variants.len() as u32) & 0xFFFF;
451        if signed {
452            info |= 1 << 31;
453        }
454        Self {
455            name_offset,
456            info,
457            size: 4,
458            variants,
459        }
460    }
461
462    pub(crate) const fn is_signed(&self) -> bool {
463        self.info >> 31 == 1
464    }
465
466    pub(crate) const fn set_signed(&mut self, signed: bool) {
467        if signed {
468            self.info |= 1 << 31;
469        } else {
470            self.info &= !(1 << 31);
471        }
472    }
473}
474
475#[repr(C)]
476#[derive(Debug, Clone, Copy)]
477pub struct BtfEnum64 {
478    pub(crate) name_offset: u32,
479    pub(crate) value_low: u32,
480    pub(crate) value_high: u32,
481}
482
483impl BtfEnum64 {
484    pub const fn new(name_offset: u32, value: u64) -> Self {
485        Self {
486            name_offset,
487            value_low: value as u32,
488            value_high: (value >> 32) as u32,
489        }
490    }
491}
492
493#[repr(C)]
494#[derive(Clone, Debug)]
495pub struct Enum64 {
496    pub(crate) name_offset: u32,
497    info: u32,
498    pub(crate) size: u32,
499    pub(crate) variants: Vec<BtfEnum64>,
500}
501
502impl Enum64 {
503    pub(crate) fn to_bytes(&self) -> Vec<u8> {
504        let Self {
505            name_offset,
506            info,
507            size,
508            variants,
509        } = self;
510        [
511            bytes_of::<u32>(name_offset),
512            bytes_of::<u32>(info),
513            bytes_of::<u32>(size),
514        ]
515        .into_iter()
516        .chain(variants.iter().flat_map(
517            |BtfEnum64 {
518                 name_offset,
519                 value_low,
520                 value_high,
521             }| {
522                [
523                    bytes_of::<u32>(name_offset),
524                    bytes_of::<u32>(value_low),
525                    bytes_of::<u32>(value_high),
526                ]
527            },
528        ))
529        .flatten()
530        .copied()
531        .collect()
532    }
533
534    pub(crate) const fn kind(&self) -> BtfKind {
535        BtfKind::Enum64
536    }
537
538    pub(crate) const fn type_info_size(&self) -> usize {
539        size_of::<Fwd>() + size_of::<BtfEnum64>() * self.variants.len()
540    }
541
542    pub(crate) const fn is_signed(&self) -> bool {
543        self.info >> 31 == 1
544    }
545
546    pub const fn new(name_offset: u32, signed: bool, variants: Vec<BtfEnum64>) -> Self {
547        let mut info = (BtfKind::Enum64 as u32) << 24;
548        if signed {
549            info |= 1 << 31
550        }
551        info |= (variants.len() as u32) & 0xFFFF;
552        Self {
553            name_offset,
554            info,
555            // According to the documentation:
556            //
557            // https://www.kernel.org/doc/html/next/bpf/btf.html
558            //
559            // The size may be 1/2/4/8. Since BtfEnum64::new() takes a u64, we
560            // can assume that the size is 8.
561            size: 8,
562            variants,
563        }
564    }
565}
566
567#[repr(C)]
568#[derive(Clone, Debug)]
569pub(crate) struct BtfMember {
570    pub(crate) name_offset: u32,
571    pub(crate) btf_type: u32,
572    pub(crate) offset: u32,
573}
574
575#[repr(C)]
576#[derive(Clone, Debug)]
577pub struct Struct {
578    pub(crate) name_offset: u32,
579    info: u32,
580    pub(crate) size: u32,
581    pub(crate) members: Vec<BtfMember>,
582}
583
584impl Struct {
585    pub(crate) fn to_bytes(&self) -> Vec<u8> {
586        let Self {
587            name_offset,
588            info,
589            size,
590            members,
591        } = self;
592        [
593            bytes_of::<u32>(name_offset),
594            bytes_of::<u32>(info),
595            bytes_of::<u32>(size),
596        ]
597        .into_iter()
598        .chain(members.iter().flat_map(
599            |BtfMember {
600                 name_offset,
601                 btf_type,
602                 offset,
603             }| {
604                [
605                    bytes_of::<u32>(name_offset),
606                    bytes_of::<u32>(btf_type),
607                    bytes_of::<u32>(offset),
608                ]
609            },
610        ))
611        .flatten()
612        .copied()
613        .collect()
614    }
615
616    pub(crate) const fn kind(&self) -> BtfKind {
617        BtfKind::Struct
618    }
619
620    pub(crate) const fn type_info_size(&self) -> usize {
621        size_of::<Fwd>() + size_of::<BtfMember>() * self.members.len()
622    }
623
624    pub(crate) const fn new(name_offset: u32, members: Vec<BtfMember>, size: u32) -> Self {
625        let mut info = (BtfKind::Struct as u32) << 24;
626        info |= (members.len() as u32) & 0xFFFF;
627        Self {
628            name_offset,
629            info,
630            size,
631            members,
632        }
633    }
634
635    pub(crate) const fn member_bit_offset(&self, member: &BtfMember) -> usize {
636        let k_flag = self.info >> 31 == 1;
637        let bit_offset = if k_flag {
638            member.offset & 0xFFFFFF
639        } else {
640            member.offset
641        };
642
643        bit_offset as usize
644    }
645
646    pub(crate) const fn member_bit_field_size(&self, member: &BtfMember) -> usize {
647        let k_flag = (self.info >> 31) == 1;
648        let size = if k_flag { member.offset >> 24 } else { 0 };
649
650        size as usize
651    }
652}
653
654/// Snapshot of a single `ENUM64` variant so we can recover its 64-bit constant
655/// after the type is rewritten into a UNION.
656#[derive(Clone, Debug)]
657pub(crate) struct Enum64VariantFallback {
658    pub(crate) name_offset: u32,
659    pub(crate) value: u64,
660}
661
662/// Aggregate of the metadata we need to faithfully reconstruct a downgraded
663/// `ENUM64` during CO-RE relocation.
664#[derive(Clone, Debug)]
665pub(crate) struct Enum64Fallback {
666    pub(crate) signed: bool,
667    pub(crate) variants: Vec<Enum64VariantFallback>,
668}
669
670#[repr(C)]
671#[derive(Clone, Debug)]
672pub struct Union {
673    pub(crate) name_offset: u32,
674    info: u32,
675    pub(crate) size: u32,
676    pub(crate) members: Vec<BtfMember>,
677    pub(crate) enum64_fallback: Option<Enum64Fallback>,
678}
679
680impl Union {
681    pub(crate) const fn new(
682        name_offset: u32,
683        size: u32,
684        members: Vec<BtfMember>,
685        enum64_fallback: Option<Enum64Fallback>,
686    ) -> Self {
687        let mut info = (BtfKind::Union as u32) << 24;
688        info |= (members.len() as u32) & 0xFFFF;
689        Self {
690            name_offset,
691            info,
692            size,
693            members,
694            enum64_fallback,
695        }
696    }
697
698    pub(crate) fn to_bytes(&self) -> Vec<u8> {
699        let Self {
700            name_offset,
701            info,
702            size,
703            members,
704            enum64_fallback: _,
705        } = self;
706        [
707            bytes_of::<u32>(name_offset),
708            bytes_of::<u32>(info),
709            bytes_of::<u32>(size),
710        ]
711        .into_iter()
712        .chain(members.iter().flat_map(
713            |BtfMember {
714                 name_offset,
715                 btf_type,
716                 offset,
717             }| {
718                [
719                    bytes_of::<u32>(name_offset),
720                    bytes_of::<u32>(btf_type),
721                    bytes_of::<u32>(offset),
722                ]
723            },
724        ))
725        .flatten()
726        .copied()
727        .collect()
728    }
729
730    pub(crate) const fn kind(&self) -> BtfKind {
731        BtfKind::Union
732    }
733
734    pub(crate) const fn type_info_size(&self) -> usize {
735        size_of::<Fwd>() + size_of::<BtfMember>() * self.members.len()
736    }
737
738    pub(crate) const fn member_bit_offset(&self, member: &BtfMember) -> usize {
739        let k_flag = self.info >> 31 == 1;
740        let bit_offset = if k_flag {
741            member.offset & 0xFFFFFF
742        } else {
743            member.offset
744        };
745
746        bit_offset as usize
747    }
748
749    pub(crate) const fn member_bit_field_size(&self, member: &BtfMember) -> usize {
750        let k_flag = (self.info >> 31) == 1;
751        let size = if k_flag { member.offset >> 24 } else { 0 };
752
753        size as usize
754    }
755}
756
757#[repr(C)]
758#[derive(Clone, Debug)]
759pub(crate) struct BtfArray {
760    pub(crate) element_type: u32,
761    pub(crate) index_type: u32,
762    pub(crate) len: u32,
763}
764
765#[repr(C)]
766#[derive(Clone, Debug)]
767pub struct Array {
768    pub(crate) name_offset: u32,
769    info: u32,
770    _unused: u32,
771    #[expect(clippy::struct_field_names, reason = "TODO")]
772    pub(crate) array: BtfArray,
773}
774
775impl Array {
776    pub(crate) fn to_bytes(&self) -> Vec<u8> {
777        let Self {
778            name_offset,
779            info,
780            _unused,
781            array,
782        } = self;
783        [
784            bytes_of::<u32>(name_offset),
785            bytes_of::<u32>(info),
786            #[expect(clippy::used_underscore_binding, reason = "need them bytes")]
787            bytes_of::<u32>(_unused),
788            bytes_of::<BtfArray>(array),
789        ]
790        .concat()
791    }
792
793    pub(crate) const fn kind(&self) -> BtfKind {
794        BtfKind::Array
795    }
796
797    pub(crate) const fn type_info_size(&self) -> usize {
798        size_of::<Self>()
799    }
800
801    #[cfg(test)]
802    pub(crate) const fn new(
803        name_offset: u32,
804        element_type: u32,
805        index_type: u32,
806        len: u32,
807    ) -> Self {
808        let info = (BtfKind::Array as u32) << 24;
809        Self {
810            name_offset,
811            info,
812            _unused: 0,
813            array: BtfArray {
814                element_type,
815                index_type,
816                len,
817            },
818        }
819    }
820}
821
822#[repr(C)]
823#[derive(Clone, Debug)]
824pub struct BtfParam {
825    pub name_offset: u32,
826    pub btf_type: u32,
827}
828
829#[repr(C)]
830#[derive(Clone, Debug)]
831pub struct FuncProto {
832    pub(crate) name_offset: u32,
833    info: u32,
834    pub(crate) return_type: u32,
835    pub(crate) params: Vec<BtfParam>,
836}
837
838impl FuncProto {
839    pub(crate) fn to_bytes(&self) -> Vec<u8> {
840        let Self {
841            name_offset,
842            info,
843            return_type,
844            params,
845        } = self;
846        [
847            bytes_of::<u32>(name_offset),
848            bytes_of::<u32>(info),
849            bytes_of::<u32>(return_type),
850        ]
851        .into_iter()
852        .chain(params.iter().flat_map(
853            |BtfParam {
854                 name_offset,
855                 btf_type,
856             }| { [bytes_of::<u32>(name_offset), bytes_of::<u32>(btf_type)] },
857        ))
858        .flatten()
859        .copied()
860        .collect()
861    }
862
863    pub(crate) const fn kind(&self) -> BtfKind {
864        BtfKind::FuncProto
865    }
866
867    pub(crate) const fn type_info_size(&self) -> usize {
868        size_of::<Fwd>() + size_of::<BtfParam>() * self.params.len()
869    }
870
871    pub const fn new(params: Vec<BtfParam>, return_type: u32) -> Self {
872        let mut info = (BtfKind::FuncProto as u32) << 24;
873        info |= (params.len() as u32) & 0xFFFF;
874        Self {
875            name_offset: 0,
876            info,
877            return_type,
878            params,
879        }
880    }
881}
882
883#[repr(u32)]
884#[derive(Clone, Debug, PartialEq, Eq)]
885pub enum VarLinkage {
886    Static,
887    Global,
888    Extern,
889    Unknown,
890}
891
892impl From<u32> for VarLinkage {
893    fn from(v: u32) -> Self {
894        match v {
895            0 => Self::Static,
896            1 => Self::Global,
897            2 => Self::Extern,
898            _ => Self::Unknown,
899        }
900    }
901}
902
903#[repr(C)]
904#[derive(Clone, Debug)]
905pub struct Var {
906    pub(crate) name_offset: u32,
907    info: u32,
908    pub(crate) btf_type: u32,
909    pub(crate) linkage: VarLinkage,
910}
911
912impl Var {
913    pub(crate) fn to_bytes(&self) -> Vec<u8> {
914        let Self {
915            name_offset,
916            info,
917            btf_type,
918            linkage,
919        } = self;
920        [
921            bytes_of::<u32>(name_offset),
922            bytes_of::<u32>(info),
923            bytes_of::<u32>(btf_type),
924            bytes_of::<VarLinkage>(linkage),
925        ]
926        .concat()
927    }
928
929    pub(crate) const fn kind(&self) -> BtfKind {
930        BtfKind::Var
931    }
932
933    pub(crate) const fn type_info_size(&self) -> usize {
934        size_of::<Self>()
935    }
936
937    pub const fn new(name_offset: u32, btf_type: u32, linkage: VarLinkage) -> Self {
938        let info = (BtfKind::Var as u32) << 24;
939        Self {
940            name_offset,
941            info,
942            btf_type,
943            linkage,
944        }
945    }
946}
947
948#[repr(C)]
949#[derive(Clone, Debug)]
950pub struct DataSecEntry {
951    pub btf_type: u32,
952    pub offset: u32,
953    pub size: u32,
954}
955
956#[repr(C)]
957#[derive(Clone, Debug)]
958pub struct DataSec {
959    pub(crate) name_offset: u32,
960    info: u32,
961    pub(crate) size: u32,
962    pub(crate) entries: Vec<DataSecEntry>,
963}
964
965impl DataSec {
966    pub(crate) fn to_bytes(&self) -> Vec<u8> {
967        let Self {
968            name_offset,
969            info,
970            size,
971            entries,
972        } = self;
973        [
974            bytes_of::<u32>(name_offset),
975            bytes_of::<u32>(info),
976            bytes_of::<u32>(size),
977        ]
978        .into_iter()
979        .chain(entries.iter().flat_map(
980            |DataSecEntry {
981                 btf_type,
982                 offset,
983                 size,
984             }| {
985                [
986                    bytes_of::<u32>(btf_type),
987                    bytes_of::<u32>(offset),
988                    bytes_of::<u32>(size),
989                ]
990            },
991        ))
992        .flatten()
993        .copied()
994        .collect()
995    }
996
997    pub(crate) const fn kind(&self) -> BtfKind {
998        BtfKind::DataSec
999    }
1000
1001    pub(crate) const fn type_info_size(&self) -> usize {
1002        size_of::<Fwd>() + size_of::<DataSecEntry>() * self.entries.len()
1003    }
1004
1005    pub const fn new(name_offset: u32, entries: Vec<DataSecEntry>, size: u32) -> Self {
1006        let mut info = (BtfKind::DataSec as u32) << 24;
1007        info |= (entries.len() as u32) & 0xFFFF;
1008        Self {
1009            name_offset,
1010            info,
1011            size,
1012            entries,
1013        }
1014    }
1015}
1016
1017#[repr(C)]
1018#[derive(Clone, Debug)]
1019pub struct DeclTag {
1020    pub(crate) name_offset: u32,
1021    info: u32,
1022    pub(crate) btf_type: u32,
1023    pub(crate) component_index: i32,
1024}
1025
1026impl DeclTag {
1027    pub(crate) fn to_bytes(&self) -> Vec<u8> {
1028        let Self {
1029            name_offset,
1030            info,
1031            btf_type,
1032            component_index,
1033        } = self;
1034        [
1035            bytes_of::<u32>(name_offset),
1036            bytes_of::<u32>(info),
1037            bytes_of::<u32>(btf_type),
1038            bytes_of::<i32>(component_index),
1039        ]
1040        .concat()
1041    }
1042
1043    pub(crate) const fn kind(&self) -> BtfKind {
1044        BtfKind::DeclTag
1045    }
1046
1047    pub(crate) const fn type_info_size(&self) -> usize {
1048        size_of::<Self>()
1049    }
1050
1051    pub const fn new(name_offset: u32, btf_type: u32, component_index: i32) -> Self {
1052        let info = (BtfKind::DeclTag as u32) << 24;
1053        Self {
1054            name_offset,
1055            info,
1056            btf_type,
1057            component_index,
1058        }
1059    }
1060}
1061
1062#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
1063#[repr(u32)]
1064pub enum BtfKind {
1065    #[default]
1066    Unknown = 0,
1067    Int = 1,
1068    Ptr = 2,
1069    Array = 3,
1070    Struct = 4,
1071    Union = 5,
1072    Enum = 6,
1073    Fwd = 7,
1074    Typedef = 8,
1075    Volatile = 9,
1076    Const = 10,
1077    Restrict = 11,
1078    Func = 12,
1079    FuncProto = 13,
1080    Var = 14,
1081    DataSec = 15,
1082    Float = 16,
1083    DeclTag = 17,
1084    TypeTag = 18,
1085    Enum64 = 19,
1086}
1087
1088impl TryFrom<u32> for BtfKind {
1089    type Error = BtfError;
1090
1091    fn try_from(v: u32) -> Result<Self, Self::Error> {
1092        Ok(match v {
1093            0 => Self::Unknown,
1094            1 => Self::Int,
1095            2 => Self::Ptr,
1096            3 => Self::Array,
1097            4 => Self::Struct,
1098            5 => Self::Union,
1099            6 => Self::Enum,
1100            7 => Self::Fwd,
1101            8 => Self::Typedef,
1102            9 => Self::Volatile,
1103            10 => Self::Const,
1104            11 => Self::Restrict,
1105            12 => Self::Func,
1106            13 => Self::FuncProto,
1107            14 => Self::Var,
1108            15 => Self::DataSec,
1109            16 => Self::Float,
1110            17 => Self::DeclTag,
1111            18 => Self::TypeTag,
1112            19 => Self::Enum64,
1113            kind => return Err(BtfError::InvalidTypeKind { kind }),
1114        })
1115    }
1116}
1117
1118impl Display for BtfKind {
1119    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1120        match self {
1121            Self::Unknown => write!(f, "[UNKNOWN]"),
1122            Self::Int => write!(f, "[INT]"),
1123            Self::Float => write!(f, "[FLOAT]"),
1124            Self::Ptr => write!(f, "[PTR]"),
1125            Self::Array => write!(f, "[ARRAY]"),
1126            Self::Struct => write!(f, "[STRUCT]"),
1127            Self::Union => write!(f, "[UNION]"),
1128            Self::Enum => write!(f, "[ENUM]"),
1129            Self::Fwd => write!(f, "[FWD]"),
1130            Self::Typedef => write!(f, "[TYPEDEF]"),
1131            Self::Volatile => write!(f, "[VOLATILE]"),
1132            Self::Const => write!(f, "[CONST]"),
1133            Self::Restrict => write!(f, "[RESTRICT]"),
1134            Self::Func => write!(f, "[FUNC]"),
1135            Self::FuncProto => write!(f, "[FUNC_PROTO]"),
1136            Self::Var => write!(f, "[VAR]"),
1137            Self::DataSec => write!(f, "[DATASEC]"),
1138            Self::DeclTag => write!(f, "[DECL_TAG]"),
1139            Self::TypeTag => write!(f, "[TYPE_TAG]"),
1140            Self::Enum64 => write!(f, "[ENUM64]"),
1141        }
1142    }
1143}
1144
1145const unsafe fn read<T>(data: &[u8]) -> Result<T, BtfError> {
1146    if size_of::<T>() > data.len() {
1147        return Err(BtfError::InvalidTypeInfo);
1148    }
1149
1150    Ok(unsafe { ptr::read_unaligned(data.as_ptr().cast()) })
1151}
1152
1153unsafe fn read_array<T>(data: &[u8], len: usize) -> Result<Vec<T>, BtfError> {
1154    if size_of::<T>() * len > data.len() {
1155        return Err(BtfError::InvalidTypeInfo);
1156    }
1157    let data = &data[0..size_of::<T>() * len];
1158    let r = data
1159        .chunks(size_of::<T>())
1160        .map(|chunk| unsafe { ptr::read_unaligned(chunk.as_ptr().cast()) })
1161        .collect();
1162    Ok(r)
1163}
1164
1165impl BtfType {
1166    pub(crate) unsafe fn read(data: &[u8], endianness: Endianness) -> Result<Self, BtfError> {
1167        let ty = unsafe { read_array::<u32>(data, 3)? };
1168        let data = &data[size_of::<u32>() * 3..];
1169        let vlen = type_vlen(ty[1]);
1170        Ok(match type_kind(ty[1])? {
1171            BtfKind::Unknown => Self::Unknown,
1172            BtfKind::Fwd => Self::Fwd(Fwd {
1173                name_offset: ty[0],
1174                info: ty[1],
1175                _unused: 0,
1176            }),
1177            BtfKind::Const => Self::Const(Const {
1178                name_offset: ty[0],
1179                info: ty[1],
1180                btf_type: ty[2],
1181            }),
1182            BtfKind::Volatile => Self::Volatile(Volatile {
1183                name_offset: ty[0],
1184                info: ty[1],
1185                btf_type: ty[2],
1186            }),
1187            BtfKind::Restrict => Self::Restrict(Restrict {
1188                name_offset: ty[0],
1189                _info: ty[1],
1190                btf_type: ty[2],
1191            }),
1192            BtfKind::Ptr => Self::Ptr(Ptr {
1193                name_offset: ty[0],
1194                info: ty[1],
1195                btf_type: ty[2],
1196            }),
1197            BtfKind::Typedef => Self::Typedef(Typedef {
1198                name_offset: ty[0],
1199                info: ty[1],
1200                btf_type: ty[2],
1201            }),
1202            BtfKind::Func => Self::Func(Func {
1203                name_offset: ty[0],
1204                info: ty[1],
1205                btf_type: ty[2],
1206            }),
1207            BtfKind::Int => {
1208                if size_of::<u32>() > data.len() {
1209                    return Err(BtfError::InvalidTypeInfo);
1210                }
1211                let read_u32 = if endianness == Endianness::Little {
1212                    u32::from_le_bytes
1213                } else {
1214                    u32::from_be_bytes
1215                };
1216                Self::Int(Int {
1217                    name_offset: ty[0],
1218                    info: ty[1],
1219                    size: ty[2],
1220                    data: read_u32(data[..size_of::<u32>()].try_into().unwrap()),
1221                })
1222            }
1223            BtfKind::Float => Self::Float(Float {
1224                name_offset: ty[0],
1225                info: ty[1],
1226                size: ty[2],
1227            }),
1228            BtfKind::Enum => Self::Enum(Enum {
1229                name_offset: ty[0],
1230                info: ty[1],
1231                size: ty[2],
1232                variants: unsafe { read_array::<BtfEnum>(data, vlen)? },
1233            }),
1234            BtfKind::Enum64 => Self::Enum64(Enum64 {
1235                name_offset: ty[0],
1236                info: ty[1],
1237                size: ty[2],
1238                variants: unsafe { read_array::<BtfEnum64>(data, vlen)? },
1239            }),
1240            BtfKind::Array => Self::Array(Array {
1241                name_offset: ty[0],
1242                info: ty[1],
1243                _unused: 0,
1244                array: unsafe { read(data)? },
1245            }),
1246            BtfKind::Struct => Self::Struct(Struct {
1247                name_offset: ty[0],
1248                info: ty[1],
1249                size: ty[2],
1250                members: unsafe { read_array::<BtfMember>(data, vlen)? },
1251            }),
1252            BtfKind::Union => Self::Union(Union {
1253                name_offset: ty[0],
1254                info: ty[1],
1255                size: ty[2],
1256                members: unsafe { read_array::<BtfMember>(data, vlen)? },
1257                enum64_fallback: None,
1258            }),
1259            BtfKind::FuncProto => Self::FuncProto(FuncProto {
1260                name_offset: ty[0],
1261                info: ty[1],
1262                return_type: ty[2],
1263                params: unsafe { read_array::<BtfParam>(data, vlen)? },
1264            }),
1265            BtfKind::Var => Self::Var(Var {
1266                name_offset: ty[0],
1267                info: ty[1],
1268                btf_type: ty[2],
1269                linkage: unsafe { read(data)? },
1270            }),
1271            BtfKind::DataSec => Self::DataSec(DataSec {
1272                name_offset: ty[0],
1273                info: ty[1],
1274                size: ty[2],
1275                entries: unsafe { read_array::<DataSecEntry>(data, vlen)? },
1276            }),
1277            BtfKind::DeclTag => Self::DeclTag(DeclTag {
1278                name_offset: ty[0],
1279                info: ty[1],
1280                btf_type: ty[2],
1281                component_index: unsafe { read(data)? },
1282            }),
1283            BtfKind::TypeTag => Self::TypeTag(TypeTag {
1284                name_offset: ty[0],
1285                info: ty[1],
1286                btf_type: ty[2],
1287            }),
1288        })
1289    }
1290
1291    pub(crate) fn to_bytes(&self) -> Vec<u8> {
1292        match self {
1293            Self::Unknown => vec![],
1294            Self::Fwd(t) => t.to_bytes(),
1295            Self::Const(t) => t.to_bytes(),
1296            Self::Volatile(t) => t.to_bytes(),
1297            Self::Restrict(t) => t.to_bytes(),
1298            Self::Ptr(t) => t.to_bytes(),
1299            Self::Typedef(t) => t.to_bytes(),
1300            Self::Func(t) => t.to_bytes(),
1301            Self::Int(t) => t.to_bytes(),
1302            Self::Float(t) => t.to_bytes(),
1303            Self::Enum(t) => t.to_bytes(),
1304            Self::Enum64(t) => t.to_bytes(),
1305            Self::Array(t) => t.to_bytes(),
1306            Self::Struct(t) => t.to_bytes(),
1307            Self::Union(t) => t.to_bytes(),
1308            Self::FuncProto(t) => t.to_bytes(),
1309            Self::Var(t) => t.to_bytes(),
1310            Self::DataSec(t) => t.to_bytes(),
1311            Self::DeclTag(t) => t.to_bytes(),
1312            Self::TypeTag(t) => t.to_bytes(),
1313        }
1314    }
1315
1316    pub(crate) const fn size(&self) -> Option<u32> {
1317        match self {
1318            Self::Int(t) => Some(t.size),
1319            Self::Float(t) => Some(t.size),
1320            Self::Enum(t) => Some(t.size),
1321            Self::Enum64(t) => Some(t.size),
1322            Self::Struct(t) => Some(t.size),
1323            Self::Union(t) => Some(t.size),
1324            Self::DataSec(t) => Some(t.size),
1325            Self::Ptr(_) => Some(size_of::<&()>() as u32),
1326            _ => None,
1327        }
1328    }
1329
1330    pub(crate) const fn btf_type(&self) -> Option<u32> {
1331        match self {
1332            Self::Const(t) => Some(t.btf_type),
1333            Self::Volatile(t) => Some(t.btf_type),
1334            Self::Restrict(t) => Some(t.btf_type),
1335            Self::Ptr(t) => Some(t.btf_type),
1336            Self::Typedef(t) => Some(t.btf_type),
1337            // FuncProto contains the return type here, and doesn't directly reference another type
1338            Self::FuncProto(t) => Some(t.return_type),
1339            Self::Var(t) => Some(t.btf_type),
1340            Self::DeclTag(t) => Some(t.btf_type),
1341            Self::TypeTag(t) => Some(t.btf_type),
1342            _ => None,
1343        }
1344    }
1345
1346    pub(crate) const fn type_info_size(&self) -> usize {
1347        match self {
1348            Self::Unknown => size_of::<Fwd>(),
1349            Self::Fwd(t) => t.type_info_size(),
1350            Self::Const(t) => t.type_info_size(),
1351            Self::Volatile(t) => t.type_info_size(),
1352            Self::Restrict(t) => t.type_info_size(),
1353            Self::Ptr(t) => t.type_info_size(),
1354            Self::Typedef(t) => t.type_info_size(),
1355            Self::Func(t) => t.type_info_size(),
1356            Self::Int(t) => t.type_info_size(),
1357            Self::Float(t) => t.type_info_size(),
1358            Self::Enum(t) => t.type_info_size(),
1359            Self::Enum64(t) => t.type_info_size(),
1360            Self::Array(t) => t.type_info_size(),
1361            Self::Struct(t) => t.type_info_size(),
1362            Self::Union(t) => t.type_info_size(),
1363            Self::FuncProto(t) => t.type_info_size(),
1364            Self::Var(t) => t.type_info_size(),
1365            Self::DataSec(t) => t.type_info_size(),
1366            Self::DeclTag(t) => t.type_info_size(),
1367            Self::TypeTag(t) => t.type_info_size(),
1368        }
1369    }
1370
1371    pub(crate) const fn name_offset(&self) -> u32 {
1372        match self {
1373            Self::Unknown => 0,
1374            Self::Fwd(t) => t.name_offset,
1375            Self::Const(t) => t.name_offset,
1376            Self::Volatile(t) => t.name_offset,
1377            Self::Restrict(t) => t.name_offset,
1378            Self::Ptr(t) => t.name_offset,
1379            Self::Typedef(t) => t.name_offset,
1380            Self::Func(t) => t.name_offset,
1381            Self::Int(t) => t.name_offset,
1382            Self::Float(t) => t.name_offset,
1383            Self::Enum(t) => t.name_offset,
1384            Self::Enum64(t) => t.name_offset,
1385            Self::Array(t) => t.name_offset,
1386            Self::Struct(t) => t.name_offset,
1387            Self::Union(t) => t.name_offset,
1388            Self::FuncProto(t) => t.name_offset,
1389            Self::Var(t) => t.name_offset,
1390            Self::DataSec(t) => t.name_offset,
1391            Self::DeclTag(t) => t.name_offset,
1392            Self::TypeTag(t) => t.name_offset,
1393        }
1394    }
1395
1396    pub(crate) const fn kind(&self) -> BtfKind {
1397        match self {
1398            Self::Unknown => BtfKind::Unknown,
1399            Self::Fwd(t) => t.kind(),
1400            Self::Const(t) => t.kind(),
1401            Self::Volatile(t) => t.kind(),
1402            Self::Restrict(t) => t.kind(),
1403            Self::Ptr(t) => t.kind(),
1404            Self::Typedef(t) => t.kind(),
1405            Self::Func(t) => t.kind(),
1406            Self::Int(t) => t.kind(),
1407            Self::Float(t) => t.kind(),
1408            Self::Enum(t) => t.kind(),
1409            Self::Enum64(t) => t.kind(),
1410            Self::Array(t) => t.kind(),
1411            Self::Struct(t) => t.kind(),
1412            Self::Union(t) => t.kind(),
1413            Self::FuncProto(t) => t.kind(),
1414            Self::Var(t) => t.kind(),
1415            Self::DataSec(t) => t.kind(),
1416            Self::DeclTag(t) => t.kind(),
1417            Self::TypeTag(t) => t.kind(),
1418        }
1419    }
1420
1421    pub(crate) const fn is_composite(&self) -> bool {
1422        matches!(self, Self::Struct(_) | Self::Union(_))
1423    }
1424
1425    pub(crate) fn members(&self) -> Option<impl Iterator<Item = &BtfMember>> {
1426        match self {
1427            Self::Struct(t) => Some(t.members.iter()),
1428            Self::Union(t) => Some(t.members.iter()),
1429            _ => None,
1430        }
1431    }
1432
1433    pub(crate) const fn member_bit_field_size(&self, member: &BtfMember) -> Option<usize> {
1434        match self {
1435            Self::Struct(t) => Some(t.member_bit_field_size(member)),
1436            Self::Union(t) => Some(t.member_bit_field_size(member)),
1437            _ => None,
1438        }
1439    }
1440
1441    pub(crate) const fn member_bit_offset(&self, member: &BtfMember) -> Option<usize> {
1442        match self {
1443            Self::Struct(t) => Some(t.member_bit_offset(member)),
1444            Self::Union(t) => Some(t.member_bit_offset(member)),
1445            _ => None,
1446        }
1447    }
1448
1449    pub(crate) fn is_compatible(&self, other: &Self) -> bool {
1450        if self.kind() == other.kind() {
1451            return true;
1452        }
1453
1454        matches!(
1455            (self.kind(), other.kind()),
1456            (BtfKind::Enum, BtfKind::Enum64) | (BtfKind::Enum64, BtfKind::Enum)
1457        )
1458    }
1459}
1460
1461fn type_kind(info: u32) -> Result<BtfKind, BtfError> {
1462    ((info >> 24) & 0x1F).try_into()
1463}
1464
1465const fn type_vlen(info: u32) -> usize {
1466    (info & 0xFFFF) as usize
1467}
1468
1469pub(crate) fn types_are_compatible(
1470    local_btf: &Btf,
1471    root_local_id: u32,
1472    target_btf: &Btf,
1473    root_target_id: u32,
1474) -> Result<bool, BtfError> {
1475    let mut local_id = root_local_id;
1476    let mut target_id = root_target_id;
1477    let local_ty = local_btf.type_by_id(local_id)?;
1478    let target_ty = target_btf.type_by_id(target_id)?;
1479
1480    if !local_ty.is_compatible(target_ty) {
1481        return Ok(false);
1482    }
1483
1484    for () in core::iter::repeat_n((), MAX_RESOLVE_DEPTH) {
1485        local_id = local_btf.resolve_type(local_id)?;
1486        target_id = target_btf.resolve_type(target_id)?;
1487        let local_ty = local_btf.type_by_id(local_id)?;
1488        let target_ty = target_btf.type_by_id(target_id)?;
1489
1490        if !local_ty.is_compatible(target_ty) {
1491            return Ok(false);
1492        }
1493
1494        match local_ty {
1495            BtfType::Unknown
1496            | BtfType::Struct(_)
1497            | BtfType::Union(_)
1498            | BtfType::Enum(_)
1499            | BtfType::Enum64(_)
1500            | BtfType::Fwd(_)
1501            | BtfType::Float(_) => return Ok(true),
1502            BtfType::Int(local) => {
1503                if let BtfType::Int(target) = target_ty {
1504                    return Ok(local.offset() == 0 && target.offset() == 0);
1505                }
1506            }
1507            BtfType::Ptr(local) => {
1508                if let BtfType::Ptr(target) = target_ty {
1509                    local_id = local.btf_type;
1510                    target_id = target.btf_type;
1511                }
1512            }
1513            BtfType::Array(Array { array: local, .. }) => {
1514                if let BtfType::Array(Array { array: target, .. }) = target_ty {
1515                    local_id = local.element_type;
1516                    target_id = target.element_type;
1517                }
1518            }
1519            BtfType::FuncProto(local) => {
1520                if let BtfType::FuncProto(target) = target_ty {
1521                    if local.params.len() != target.params.len() {
1522                        return Ok(false);
1523                    }
1524
1525                    for (l_param, t_param) in local.params.iter().zip(target.params.iter()) {
1526                        let local_id = local_btf.resolve_type(l_param.btf_type)?;
1527                        let target_id = target_btf.resolve_type(t_param.btf_type)?;
1528                        if !types_are_compatible(local_btf, local_id, target_btf, target_id)? {
1529                            return Ok(false);
1530                        }
1531                    }
1532
1533                    local_id = local.return_type;
1534                    target_id = target.return_type;
1535                }
1536            }
1537            #[expect(clippy::unreachable, reason = "unexpected type")]
1538            local_ty => unreachable!("unexpected type {:?}", local_ty),
1539        }
1540    }
1541
1542    Err(BtfError::MaximumTypeDepthReached { type_id: local_id })
1543}
1544
1545pub(crate) fn fields_are_compatible(
1546    local_btf: &Btf,
1547    mut local_id: u32,
1548    target_btf: &Btf,
1549    mut target_id: u32,
1550) -> Result<bool, BtfError> {
1551    for () in core::iter::repeat_n((), MAX_RESOLVE_DEPTH) {
1552        local_id = local_btf.resolve_type(local_id)?;
1553        target_id = target_btf.resolve_type(target_id)?;
1554        let local_ty = local_btf.type_by_id(local_id)?;
1555        let target_ty = target_btf.type_by_id(target_id)?;
1556
1557        if local_ty.is_composite() && target_ty.is_composite() {
1558            return Ok(true);
1559        }
1560
1561        if !local_ty.is_compatible(target_ty) {
1562            return Ok(false);
1563        }
1564
1565        match local_ty {
1566            BtfType::Fwd(_) | BtfType::Enum(_) | BtfType::Enum64(_) => {
1567                let flavorless_name =
1568                    |name: &str| name.split_once("___").map_or(name, |x| x.0).to_string();
1569
1570                let local_name = flavorless_name(&local_btf.type_name(local_ty)?);
1571                let target_name = flavorless_name(&target_btf.type_name(target_ty)?);
1572
1573                return Ok(local_name == target_name);
1574            }
1575            BtfType::Int(local) => {
1576                if let BtfType::Int(target) = target_ty {
1577                    return Ok(local.offset() == 0 && target.offset() == 0);
1578                }
1579            }
1580            BtfType::Float(_) => return Ok(true),
1581            BtfType::Ptr(_) => return Ok(true),
1582            BtfType::Array(Array { array: local, .. }) => {
1583                if let BtfType::Array(Array { array: target, .. }) = target_ty {
1584                    local_id = local.element_type;
1585                    target_id = target.element_type;
1586                }
1587            }
1588            #[expect(clippy::unreachable, reason = "unexpected type")]
1589            local_ty => unreachable!("unexpected type {:?}", local_ty),
1590        }
1591    }
1592
1593    Err(BtfError::MaximumTypeDepthReached { type_id: local_id })
1594}
1595
1596const fn bytes_of<T>(val: &T) -> &[u8] {
1597    // Safety: all btf types are POD
1598    //
1599    // TODO: This is a fragile assumption and we should stop doing this. We should also remove
1600    // repr(C) from our types, it doesn't make sense to rely on this.
1601    unsafe { crate::util::bytes_of(val) }
1602}
1603
1604#[cfg(test)]
1605mod tests {
1606    use assert_matches::assert_matches;
1607
1608    use super::*;
1609
1610    #[test]
1611    fn test_read_btf_type_int() {
1612        let endianness = Endianness::default();
1613        let bpf_type = BtfType::Int(Int::new(1, 8, IntEncoding::None, 0));
1614        let data: &[u8] = &bpf_type.to_bytes();
1615        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Int(new @ Int {
1616            name_offset,
1617            info: _,
1618            size,
1619            data: _,
1620        }) => {
1621                assert_eq!(name_offset, 1);
1622                assert_eq!(size, 8);
1623                assert_eq!(new.bits(), 64);
1624                assert_eq!(new.to_bytes(), data);
1625        });
1626    }
1627
1628    #[test]
1629    fn test_read_btf_type_ptr() {
1630        let endianness = Endianness::default();
1631        let bpf_type = BtfType::Ptr(Ptr::new(0, 0x06));
1632        let data: &[u8] = &bpf_type.to_bytes();
1633        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Ptr(got) => {
1634            assert_eq!(got.to_bytes(), data);
1635        });
1636    }
1637
1638    #[test]
1639    fn test_read_btf_type_array() {
1640        let endianness = Endianness::default();
1641        let bpf_type = BtfType::Array(Array::new(0, 1, 0x12, 2));
1642        let data: &[u8] = &bpf_type.to_bytes();
1643        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Array(got) => {
1644            assert_eq!(got.to_bytes(), data);
1645        });
1646    }
1647
1648    #[test]
1649    fn test_read_btf_type_struct() {
1650        let endianness = Endianness::default();
1651        let members = vec![BtfMember {
1652            name_offset: 0x0247,
1653            btf_type: 0x12,
1654            offset: 0,
1655        }];
1656        let bpf_type = BtfType::Struct(Struct::new(0, members, 4));
1657        let data: &[u8] = &bpf_type.to_bytes();
1658        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Struct(got) => {
1659            assert_eq!(got.to_bytes(), data);
1660        });
1661    }
1662
1663    #[test]
1664    fn test_read_btf_type_union() {
1665        let endianness = Endianness::default();
1666        let members = vec![BtfMember {
1667            name_offset: 0x040d,
1668            btf_type: 0x68,
1669            offset: 0,
1670        }];
1671        let bpf_type = BtfType::Union(Union::new(0, 4, members, None));
1672        let data: &[u8] = &bpf_type.to_bytes();
1673        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Union(got) => {
1674            assert_eq!(got.to_bytes(), data);
1675        });
1676    }
1677
1678    #[test]
1679    fn test_read_btf_type_enum() {
1680        let endianness = Endianness::default();
1681        let enum1 = BtfEnum::new(0xc9, 0);
1682        let enum2 = BtfEnum::new(0xcf, 1);
1683        let variants = vec![enum1, enum2];
1684        let bpf_type = BtfType::Enum(Enum::new(0, false, variants));
1685        let data: &[u8] = &bpf_type.to_bytes();
1686        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum(got) => {
1687            assert_eq!(got.to_bytes(), data);
1688        });
1689    }
1690
1691    #[test]
1692    fn test_read_btf_type_fwd() {
1693        let endianness = Endianness::default();
1694        let info = (BtfKind::Fwd as u32) << 24;
1695        let bpf_type = BtfType::Fwd(Fwd {
1696            name_offset: 0x550b,
1697            info,
1698            _unused: 0,
1699        });
1700        let data: &[u8] = &bpf_type.to_bytes();
1701        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Fwd(got) => {
1702            assert_eq!(got.to_bytes(), data);
1703        });
1704    }
1705
1706    #[test]
1707    fn test_read_btf_type_typedef() {
1708        let endianness = Endianness::default();
1709        let bpf_type = BtfType::Typedef(Typedef::new(0x31, 0x0b));
1710        let data: &[u8] = &bpf_type.to_bytes();
1711        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Typedef(got) => {
1712            assert_eq!(got.to_bytes(), data);
1713        });
1714    }
1715
1716    #[test]
1717    fn test_read_btf_type_volatile() {
1718        let endianness = Endianness::default();
1719        let info = (BtfKind::Volatile as u32) << 24;
1720        let bpf_type = BtfType::Volatile(Volatile {
1721            name_offset: 0,
1722            info,
1723            btf_type: 0x24,
1724        });
1725        let data: &[u8] = &bpf_type.to_bytes();
1726        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Volatile(got) => {
1727            assert_eq!(got.to_bytes(), data);
1728        });
1729    }
1730
1731    #[test]
1732    fn test_read_btf_type_const() {
1733        let endianness = Endianness::default();
1734        let bpf_type = BtfType::Const(Const::new(1));
1735        let data: &[u8] = &bpf_type.to_bytes();
1736        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Const(got) => {
1737            assert_eq!(got.to_bytes(), data);
1738        });
1739    }
1740
1741    #[test]
1742    fn test_read_btf_type_restrict() {
1743        let endianness = Endianness::default();
1744        let info = (BtfKind::Restrict as u32) << 24;
1745        let bpf_type = BtfType::Restrict(Restrict {
1746            name_offset: 0,
1747            _info: info,
1748            btf_type: 4,
1749        });
1750        let data: &[u8] = &bpf_type.to_bytes();
1751        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Restrict(got) => {
1752            assert_eq!(got.to_bytes(), data);
1753        });
1754    }
1755
1756    #[test]
1757    fn test_read_btf_type_func() {
1758        let endianness = Endianness::default();
1759        let bpf_type = BtfType::Func(Func::new(0x000f8b17, 0xe4f0, FuncLinkage::Global));
1760        let data: &[u8] = &bpf_type.to_bytes();
1761        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Func(got) => {
1762            assert_eq!(got.to_bytes(), data);
1763        });
1764    }
1765
1766    #[test]
1767    fn test_read_btf_type_func_proto() {
1768        let endianness = Endianness::default();
1769        let params = vec![BtfParam {
1770            name_offset: 0,
1771            btf_type: 0x12,
1772        }];
1773        let bpf_type = BtfType::FuncProto(FuncProto::new(params, 0));
1774        let data: &[u8] = &bpf_type.to_bytes();
1775        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::FuncProto(got) => {
1776            assert_eq!(got.to_bytes(), data);
1777        });
1778    }
1779
1780    #[test]
1781    fn test_read_btf_type_func_var() {
1782        let endianness = Endianness::default();
1783        // NOTE: There was no data in /sys/kernell/btf/vmlinux for this type
1784        let bpf_type = BtfType::Var(Var::new(0, 0xf0, VarLinkage::Static));
1785        let data: &[u8] = &bpf_type.to_bytes();
1786        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Var(got) => {
1787            assert_eq!(got.to_bytes(), data);
1788        });
1789    }
1790
1791    #[test]
1792    fn test_read_btf_type_func_datasec() {
1793        let endianness = Endianness::default();
1794        let entries = vec![DataSecEntry {
1795            btf_type: 11,
1796            offset: 0,
1797            size: 4,
1798        }];
1799        let bpf_type = BtfType::DataSec(DataSec::new(0xd9, entries, 0));
1800        let data: &[u8] = &bpf_type.to_bytes();
1801        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::DataSec(DataSec {
1802            name_offset: _,
1803            info: _,
1804            size,
1805            entries,
1806         }) => {
1807                assert_eq!(size, 0);
1808                assert_matches!(*entries, [
1809                    DataSecEntry {
1810                        btf_type: 11,
1811                        offset: 0,
1812                        size: 4,
1813                    }
1814                ]);
1815            }
1816        );
1817    }
1818
1819    #[test]
1820    fn test_read_btf_type_float() {
1821        let endianness = Endianness::default();
1822        let bpf_type = BtfType::Float(Float::new(0x02fd, 8));
1823        let data: &[u8] = &bpf_type.to_bytes();
1824        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Float(got) => {
1825            assert_eq!(got.to_bytes(), data);
1826        });
1827    }
1828
1829    #[test]
1830    fn test_write_btf_func_proto() {
1831        let params = vec![
1832            BtfParam {
1833                name_offset: 1,
1834                btf_type: 1,
1835            },
1836            BtfParam {
1837                name_offset: 3,
1838                btf_type: 1,
1839            },
1840        ];
1841        let func_proto = FuncProto::new(params, 2);
1842        let data = func_proto.to_bytes();
1843        assert_matches!(unsafe { BtfType::read(&data, Endianness::default()) }.unwrap(), BtfType::FuncProto(FuncProto {
1844            name_offset: _,
1845            info: _,
1846            return_type: _,
1847            params,
1848        }) => {
1849            assert_matches!(*params, [
1850                _,
1851                _,
1852            ])
1853        });
1854    }
1855
1856    #[test]
1857    fn test_types_are_compatible() {
1858        let mut btf = Btf::new();
1859        let name_offset = btf.add_string("u32");
1860        let u32t = btf.add_type(BtfType::Int(Int::new(name_offset, 4, IntEncoding::None, 0)));
1861        let name_offset = btf.add_string("u64");
1862        let u64t = btf.add_type(BtfType::Int(Int::new(name_offset, 8, IntEncoding::None, 0)));
1863        let name_offset = btf.add_string("widgets");
1864        let array_type = btf.add_type(BtfType::Array(Array::new(name_offset, u64t, u32t, 16)));
1865
1866        assert!(types_are_compatible(&btf, u32t, &btf, u32t).unwrap());
1867        // int types are compatible if offsets match. size and encoding aren't compared
1868        assert!(types_are_compatible(&btf, u32t, &btf, u64t).unwrap());
1869        assert!(types_are_compatible(&btf, array_type, &btf, array_type).unwrap());
1870    }
1871
1872    #[test]
1873    fn test_read_btf_type_enum64() {
1874        let endianness = Endianness::default();
1875        let variants = vec![BtfEnum64::new(0, 0xbbbbbbbbaaaaaaaau64)];
1876        let bpf_type = BtfType::Enum64(Enum64::new(0, false, variants));
1877        let data: &[u8] = &bpf_type.to_bytes();
1878        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum64(got) => {
1879            assert_eq!(got.to_bytes(), data);
1880        });
1881    }
1882}