btf/
types.rs

1use std::cmp::{max, min};
2use std::ffi::{c_char, CStr};
3use std::fmt;
4use std::mem::size_of;
5
6use object::{Object, ObjectSection};
7use scroll::Pread;
8use scroll_derive::{IOread, IOwrite, Pread as DerivePread, Pwrite, SizeWith};
9
10use crate::{btf_error, BtfError, BtfResult};
11
12pub const BTF_ELF_SEC: &str = ".BTF";
13pub const BTF_EXT_ELF_SEC: &str = ".BTF.ext";
14
15pub const BTF_MAGIC: u16 = 0xeB9F;
16pub const BTF_VERSION: u8 = 1;
17
18pub const BTF_KIND_UNKN: u32 = 0;
19pub const BTF_KIND_INT: u32 = 1;
20pub const BTF_KIND_PTR: u32 = 2;
21pub const BTF_KIND_ARRAY: u32 = 3;
22pub const BTF_KIND_STRUCT: u32 = 4;
23pub const BTF_KIND_UNION: u32 = 5;
24pub const BTF_KIND_ENUM: u32 = 6;
25pub const BTF_KIND_FWD: u32 = 7;
26pub const BTF_KIND_TYPEDEF: u32 = 8;
27pub const BTF_KIND_VOLATILE: u32 = 9;
28pub const BTF_KIND_CONST: u32 = 10;
29pub const BTF_KIND_RESTRICT: u32 = 11;
30pub const BTF_KIND_FUNC: u32 = 12;
31pub const BTF_KIND_FUNC_PROTO: u32 = 13;
32pub const BTF_KIND_VAR: u32 = 14;
33pub const BTF_KIND_DATASEC: u32 = 15;
34pub const BTF_KIND_FLOAT: u32 = 16;
35pub const BTF_KIND_DECL_TAG: u32 = 17;
36pub const BTF_KIND_TYPE_TAG: u32 = 18;
37pub const BTF_KIND_ENUM64: u32 = 19;
38pub const BTF_KIND_MAX: u32 = 19;
39pub const NR_BTF_KINDS: u32 = BTF_KIND_MAX + 1;
40
41pub const BTF_INT_SIGNED: u32 = 0b001;
42pub const BTF_INT_CHAR: u32 = 0b010;
43pub const BTF_INT_BOOL: u32 = 0b100;
44
45pub const BTF_VAR_STATIC: u32 = 0;
46pub const BTF_VAR_GLOBAL_ALLOCATED: u32 = 1;
47pub const BTF_VAR_GLOBAL_EXTERNAL: u32 = 2;
48
49pub const BTF_FUNC_STATIC: u32 = 0;
50pub const BTF_FUNC_GLOBAL: u32 = 1;
51pub const BTF_FUNC_EXTERN: u32 = 2;
52
53#[repr(C)]
54#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
55pub struct btf_header {
56    pub magic: u16,
57    pub version: u8,
58    pub flags: u8,
59    pub hdr_len: u32,
60    pub type_off: u32,
61    pub type_len: u32,
62    pub str_off: u32,
63    pub str_len: u32,
64}
65
66#[repr(C)]
67#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
68pub struct btf_type {
69    pub name_off: u32,
70    pub info: u32,
71    pub type_id: u32,
72}
73
74#[repr(C)]
75#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
76pub struct btf_enum {
77    pub name_off: u32,
78    pub val: i32,
79}
80
81#[repr(C)]
82#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
83pub struct btf_array {
84    pub val_type_id: u32,
85    pub idx_type_id: u32,
86    pub nelems: u32,
87}
88
89#[repr(C)]
90#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
91pub struct btf_member {
92    pub name_off: u32,
93    pub type_id: u32,
94    pub offset: u32,
95}
96
97#[repr(C)]
98#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
99pub struct btf_param {
100    pub name_off: u32,
101    pub type_id: u32,
102}
103
104#[repr(C)]
105#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
106pub struct btf_datasec_var {
107    pub type_id: u32,
108    pub offset: u32,
109    pub size: u32,
110}
111
112#[repr(C)]
113#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
114pub struct btf_enum64 {
115    pub name_off: u32,
116    pub val_lo32: u32,
117    pub val_hi32: u32,
118}
119
120#[repr(C)]
121#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
122pub struct btf_ext_min_header {
123    pub magic: u16,
124    pub version: u8,
125    pub flags: u8,
126    pub hdr_len: u32,
127}
128
129#[repr(C)]
130#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
131pub struct btf_ext_header_v1 {
132    pub magic: u16,
133    pub version: u8,
134    pub flags: u8,
135    pub hdr_len: u32,
136    pub func_info_off: u32,
137    pub func_info_len: u32,
138    pub line_info_off: u32,
139    pub line_info_len: u32,
140}
141
142#[repr(C)]
143#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
144pub struct btf_ext_header_v2 {
145    pub magic: u16,
146    pub version: u8,
147    pub flags: u8,
148    pub hdr_len: u32,
149    pub func_info_off: u32,
150    pub func_info_len: u32,
151    pub line_info_off: u32,
152    pub line_info_len: u32,
153    pub core_reloc_off: u32,
154    pub core_reloc_len: u32,
155}
156
157#[repr(C)]
158#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
159pub struct btf_ext_info_sec {
160    pub sec_name_off: u32,
161    pub num_info: u32,
162}
163
164#[repr(C)]
165#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
166pub struct btf_ext_func_info {
167    pub insn_off: u32,
168    pub type_id: u32,
169}
170
171#[repr(C)]
172#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
173pub struct btf_ext_line_info {
174    pub insn_off: u32,
175    pub file_name_off: u32,
176    pub line_off: u32,
177    pub line_col: u32,
178}
179
180pub const BTF_FIELD_BYTE_OFFSET: u32 = 0;
181pub const BTF_FIELD_BYTE_SIZE: u32 = 1;
182pub const BTF_FIELD_EXISTS: u32 = 2;
183pub const BTF_FIELD_SIGNED: u32 = 3;
184pub const BTF_FIELD_LSHIFT_U64: u32 = 4;
185pub const BTF_FIELD_RSHIFT_U64: u32 = 5;
186pub const BTF_TYPE_LOCAL_ID: u32 = 6;
187pub const BTF_TYPE_TARGET_ID: u32 = 7;
188pub const BTF_TYPE_EXISTS: u32 = 8;
189pub const BTF_TYPE_SIZE: u32 = 9;
190pub const BTF_ENUMVAL_EXISTS: u32 = 10;
191pub const BTF_ENUMVAL_VALUE: u32 = 11;
192pub const BTF_TYPE_MATCHES: u32 = 12;
193
194#[repr(C)]
195#[derive(Debug, Copy, Clone, DerivePread, Pwrite, IOread, IOwrite, SizeWith)]
196pub struct btf_ext_core_reloc {
197    pub insn_off: u32,
198    pub type_id: u32,
199    pub access_spec_off: u32,
200    pub kind: u32,
201}
202
203const EMPTY: &'static str = "";
204const ANON_NAME: &'static str = "<anon>";
205
206fn disp_name(s: &str) -> &str {
207    if s == "" {
208        ANON_NAME
209    } else {
210        s
211    }
212}
213
214#[derive(Debug, Copy, Clone, PartialEq)]
215pub enum BtfIntEncoding {
216    None,
217    Signed,
218    Char,
219    Bool,
220}
221
222impl fmt::Display for BtfIntEncoding {
223    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224        match self {
225            BtfIntEncoding::None => write!(f, "none"),
226            BtfIntEncoding::Signed => write!(f, "signed"),
227            BtfIntEncoding::Char => write!(f, "char"),
228            BtfIntEncoding::Bool => write!(f, "bool"),
229        }
230    }
231}
232
233#[derive(Debug)]
234pub struct BtfInt<'a> {
235    pub name: &'a str,
236    pub bits: u32,
237    pub offset: u32,
238    pub encoding: BtfIntEncoding,
239}
240
241impl<'a> fmt::Display for BtfInt<'a> {
242    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243        write!(
244            f,
245            "<{}> '{}' bits:{} off:{}",
246            "INT",
247            disp_name(self.name),
248            self.bits,
249            self.offset
250        )?;
251        match self.encoding {
252            BtfIntEncoding::None => (),
253            _ => write!(f, " enc:{}", self.encoding)?,
254        }
255        Ok(())
256    }
257}
258
259#[derive(Debug)]
260pub struct BtfPtr {
261    pub type_id: u32,
262}
263
264impl fmt::Display for BtfPtr {
265    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266        write!(f, "<{}> --> [{}]", "PTR", self.type_id)
267    }
268}
269
270#[derive(Debug)]
271pub struct BtfArray {
272    pub nelems: u32,
273    pub idx_type_id: u32,
274    pub val_type_id: u32,
275}
276
277impl fmt::Display for BtfArray {
278    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
279        write!(
280            f,
281            "<{}> n:{} idx-->[{}] val-->[{}]",
282            "ARRAY", self.nelems, self.idx_type_id, self.val_type_id
283        )
284    }
285}
286
287#[derive(Debug)]
288pub struct BtfMember<'a> {
289    pub name: &'a str,
290    pub type_id: u32,
291    pub bit_offset: u32,
292    pub bit_size: u8,
293}
294
295impl<'a> fmt::Display for BtfMember<'a> {
296    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297        write!(f, "'{}' off:{}", disp_name(self.name), self.bit_offset)?;
298        if self.bit_size != 0 {
299            write!(f, " sz:{}", self.bit_size)?;
300        }
301        write!(f, " --> [{}]", self.type_id)
302    }
303}
304
305#[derive(Debug)]
306pub struct BtfComposite<'a> {
307    pub is_struct: bool,
308    pub name: &'a str,
309    pub sz: u32,
310    pub members: Vec<BtfMember<'a>>,
311}
312
313impl<'a> fmt::Display for BtfComposite<'a> {
314    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
315        write!(
316            f,
317            "<{}> '{}' sz:{} n:{}",
318            if self.is_struct { "STRUCT" } else { "UNION" },
319            disp_name(self.name),
320            self.sz,
321            self.members.len()
322        )?;
323        for i in 0..self.members.len() {
324            write!(f, "\n\t#{:02} {}", i, self.members[i])?;
325        }
326        Ok(())
327    }
328}
329
330#[derive(Debug)]
331pub struct BtfEnumValue<'a> {
332    pub name: &'a str,
333    pub value: i32,
334}
335
336impl<'a> fmt::Display for BtfEnumValue<'a> {
337    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338        write!(f, "{} = {}", disp_name(self.name), self.value)
339    }
340}
341
342#[derive(Debug)]
343pub struct BtfEnum<'a> {
344    pub name: &'a str,
345    pub sz: u32,
346    pub values: Vec<BtfEnumValue<'a>>,
347}
348
349impl<'a> fmt::Display for BtfEnum<'a> {
350    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351        write!(
352            f,
353            "<{}> '{}' sz:{} n:{}",
354            "ENUM",
355            disp_name(self.name),
356            self.sz,
357            self.values.len()
358        )?;
359        for i in 0..self.values.len() {
360            write!(f, "\n\t#{:02} {}", i, self.values[i])?;
361        }
362        Ok(())
363    }
364}
365
366#[derive(Debug)]
367pub struct BtfEnum64Value<'a> {
368    pub name: &'a str,
369    pub value: i64,
370}
371
372impl<'a> fmt::Display for BtfEnum64Value<'a> {
373    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
374        write!(f, "{} = {}", disp_name(self.name), self.value)
375    }
376}
377
378#[derive(Debug)]
379pub struct BtfEnum64<'a> {
380    pub name: &'a str,
381    pub sz: u32,
382    pub values: Vec<BtfEnum64Value<'a>>,
383}
384
385impl<'a> fmt::Display for BtfEnum64<'a> {
386    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
387        write!(
388            f,
389            "<{}> '{}' sz:{} n:{}",
390            "ENUM64",
391            disp_name(self.name),
392            self.sz,
393            self.values.len()
394        )?;
395        for i in 0..self.values.len() {
396            write!(f, "\n\t#{:02} {}", i, self.values[i])?;
397        }
398        Ok(())
399    }
400}
401
402#[derive(Debug, Copy, Clone, PartialEq)]
403pub enum BtfFwdKind {
404    Struct,
405    Union,
406}
407
408impl fmt::Display for BtfFwdKind {
409    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410        match self {
411            BtfFwdKind::Struct => write!(f, "struct"),
412            BtfFwdKind::Union => write!(f, "union"),
413        }
414    }
415}
416
417#[derive(Debug)]
418pub struct BtfFwd<'a> {
419    pub name: &'a str,
420    pub kind: BtfFwdKind,
421}
422
423impl<'a> fmt::Display for BtfFwd<'a> {
424    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425        write!(
426            f,
427            "<{}> '{}' kind:{}",
428            "FWD",
429            disp_name(self.name),
430            self.kind
431        )
432    }
433}
434
435#[derive(Debug)]
436pub struct BtfTypedef<'a> {
437    pub name: &'a str,
438    pub type_id: u32,
439}
440
441impl<'a> fmt::Display for BtfTypedef<'a> {
442    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
443        write!(
444            f,
445            "<{}> '{}' --> [{}]",
446            "TYPEDEF",
447            disp_name(self.name),
448            self.type_id
449        )
450    }
451}
452
453#[derive(Debug)]
454pub struct BtfVolatile {
455    pub type_id: u32,
456}
457
458impl fmt::Display for BtfVolatile {
459    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
460        write!(f, "<{}> --> [{}]", "VOLATILE", self.type_id)
461    }
462}
463
464#[derive(Debug)]
465pub struct BtfConst {
466    pub type_id: u32,
467}
468
469impl fmt::Display for BtfConst {
470    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471        write!(f, "<{}> --> [{}]", "CONST", self.type_id)
472    }
473}
474
475#[derive(Debug)]
476pub struct BtfRestrict {
477    pub type_id: u32,
478}
479
480impl fmt::Display for BtfRestrict {
481    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
482        write!(f, "<{}> --> [{}]", "RESTRICT", self.type_id)
483    }
484}
485
486#[derive(Debug, Copy, Clone, PartialEq)]
487pub enum BtfFuncKind {
488    Unknown,
489    Static,
490    Global,
491    Extern,
492}
493
494impl fmt::Display for BtfFuncKind {
495    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
496        match self {
497            BtfFuncKind::Unknown => write!(f, "<unknown>"),
498            BtfFuncKind::Static => write!(f, "static"),
499            BtfFuncKind::Global => write!(f, "global"),
500            BtfFuncKind::Extern => write!(f, "extern"),
501        }
502    }
503}
504
505#[derive(Debug)]
506pub struct BtfFunc<'a> {
507    pub name: &'a str,
508    pub proto_type_id: u32,
509    pub kind: BtfFuncKind,
510}
511
512impl<'a> fmt::Display for BtfFunc<'a> {
513    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
514        write!(
515            f,
516            "<{}> '{}' --> {} [{}]",
517            "FUNC",
518            disp_name(self.name),
519            self.kind,
520            self.proto_type_id
521        )
522    }
523}
524
525#[derive(Debug)]
526pub struct BtfFuncParam<'a> {
527    pub name: &'a str,
528    pub type_id: u32,
529}
530
531impl<'a> fmt::Display for BtfFuncParam<'a> {
532    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
533        write!(f, "'{}' --> [{}]", disp_name(self.name), self.type_id)
534    }
535}
536
537#[derive(Debug)]
538pub struct BtfFuncProto<'a> {
539    pub res_type_id: u32,
540    pub params: Vec<BtfFuncParam<'a>>,
541}
542
543impl<'a> fmt::Display for BtfFuncProto<'a> {
544    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545        write!(
546            f,
547            "<{}> r-->[{}] n:{}",
548            "FUNC_PROTO",
549            self.res_type_id,
550            self.params.len()
551        )?;
552        for i in 0..self.params.len() {
553            write!(f, "\n\t#{:02} {}", i, self.params[i])?;
554        }
555        Ok(())
556    }
557}
558
559#[derive(Debug, Copy, Clone, PartialEq)]
560pub enum BtfVarKind {
561    Static,
562    GlobalAlloc,
563    GlobalExtern,
564}
565
566impl fmt::Display for BtfVarKind {
567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568        match self {
569            BtfVarKind::Static => write!(f, "static"),
570            BtfVarKind::GlobalAlloc => write!(f, "global-alloc"),
571            BtfVarKind::GlobalExtern => write!(f, "global-extern"),
572        }
573    }
574}
575
576#[derive(Debug)]
577pub struct BtfVar<'a> {
578    pub name: &'a str,
579    pub type_id: u32,
580    pub kind: BtfVarKind,
581}
582
583impl<'a> fmt::Display for BtfVar<'a> {
584    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
585        write!(
586            f,
587            "<{}> '{}' kind:{} --> [{}]",
588            "VAR",
589            disp_name(self.name),
590            self.kind,
591            self.type_id
592        )
593    }
594}
595
596#[derive(Debug)]
597pub struct BtfDatasecVar {
598    pub type_id: u32,
599    pub offset: u32,
600    pub sz: u32,
601}
602
603impl fmt::Display for BtfDatasecVar {
604    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
605        write!(
606            f,
607            "off:{} sz:{} --> [{}]",
608            self.offset, self.sz, self.type_id
609        )
610    }
611}
612
613#[derive(Debug)]
614pub struct BtfDatasec<'a> {
615    pub name: &'a str,
616    pub sz: u32,
617    pub vars: Vec<BtfDatasecVar>,
618}
619
620impl<'a> fmt::Display for BtfDatasec<'a> {
621    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
622        write!(
623            f,
624            "<{}> '{}' sz:{} n:{}",
625            "DATASEC",
626            disp_name(self.name),
627            self.sz,
628            self.vars.len()
629        )?;
630        for i in 0..self.vars.len() {
631            write!(f, "\n\t#{:02} {}", i, self.vars[i])?;
632        }
633        Ok(())
634    }
635}
636
637#[derive(Debug)]
638pub struct BtfFloat<'a> {
639    pub name: &'a str,
640    pub sz: u32,
641}
642
643impl<'a> fmt::Display for BtfFloat<'a> {
644    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
645        write!(f, "<{}> '{}' sz:{}", "FLOAT", disp_name(self.name), self.sz)?;
646        Ok(())
647    }
648}
649
650#[derive(Debug)]
651pub struct BtfDeclTag<'a> {
652    pub name: &'a str,
653    pub type_id: u32,
654    pub comp_idx: u32,
655}
656
657impl<'a> fmt::Display for BtfDeclTag<'a> {
658    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
659        write!(
660            f,
661            "<{}> '{}' --> [{}] comp_idx:{}",
662            "DECL_TAG",
663            disp_name(self.name),
664            self.type_id,
665            self.comp_idx,
666        )
667    }
668}
669
670#[derive(Debug)]
671pub struct BtfTypeTag<'a> {
672    pub name: &'a str,
673    pub type_id: u32,
674}
675
676impl<'a> fmt::Display for BtfTypeTag<'a> {
677    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
678        write!(
679            f,
680            "<{}> '{}' --> [{}]",
681            "TYPE_TAG",
682            disp_name(self.name),
683            self.type_id
684        )
685    }
686}
687
688#[derive(Debug)]
689pub enum BtfType<'a> {
690    Void,
691    Int(BtfInt<'a>),
692    Ptr(BtfPtr),
693    Array(BtfArray),
694    Struct(BtfComposite<'a>),
695    Union(BtfComposite<'a>),
696    Enum(BtfEnum<'a>),
697    Fwd(BtfFwd<'a>),
698    Typedef(BtfTypedef<'a>),
699    Volatile(BtfVolatile),
700    Const(BtfConst),
701    Restrict(BtfRestrict),
702    Func(BtfFunc<'a>),
703    FuncProto(BtfFuncProto<'a>),
704    Var(BtfVar<'a>),
705    Datasec(BtfDatasec<'a>),
706    Float(BtfFloat<'a>),
707    DeclTag(BtfDeclTag<'a>),
708    TypeTag(BtfTypeTag<'a>),
709    Enum64(BtfEnum64<'a>),
710}
711
712impl<'a> fmt::Display for BtfType<'a> {
713    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
714        match self {
715            BtfType::Void => write!(f, "<{}>", "VOID"),
716            BtfType::Int(t) => t.fmt(f),
717            BtfType::Ptr(t) => t.fmt(f),
718            BtfType::Array(t) => t.fmt(f),
719            BtfType::Struct(t) => t.fmt(f),
720            BtfType::Union(t) => t.fmt(f),
721            BtfType::Enum(t) => t.fmt(f),
722            BtfType::Fwd(t) => t.fmt(f),
723            BtfType::Typedef(t) => t.fmt(f),
724            BtfType::Volatile(t) => t.fmt(f),
725            BtfType::Const(t) => t.fmt(f),
726            BtfType::Restrict(t) => t.fmt(f),
727            BtfType::Func(t) => t.fmt(f),
728            BtfType::FuncProto(t) => t.fmt(f),
729            BtfType::Var(t) => t.fmt(f),
730            BtfType::Datasec(t) => t.fmt(f),
731            BtfType::Float(t) => t.fmt(f),
732            BtfType::DeclTag(t) => t.fmt(f),
733            BtfType::TypeTag(t) => t.fmt(f),
734            BtfType::Enum64(t) => t.fmt(f),
735        }
736    }
737}
738
739impl<'a> BtfType<'a> {
740    pub fn kind(&self) -> BtfKind {
741        match self {
742            BtfType::Void => BtfKind::Void,
743            BtfType::Int(_) => BtfKind::Int,
744            BtfType::Ptr(_) => BtfKind::Ptr,
745            BtfType::Array(_) => BtfKind::Array,
746            BtfType::Struct(_) => BtfKind::Struct,
747            BtfType::Union(_) => BtfKind::Union,
748            BtfType::Enum(_) => BtfKind::Enum,
749            BtfType::Fwd(_) => BtfKind::Fwd,
750            BtfType::Typedef(_) => BtfKind::Typedef,
751            BtfType::Volatile(_) => BtfKind::Volatile,
752            BtfType::Const(_) => BtfKind::Const,
753            BtfType::Restrict(_) => BtfKind::Restrict,
754            BtfType::Func(_) => BtfKind::Func,
755            BtfType::FuncProto(_) => BtfKind::FuncProto,
756            BtfType::Var(_) => BtfKind::Var,
757            BtfType::Datasec(_) => BtfKind::Datasec,
758            BtfType::Float(_) => BtfKind::Float,
759            BtfType::DeclTag(_) => BtfKind::DeclTag,
760            BtfType::TypeTag(_) => BtfKind::TypeTag,
761            BtfType::Enum64(_) => BtfKind::Enum64,
762        }
763    }
764
765    pub fn name(&self) -> &str {
766        match self {
767            BtfType::Void => EMPTY,
768            BtfType::Int(t) => &t.name,
769            BtfType::Ptr(_) => EMPTY,
770            BtfType::Array(_) => EMPTY,
771            BtfType::Struct(t) => &t.name,
772            BtfType::Union(t) => &t.name,
773            BtfType::Enum(t) => &t.name,
774            BtfType::Fwd(t) => &t.name,
775            BtfType::Typedef(t) => &t.name,
776            BtfType::Volatile(_) => EMPTY,
777            BtfType::Const(_) => EMPTY,
778            BtfType::Restrict(_) => EMPTY,
779            BtfType::Func(t) => &t.name,
780            BtfType::FuncProto(_) => EMPTY,
781            BtfType::Var(t) => &t.name,
782            BtfType::Datasec(t) => &t.name,
783            BtfType::Float(t) => &t.name,
784            BtfType::DeclTag(t) => &t.name,
785            BtfType::TypeTag(t) => &t.name,
786            BtfType::Enum64(t) => &t.name,
787        }
788    }
789}
790
791#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
792pub enum BtfKind {
793    Void,
794    Int,
795    Ptr,
796    Array,
797    Struct,
798    Union,
799    Enum,
800    Fwd,
801    Typedef,
802    Volatile,
803    Const,
804    Restrict,
805    Func,
806    FuncProto,
807    Var,
808    Datasec,
809    Float,
810    DeclTag,
811    TypeTag,
812    Enum64,
813}
814
815impl std::str::FromStr for BtfKind {
816    type Err = BtfError;
817
818    fn from_str(s: &str) -> Result<Self, Self::Err> {
819        match s {
820            "void" => Ok(BtfKind::Void),
821            "int" | "i" => Ok(BtfKind::Int),
822            "ptr" | "p" => Ok(BtfKind::Ptr),
823            "array" | "arr" | "a" => Ok(BtfKind::Array),
824            "struct" | "s" => Ok(BtfKind::Struct),
825            "union" | "u" => Ok(BtfKind::Union),
826            "enum" | "e" => Ok(BtfKind::Enum),
827            "fwd" => Ok(BtfKind::Fwd),
828            "typedef" | "t" => Ok(BtfKind::Typedef),
829            "volatile" => Ok(BtfKind::Volatile),
830            "const" => Ok(BtfKind::Const),
831            "restrict" => Ok(BtfKind::Restrict),
832            "func_proto" | "funcproto" | "fnproto" | "fp" => Ok(BtfKind::FuncProto),
833            "func" | "fn" => Ok(BtfKind::Func),
834            "var" | "v" => Ok(BtfKind::Var),
835            "datasec" => Ok(BtfKind::Datasec),
836            "float" => Ok(BtfKind::Float),
837            "decl_tag" => Ok(BtfKind::DeclTag),
838            "type_tag" => Ok(BtfKind::TypeTag),
839            "enum64" | "e64" => Ok(BtfKind::Enum64),
840            _ => Err(BtfError::new_owned(format!(
841                "unrecognized btf kind: '{}'",
842                s
843            ))),
844        }
845    }
846}
847
848#[derive(Debug)]
849pub struct BtfExtSection<'a, T> {
850    pub name: &'a str,
851    pub rec_sz: usize,
852    pub recs: Vec<T>,
853}
854
855#[derive(Debug)]
856pub struct BtfExtFunc {
857    pub insn_off: u32,
858    pub type_id: u32,
859}
860
861impl fmt::Display for BtfExtFunc {
862    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
863        write!(
864            f,
865            "func: insn #{} --> [{}]",
866            self.insn_off / 8,
867            self.type_id
868        )
869    }
870}
871
872#[derive(Debug)]
873pub struct BtfExtLine<'a> {
874    pub insn_off: u32,
875    pub file_name: &'a str,
876    pub src_line: &'a str,
877    pub line_num: u32,
878    pub col_num: u32,
879}
880
881impl<'a> fmt::Display for BtfExtLine<'a> {
882    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
883        write!(
884            f,
885            "line: insn #{} --> {}:{} @ {}\n\t{}",
886            self.insn_off / 8,
887            self.line_num,
888            self.col_num,
889            self.file_name,
890            self.src_line
891        )
892    }
893}
894
895#[derive(Debug, Copy, Clone, PartialEq)]
896pub enum BtfCoreRelocKind {
897    ByteOff = 0,
898    ByteSz = 1,
899    FieldExists = 2,
900    Signed = 3,
901    LShiftU64 = 4,
902    RShiftU64 = 5,
903    LocalTypeId = 6,
904    TargetTypeId = 7,
905    TypeExists = 8,
906    TypeSize = 9,
907    EnumvalExists = 10,
908    EnumvalValue = 11,
909    TypeMatches = 12,
910}
911
912impl fmt::Display for BtfCoreRelocKind {
913    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
914        match self {
915            BtfCoreRelocKind::ByteOff => write!(f, "byte_off"),
916            BtfCoreRelocKind::ByteSz => write!(f, "byte_sz"),
917            BtfCoreRelocKind::FieldExists => write!(f, "field_exists"),
918            BtfCoreRelocKind::Signed => write!(f, "signed"),
919            BtfCoreRelocKind::LShiftU64 => write!(f, "lshift_u64"),
920            BtfCoreRelocKind::RShiftU64 => write!(f, "rshift_u64"),
921            BtfCoreRelocKind::LocalTypeId => write!(f, "local_type_id"),
922            BtfCoreRelocKind::TargetTypeId => write!(f, "target_type_id"),
923            BtfCoreRelocKind::TypeExists => write!(f, "type_exists"),
924            BtfCoreRelocKind::TypeMatches => write!(f, "type_matches"),
925            BtfCoreRelocKind::TypeSize => write!(f, "type_size"),
926            BtfCoreRelocKind::EnumvalExists => write!(f, "enumval_exists"),
927            BtfCoreRelocKind::EnumvalValue => write!(f, "enumval_value"),
928        }
929    }
930}
931
932#[derive(Debug)]
933pub struct BtfExtCoreReloc<'a> {
934    pub insn_off: u32,
935    pub type_id: u32,
936    pub access_spec_str: &'a str,
937    pub access_spec: Vec<usize>,
938    pub kind: BtfCoreRelocKind,
939}
940
941impl<'a> fmt::Display for BtfExtCoreReloc<'a> {
942    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943        write!(
944            f,
945            "core_reloc: insn #{} --> [{}] + {}: {}",
946            self.insn_off / 8,
947            self.type_id,
948            self.access_spec_str,
949            self.kind,
950        )
951    }
952}
953
954#[derive(Debug)]
955pub struct Btf<'a> {
956    endian: scroll::Endian,
957    types: Vec<BtfType<'a>>,
958    ptr_sz: u32,
959
960    // .BTF.ext stuff
961    has_ext: bool,
962    func_secs: Vec<BtfExtSection<'a, BtfExtFunc>>,
963    line_secs: Vec<BtfExtSection<'a, BtfExtLine<'a>>>,
964    core_reloc_secs: Vec<BtfExtSection<'a, BtfExtCoreReloc<'a>>>,
965}
966
967impl<'a> Btf<'a> {
968    pub fn ptr_sz(&self) -> u32 {
969        self.ptr_sz
970    }
971
972    pub fn types(&self) -> &[BtfType] {
973        &self.types
974    }
975
976    pub fn type_by_id(&self, type_id: u32) -> &BtfType {
977        &self.types[type_id as usize]
978    }
979
980    pub fn type_cnt(&self) -> u32 {
981        self.types.len() as u32
982    }
983
984    pub fn has_ext(&self) -> bool {
985        self.has_ext
986    }
987
988    pub fn func_secs(&self) -> &[BtfExtSection<BtfExtFunc>] {
989        &self.func_secs
990    }
991
992    pub fn line_secs(&self) -> &[BtfExtSection<BtfExtLine>] {
993        &self.line_secs
994    }
995
996    pub fn core_reloc_secs(&self) -> &[BtfExtSection<BtfExtCoreReloc>] {
997        &self.core_reloc_secs
998    }
999
1000    pub fn get_size_of(&self, type_id: u32) -> u32 {
1001        match self.type_by_id(type_id) {
1002            BtfType::Void => 0,
1003            BtfType::Int(t) => (t.bits + 7) / 8,
1004            BtfType::Volatile(t) => self.get_size_of(t.type_id),
1005            BtfType::Const(t) => self.get_size_of(t.type_id),
1006            BtfType::Restrict(t) => self.get_size_of(t.type_id),
1007            BtfType::Ptr(_) => self.ptr_sz,
1008            BtfType::Array(t) => t.nelems * self.get_size_of(t.val_type_id),
1009            BtfType::FuncProto(_) => 0,
1010            BtfType::Struct(t) => t.sz,
1011            BtfType::Union(t) => t.sz,
1012            BtfType::Enum(t) => t.sz,
1013            BtfType::Fwd(_) => 0,
1014            BtfType::Typedef(t) => self.get_size_of(t.type_id),
1015            BtfType::Func(_) => 0,
1016            BtfType::Var(_) => 0,
1017            BtfType::Datasec(t) => t.sz,
1018            BtfType::Float(t) => t.sz,
1019            BtfType::DeclTag(t) => self.get_size_of(t.type_id),
1020            BtfType::TypeTag(t) => self.get_size_of(t.type_id),
1021            BtfType::Enum64(t) => t.sz,
1022        }
1023    }
1024
1025    pub fn get_align_of(&self, type_id: u32) -> u32 {
1026        match self.type_by_id(type_id) {
1027            BtfType::Void => 0,
1028            BtfType::Int(t) => min(self.ptr_sz, (t.bits + 7) / 8),
1029            BtfType::Volatile(t) => self.get_align_of(t.type_id),
1030            BtfType::Const(t) => self.get_align_of(t.type_id),
1031            BtfType::Restrict(t) => self.get_align_of(t.type_id),
1032            BtfType::Ptr(_) => self.ptr_sz,
1033            BtfType::Array(t) => self.get_align_of(t.val_type_id),
1034            BtfType::FuncProto(_) => 0,
1035            BtfType::Struct(t) => {
1036                let mut align = 1;
1037                for m in &t.members {
1038                    align = max(align, self.get_align_of(m.type_id));
1039                }
1040                align
1041            }
1042            BtfType::Union(t) => {
1043                let mut align = 1;
1044                for m in &t.members {
1045                    align = max(align, self.get_align_of(m.type_id));
1046                }
1047                align
1048            }
1049            BtfType::Enum(t) => min(self.ptr_sz, t.sz),
1050            BtfType::Fwd(_) => 0,
1051            BtfType::Typedef(t) => self.get_align_of(t.type_id),
1052            BtfType::Func(_) => 0,
1053            BtfType::Var(_) => 0,
1054            BtfType::Datasec(_) => 0,
1055            BtfType::Float(t) => min(self.ptr_sz, t.sz),
1056            BtfType::DeclTag(_) => 0,
1057            BtfType::TypeTag(t) => self.get_align_of(t.type_id),
1058            BtfType::Enum64(t) => min(self.ptr_sz, t.sz),
1059        }
1060    }
1061
1062    pub fn skip_mods(&self, mut type_id: u32) -> u32 {
1063        loop {
1064            match self.type_by_id(type_id) {
1065                BtfType::Volatile(t) => type_id = t.type_id,
1066                BtfType::Const(t) => type_id = t.type_id,
1067                BtfType::Restrict(t) => type_id = t.type_id,
1068                BtfType::TypeTag(t) => type_id = t.type_id,
1069                _ => return type_id,
1070            }
1071        }
1072    }
1073
1074    pub fn skip_mods_and_typedefs(&self, mut type_id: u32) -> u32 {
1075        loop {
1076            match self.type_by_id(type_id) {
1077                BtfType::Volatile(t) => type_id = t.type_id,
1078                BtfType::Const(t) => type_id = t.type_id,
1079                BtfType::Restrict(t) => type_id = t.type_id,
1080                BtfType::Typedef(t) => type_id = t.type_id,
1081                BtfType::TypeTag(t) => type_id = t.type_id,
1082                _ => return type_id,
1083            }
1084        }
1085    }
1086
1087    pub fn load(elf: &object::File<'a>) -> BtfResult<Btf<'a>> {
1088        let endian = if elf.is_little_endian() {
1089            scroll::LE
1090        } else {
1091            scroll::BE
1092        };
1093        let mut btf = Btf::<'a> {
1094            endian: endian,
1095            ptr_sz: if elf.is_64() { 8 } else { 4 },
1096            types: vec![BtfType::Void],
1097            has_ext: false,
1098            func_secs: Vec::new(),
1099            line_secs: Vec::new(),
1100            core_reloc_secs: Vec::new(),
1101        };
1102
1103        let btf_section = elf
1104            .section_by_name(BTF_ELF_SEC)
1105            .ok_or_else(|| Box::new(BtfError::new("No .BTF section found!")))?;
1106        let data = match btf_section.data() {
1107            Ok(d) => d,
1108            _ => panic!("expected borrowed data"),
1109        };
1110        let hdr = data.pread_with::<btf_header>(0, endian)?;
1111        if hdr.magic != BTF_MAGIC {
1112            return btf_error(format!("Invalid BTF magic: {}", hdr.magic));
1113        }
1114        if hdr.version != BTF_VERSION {
1115            return btf_error(format!(
1116                "Unsupported BTF version: {}, expect: {}",
1117                hdr.version, BTF_VERSION
1118            ));
1119        }
1120
1121        let str_off = (hdr.hdr_len + hdr.str_off) as usize;
1122        let str_data = &data[str_off..str_off + hdr.str_len as usize];
1123
1124        let type_off = (hdr.hdr_len + hdr.type_off) as usize;
1125        let type_data = &data[type_off..type_off + hdr.type_len as usize];
1126        let mut off: usize = 0;
1127        while off < hdr.type_len as usize {
1128            let t = btf.load_type(&type_data[off..], str_data)?;
1129            off += Btf::type_size(&t);
1130            btf.types.push(t);
1131        }
1132
1133        if let Some(ext_section) = elf.section_by_name(BTF_EXT_ELF_SEC) {
1134            btf.has_ext = true;
1135            let ext_data = match ext_section.data() {
1136                Ok(d) => d,
1137                _ => panic!("expected borrowed data"),
1138            };
1139            let ext_hdr = ext_data.pread_with::<btf_ext_header_v1>(0, endian)?;
1140            if ext_hdr.magic != BTF_MAGIC {
1141                return btf_error(format!("Invalid .BTF.ext magic: {}", ext_hdr.magic));
1142            }
1143            if ext_hdr.version != BTF_VERSION {
1144                return btf_error(format!(
1145                    "Unsupported .BTF.ext version: {}, expect: {}",
1146                    ext_hdr.version, BTF_VERSION
1147                ));
1148            }
1149            let ext_hdr2 = if ext_hdr.hdr_len >= size_of::<btf_ext_header_v2>() as u32 {
1150                Some(ext_data.pread_with::<btf_ext_header_v2>(0, endian)?)
1151            } else {
1152                None
1153            };
1154            if ext_hdr.func_info_len > 0 {
1155                let func_off = (ext_hdr.hdr_len + ext_hdr.func_info_off) as usize;
1156                let func_data = &ext_data[func_off..func_off + ext_hdr.func_info_len as usize];
1157                btf.func_secs = btf.load_func_secs(func_data, str_data)?;
1158            }
1159            if ext_hdr.line_info_len > 0 {
1160                let line_off = (ext_hdr.hdr_len + ext_hdr.line_info_off) as usize;
1161                let line_data = &ext_data[line_off..line_off + ext_hdr.line_info_len as usize];
1162                btf.line_secs = btf.load_line_secs(line_data, str_data)?;
1163            }
1164            if let Some(h) = ext_hdr2 {
1165                if h.core_reloc_len > 0 {
1166                    let reloc_off = (h.hdr_len + h.core_reloc_off) as usize;
1167                    let reloc_data = &ext_data[reloc_off..reloc_off + h.core_reloc_len as usize];
1168                    btf.core_reloc_secs = btf.load_core_reloc_secs(reloc_data, str_data)?;
1169                }
1170            }
1171        }
1172
1173        Ok(btf)
1174    }
1175
1176    pub fn type_size(t: &BtfType) -> usize {
1177        let common = size_of::<btf_type>();
1178        match t {
1179            BtfType::Void => 0,
1180            BtfType::Ptr(_)
1181            | BtfType::Fwd(_)
1182            | BtfType::Typedef(_)
1183            | BtfType::Volatile(_)
1184            | BtfType::Const(_)
1185            | BtfType::Restrict(_)
1186            | BtfType::Func(_)
1187            | BtfType::Float(_)
1188            | BtfType::TypeTag(_) => common,
1189            BtfType::Int(_) | BtfType::Var(_) | BtfType::DeclTag(_) => common + size_of::<u32>(),
1190            BtfType::Array(_) => common + size_of::<btf_array>(),
1191            BtfType::Struct(t) => common + t.members.len() * size_of::<btf_member>(),
1192            BtfType::Union(t) => common + t.members.len() * size_of::<btf_member>(),
1193            BtfType::Enum(t) => common + t.values.len() * size_of::<btf_enum>(),
1194            BtfType::Enum64(t) => common + t.values.len() * size_of::<btf_enum64>(),
1195            BtfType::FuncProto(t) => common + t.params.len() * size_of::<btf_param>(),
1196            BtfType::Datasec(t) => common + t.vars.len() * size_of::<btf_datasec_var>(),
1197        }
1198    }
1199
1200    fn load_type(&self, data: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1201        let t = data.pread_with::<btf_type>(0, self.endian)?;
1202        let extra = &data[size_of::<btf_type>()..];
1203        let kind = Btf::get_kind(t.info);
1204        match kind {
1205            BTF_KIND_INT => self.load_int(&t, extra, strs),
1206            BTF_KIND_PTR => Ok(BtfType::Ptr(BtfPtr { type_id: t.type_id })),
1207            BTF_KIND_ARRAY => self.load_array(extra),
1208            BTF_KIND_STRUCT => self.load_struct(&t, extra, strs),
1209            BTF_KIND_UNION => self.load_union(&t, extra, strs),
1210            BTF_KIND_ENUM => self.load_enum(&t, extra, strs),
1211            BTF_KIND_FWD => self.load_fwd(&t, strs),
1212            BTF_KIND_TYPEDEF => Ok(BtfType::Typedef(BtfTypedef {
1213                name: Btf::get_btf_str(strs, t.name_off)?,
1214                type_id: t.type_id,
1215            })),
1216            BTF_KIND_VOLATILE => Ok(BtfType::Volatile(BtfVolatile { type_id: t.type_id })),
1217            BTF_KIND_CONST => Ok(BtfType::Const(BtfConst { type_id: t.type_id })),
1218            BTF_KIND_RESTRICT => Ok(BtfType::Restrict(BtfRestrict { type_id: t.type_id })),
1219            BTF_KIND_FUNC => Ok(BtfType::Func(BtfFunc {
1220                name: Btf::get_btf_str(strs, t.name_off)?,
1221                proto_type_id: t.type_id,
1222                kind: match Btf::get_vlen(t.info) {
1223                    BTF_FUNC_STATIC => BtfFuncKind::Static,
1224                    BTF_FUNC_GLOBAL => BtfFuncKind::Global,
1225                    BTF_FUNC_EXTERN => BtfFuncKind::Extern,
1226                    _ => BtfFuncKind::Unknown,
1227                },
1228            })),
1229            BTF_KIND_FUNC_PROTO => self.load_func_proto(&t, extra, strs),
1230            BTF_KIND_VAR => self.load_var(&t, extra, strs),
1231            BTF_KIND_DATASEC => self.load_datasec(&t, extra, strs),
1232            BTF_KIND_FLOAT => Ok(BtfType::Float(BtfFloat {
1233                name: Btf::get_btf_str(strs, t.name_off)?,
1234                sz: t.type_id,
1235            })),
1236            BTF_KIND_DECL_TAG => self.load_decl_tag(&t, extra, strs),
1237            BTF_KIND_TYPE_TAG => Ok(BtfType::TypeTag(BtfTypeTag {
1238                name: Btf::get_btf_str(strs, t.name_off)?,
1239                type_id: t.type_id,
1240            })),
1241            BTF_KIND_ENUM64 => self.load_enum64(&t, extra, strs),
1242            _ => btf_error(format!("Unknown BTF kind: {}", kind)),
1243        }
1244    }
1245
1246    fn load_int(&self, t: &btf_type, extra: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1247        let info = extra.pread_with::<u32>(0, self.endian)?;
1248        let enc = (info >> 24) & 0xf;
1249        let off = (info >> 16) & 0xff;
1250        let bits = info & 0xff;
1251        Ok(BtfType::Int(BtfInt {
1252            name: Btf::get_btf_str(strs, t.name_off)?,
1253            bits: bits,
1254            offset: off,
1255            encoding: match enc {
1256                0 => BtfIntEncoding::None,
1257                BTF_INT_SIGNED => BtfIntEncoding::Signed,
1258                BTF_INT_CHAR => BtfIntEncoding::Char,
1259                BTF_INT_BOOL => BtfIntEncoding::Bool,
1260                _ => {
1261                    return btf_error(format!("Unknown BTF int encoding: {}", enc));
1262                }
1263            },
1264        }))
1265    }
1266
1267    fn load_array(&self, extra: &'a [u8]) -> BtfResult<BtfType<'a>> {
1268        let info = extra.pread_with::<btf_array>(0, self.endian)?;
1269        Ok(BtfType::Array(BtfArray {
1270            nelems: info.nelems,
1271            idx_type_id: info.idx_type_id,
1272            val_type_id: info.val_type_id,
1273        }))
1274    }
1275
1276    fn load_struct(&self, t: &btf_type, extra: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1277        Ok(BtfType::Struct(BtfComposite {
1278            is_struct: true,
1279            name: Btf::get_btf_str(strs, t.name_off)?,
1280            sz: t.type_id, // it's a type/size union in C
1281            members: self.load_members(t, extra, strs)?,
1282        }))
1283    }
1284
1285    fn load_union(&self, t: &btf_type, extra: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1286        Ok(BtfType::Union(BtfComposite {
1287            is_struct: false,
1288            name: Btf::get_btf_str(strs, t.name_off)?,
1289            sz: t.type_id, // it's a type/size union in C
1290            members: self.load_members(t, extra, strs)?,
1291        }))
1292    }
1293
1294    fn load_members(
1295        &self,
1296        t: &btf_type,
1297        extra: &'a [u8],
1298        strs: &'a [u8],
1299    ) -> BtfResult<Vec<BtfMember<'a>>> {
1300        let mut res = Vec::new();
1301        let mut off: usize = 0;
1302        let bits = Btf::get_kind_flag(t.info);
1303
1304        for _ in 0..Btf::get_vlen(t.info) {
1305            let m = extra.pread_with::<btf_member>(off, self.endian)?;
1306            res.push(BtfMember {
1307                name: Btf::get_btf_str(strs, m.name_off)?,
1308                type_id: m.type_id,
1309                bit_size: if bits { (m.offset >> 24) as u8 } else { 0 },
1310                bit_offset: if bits { m.offset & 0xffffff } else { m.offset },
1311            });
1312            off += size_of::<btf_member>();
1313        }
1314        Ok(res)
1315    }
1316
1317    fn load_enum(&self, t: &btf_type, extra: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1318        let mut vals = Vec::new();
1319        let mut off: usize = 0;
1320
1321        for _ in 0..Btf::get_vlen(t.info) {
1322            let v = extra.pread_with::<btf_enum>(off, self.endian)?;
1323            vals.push(BtfEnumValue {
1324                name: Btf::get_btf_str(strs, v.name_off)?,
1325                value: v.val,
1326            });
1327            off += size_of::<btf_enum>();
1328        }
1329        Ok(BtfType::Enum(BtfEnum {
1330            name: Btf::get_btf_str(strs, t.name_off)?,
1331            sz: t.type_id, // it's a type/size union in C
1332            values: vals,
1333        }))
1334    }
1335
1336    fn load_enum64(&self, t: &btf_type, extra: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1337        let mut vals = Vec::new();
1338        let mut off: usize = 0;
1339
1340        for _ in 0..Btf::get_vlen(t.info) {
1341            let v = extra.pread_with::<btf_enum64>(off, self.endian)?;
1342            vals.push(BtfEnum64Value {
1343                name: Btf::get_btf_str(strs, v.name_off)?,
1344                value: i64::from(v.val_lo32) + i64::from(v.val_hi32) << 32,
1345            });
1346            off += size_of::<btf_enum64>();
1347        }
1348        Ok(BtfType::Enum64(BtfEnum64 {
1349            name: Btf::get_btf_str(strs, t.name_off)?,
1350            sz: t.type_id, // it's a type/size union in C
1351            values: vals,
1352        }))
1353    }
1354
1355    fn load_fwd(&self, t: &btf_type, strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1356        Ok(BtfType::Fwd(BtfFwd {
1357            name: Btf::get_btf_str(strs, t.name_off)?,
1358            kind: if Btf::get_kind_flag(t.info) {
1359                BtfFwdKind::Union
1360            } else {
1361                BtfFwdKind::Struct
1362            },
1363        }))
1364    }
1365
1366    fn load_func_proto(
1367        &self,
1368        t: &btf_type,
1369        extra: &'a [u8],
1370        strs: &'a [u8],
1371    ) -> BtfResult<BtfType<'a>> {
1372        let mut params = Vec::new();
1373        let mut off: usize = 0;
1374
1375        for _ in 0..Btf::get_vlen(t.info) {
1376            let p = extra.pread_with::<btf_param>(off, self.endian)?;
1377            params.push(BtfFuncParam {
1378                name: Btf::get_btf_str(strs, p.name_off)?,
1379                type_id: p.type_id,
1380            });
1381            off += size_of::<btf_param>();
1382        }
1383        Ok(BtfType::FuncProto(BtfFuncProto {
1384            res_type_id: t.type_id,
1385            params: params,
1386        }))
1387    }
1388
1389    fn load_var(&self, t: &btf_type, extra: &'a [u8], strs: &'a [u8]) -> BtfResult<BtfType<'a>> {
1390        let kind = extra.pread_with::<u32>(0, self.endian)?;
1391        Ok(BtfType::Var(BtfVar {
1392            name: Btf::get_btf_str(strs, t.name_off)?,
1393            type_id: t.type_id,
1394            kind: match kind {
1395                BTF_VAR_STATIC => BtfVarKind::Static,
1396                BTF_VAR_GLOBAL_ALLOCATED => BtfVarKind::GlobalAlloc,
1397                BTF_VAR_GLOBAL_EXTERNAL => BtfVarKind::GlobalExtern,
1398                _ => {
1399                    return btf_error(format!("Unknown BTF var kind: {}", kind));
1400                }
1401            },
1402        }))
1403    }
1404
1405    fn load_datasec(
1406        &self,
1407        t: &btf_type,
1408        extra: &'a [u8],
1409        strs: &'a [u8],
1410    ) -> BtfResult<BtfType<'a>> {
1411        let mut vars = Vec::new();
1412        let mut off: usize = 0;
1413
1414        for _ in 0..Btf::get_vlen(t.info) {
1415            let v = extra.pread_with::<btf_datasec_var>(off, self.endian)?;
1416            vars.push(BtfDatasecVar {
1417                type_id: v.type_id,
1418                offset: v.offset,
1419                sz: v.size,
1420            });
1421            off += size_of::<btf_datasec_var>();
1422        }
1423        Ok(BtfType::Datasec(BtfDatasec {
1424            name: Btf::get_btf_str(strs, t.name_off)?,
1425            sz: t.type_id, // it's a type/size union in C
1426            vars: vars,
1427        }))
1428    }
1429
1430    fn load_decl_tag(
1431        &self,
1432        t: &btf_type,
1433        extra: &'a [u8],
1434        strs: &'a [u8],
1435    ) -> BtfResult<BtfType<'a>> {
1436        let comp_idx = extra.pread_with::<u32>(0, self.endian)?;
1437        Ok(BtfType::DeclTag(BtfDeclTag {
1438            name: Btf::get_btf_str(strs, t.name_off)?,
1439            type_id: t.type_id,
1440            comp_idx: comp_idx,
1441        }))
1442    }
1443
1444    fn get_vlen(info: u32) -> u32 {
1445        info & 0xffff
1446    }
1447
1448    fn get_kind(info: u32) -> u32 {
1449        (info >> 24) & 0x1f
1450    }
1451
1452    fn get_kind_flag(info: u32) -> bool {
1453        (info >> 31) == 1
1454    }
1455
1456    fn load_func_secs(
1457        &self,
1458        mut data: &'a [u8],
1459        strs: &'a [u8],
1460    ) -> BtfResult<Vec<BtfExtSection<'a, BtfExtFunc>>> {
1461        let rec_sz = data.pread_with::<u32>(0, self.endian)?;
1462        if rec_sz < size_of::<btf_ext_func_info>() as u32 {
1463            return btf_error(format!(
1464                "Too small func info record size: {}, expect at least: {}",
1465                rec_sz,
1466                size_of::<btf_ext_func_info>()
1467            ));
1468        }
1469
1470        data = &data[size_of::<u32>()..];
1471        let mut secs = Vec::new();
1472        while !data.is_empty() {
1473            let sec_hdr = data.pread_with::<btf_ext_info_sec>(0, self.endian)?;
1474            data = &data[size_of::<btf_ext_info_sec>()..];
1475
1476            let mut recs = Vec::new();
1477            for i in 0..sec_hdr.num_info {
1478                let off = (i * rec_sz) as usize;
1479                let rec = data.pread_with::<btf_ext_func_info>(off, self.endian)?;
1480                recs.push(BtfExtFunc {
1481                    insn_off: rec.insn_off,
1482                    type_id: rec.type_id,
1483                });
1484            }
1485            secs.push(BtfExtSection::<BtfExtFunc> {
1486                name: Btf::get_btf_str(strs, sec_hdr.sec_name_off)?,
1487                rec_sz: rec_sz as usize,
1488                recs: recs,
1489            });
1490
1491            data = &data[(sec_hdr.num_info * rec_sz) as usize..];
1492        }
1493        Ok(secs)
1494    }
1495
1496    fn load_line_secs(
1497        &self,
1498        mut data: &'a [u8],
1499        strs: &'a [u8],
1500    ) -> BtfResult<Vec<BtfExtSection<'a, BtfExtLine<'a>>>> {
1501        let rec_sz = data.pread_with::<u32>(0, self.endian)?;
1502        if rec_sz < size_of::<btf_ext_line_info>() as u32 {
1503            return btf_error(format!(
1504                "Too small line info record size: {}, expect at least: {}",
1505                rec_sz,
1506                size_of::<btf_ext_line_info>()
1507            ));
1508        }
1509        data = &data[size_of::<u32>()..];
1510        let mut secs = Vec::new();
1511        while !data.is_empty() {
1512            let sec_hdr = data.pread_with::<btf_ext_info_sec>(0, self.endian)?;
1513            data = &data[size_of::<btf_ext_info_sec>()..];
1514
1515            let mut recs = Vec::new();
1516            for i in 0..sec_hdr.num_info {
1517                let off = (i * rec_sz) as usize;
1518                let rec = data.pread_with::<btf_ext_line_info>(off, self.endian)?;
1519                recs.push(BtfExtLine {
1520                    insn_off: rec.insn_off,
1521                    file_name: Btf::get_btf_str(strs, rec.file_name_off)?,
1522                    src_line: Btf::get_btf_str(strs, rec.line_off)?,
1523                    line_num: rec.line_col >> 10,
1524                    col_num: rec.line_col & 0x3ff,
1525                });
1526            }
1527            secs.push(BtfExtSection::<BtfExtLine> {
1528                name: Btf::get_btf_str(strs, sec_hdr.sec_name_off)?,
1529                rec_sz: rec_sz as usize,
1530                recs: recs,
1531            });
1532
1533            data = &data[(sec_hdr.num_info * rec_sz) as usize..];
1534        }
1535        Ok(secs)
1536    }
1537
1538    fn load_core_reloc_secs(
1539        &self,
1540        mut data: &'a [u8],
1541        strs: &'a [u8],
1542    ) -> BtfResult<Vec<BtfExtSection<'a, BtfExtCoreReloc<'a>>>> {
1543        let rec_sz = data.pread_with::<u32>(0, self.endian)?;
1544        if rec_sz < size_of::<btf_ext_core_reloc>() as u32 {
1545            return btf_error(format!(
1546                "Too small CO-RE reloc record size: {}, expect at least: {}",
1547                rec_sz,
1548                size_of::<btf_ext_core_reloc>()
1549            ));
1550        }
1551        data = &data[size_of::<u32>()..];
1552        let mut secs = Vec::new();
1553        while !data.is_empty() {
1554            let sec_hdr = data.pread_with::<btf_ext_info_sec>(0, self.endian)?;
1555            data = &data[size_of::<btf_ext_info_sec>()..];
1556
1557            let mut recs = Vec::new();
1558            for i in 0..sec_hdr.num_info {
1559                let off = (i * rec_sz) as usize;
1560                let rec = data.pread_with::<btf_ext_core_reloc>(off, self.endian)?;
1561                let kind = match rec.kind {
1562                    BTF_FIELD_BYTE_OFFSET => BtfCoreRelocKind::ByteOff,
1563                    BTF_FIELD_BYTE_SIZE => BtfCoreRelocKind::ByteSz,
1564                    BTF_FIELD_EXISTS => BtfCoreRelocKind::FieldExists,
1565                    BTF_FIELD_SIGNED => BtfCoreRelocKind::Signed,
1566                    BTF_FIELD_LSHIFT_U64 => BtfCoreRelocKind::LShiftU64,
1567                    BTF_FIELD_RSHIFT_U64 => BtfCoreRelocKind::RShiftU64,
1568                    BTF_TYPE_LOCAL_ID => BtfCoreRelocKind::LocalTypeId,
1569                    BTF_TYPE_TARGET_ID => BtfCoreRelocKind::TargetTypeId,
1570                    BTF_TYPE_EXISTS => BtfCoreRelocKind::TypeExists,
1571                    BTF_TYPE_MATCHES => BtfCoreRelocKind::TypeMatches,
1572                    BTF_TYPE_SIZE => BtfCoreRelocKind::TypeSize,
1573                    BTF_ENUMVAL_EXISTS => BtfCoreRelocKind::EnumvalExists,
1574                    BTF_ENUMVAL_VALUE => BtfCoreRelocKind::EnumvalValue,
1575                    _ => {
1576                        return btf_error(format!("Unknown BTF CO-RE reloc kind: {}", rec.kind));
1577                    }
1578                };
1579                let relo = {
1580                    let access_spec_str = Btf::get_btf_str(strs, rec.access_spec_off)?;
1581                    let access_spec = Btf::parse_reloc_access_spec(&access_spec_str)?;
1582                    BtfExtCoreReloc {
1583                        insn_off: rec.insn_off,
1584                        type_id: rec.type_id,
1585                        access_spec_str: access_spec_str,
1586                        access_spec: access_spec,
1587                        kind: kind,
1588                    }
1589                };
1590                recs.push(relo);
1591            }
1592            secs.push(BtfExtSection::<BtfExtCoreReloc> {
1593                name: Btf::get_btf_str(strs, sec_hdr.sec_name_off)?,
1594                rec_sz: rec_sz as usize,
1595                recs: recs,
1596            });
1597
1598            data = &data[(sec_hdr.num_info * rec_sz) as usize..];
1599        }
1600        Ok(secs)
1601    }
1602    fn parse_reloc_access_spec(access_spec_str: &str) -> BtfResult<Vec<usize>> {
1603        let mut spec = Vec::new();
1604        for p in access_spec_str.split(':') {
1605            spec.push(p.parse::<usize>()?);
1606        }
1607        Ok(spec)
1608    }
1609
1610    fn get_btf_str(strs: &[u8], off: u32) -> BtfResult<&str> {
1611        let c_str = unsafe { CStr::from_ptr(&strs[off as usize] as *const u8 as *const c_char) };
1612        Ok(c_str.to_str()?)
1613    }
1614}