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 #[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 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#[derive(Clone, Debug)]
657pub(crate) struct Enum64VariantFallback {
658 pub(crate) name_offset: u32,
659 pub(crate) value: u64,
660}
661
662#[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 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 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 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 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}