1#![allow(dead_code)]
2
3use std::{
4 convert::AsRef,
5 fs::File,
6 io::{BufReader, Cursor, Read},
7 path::Path,
8 sync::Arc,
9};
10
11use anyhow::{bail, Result};
12
13use crate::cbtf;
14use crate::obj::BtfObj;
15
16pub struct Btf {
19 obj: Arc<BtfObj>,
20 base: Option<Arc<BtfObj>>,
21}
22
23impl Btf {
24 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Btf> {
28 Ok(Btf {
29 obj: Arc::new(BtfObj::from_reader(
30 &mut BufReader::new(File::open(path)?),
31 None,
32 )?),
33 base: None,
34 })
35 }
36
37 pub fn from_split_file<P: AsRef<Path>>(path: P, base: &Btf) -> Result<Btf> {
40 if !path.as_ref().is_file() {
41 bail!("Invalid BTF file {}", path.as_ref().display());
42 }
43
44 Ok(Btf {
45 obj: Arc::new(BtfObj::from_reader(
46 &mut BufReader::new(File::open(path)?),
47 Some(base.obj.clone()),
48 )?),
49 base: Some(base.obj.clone()),
50 })
51 }
52
53 pub fn from_bytes(bytes: &[u8]) -> Result<Btf> {
55 Ok(Btf {
56 obj: Arc::new(BtfObj::from_reader(&mut Cursor::new(bytes), None)?),
57 base: None,
58 })
59 }
60
61 pub fn from_split_bytes(bytes: &[u8], base: &Btf) -> Result<Btf> {
63 let base = base.obj.clone();
64 Ok(Btf {
65 obj: Arc::new(BtfObj::from_reader(
66 &mut Cursor::new(bytes),
67 Some(base.clone()),
68 )?),
69 base: Some(base),
70 })
71 }
72
73 pub fn resolve_ids_by_name(&self, name: &str) -> Result<Vec<u32>> {
75 let mut ids = Vec::new();
76
77 if let Some(base) = &self.base {
78 if let Ok(mut ids_base) = base.resolve_ids_by_name(name) {
79 ids.append(&mut ids_base);
80 }
81 }
82 if let Ok(mut ids_obj) = self.obj.resolve_ids_by_name(name) {
83 ids.append(&mut ids_obj);
84 }
85
86 if ids.is_empty() {
87 bail!("No id linked to name {name}");
88 }
89 Ok(ids)
90 }
91
92 pub fn resolve_type_by_id(&self, id: u32) -> Result<Type> {
94 match &self.base {
95 Some(base) => base
96 .resolve_type_by_id(id)
97 .or_else(|_| self.obj.resolve_type_by_id(id)),
98 None => self.obj.resolve_type_by_id(id),
99 }
100 }
101
102 pub fn resolve_types_by_name(&self, name: &str) -> Result<Vec<Type>> {
104 let mut types = Vec::new();
105
106 if let Some(base) = &self.base {
107 if let Ok(mut types_base) = base.resolve_types_by_name(name) {
108 types.append(&mut types_base);
109 }
110 }
111 if let Ok(mut types_obj) = self.obj.resolve_types_by_name(name) {
112 types.append(&mut types_obj);
113 }
114
115 if types.is_empty() {
116 bail!("No id linked to name {name}");
119 }
120 Ok(types)
121 }
122
123 pub fn resolve_name<T: BtfType + ?Sized>(&self, r#type: &T) -> Result<String> {
126 match &self.base {
127 Some(base) => base
128 .resolve_name(r#type)
129 .or_else(|_| self.obj.resolve_name(r#type)),
130 None => self.obj.resolve_name(r#type),
131 }
132 }
133
134 pub fn resolve_chained_type<T: BtfType + ?Sized>(&self, r#type: &T) -> Result<Type> {
138 self.resolve_type_by_id(r#type.get_type_id()?)
139 }
140
141 pub fn type_iter<'a, T: BtfType + ?Sized>(&'a self, r#type: &'a T) -> TypeIter {
145 let ty = self.resolve_chained_type(r#type).ok();
146 TypeIter {
147 btf: self,
148 r#type: ty,
149 }
150 }
151}
152
153pub struct TypeIter<'a> {
155 btf: &'a Btf,
156 r#type: Option<Type>,
157}
158
159impl<'a> Iterator for TypeIter<'a> {
161 type Item = Type;
162
163 fn next(&mut self) -> Option<Self::Item> {
164 match self.r#type.clone() {
165 None => None,
166 Some(ty) => {
167 self.r#type = match ty.as_btf_type() {
168 Some(x) => self.btf.resolve_chained_type(x).ok(),
169 None => None,
172 };
173 Some(ty)
174 }
175 }
176 }
177}
178
179#[derive(Clone, Debug)]
182pub enum Type {
183 Void,
184 Int(Int),
185 Ptr(Ptr),
186 Array(Array),
187 Struct(Struct),
188 Union(Union),
189 Enum(Enum),
190 Fwd(Fwd),
191 Typedef(Typedef),
192 Volatile(Volatile),
193 Const(Const),
194 Restrict(Restrict),
195 Func(Func),
196 FuncProto(FuncProto),
197 Var(Var),
198 Datasec(Datasec),
199 Float(Float),
200 DeclTag(DeclTag),
201 TypeTag(TypeTag),
202 Enum64(Enum64),
203}
204
205impl Type {
206 pub fn name(&self) -> &'static str {
207 match &self {
208 Type::Void => "void",
209 Type::Int(_) => "int",
210 Type::Ptr(_) => "ptr",
211 Type::Array(_) => "array",
212 Type::Struct(_) => "struct",
213 Type::Union(_) => "union",
214 Type::Enum(_) => "enum",
215 Type::Fwd(_) => "fwd",
216 Type::Typedef(_) => "typedef",
217 Type::Volatile(_) => "volatile",
218 Type::Const(_) => "const",
219 Type::Restrict(_) => "restrict",
220 Type::Func(_) => "func",
221 Type::FuncProto(_) => "func-proto",
222 Type::Var(_) => "var",
223 Type::Datasec(_) => "datasec",
224 Type::Float(_) => "float",
225 Type::DeclTag(_) => "decl-tag",
226 Type::TypeTag(_) => "type-tag",
227 Type::Enum64(_) => "enum64",
228 }
229 }
230
231 pub fn as_btf_type(&self) -> Option<&dyn BtfType> {
232 match self {
233 Type::Int(i) => Some(i),
234 Type::Ptr(p) => Some(p),
235 Type::Array(a) => Some(a),
236 Type::Struct(s) => Some(s),
237 Type::Union(u) => Some(u),
238 Type::Enum(e) => Some(e),
239 Type::Fwd(f) => Some(f),
240 Type::Typedef(td) => Some(td),
241 Type::Volatile(v) => Some(v),
242 Type::Const(c) => Some(c),
243 Type::Restrict(r) => Some(r),
244 Type::Func(fu) => Some(fu),
245 Type::Var(v) => Some(v),
246 Type::Datasec(ds) => Some(ds),
247 Type::Float(f) => Some(f),
248 Type::DeclTag(dt) => Some(dt),
249 Type::TypeTag(tt) => Some(tt),
250 Type::Enum64(e64) => Some(e64),
251 _ => None,
252 }
253 }
254}
255
256pub trait BtfType {
257 fn get_name_offset(&self) -> Result<u32> {
258 bail!("No name offset in type");
259 }
260
261 fn get_type_id(&self) -> Result<u32> {
262 bail!("No type offset in type");
263 }
264}
265
266#[derive(Clone, Debug)]
268pub struct Int {
269 btf_type: cbtf::btf_type,
270 btf_int: cbtf::btf_int,
271}
272
273impl Int {
274 pub(super) fn from_reader<R: Read>(
275 reader: &mut R,
276 endianness: &cbtf::Endianness,
277 btf_type: cbtf::btf_type,
278 ) -> Result<Int> {
279 Ok(Int {
280 btf_type,
281 btf_int: cbtf::btf_int::from_reader(reader, endianness)?,
282 })
283 }
284
285 pub fn is_signed(&self) -> bool {
286 self.btf_int.encoding() & cbtf::BTF_INT_SIGNED == cbtf::BTF_INT_SIGNED
287 }
288
289 pub fn is_char(&self) -> bool {
290 self.btf_int.encoding() & cbtf::BTF_INT_CHAR == cbtf::BTF_INT_CHAR
291 }
292
293 pub fn is_bool(&self) -> bool {
294 self.btf_int.encoding() & cbtf::BTF_INT_BOOL == cbtf::BTF_INT_BOOL
295 }
296
297 pub fn size(&self) -> usize {
298 self.btf_type.size()
299 }
300}
301
302impl BtfType for Int {
303 fn get_name_offset(&self) -> Result<u32> {
304 Ok(self.btf_type.name_off)
305 }
306}
307
308#[derive(Clone, Debug)]
310pub struct Ptr {
311 btf_type: cbtf::btf_type,
312}
313
314impl Ptr {
315 pub(super) fn new(btf_type: cbtf::btf_type) -> Ptr {
316 Ptr { btf_type }
317 }
318}
319
320impl BtfType for Ptr {
321 fn get_type_id(&self) -> Result<u32> {
322 Ok(self.btf_type.r#type())
323 }
324}
325
326#[derive(Clone, Debug)]
328pub struct Array {
329 btf_type: cbtf::btf_type,
330 btf_array: cbtf::btf_array,
331}
332
333#[allow(clippy::len_without_is_empty)]
334impl Array {
335 pub(super) fn from_reader<R: Read>(
336 reader: &mut R,
337 endianness: &cbtf::Endianness,
338 btf_type: cbtf::btf_type,
339 ) -> Result<Array> {
340 Ok(Array {
341 btf_type,
342 btf_array: cbtf::btf_array::from_reader(reader, endianness)?,
343 })
344 }
345
346 pub fn len(&self) -> usize {
347 self.btf_array.nelems as usize
348 }
349}
350
351impl BtfType for Array {
352 fn get_type_id(&self) -> Result<u32> {
353 Ok(self.btf_array.r#type)
354 }
355}
356
357#[derive(Clone, Debug)]
359pub struct Struct {
360 btf_type: cbtf::btf_type,
361 pub members: Vec<Member>,
362}
363
364impl Struct {
365 pub(super) fn from_reader<R: Read>(
366 reader: &mut R,
367 endianness: &cbtf::Endianness,
368 btf_type: cbtf::btf_type,
369 ) -> Result<Struct> {
370 let mut members = Vec::new();
371
372 for _ in 0..btf_type.vlen() {
373 members.push(Member::from_reader(
374 reader,
375 endianness,
376 btf_type.kind_flag(),
377 )?);
378 }
379
380 Ok(Struct { btf_type, members })
381 }
382
383 pub fn size(&self) -> usize {
384 self.btf_type.size()
385 }
386}
387
388impl BtfType for Struct {
389 fn get_name_offset(&self) -> Result<u32> {
390 Ok(self.btf_type.name_off)
391 }
392}
393
394pub type Union = Struct;
396
397#[derive(Clone, Debug)]
399pub struct Member {
400 kind_flag: u32,
401 btf_member: cbtf::btf_member,
402}
403
404impl Member {
405 pub(super) fn from_reader<R: Read>(
406 reader: &mut R,
407 endianness: &cbtf::Endianness,
408 kind_flag: u32,
409 ) -> Result<Member> {
410 Ok(Member {
411 kind_flag,
412 btf_member: cbtf::btf_member::from_reader(reader, endianness)?,
413 })
414 }
415
416 pub fn bit_offset(&self) -> u32 {
417 match self.kind_flag {
418 1 => self.btf_member.offset & 0xffffff,
419 _ => self.btf_member.offset,
420 }
421 }
422
423 pub fn bitfield_size(&self) -> Option<u32> {
424 match self.kind_flag {
425 1 => Some(self.btf_member.offset >> 24),
426 _ => None,
427 }
428 }
429}
430
431impl BtfType for Member {
432 fn get_name_offset(&self) -> Result<u32> {
433 Ok(self.btf_member.name_off)
434 }
435
436 fn get_type_id(&self) -> Result<u32> {
437 Ok(self.btf_member.r#type)
438 }
439}
440
441#[derive(Clone, Debug)]
443pub struct Enum {
444 btf_type: cbtf::btf_type,
445 pub members: Vec<EnumMember>,
446}
447
448#[allow(clippy::len_without_is_empty)]
449impl Enum {
450 pub(super) fn from_reader<R: Read>(
451 reader: &mut R,
452 endianness: &cbtf::Endianness,
453 btf_type: cbtf::btf_type,
454 ) -> Result<Enum> {
455 let mut members = Vec::new();
456
457 for _ in 0..btf_type.vlen() {
458 members.push(EnumMember::from_reader(reader, endianness)?);
459 }
460
461 Ok(Enum { btf_type, members })
462 }
463
464 pub fn is_signed(&self) -> bool {
465 self.btf_type.kind_flag() == 1
466 }
467
468 pub fn len(&self) -> usize {
469 self.btf_type.vlen() as usize
470 }
471
472 pub fn size(&self) -> usize {
473 self.btf_type.size()
474 }
475}
476
477impl BtfType for Enum {
478 fn get_name_offset(&self) -> Result<u32> {
479 Ok(self.btf_type.name_off)
480 }
481}
482
483#[derive(Clone, Debug)]
485pub struct EnumMember {
486 btf_enum: cbtf::btf_enum,
487}
488
489impl EnumMember {
490 pub(super) fn from_reader<R: Read>(
491 reader: &mut R,
492 endianness: &cbtf::Endianness,
493 ) -> Result<EnumMember> {
494 Ok(EnumMember {
495 btf_enum: cbtf::btf_enum::from_reader(reader, endianness)?,
496 })
497 }
498
499 pub fn val(&self) -> u32 {
500 self.btf_enum.val
501 }
502}
503
504impl BtfType for EnumMember {
505 fn get_name_offset(&self) -> Result<u32> {
506 Ok(self.btf_enum.name_off)
507 }
508}
509
510#[derive(Clone, Debug)]
512pub struct Fwd {
513 btf_type: cbtf::btf_type,
514}
515
516impl Fwd {
517 pub(super) fn new(btf_type: cbtf::btf_type) -> Fwd {
518 Fwd { btf_type }
519 }
520
521 pub fn is_struct(&self) -> bool {
523 self.btf_type.kind_flag() == 0
524 }
525
526 pub fn is_union(&self) -> bool {
528 self.btf_type.kind_flag() == 1
529 }
530}
531
532impl BtfType for Fwd {
533 fn get_name_offset(&self) -> Result<u32> {
534 Ok(self.btf_type.name_off)
535 }
536}
537
538#[derive(Clone, Debug)]
540pub struct Typedef {
541 btf_type: cbtf::btf_type,
542}
543
544impl Typedef {
545 pub(super) fn new(btf_type: cbtf::btf_type) -> Typedef {
546 Typedef { btf_type }
547 }
548}
549
550impl BtfType for Typedef {
551 fn get_name_offset(&self) -> Result<u32> {
552 Ok(self.btf_type.name_off)
553 }
554
555 fn get_type_id(&self) -> Result<u32> {
556 Ok(self.btf_type.r#type())
557 }
558}
559
560pub type TypeTag = Typedef;
562
563#[derive(Clone, Debug)]
565pub struct Volatile {
566 btf_type: cbtf::btf_type,
567}
568
569impl Volatile {
570 pub(super) fn new(btf_type: cbtf::btf_type) -> Volatile {
571 Volatile { btf_type }
572 }
573}
574
575impl BtfType for Volatile {
576 fn get_type_id(&self) -> Result<u32> {
577 Ok(self.btf_type.r#type())
578 }
579}
580
581pub type Const = Volatile;
583
584pub type Restrict = Volatile;
586
587#[derive(Clone, Debug)]
589pub struct Func {
590 btf_type: cbtf::btf_type,
591}
592
593impl Func {
594 pub(super) fn new(btf_type: cbtf::btf_type) -> Func {
595 Func { btf_type }
596 }
597
598 pub fn is_static(&self) -> bool {
599 self.btf_type.vlen() == cbtf::BTF_FUNC_STATIC
600 }
601
602 pub fn is_global(&self) -> bool {
603 self.btf_type.vlen() == cbtf::BTF_FUNC_GLOBAL
604 }
605
606 pub fn is_extern(&self) -> bool {
607 self.btf_type.vlen() == cbtf::BTF_FUNC_EXTERN
608 }
609}
610
611impl BtfType for Func {
612 fn get_name_offset(&self) -> Result<u32> {
613 Ok(self.btf_type.name_off)
614 }
615
616 fn get_type_id(&self) -> Result<u32> {
617 Ok(self.btf_type.r#type())
618 }
619}
620
621#[derive(Clone, Debug)]
623pub struct FuncProto {
624 btf_type: cbtf::btf_type,
625 pub parameters: Vec<Parameter>,
626}
627
628impl FuncProto {
629 pub(super) fn from_reader<R: Read>(
630 reader: &mut R,
631 endianness: &cbtf::Endianness,
632 btf_type: cbtf::btf_type,
633 ) -> Result<FuncProto> {
634 let mut parameters = Vec::new();
635
636 for _ in 0..btf_type.vlen() {
637 parameters.push(Parameter::from_reader(reader, endianness)?);
638 }
639
640 Ok(FuncProto {
641 btf_type,
642 parameters,
643 })
644 }
645
646 pub fn return_type_id(&self) -> u32 {
647 self.btf_type.r#type()
648 }
649}
650
651#[derive(Clone, Debug)]
653pub struct Parameter {
654 btf_param: cbtf::btf_param,
655}
656
657impl Parameter {
658 pub(super) fn from_reader<R: Read>(
659 reader: &mut R,
660 endianness: &cbtf::Endianness,
661 ) -> Result<Parameter> {
662 Ok(Parameter {
663 btf_param: cbtf::btf_param::from_reader(reader, endianness)?,
664 })
665 }
666
667 pub fn is_variadic(&self) -> bool {
668 self.btf_param.name_off == 0 && self.btf_param.r#type == 0
669 }
670}
671
672impl BtfType for Parameter {
673 fn get_name_offset(&self) -> Result<u32> {
674 Ok(self.btf_param.name_off)
675 }
676
677 fn get_type_id(&self) -> Result<u32> {
678 Ok(self.btf_param.r#type)
679 }
680}
681
682#[derive(Clone, Debug)]
684pub struct Var {
685 btf_type: cbtf::btf_type,
686 btf_var: cbtf::btf_var,
687}
688
689impl Var {
690 pub(super) fn from_reader<R: Read>(
691 reader: &mut R,
692 endianness: &cbtf::Endianness,
693 btf_type: cbtf::btf_type,
694 ) -> Result<Var> {
695 Ok(Var {
696 btf_type,
697 btf_var: cbtf::btf_var::from_reader(reader, endianness)?,
698 })
699 }
700
701 pub fn is_static(&self) -> bool {
702 self.btf_var.linkage == 0
703 }
704
705 pub fn is_global(&self) -> bool {
706 self.btf_var.linkage == 1
707 }
708}
709
710impl BtfType for Var {
711 fn get_name_offset(&self) -> Result<u32> {
712 Ok(self.btf_type.name_off)
713 }
714
715 fn get_type_id(&self) -> Result<u32> {
716 Ok(self.btf_type.r#type())
717 }
718}
719
720#[derive(Clone, Debug)]
722pub struct Datasec {
723 btf_type: cbtf::btf_type,
724 pub variables: Vec<VarSecinfo>,
725}
726
727impl Datasec {
728 pub(super) fn from_reader<R: Read>(
729 reader: &mut R,
730 endianness: &cbtf::Endianness,
731 btf_type: cbtf::btf_type,
732 ) -> Result<Datasec> {
733 let mut variables = Vec::new();
734
735 for _ in 0..btf_type.vlen() {
736 variables.push(VarSecinfo::from_reader(reader, endianness)?);
737 }
738
739 Ok(Datasec {
740 btf_type,
741 variables,
742 })
743 }
744}
745
746impl BtfType for Datasec {
747 fn get_name_offset(&self) -> Result<u32> {
748 Ok(self.btf_type.name_off)
749 }
750}
751
752#[derive(Clone, Debug)]
754pub struct VarSecinfo {
755 btf_var_secinfo: cbtf::btf_var_secinfo,
756}
757
758impl VarSecinfo {
759 pub(super) fn from_reader<R: Read>(
760 reader: &mut R,
761 endianness: &cbtf::Endianness,
762 ) -> Result<VarSecinfo> {
763 Ok(VarSecinfo {
764 btf_var_secinfo: cbtf::btf_var_secinfo::from_reader(reader, endianness)?,
765 })
766 }
767
768 pub fn offset(&self) -> u32 {
769 self.btf_var_secinfo.offset
770 }
771
772 pub fn size(&self) -> usize {
773 self.btf_var_secinfo.size as usize
774 }
775}
776
777impl BtfType for VarSecinfo {
778 fn get_type_id(&self) -> Result<u32> {
779 Ok(self.btf_var_secinfo.r#type)
780 }
781}
782
783#[derive(Clone, Debug)]
785pub struct Float {
786 btf_type: cbtf::btf_type,
787}
788
789impl Float {
790 pub(super) fn new(btf_type: cbtf::btf_type) -> Float {
791 Float { btf_type }
792 }
793
794 pub fn size(&self) -> usize {
795 self.btf_type.size()
796 }
797}
798
799impl BtfType for Float {
800 fn get_name_offset(&self) -> Result<u32> {
801 Ok(self.btf_type.name_off)
802 }
803}
804
805#[derive(Clone, Debug)]
807pub struct DeclTag {
808 btf_type: cbtf::btf_type,
809 btf_decl_tag: cbtf::btf_decl_tag,
810}
811
812impl DeclTag {
813 pub(super) fn from_reader<R: Read>(
814 reader: &mut R,
815 endianness: &cbtf::Endianness,
816 btf_type: cbtf::btf_type,
817 ) -> Result<DeclTag> {
818 Ok(DeclTag {
819 btf_type,
820 btf_decl_tag: cbtf::btf_decl_tag::from_reader(reader, endianness)?,
821 })
822 }
823
824 pub fn component_index(&self) -> Option<u32> {
825 let component_idx = self.btf_decl_tag.component_idx;
826 match component_idx {
827 x if x < 0 => None,
828 x => Some(x as u32),
829 }
830 }
831}
832
833impl BtfType for DeclTag {
834 fn get_name_offset(&self) -> Result<u32> {
835 Ok(self.btf_type.name_off)
836 }
837
838 fn get_type_id(&self) -> Result<u32> {
839 Ok(self.btf_type.r#type())
840 }
841}
842
843#[derive(Clone, Debug)]
845pub struct Enum64 {
846 btf_type: cbtf::btf_type,
847 pub members: Vec<Enum64Member>,
848}
849
850#[allow(clippy::len_without_is_empty)]
851impl Enum64 {
852 pub(super) fn from_reader<R: Read>(
853 reader: &mut R,
854 endianness: &cbtf::Endianness,
855 btf_type: cbtf::btf_type,
856 ) -> Result<Enum64> {
857 let mut members = Vec::new();
858
859 for _ in 0..btf_type.vlen() {
860 members.push(Enum64Member::from_reader(reader, endianness)?);
861 }
862
863 Ok(Enum64 { btf_type, members })
864 }
865
866 pub fn is_signed(&self) -> bool {
867 self.btf_type.kind_flag() == 1
868 }
869
870 pub fn len(&self) -> usize {
871 self.btf_type.vlen() as usize
872 }
873
874 pub fn size(&self) -> usize {
875 self.btf_type.size()
876 }
877}
878
879impl BtfType for Enum64 {
880 fn get_name_offset(&self) -> Result<u32> {
881 Ok(self.btf_type.name_off)
882 }
883}
884
885#[derive(Clone, Debug)]
887pub struct Enum64Member {
888 btf_enum64: cbtf::btf_enum64,
889}
890
891impl Enum64Member {
892 pub(super) fn from_reader<R: Read>(
893 reader: &mut R,
894 endianness: &cbtf::Endianness,
895 ) -> Result<Enum64Member> {
896 Ok(Enum64Member {
897 btf_enum64: cbtf::btf_enum64::from_reader(reader, endianness)?,
898 })
899 }
900
901 pub fn val(&self) -> u64 {
902 (self.btf_enum64.val_hi32 as u64) << 32 | self.btf_enum64.val_lo32 as u64
903 }
904}
905
906impl BtfType for Enum64Member {
907 fn get_name_offset(&self) -> Result<u32> {
908 Ok(self.btf_enum64.name_off)
909 }
910}