aya_obj/btf/
types.rs

1#![expect(missing_docs)]
2
3use alloc::{string::ToString as _, vec, vec::Vec};
4use core::{fmt::Display, mem, ptr};
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) fn kind(&self) -> BtfKind {
48        BtfKind::Fwd
49    }
50
51    pub(crate) fn type_info_size(&self) -> usize {
52        mem::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) fn kind(&self) -> BtfKind {
70        BtfKind::Const
71    }
72
73    pub(crate) fn type_info_size(&self) -> usize {
74        mem::size_of::<Self>()
75    }
76
77    pub(crate) 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) fn kind(&self) -> BtfKind {
101        BtfKind::Volatile
102    }
103
104    pub(crate) fn type_info_size(&self) -> usize {
105        mem::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) fn kind(&self) -> BtfKind {
122        BtfKind::Restrict
123    }
124
125    pub(crate) fn type_info_size(&self) -> usize {
126        mem::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) fn kind(&self) -> BtfKind {
144        BtfKind::Ptr
145    }
146
147    pub(crate) fn type_info_size(&self) -> usize {
148        mem::size_of::<Self>()
149    }
150
151    pub 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) fn kind(&self) -> BtfKind {
175        BtfKind::Typedef
176    }
177
178    pub(crate) fn type_info_size(&self) -> usize {
179        mem::size_of::<Self>()
180    }
181
182    pub(crate) 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) fn kind(&self) -> BtfKind {
206        BtfKind::Float
207    }
208    pub(crate) fn type_info_size(&self) -> usize {
209        mem::size_of::<Self>()
210    }
211
212    pub 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) fn kind(&self) -> BtfKind {
256        BtfKind::Func
257    }
258    pub(crate) fn type_info_size(&self) -> usize {
259        mem::size_of::<Self>()
260    }
261
262    pub 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 & 0xFFF).into()
274    }
275
276    pub(crate) 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) fn kind(&self) -> BtfKind {
295        BtfKind::TypeTag
296    }
297
298    pub(crate) fn type_info_size(&self) -> usize {
299        mem::size_of::<Self>()
300    }
301
302    pub 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) fn kind(&self) -> BtfKind {
361        BtfKind::Int
362    }
363    pub(crate) fn type_info_size(&self) -> usize {
364        mem::size_of::<Self>()
365    }
366
367    pub 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) 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) 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 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) fn kind(&self) -> BtfKind {
441        BtfKind::Enum
442    }
443
444    pub(crate) fn type_info_size(&self) -> usize {
445        mem::size_of::<Fwd>() + mem::size_of::<BtfEnum>() * self.variants.len()
446    }
447
448    pub 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) fn is_signed(&self) -> bool {
463        self.info >> 31 == 1
464    }
465
466    pub(crate) 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 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) fn kind(&self) -> BtfKind {
535        BtfKind::Enum64
536    }
537
538    pub(crate) fn type_info_size(&self) -> usize {
539        mem::size_of::<Fwd>() + mem::size_of::<BtfEnum64>() * self.variants.len()
540    }
541
542    pub(crate) fn is_signed(&self) -> bool {
543        self.info >> 31 == 1
544    }
545
546    pub 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) fn kind(&self) -> BtfKind {
617        BtfKind::Struct
618    }
619
620    pub(crate) fn type_info_size(&self) -> usize {
621        mem::size_of::<Fwd>() + mem::size_of::<BtfMember>() * self.members.len()
622    }
623
624    pub(crate) 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) 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) 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) 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) fn kind(&self) -> BtfKind {
731        BtfKind::Union
732    }
733
734    pub(crate) fn type_info_size(&self) -> usize {
735        mem::size_of::<Fwd>() + mem::size_of::<BtfMember>() * self.members.len()
736    }
737
738    pub(crate) 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) 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    pub(crate) array: BtfArray,
772}
773
774impl Array {
775    pub(crate) fn to_bytes(&self) -> Vec<u8> {
776        let Self {
777            name_offset,
778            info,
779            _unused,
780            array,
781        } = self;
782        [
783            bytes_of::<u32>(name_offset),
784            bytes_of::<u32>(info),
785            bytes_of::<u32>(_unused),
786            bytes_of::<BtfArray>(array),
787        ]
788        .concat()
789    }
790
791    pub(crate) fn kind(&self) -> BtfKind {
792        BtfKind::Array
793    }
794
795    pub(crate) fn type_info_size(&self) -> usize {
796        mem::size_of::<Self>()
797    }
798
799    #[cfg(test)]
800    pub(crate) fn new(name_offset: u32, element_type: u32, index_type: u32, len: u32) -> Self {
801        let info = (BtfKind::Array as u32) << 24;
802        Self {
803            name_offset,
804            info,
805            _unused: 0,
806            array: BtfArray {
807                element_type,
808                index_type,
809                len,
810            },
811        }
812    }
813}
814
815#[repr(C)]
816#[derive(Clone, Debug)]
817pub struct BtfParam {
818    pub name_offset: u32,
819    pub btf_type: u32,
820}
821
822#[repr(C)]
823#[derive(Clone, Debug)]
824pub struct FuncProto {
825    pub(crate) name_offset: u32,
826    info: u32,
827    pub(crate) return_type: u32,
828    pub(crate) params: Vec<BtfParam>,
829}
830
831impl FuncProto {
832    pub(crate) fn to_bytes(&self) -> Vec<u8> {
833        let Self {
834            name_offset,
835            info,
836            return_type,
837            params,
838        } = self;
839        [
840            bytes_of::<u32>(name_offset),
841            bytes_of::<u32>(info),
842            bytes_of::<u32>(return_type),
843        ]
844        .into_iter()
845        .chain(params.iter().flat_map(
846            |BtfParam {
847                 name_offset,
848                 btf_type,
849             }| { [bytes_of::<u32>(name_offset), bytes_of::<u32>(btf_type)] },
850        ))
851        .flatten()
852        .copied()
853        .collect()
854    }
855
856    pub(crate) fn kind(&self) -> BtfKind {
857        BtfKind::FuncProto
858    }
859
860    pub(crate) fn type_info_size(&self) -> usize {
861        mem::size_of::<Fwd>() + mem::size_of::<BtfParam>() * self.params.len()
862    }
863
864    pub fn new(params: Vec<BtfParam>, return_type: u32) -> Self {
865        let mut info = (BtfKind::FuncProto as u32) << 24;
866        info |= (params.len() as u32) & 0xFFFF;
867        Self {
868            name_offset: 0,
869            info,
870            return_type,
871            params,
872        }
873    }
874}
875
876#[repr(u32)]
877#[derive(Clone, Debug, PartialEq, Eq)]
878pub enum VarLinkage {
879    Static,
880    Global,
881    Extern,
882    Unknown,
883}
884
885impl From<u32> for VarLinkage {
886    fn from(v: u32) -> Self {
887        match v {
888            0 => Self::Static,
889            1 => Self::Global,
890            2 => Self::Extern,
891            _ => Self::Unknown,
892        }
893    }
894}
895
896#[repr(C)]
897#[derive(Clone, Debug)]
898pub struct Var {
899    pub(crate) name_offset: u32,
900    info: u32,
901    pub(crate) btf_type: u32,
902    pub(crate) linkage: VarLinkage,
903}
904
905impl Var {
906    pub(crate) fn to_bytes(&self) -> Vec<u8> {
907        let Self {
908            name_offset,
909            info,
910            btf_type,
911            linkage,
912        } = self;
913        [
914            bytes_of::<u32>(name_offset),
915            bytes_of::<u32>(info),
916            bytes_of::<u32>(btf_type),
917            bytes_of::<VarLinkage>(linkage),
918        ]
919        .concat()
920    }
921
922    pub(crate) fn kind(&self) -> BtfKind {
923        BtfKind::Var
924    }
925
926    pub(crate) fn type_info_size(&self) -> usize {
927        mem::size_of::<Self>()
928    }
929
930    pub fn new(name_offset: u32, btf_type: u32, linkage: VarLinkage) -> Self {
931        let info = (BtfKind::Var as u32) << 24;
932        Self {
933            name_offset,
934            info,
935            btf_type,
936            linkage,
937        }
938    }
939}
940
941#[repr(C)]
942#[derive(Clone, Debug)]
943pub struct DataSecEntry {
944    pub btf_type: u32,
945    pub offset: u32,
946    pub size: u32,
947}
948
949#[repr(C)]
950#[derive(Clone, Debug)]
951pub struct DataSec {
952    pub(crate) name_offset: u32,
953    info: u32,
954    pub(crate) size: u32,
955    pub(crate) entries: Vec<DataSecEntry>,
956}
957
958impl DataSec {
959    pub(crate) fn to_bytes(&self) -> Vec<u8> {
960        let Self {
961            name_offset,
962            info,
963            size,
964            entries,
965        } = self;
966        [
967            bytes_of::<u32>(name_offset),
968            bytes_of::<u32>(info),
969            bytes_of::<u32>(size),
970        ]
971        .into_iter()
972        .chain(entries.iter().flat_map(
973            |DataSecEntry {
974                 btf_type,
975                 offset,
976                 size,
977             }| {
978                [
979                    bytes_of::<u32>(btf_type),
980                    bytes_of::<u32>(offset),
981                    bytes_of::<u32>(size),
982                ]
983            },
984        ))
985        .flatten()
986        .copied()
987        .collect()
988    }
989
990    pub(crate) fn kind(&self) -> BtfKind {
991        BtfKind::DataSec
992    }
993
994    pub(crate) fn type_info_size(&self) -> usize {
995        mem::size_of::<Fwd>() + mem::size_of::<DataSecEntry>() * self.entries.len()
996    }
997
998    pub fn new(name_offset: u32, entries: Vec<DataSecEntry>, size: u32) -> Self {
999        let mut info = (BtfKind::DataSec as u32) << 24;
1000        info |= (entries.len() as u32) & 0xFFFF;
1001        Self {
1002            name_offset,
1003            info,
1004            size,
1005            entries,
1006        }
1007    }
1008}
1009
1010#[repr(C)]
1011#[derive(Clone, Debug)]
1012pub struct DeclTag {
1013    pub(crate) name_offset: u32,
1014    info: u32,
1015    pub(crate) btf_type: u32,
1016    pub(crate) component_index: i32,
1017}
1018
1019impl DeclTag {
1020    pub(crate) fn to_bytes(&self) -> Vec<u8> {
1021        let Self {
1022            name_offset,
1023            info,
1024            btf_type,
1025            component_index,
1026        } = self;
1027        [
1028            bytes_of::<u32>(name_offset),
1029            bytes_of::<u32>(info),
1030            bytes_of::<u32>(btf_type),
1031            bytes_of::<i32>(component_index),
1032        ]
1033        .concat()
1034    }
1035
1036    pub(crate) fn kind(&self) -> BtfKind {
1037        BtfKind::DeclTag
1038    }
1039
1040    pub(crate) fn type_info_size(&self) -> usize {
1041        mem::size_of::<Self>()
1042    }
1043
1044    pub fn new(name_offset: u32, btf_type: u32, component_index: i32) -> Self {
1045        let info = (BtfKind::DeclTag as u32) << 24;
1046        Self {
1047            name_offset,
1048            info,
1049            btf_type,
1050            component_index,
1051        }
1052    }
1053}
1054
1055#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
1056#[repr(u32)]
1057pub enum BtfKind {
1058    #[default]
1059    Unknown = 0,
1060    Int = 1,
1061    Ptr = 2,
1062    Array = 3,
1063    Struct = 4,
1064    Union = 5,
1065    Enum = 6,
1066    Fwd = 7,
1067    Typedef = 8,
1068    Volatile = 9,
1069    Const = 10,
1070    Restrict = 11,
1071    Func = 12,
1072    FuncProto = 13,
1073    Var = 14,
1074    DataSec = 15,
1075    Float = 16,
1076    DeclTag = 17,
1077    TypeTag = 18,
1078    Enum64 = 19,
1079}
1080
1081impl TryFrom<u32> for BtfKind {
1082    type Error = BtfError;
1083
1084    fn try_from(v: u32) -> Result<Self, Self::Error> {
1085        use BtfKind::*;
1086        Ok(match v {
1087            0 => Unknown,
1088            1 => Int,
1089            2 => Ptr,
1090            3 => Array,
1091            4 => Struct,
1092            5 => Union,
1093            6 => Enum,
1094            7 => Fwd,
1095            8 => Typedef,
1096            9 => Volatile,
1097            10 => Const,
1098            11 => Restrict,
1099            12 => Func,
1100            13 => FuncProto,
1101            14 => Var,
1102            15 => DataSec,
1103            16 => Float,
1104            17 => DeclTag,
1105            18 => TypeTag,
1106            19 => Enum64,
1107            kind => return Err(BtfError::InvalidTypeKind { kind }),
1108        })
1109    }
1110}
1111
1112impl Display for BtfKind {
1113    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1114        match self {
1115            Self::Unknown => write!(f, "[UNKNOWN]"),
1116            Self::Int => write!(f, "[INT]"),
1117            Self::Float => write!(f, "[FLOAT]"),
1118            Self::Ptr => write!(f, "[PTR]"),
1119            Self::Array => write!(f, "[ARRAY]"),
1120            Self::Struct => write!(f, "[STRUCT]"),
1121            Self::Union => write!(f, "[UNION]"),
1122            Self::Enum => write!(f, "[ENUM]"),
1123            Self::Fwd => write!(f, "[FWD]"),
1124            Self::Typedef => write!(f, "[TYPEDEF]"),
1125            Self::Volatile => write!(f, "[VOLATILE]"),
1126            Self::Const => write!(f, "[CONST]"),
1127            Self::Restrict => write!(f, "[RESTRICT]"),
1128            Self::Func => write!(f, "[FUNC]"),
1129            Self::FuncProto => write!(f, "[FUNC_PROTO]"),
1130            Self::Var => write!(f, "[VAR]"),
1131            Self::DataSec => write!(f, "[DATASEC]"),
1132            Self::DeclTag => write!(f, "[DECL_TAG]"),
1133            Self::TypeTag => write!(f, "[TYPE_TAG]"),
1134            Self::Enum64 => write!(f, "[ENUM64]"),
1135        }
1136    }
1137}
1138
1139unsafe fn read<T>(data: &[u8]) -> Result<T, BtfError> {
1140    if mem::size_of::<T>() > data.len() {
1141        return Err(BtfError::InvalidTypeInfo);
1142    }
1143
1144    Ok(unsafe { ptr::read_unaligned(data.as_ptr().cast()) })
1145}
1146
1147unsafe fn read_array<T>(data: &[u8], len: usize) -> Result<Vec<T>, BtfError> {
1148    if mem::size_of::<T>() * len > data.len() {
1149        return Err(BtfError::InvalidTypeInfo);
1150    }
1151    let data = &data[0..mem::size_of::<T>() * len];
1152    let r = data
1153        .chunks(mem::size_of::<T>())
1154        .map(|chunk| unsafe { ptr::read_unaligned(chunk.as_ptr().cast()) })
1155        .collect();
1156    Ok(r)
1157}
1158
1159impl BtfType {
1160    pub(crate) unsafe fn read(data: &[u8], endianness: Endianness) -> Result<Self, BtfError> {
1161        let ty = unsafe { read_array::<u32>(data, 3)? };
1162        let data = &data[mem::size_of::<u32>() * 3..];
1163        let vlen = type_vlen(ty[1]);
1164        Ok(match type_kind(ty[1])? {
1165            BtfKind::Unknown => Self::Unknown,
1166            BtfKind::Fwd => Self::Fwd(Fwd {
1167                name_offset: ty[0],
1168                info: ty[1],
1169                _unused: 0,
1170            }),
1171            BtfKind::Const => Self::Const(Const {
1172                name_offset: ty[0],
1173                info: ty[1],
1174                btf_type: ty[2],
1175            }),
1176            BtfKind::Volatile => Self::Volatile(Volatile {
1177                name_offset: ty[0],
1178                info: ty[1],
1179                btf_type: ty[2],
1180            }),
1181            BtfKind::Restrict => Self::Restrict(Restrict {
1182                name_offset: ty[0],
1183                _info: ty[1],
1184                btf_type: ty[2],
1185            }),
1186            BtfKind::Ptr => Self::Ptr(Ptr {
1187                name_offset: ty[0],
1188                info: ty[1],
1189                btf_type: ty[2],
1190            }),
1191            BtfKind::Typedef => Self::Typedef(Typedef {
1192                name_offset: ty[0],
1193                info: ty[1],
1194                btf_type: ty[2],
1195            }),
1196            BtfKind::Func => Self::Func(Func {
1197                name_offset: ty[0],
1198                info: ty[1],
1199                btf_type: ty[2],
1200            }),
1201            BtfKind::Int => {
1202                if mem::size_of::<u32>() > data.len() {
1203                    return Err(BtfError::InvalidTypeInfo);
1204                }
1205                let read_u32 = if endianness == Endianness::Little {
1206                    u32::from_le_bytes
1207                } else {
1208                    u32::from_be_bytes
1209                };
1210                Self::Int(Int {
1211                    name_offset: ty[0],
1212                    info: ty[1],
1213                    size: ty[2],
1214                    data: read_u32(data[..mem::size_of::<u32>()].try_into().unwrap()),
1215                })
1216            }
1217            BtfKind::Float => Self::Float(Float {
1218                name_offset: ty[0],
1219                info: ty[1],
1220                size: ty[2],
1221            }),
1222            BtfKind::Enum => Self::Enum(Enum {
1223                name_offset: ty[0],
1224                info: ty[1],
1225                size: ty[2],
1226                variants: unsafe { read_array::<BtfEnum>(data, vlen)? },
1227            }),
1228            BtfKind::Enum64 => Self::Enum64(Enum64 {
1229                name_offset: ty[0],
1230                info: ty[1],
1231                size: ty[2],
1232                variants: unsafe { read_array::<BtfEnum64>(data, vlen)? },
1233            }),
1234            BtfKind::Array => Self::Array(Array {
1235                name_offset: ty[0],
1236                info: ty[1],
1237                _unused: 0,
1238                array: unsafe { read(data)? },
1239            }),
1240            BtfKind::Struct => Self::Struct(Struct {
1241                name_offset: ty[0],
1242                info: ty[1],
1243                size: ty[2],
1244                members: unsafe { read_array::<BtfMember>(data, vlen)? },
1245            }),
1246            BtfKind::Union => Self::Union(Union {
1247                name_offset: ty[0],
1248                info: ty[1],
1249                size: ty[2],
1250                members: unsafe { read_array::<BtfMember>(data, vlen)? },
1251                enum64_fallback: None,
1252            }),
1253            BtfKind::FuncProto => Self::FuncProto(FuncProto {
1254                name_offset: ty[0],
1255                info: ty[1],
1256                return_type: ty[2],
1257                params: unsafe { read_array::<BtfParam>(data, vlen)? },
1258            }),
1259            BtfKind::Var => Self::Var(Var {
1260                name_offset: ty[0],
1261                info: ty[1],
1262                btf_type: ty[2],
1263                linkage: unsafe { read(data)? },
1264            }),
1265            BtfKind::DataSec => Self::DataSec(DataSec {
1266                name_offset: ty[0],
1267                info: ty[1],
1268                size: ty[2],
1269                entries: unsafe { read_array::<DataSecEntry>(data, vlen)? },
1270            }),
1271            BtfKind::DeclTag => Self::DeclTag(DeclTag {
1272                name_offset: ty[0],
1273                info: ty[1],
1274                btf_type: ty[2],
1275                component_index: unsafe { read(data)? },
1276            }),
1277            BtfKind::TypeTag => Self::TypeTag(TypeTag {
1278                name_offset: ty[0],
1279                info: ty[1],
1280                btf_type: ty[2],
1281            }),
1282        })
1283    }
1284
1285    pub(crate) fn to_bytes(&self) -> Vec<u8> {
1286        match self {
1287            Self::Unknown => vec![],
1288            Self::Fwd(t) => t.to_bytes(),
1289            Self::Const(t) => t.to_bytes(),
1290            Self::Volatile(t) => t.to_bytes(),
1291            Self::Restrict(t) => t.to_bytes(),
1292            Self::Ptr(t) => t.to_bytes(),
1293            Self::Typedef(t) => t.to_bytes(),
1294            Self::Func(t) => t.to_bytes(),
1295            Self::Int(t) => t.to_bytes(),
1296            Self::Float(t) => t.to_bytes(),
1297            Self::Enum(t) => t.to_bytes(),
1298            Self::Enum64(t) => t.to_bytes(),
1299            Self::Array(t) => t.to_bytes(),
1300            Self::Struct(t) => t.to_bytes(),
1301            Self::Union(t) => t.to_bytes(),
1302            Self::FuncProto(t) => t.to_bytes(),
1303            Self::Var(t) => t.to_bytes(),
1304            Self::DataSec(t) => t.to_bytes(),
1305            Self::DeclTag(t) => t.to_bytes(),
1306            Self::TypeTag(t) => t.to_bytes(),
1307        }
1308    }
1309
1310    pub(crate) fn size(&self) -> Option<u32> {
1311        match self {
1312            Self::Int(t) => Some(t.size),
1313            Self::Float(t) => Some(t.size),
1314            Self::Enum(t) => Some(t.size),
1315            Self::Enum64(t) => Some(t.size),
1316            Self::Struct(t) => Some(t.size),
1317            Self::Union(t) => Some(t.size),
1318            Self::DataSec(t) => Some(t.size),
1319            Self::Ptr(_) => Some(mem::size_of::<&()>() as u32),
1320            _ => None,
1321        }
1322    }
1323
1324    pub(crate) fn btf_type(&self) -> Option<u32> {
1325        match self {
1326            Self::Const(t) => Some(t.btf_type),
1327            Self::Volatile(t) => Some(t.btf_type),
1328            Self::Restrict(t) => Some(t.btf_type),
1329            Self::Ptr(t) => Some(t.btf_type),
1330            Self::Typedef(t) => Some(t.btf_type),
1331            // FuncProto contains the return type here, and doesn't directly reference another type
1332            Self::FuncProto(t) => Some(t.return_type),
1333            Self::Var(t) => Some(t.btf_type),
1334            Self::DeclTag(t) => Some(t.btf_type),
1335            Self::TypeTag(t) => Some(t.btf_type),
1336            _ => None,
1337        }
1338    }
1339
1340    pub(crate) fn type_info_size(&self) -> usize {
1341        match self {
1342            Self::Unknown => mem::size_of::<Fwd>(),
1343            Self::Fwd(t) => t.type_info_size(),
1344            Self::Const(t) => t.type_info_size(),
1345            Self::Volatile(t) => t.type_info_size(),
1346            Self::Restrict(t) => t.type_info_size(),
1347            Self::Ptr(t) => t.type_info_size(),
1348            Self::Typedef(t) => t.type_info_size(),
1349            Self::Func(t) => t.type_info_size(),
1350            Self::Int(t) => t.type_info_size(),
1351            Self::Float(t) => t.type_info_size(),
1352            Self::Enum(t) => t.type_info_size(),
1353            Self::Enum64(t) => t.type_info_size(),
1354            Self::Array(t) => t.type_info_size(),
1355            Self::Struct(t) => t.type_info_size(),
1356            Self::Union(t) => t.type_info_size(),
1357            Self::FuncProto(t) => t.type_info_size(),
1358            Self::Var(t) => t.type_info_size(),
1359            Self::DataSec(t) => t.type_info_size(),
1360            Self::DeclTag(t) => t.type_info_size(),
1361            Self::TypeTag(t) => t.type_info_size(),
1362        }
1363    }
1364
1365    pub(crate) fn name_offset(&self) -> u32 {
1366        match self {
1367            Self::Unknown => 0,
1368            Self::Fwd(t) => t.name_offset,
1369            Self::Const(t) => t.name_offset,
1370            Self::Volatile(t) => t.name_offset,
1371            Self::Restrict(t) => t.name_offset,
1372            Self::Ptr(t) => t.name_offset,
1373            Self::Typedef(t) => t.name_offset,
1374            Self::Func(t) => t.name_offset,
1375            Self::Int(t) => t.name_offset,
1376            Self::Float(t) => t.name_offset,
1377            Self::Enum(t) => t.name_offset,
1378            Self::Enum64(t) => t.name_offset,
1379            Self::Array(t) => t.name_offset,
1380            Self::Struct(t) => t.name_offset,
1381            Self::Union(t) => t.name_offset,
1382            Self::FuncProto(t) => t.name_offset,
1383            Self::Var(t) => t.name_offset,
1384            Self::DataSec(t) => t.name_offset,
1385            Self::DeclTag(t) => t.name_offset,
1386            Self::TypeTag(t) => t.name_offset,
1387        }
1388    }
1389
1390    pub(crate) fn kind(&self) -> BtfKind {
1391        match self {
1392            Self::Unknown => BtfKind::Unknown,
1393            Self::Fwd(t) => t.kind(),
1394            Self::Const(t) => t.kind(),
1395            Self::Volatile(t) => t.kind(),
1396            Self::Restrict(t) => t.kind(),
1397            Self::Ptr(t) => t.kind(),
1398            Self::Typedef(t) => t.kind(),
1399            Self::Func(t) => t.kind(),
1400            Self::Int(t) => t.kind(),
1401            Self::Float(t) => t.kind(),
1402            Self::Enum(t) => t.kind(),
1403            Self::Enum64(t) => t.kind(),
1404            Self::Array(t) => t.kind(),
1405            Self::Struct(t) => t.kind(),
1406            Self::Union(t) => t.kind(),
1407            Self::FuncProto(t) => t.kind(),
1408            Self::Var(t) => t.kind(),
1409            Self::DataSec(t) => t.kind(),
1410            Self::DeclTag(t) => t.kind(),
1411            Self::TypeTag(t) => t.kind(),
1412        }
1413    }
1414
1415    pub(crate) fn is_composite(&self) -> bool {
1416        matches!(self, Self::Struct(_) | Self::Union(_))
1417    }
1418
1419    pub(crate) fn members(&self) -> Option<impl Iterator<Item = &BtfMember>> {
1420        match self {
1421            Self::Struct(t) => Some(t.members.iter()),
1422            Self::Union(t) => Some(t.members.iter()),
1423            _ => None,
1424        }
1425    }
1426
1427    pub(crate) fn member_bit_field_size(&self, member: &BtfMember) -> Option<usize> {
1428        match self {
1429            Self::Struct(t) => Some(t.member_bit_field_size(member)),
1430            Self::Union(t) => Some(t.member_bit_field_size(member)),
1431            _ => None,
1432        }
1433    }
1434
1435    pub(crate) fn member_bit_offset(&self, member: &BtfMember) -> Option<usize> {
1436        match self {
1437            Self::Struct(t) => Some(t.member_bit_offset(member)),
1438            Self::Union(t) => Some(t.member_bit_offset(member)),
1439            _ => None,
1440        }
1441    }
1442
1443    pub(crate) fn is_compatible(&self, other: &Self) -> bool {
1444        if self.kind() == other.kind() {
1445            return true;
1446        }
1447
1448        matches!(
1449            (self.kind(), other.kind()),
1450            (BtfKind::Enum, BtfKind::Enum64) | (BtfKind::Enum64, BtfKind::Enum)
1451        )
1452    }
1453}
1454
1455fn type_kind(info: u32) -> Result<BtfKind, BtfError> {
1456    ((info >> 24) & 0x1F).try_into()
1457}
1458
1459fn type_vlen(info: u32) -> usize {
1460    (info & 0xFFFF) as usize
1461}
1462
1463pub(crate) fn types_are_compatible(
1464    local_btf: &Btf,
1465    root_local_id: u32,
1466    target_btf: &Btf,
1467    root_target_id: u32,
1468) -> Result<bool, BtfError> {
1469    let mut local_id = root_local_id;
1470    let mut target_id = root_target_id;
1471    let local_ty = local_btf.type_by_id(local_id)?;
1472    let target_ty = target_btf.type_by_id(target_id)?;
1473
1474    if !local_ty.is_compatible(target_ty) {
1475        return Ok(false);
1476    }
1477
1478    for () in core::iter::repeat_n((), MAX_RESOLVE_DEPTH) {
1479        local_id = local_btf.resolve_type(local_id)?;
1480        target_id = target_btf.resolve_type(target_id)?;
1481        let local_ty = local_btf.type_by_id(local_id)?;
1482        let target_ty = target_btf.type_by_id(target_id)?;
1483
1484        if !local_ty.is_compatible(target_ty) {
1485            return Ok(false);
1486        }
1487
1488        match local_ty {
1489            BtfType::Unknown
1490            | BtfType::Struct(_)
1491            | BtfType::Union(_)
1492            | BtfType::Enum(_)
1493            | BtfType::Enum64(_)
1494            | BtfType::Fwd(_)
1495            | BtfType::Float(_) => return Ok(true),
1496            BtfType::Int(local) => {
1497                if let BtfType::Int(target) = target_ty {
1498                    return Ok(local.offset() == 0 && target.offset() == 0);
1499                }
1500            }
1501            BtfType::Ptr(local) => {
1502                if let BtfType::Ptr(target) = target_ty {
1503                    local_id = local.btf_type;
1504                    target_id = target.btf_type;
1505                    continue;
1506                }
1507            }
1508            BtfType::Array(Array { array: local, .. }) => {
1509                if let BtfType::Array(Array { array: target, .. }) = target_ty {
1510                    local_id = local.element_type;
1511                    target_id = target.element_type;
1512                    continue;
1513                }
1514            }
1515            BtfType::FuncProto(local) => {
1516                if let BtfType::FuncProto(target) = target_ty {
1517                    if local.params.len() != target.params.len() {
1518                        return Ok(false);
1519                    }
1520
1521                    for (l_param, t_param) in local.params.iter().zip(target.params.iter()) {
1522                        let local_id = local_btf.resolve_type(l_param.btf_type)?;
1523                        let target_id = target_btf.resolve_type(t_param.btf_type)?;
1524                        if !types_are_compatible(local_btf, local_id, target_btf, target_id)? {
1525                            return Ok(false);
1526                        }
1527                    }
1528
1529                    local_id = local.return_type;
1530                    target_id = target.return_type;
1531                    continue;
1532                }
1533            }
1534            local_ty => panic!("unexpected type {:?}", local_ty),
1535        }
1536    }
1537
1538    Err(BtfError::MaximumTypeDepthReached { type_id: local_id })
1539}
1540
1541pub(crate) fn fields_are_compatible(
1542    local_btf: &Btf,
1543    mut local_id: u32,
1544    target_btf: &Btf,
1545    mut target_id: u32,
1546) -> Result<bool, BtfError> {
1547    for () in core::iter::repeat_n((), MAX_RESOLVE_DEPTH) {
1548        local_id = local_btf.resolve_type(local_id)?;
1549        target_id = target_btf.resolve_type(target_id)?;
1550        let local_ty = local_btf.type_by_id(local_id)?;
1551        let target_ty = target_btf.type_by_id(target_id)?;
1552
1553        if local_ty.is_composite() && target_ty.is_composite() {
1554            return Ok(true);
1555        }
1556
1557        if !local_ty.is_compatible(target_ty) {
1558            return Ok(false);
1559        }
1560
1561        match local_ty {
1562            BtfType::Fwd(_) | BtfType::Enum(_) | BtfType::Enum64(_) => {
1563                let flavorless_name =
1564                    |name: &str| name.split_once("___").map_or(name, |x| x.0).to_string();
1565
1566                let local_name = flavorless_name(&local_btf.type_name(local_ty)?);
1567                let target_name = flavorless_name(&target_btf.type_name(target_ty)?);
1568
1569                return Ok(local_name == target_name);
1570            }
1571            BtfType::Int(local) => {
1572                if let BtfType::Int(target) = target_ty {
1573                    return Ok(local.offset() == 0 && target.offset() == 0);
1574                }
1575            }
1576            BtfType::Float(_) => return Ok(true),
1577            BtfType::Ptr(_) => return Ok(true),
1578            BtfType::Array(Array { array: local, .. }) => {
1579                if let BtfType::Array(Array { array: target, .. }) = target_ty {
1580                    local_id = local.element_type;
1581                    target_id = target.element_type;
1582                    continue;
1583                }
1584            }
1585            local_ty => panic!("unexpected type {:?}", local_ty),
1586        }
1587    }
1588
1589    Err(BtfError::MaximumTypeDepthReached { type_id: local_id })
1590}
1591
1592fn bytes_of<T>(val: &T) -> &[u8] {
1593    // Safety: all btf types are POD
1594    //
1595    // TODO: This is a fragile assumption and we should stop doing this. We should also remove
1596    // repr(C) from our types, it doesn't make sense to rely on this.
1597    unsafe { crate::util::bytes_of(val) }
1598}
1599
1600#[cfg(test)]
1601mod tests {
1602    use assert_matches::assert_matches;
1603
1604    use super::*;
1605
1606    #[test]
1607    fn test_read_btf_type_int() {
1608        let endianness = Endianness::default();
1609        let bpf_type = BtfType::Int(Int::new(1, 8, IntEncoding::None, 0));
1610        let data: &[u8] = &bpf_type.to_bytes();
1611        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Int(new @ Int {
1612            name_offset,
1613            info: _,
1614            size,
1615            data: _,
1616        }) => {
1617                assert_eq!(name_offset, 1);
1618                assert_eq!(size, 8);
1619                assert_eq!(new.bits(), 64);
1620                assert_eq!(new.to_bytes(), data);
1621        });
1622    }
1623
1624    #[test]
1625    fn test_read_btf_type_ptr() {
1626        let endianness = Endianness::default();
1627        let bpf_type = BtfType::Ptr(Ptr::new(0, 0x06));
1628        let data: &[u8] = &bpf_type.to_bytes();
1629        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Ptr(got) => {
1630            assert_eq!(got.to_bytes(), data);
1631        });
1632    }
1633
1634    #[test]
1635    fn test_read_btf_type_array() {
1636        let endianness = Endianness::default();
1637        let bpf_type = BtfType::Array(Array::new(0, 1, 0x12, 2));
1638        let data: &[u8] = &bpf_type.to_bytes();
1639        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Array(got) => {
1640            assert_eq!(got.to_bytes(), data);
1641        });
1642    }
1643
1644    #[test]
1645    fn test_read_btf_type_struct() {
1646        let endianness = Endianness::default();
1647        let members = vec![BtfMember {
1648            name_offset: 0x0247,
1649            btf_type: 0x12,
1650            offset: 0,
1651        }];
1652        let bpf_type = BtfType::Struct(Struct::new(0, members, 4));
1653        let data: &[u8] = &bpf_type.to_bytes();
1654        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Struct(got) => {
1655            assert_eq!(got.to_bytes(), data);
1656        });
1657    }
1658
1659    #[test]
1660    fn test_read_btf_type_union() {
1661        let endianness = Endianness::default();
1662        let members = vec![BtfMember {
1663            name_offset: 0x040d,
1664            btf_type: 0x68,
1665            offset: 0,
1666        }];
1667        let bpf_type = BtfType::Union(Union::new(0, 4, members, None));
1668        let data: &[u8] = &bpf_type.to_bytes();
1669        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Union(got) => {
1670            assert_eq!(got.to_bytes(), data);
1671        });
1672    }
1673
1674    #[test]
1675    fn test_read_btf_type_enum() {
1676        let endianness = Endianness::default();
1677        let enum1 = BtfEnum::new(0xc9, 0);
1678        let enum2 = BtfEnum::new(0xcf, 1);
1679        let variants = vec![enum1, enum2];
1680        let bpf_type = BtfType::Enum(Enum::new(0, false, variants));
1681        let data: &[u8] = &bpf_type.to_bytes();
1682        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum(got) => {
1683            assert_eq!(got.to_bytes(), data);
1684        });
1685    }
1686
1687    #[test]
1688    fn test_read_btf_type_fwd() {
1689        let endianness = Endianness::default();
1690        let info = (BtfKind::Fwd as u32) << 24;
1691        let bpf_type = BtfType::Fwd(Fwd {
1692            name_offset: 0x550b,
1693            info,
1694            _unused: 0,
1695        });
1696        let data: &[u8] = &bpf_type.to_bytes();
1697        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Fwd(got) => {
1698            assert_eq!(got.to_bytes(), data);
1699        });
1700    }
1701
1702    #[test]
1703    fn test_read_btf_type_typedef() {
1704        let endianness = Endianness::default();
1705        let bpf_type = BtfType::Typedef(Typedef::new(0x31, 0x0b));
1706        let data: &[u8] = &bpf_type.to_bytes();
1707        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Typedef(got) => {
1708            assert_eq!(got.to_bytes(), data);
1709        });
1710    }
1711
1712    #[test]
1713    fn test_read_btf_type_volatile() {
1714        let endianness = Endianness::default();
1715        let info = (BtfKind::Volatile as u32) << 24;
1716        let bpf_type = BtfType::Volatile(Volatile {
1717            name_offset: 0,
1718            info,
1719            btf_type: 0x24,
1720        });
1721        let data: &[u8] = &bpf_type.to_bytes();
1722        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Volatile(got) => {
1723            assert_eq!(got.to_bytes(), data);
1724        });
1725    }
1726
1727    #[test]
1728    fn test_read_btf_type_const() {
1729        let endianness = Endianness::default();
1730        let bpf_type = BtfType::Const(Const::new(1));
1731        let data: &[u8] = &bpf_type.to_bytes();
1732        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Const(got) => {
1733            assert_eq!(got.to_bytes(), data);
1734        });
1735    }
1736
1737    #[test]
1738    fn test_read_btf_type_restrict() {
1739        let endianness = Endianness::default();
1740        let info = (BtfKind::Restrict as u32) << 24;
1741        let bpf_type = BtfType::Restrict(Restrict {
1742            name_offset: 0,
1743            _info: info,
1744            btf_type: 4,
1745        });
1746        let data: &[u8] = &bpf_type.to_bytes();
1747        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Restrict(got) => {
1748            assert_eq!(got.to_bytes(), data);
1749        });
1750    }
1751
1752    #[test]
1753    fn test_read_btf_type_func() {
1754        let endianness = Endianness::default();
1755        let bpf_type = BtfType::Func(Func::new(0x000f8b17, 0xe4f0, FuncLinkage::Global));
1756        let data: &[u8] = &bpf_type.to_bytes();
1757        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Func(got) => {
1758            assert_eq!(got.to_bytes(), data);
1759        });
1760    }
1761
1762    #[test]
1763    fn test_read_btf_type_func_proto() {
1764        let endianness = Endianness::default();
1765        let params = vec![BtfParam {
1766            name_offset: 0,
1767            btf_type: 0x12,
1768        }];
1769        let bpf_type = BtfType::FuncProto(FuncProto::new(params, 0));
1770        let data: &[u8] = &bpf_type.to_bytes();
1771        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::FuncProto(got) => {
1772            assert_eq!(got.to_bytes(), data);
1773        });
1774    }
1775
1776    #[test]
1777    fn test_read_btf_type_func_var() {
1778        let endianness = Endianness::default();
1779        // NOTE: There was no data in /sys/kernell/btf/vmlinux for this type
1780        let bpf_type = BtfType::Var(Var::new(0, 0xf0, VarLinkage::Static));
1781        let data: &[u8] = &bpf_type.to_bytes();
1782        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Var(got) => {
1783            assert_eq!(got.to_bytes(), data);
1784        });
1785    }
1786
1787    #[test]
1788    fn test_read_btf_type_func_datasec() {
1789        let endianness = Endianness::default();
1790        let entries = vec![DataSecEntry {
1791            btf_type: 11,
1792            offset: 0,
1793            size: 4,
1794        }];
1795        let bpf_type = BtfType::DataSec(DataSec::new(0xd9, entries, 0));
1796        let data: &[u8] = &bpf_type.to_bytes();
1797        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::DataSec(DataSec {
1798            name_offset: _,
1799            info: _,
1800            size,
1801            entries,
1802         }) => {
1803                assert_eq!(size, 0);
1804                assert_matches!(*entries, [
1805                    DataSecEntry {
1806                        btf_type: 11,
1807                        offset: 0,
1808                        size: 4,
1809                    }
1810                ]);
1811            }
1812        );
1813    }
1814
1815    #[test]
1816    fn test_read_btf_type_float() {
1817        let endianness = Endianness::default();
1818        let bpf_type = BtfType::Float(Float::new(0x02fd, 8));
1819        let data: &[u8] = &bpf_type.to_bytes();
1820        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Float(got) => {
1821            assert_eq!(got.to_bytes(), data);
1822        });
1823    }
1824
1825    #[test]
1826    fn test_write_btf_func_proto() {
1827        let params = vec![
1828            BtfParam {
1829                name_offset: 1,
1830                btf_type: 1,
1831            },
1832            BtfParam {
1833                name_offset: 3,
1834                btf_type: 1,
1835            },
1836        ];
1837        let func_proto = FuncProto::new(params, 2);
1838        let data = func_proto.to_bytes();
1839        assert_matches!(unsafe { BtfType::read(&data, Endianness::default()) }.unwrap(), BtfType::FuncProto(FuncProto {
1840            name_offset: _,
1841            info: _,
1842            return_type: _,
1843            params,
1844        }) => {
1845            assert_matches!(*params, [
1846                _,
1847                _,
1848            ])
1849        });
1850    }
1851
1852    #[test]
1853    fn test_types_are_compatible() {
1854        let mut btf = Btf::new();
1855        let name_offset = btf.add_string("u32");
1856        let u32t = btf.add_type(BtfType::Int(Int::new(name_offset, 4, IntEncoding::None, 0)));
1857        let name_offset = btf.add_string("u64");
1858        let u64t = btf.add_type(BtfType::Int(Int::new(name_offset, 8, IntEncoding::None, 0)));
1859        let name_offset = btf.add_string("widgets");
1860        let array_type = btf.add_type(BtfType::Array(Array::new(name_offset, u64t, u32t, 16)));
1861
1862        assert!(types_are_compatible(&btf, u32t, &btf, u32t).unwrap());
1863        // int types are compatible if offsets match. size and encoding aren't compared
1864        assert!(types_are_compatible(&btf, u32t, &btf, u64t).unwrap());
1865        assert!(types_are_compatible(&btf, array_type, &btf, array_type).unwrap());
1866    }
1867
1868    #[test]
1869    fn test_read_btf_type_enum64() {
1870        let endianness = Endianness::default();
1871        let variants = vec![BtfEnum64::new(0, 0xbbbbbbbbaaaaaaaau64)];
1872        let bpf_type = BtfType::Enum64(Enum64::new(0, false, variants));
1873        let data: &[u8] = &bpf_type.to_bytes();
1874        assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum64(got) => {
1875            assert_eq!(got.to_bytes(), data);
1876        });
1877    }
1878}