aya_obj/btf/
types.rs

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