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