1use alloc::{
2 borrow::{Cow, ToOwned as _},
3 format,
4 string::String,
5 vec,
6 vec::Vec,
7};
8use core::{
9 cell::OnceCell,
10 ffi::{CStr, FromBytesUntilNulError},
11 mem, ptr,
12};
13
14use bytes::BufMut as _;
15use log::debug;
16use object::{Endianness, SectionIndex};
17
18use crate::{
19 Object,
20 btf::{
21 Array, BtfEnum, BtfEnum64, BtfKind, BtfMember, BtfType, Const, DataSec, DataSecEntry, Enum,
22 Enum64, Enum64Fallback, Enum64VariantFallback, FuncInfo, FuncLinkage, Int, IntEncoding,
23 LineInfo, Struct, Typedef, Union, Var, VarLinkage,
24 info::{FuncSecInfo, LineSecInfo},
25 relocation::Relocation,
26 },
27 generated::{btf_ext_header, btf_header},
28 util::{HashMap, bytes_of},
29};
30
31pub(crate) const MAX_RESOLVE_DEPTH: usize = 32;
32pub(crate) const MAX_SPEC_LEN: usize = 64;
33
34#[derive(thiserror::Error, Debug)]
36pub enum BtfError {
37 #[cfg(feature = "std")]
38 #[error("error parsing {path}")]
40 FileError {
41 path: std::path::PathBuf,
43 #[source]
45 error: std::io::Error,
46 },
47
48 #[error("error parsing BTF header")]
50 InvalidHeader,
51
52 #[error("invalid BTF type info segment")]
54 InvalidTypeInfo,
55
56 #[error("invalid BTF relocation info segment")]
58 InvalidRelocationInfo,
59
60 #[error("invalid BTF type kind `{kind}`")]
62 InvalidTypeKind {
63 kind: u32,
65 },
66
67 #[error("invalid BTF relocation kind `{kind}`")]
69 InvalidRelocationKind {
70 kind: u32,
72 },
73
74 #[error("invalid BTF string offset: {offset}")]
76 InvalidStringOffset {
77 offset: usize,
79 },
80
81 #[error("invalid BTF info, offset: {offset} len: {len} section_len: {section_len}")]
83 InvalidInfo {
84 offset: usize,
86 len: usize,
88 section_len: usize,
90 },
91
92 #[error("invalid BTF line info, offset: {offset} len: {len} section_len: {section_len}")]
94 InvalidLineInfo {
95 offset: usize,
97 len: usize,
99 section_len: usize,
101 },
102
103 #[error("unknown BTF type id `{type_id}`")]
105 UnknownBtfType {
106 type_id: u32,
108 },
109
110 #[error("unexpected BTF type id `{type_id}`")]
112 UnexpectedBtfType {
113 type_id: u32,
115 },
116
117 #[error("unknown BTF type `{type_name}`")]
119 UnknownBtfTypeName {
120 type_name: String,
122 },
123
124 #[error("maximum depth reached resolving BTF type")]
126 MaximumTypeDepthReached {
127 type_id: u32,
129 },
130
131 #[cfg(feature = "std")]
132 #[error("the BPF_BTF_LOAD syscall returned {io_error}. Verifier output: {verifier_log}")]
134 LoadError {
135 #[source]
137 io_error: std::io::Error,
138 verifier_log: crate::VerifierLog,
140 },
141
142 #[error("Offset not found for symbol `{symbol_name}`")]
144 SymbolOffsetNotFound {
145 symbol_name: String,
147 },
148
149 #[error("BTF type that is not VAR was found in DATASEC")]
151 InvalidDatasec,
152
153 #[error("Unable to determine the size of section `{section_name}`")]
155 UnknownSectionSize {
156 section_name: String,
158 },
159
160 #[error("Unable to get symbol name")]
162 InvalidSymbolName,
163
164 #[error("BTF map `{name}`: inner map definition cannot be pinned")]
166 InnerMapCannotBePinned {
167 name: String,
169 },
170
171 #[error("BTF map `{name}`: multi-level map-in-map is not supported")]
173 MultiLevelMapInMapNotSupported {
174 name: String,
176 },
177
178 #[error("BTF map `{name}`: `values` spec is not a zero-sized array")]
180 InvalidValuesSpec {
181 name: String,
183 },
184}
185
186#[derive(Default, Debug)]
188pub struct BtfFeatures {
189 btf_func: bool,
190 btf_func_global: bool,
191 btf_datasec: bool,
192 btf_datasec_zero: bool,
193 btf_float: bool,
194 btf_decl_tag: bool,
195 btf_type_tag: bool,
196 btf_enum64: bool,
197}
198
199impl BtfFeatures {
200 #[doc(hidden)]
201 #[expect(
202 clippy::fn_params_excessive_bools,
203 reason = "this interface is terrible"
204 )]
205 #[expect(clippy::too_many_arguments, reason = "this interface is terrible")]
206 pub const fn new(
207 btf_func: bool,
208 btf_func_global: bool,
209 btf_datasec: bool,
210 btf_datasec_zero: bool,
211 btf_float: bool,
212 btf_decl_tag: bool,
213 btf_type_tag: bool,
214 btf_enum64: bool,
215 ) -> Self {
216 Self {
217 btf_func,
218 btf_func_global,
219 btf_datasec,
220 btf_datasec_zero,
221 btf_float,
222 btf_decl_tag,
223 btf_type_tag,
224 btf_enum64,
225 }
226 }
227
228 pub const fn btf_func(&self) -> bool {
230 self.btf_func
231 }
232
233 pub const fn btf_func_global(&self) -> bool {
235 self.btf_func_global
236 }
237
238 pub const fn btf_datasec(&self) -> bool {
240 self.btf_datasec
241 }
242
243 pub const fn btf_datasec_zero(&self) -> bool {
245 self.btf_datasec_zero
246 }
247
248 pub const fn btf_float(&self) -> bool {
250 self.btf_float
251 }
252
253 pub const fn btf_decl_tag(&self) -> bool {
255 self.btf_decl_tag
256 }
257
258 pub const fn btf_type_tag(&self) -> bool {
260 self.btf_type_tag
261 }
262
263 pub const fn btf_kind_func_proto(&self) -> bool {
265 self.btf_func && self.btf_decl_tag
266 }
267
268 pub const fn btf_enum64(&self) -> bool {
270 self.btf_enum64
271 }
272}
273
274#[derive(Clone, Debug)]
283pub struct Btf {
284 header: btf_header,
285 strings: Vec<u8>,
286 types: BtfTypes,
287 _endianness: Endianness,
288}
289
290fn add_type(header: &mut btf_header, types: &mut BtfTypes, btf_type: BtfType) -> u32 {
291 let size = btf_type.type_info_size() as u32;
292 let type_id = types.len();
293 types.push(btf_type);
294 header.type_len += size;
295 header.str_off += size;
296 type_id as u32
297}
298
299impl Btf {
300 pub fn new() -> Self {
302 Self {
303 header: btf_header {
304 magic: 0xeb9f,
305 version: 0x01,
306 flags: 0x00,
307 hdr_len: 0x18,
308 type_off: 0x00,
309 type_len: 0x00,
310 str_off: 0x00,
311 str_len: 0x00,
312 },
313 strings: vec![0],
314 types: BtfTypes::default(),
315 _endianness: Endianness::default(),
316 }
317 }
318
319 pub(crate) const fn is_empty(&self) -> bool {
320 self.types.types.len() < 2
322 }
323
324 pub(crate) fn types(&self) -> impl Iterator<Item = &BtfType> {
325 self.types.types.iter()
326 }
327
328 pub fn add_string(&mut self, name: &str) -> u32 {
330 let str = name.bytes().chain(core::iter::once(0));
331 let name_offset = self.strings.len();
332 self.strings.extend(str);
333 self.header.str_len = self.strings.len() as u32;
334 name_offset as u32
335 }
336
337 pub fn add_type(&mut self, btf_type: BtfType) -> u32 {
339 add_type(&mut self.header, &mut self.types, btf_type)
340 }
341
342 #[cfg(feature = "std")]
344 pub fn from_sys_fs() -> Result<Self, BtfError> {
345 Self::parse_file("/sys/kernel/btf/vmlinux", Endianness::default())
346 }
347
348 #[cfg(feature = "std")]
350 pub fn parse_file<P: AsRef<std::path::Path>>(
351 path: P,
352 endianness: Endianness,
353 ) -> Result<Self, BtfError> {
354 use std::{borrow::ToOwned as _, fs};
355 let path = path.as_ref();
356 Self::parse(
357 &fs::read(path).map_err(|error| BtfError::FileError {
358 path: path.to_owned(),
359 error,
360 })?,
361 endianness,
362 )
363 }
364
365 pub fn parse(data: &[u8], endianness: Endianness) -> Result<Self, BtfError> {
367 if data.len() < size_of::<btf_header>() {
368 return Err(BtfError::InvalidHeader);
369 }
370
371 let header = unsafe { read_btf_header(data) };
373
374 let str_off = header.hdr_len as usize + header.str_off as usize;
375 let str_len = header.str_len as usize;
376 if str_off + str_len > data.len() {
377 return Err(BtfError::InvalidHeader);
378 }
379
380 let strings = data[str_off..str_off + str_len].to_vec();
381 let types = Self::read_type_info(&header, data, endianness)?;
382
383 Ok(Self {
384 header,
385 strings,
386 types,
387 _endianness: endianness,
388 })
389 }
390
391 fn read_type_info(
392 header: &btf_header,
393 data: &[u8],
394 endianness: Endianness,
395 ) -> Result<BtfTypes, BtfError> {
396 let hdr_len = header.hdr_len as usize;
397 let type_off = header.type_off as usize;
398 let type_len = header.type_len as usize;
399 let base = hdr_len + type_off;
400 if base + type_len > data.len() {
401 return Err(BtfError::InvalidTypeInfo);
402 }
403
404 let mut data = &data[base..base + type_len];
405 let mut types = BtfTypes::default();
406 while !data.is_empty() {
407 let ty = unsafe { BtfType::read(data, endianness)? };
411 data = &data[ty.type_info_size()..];
412 types.push(ty);
413 }
414 Ok(types)
415 }
416
417 pub(crate) fn string_at(&self, offset: u32) -> Result<Cow<'_, str>, BtfError> {
418 let btf_header {
419 hdr_len,
420 mut str_off,
421 str_len,
422 ..
423 } = self.header;
424 str_off += hdr_len;
425 if offset >= str_off + str_len {
426 return Err(BtfError::InvalidStringOffset {
427 offset: offset as usize,
428 });
429 }
430
431 let offset = offset as usize;
432
433 let s = CStr::from_bytes_until_nul(&self.strings[offset..])
434 .map_err(|FromBytesUntilNulError { .. }| BtfError::InvalidStringOffset { offset })?;
435
436 Ok(s.to_string_lossy())
437 }
438
439 pub(crate) fn type_by_id(&self, type_id: u32) -> Result<&BtfType, BtfError> {
440 self.types.type_by_id(type_id)
441 }
442
443 pub(crate) fn resolve_type(&self, root_type_id: u32) -> Result<u32, BtfError> {
444 self.types.resolve_type(root_type_id)
445 }
446
447 pub(crate) fn type_name(&self, ty: &BtfType) -> Result<Cow<'_, str>, BtfError> {
448 self.string_at(ty.name_offset())
449 }
450
451 pub(crate) fn err_type_name(&self, ty: &BtfType) -> Option<String> {
452 self.string_at(ty.name_offset()).ok().map(String::from)
453 }
454
455 pub fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result<u32, BtfError> {
457 for (type_id, ty) in self.types().enumerate() {
458 if ty.kind() != kind {
459 continue;
460 }
461 if self.type_name(ty)? == name {
462 return Ok(type_id as u32);
463 }
464 }
465
466 Err(BtfError::UnknownBtfTypeName {
467 type_name: name.to_owned(),
468 })
469 }
470
471 pub(crate) fn type_size(&self, root_type_id: u32) -> Result<usize, BtfError> {
472 let mut type_id = root_type_id;
473 let mut n_elems = 1;
474 for () in core::iter::repeat_n((), MAX_RESOLVE_DEPTH) {
475 let ty = self.types.type_by_id(type_id)?;
476 let size = match ty {
477 BtfType::Array(Array { array, .. }) => {
478 n_elems = array.len;
479 type_id = array.element_type;
480 continue;
481 }
482 other => {
483 if let Some(size) = other.size() {
484 size
485 } else if let Some(next) = other.btf_type() {
486 type_id = next;
487 continue;
488 } else {
489 return Err(BtfError::UnexpectedBtfType { type_id });
490 }
491 }
492 };
493 return Ok((size * n_elems) as usize);
494 }
495
496 Err(BtfError::MaximumTypeDepthReached {
497 type_id: root_type_id,
498 })
499 }
500
501 pub fn to_bytes(&self) -> Vec<u8> {
503 let mut buf = unsafe { bytes_of::<btf_header>(&self.header).to_vec() };
505 buf.extend(self.types.to_bytes());
506 buf.put(self.strings.as_slice());
507 buf
508 }
509
510 pub(crate) fn fixup_and_sanitize(
519 &mut self,
520 section_infos: &HashMap<String, (SectionIndex, u64)>,
521 symbol_offsets: &HashMap<String, u64>,
522 features: &BtfFeatures,
523 ) -> Result<(), BtfError> {
524 let enum64_placeholder_id = OnceCell::new();
525 let filler_var_id = OnceCell::new();
526 let mut types = mem::take(&mut self.types);
527 for i in 0..types.types.len() {
528 let t = &mut types.types[i];
529 let kind = t.kind();
530 match t {
531 BtfType::Ptr(ptr) => {
537 ptr.name_offset = 0;
538 }
539 BtfType::Var(v) if !features.btf_datasec => {
541 *t = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0));
542 }
543 BtfType::DataSec(d) if !features.btf_datasec => {
545 debug!("{kind}: not supported. replacing with STRUCT");
546
547 let mut name_offset = d.name_offset;
549 let name = self.string_at(name_offset)?;
550
551 let fixed_name = name.replace('.', "_");
554 if fixed_name != name {
555 name_offset = self.add_string(&fixed_name);
556 }
557
558 let entries = mem::take(&mut d.entries);
559
560 let members = entries
561 .iter()
562 .map(|e| {
563 let mt = types.type_by_id(e.btf_type).unwrap();
564 BtfMember {
565 name_offset: mt.name_offset(),
566 btf_type: e.btf_type,
567 offset: e.offset * 8,
568 }
569 })
570 .collect();
571
572 let t = &mut types.types[i];
574 *t = BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32));
575 }
576 BtfType::DataSec(d) if features.btf_datasec => {
581 let name = self.string_at(d.name_offset)?;
583 let name = name.into_owned();
584
585 let fixed_name = name.replace('/', ".");
588 if fixed_name != name {
589 d.name_offset = self.add_string(&fixed_name);
590 }
591
592 if d.size > 0 {
594 debug!("{kind} {name}: size fixup not required");
595 } else {
596 let Some((_, size)) = section_infos.get(&name) else {
600 return Err(BtfError::UnknownSectionSize { section_name: name });
601 };
602 debug!("{kind} {name}: fixup size to {size}");
603 d.size = *size as u32;
604
605 let old_size = d.type_info_size();
611 let mut entries = mem::take(&mut d.entries);
612 let mut section_size = d.size;
613 let name_offset = d.name_offset;
614
615 if entries.is_empty() && !features.btf_datasec_zero {
618 let filler_var_id = *filler_var_id.get_or_init(|| {
619 let filler_type_name = self.add_string("__aya_datasec_filler_type");
620 let filler_type_id = add_type(
621 &mut self.header,
622 &mut types,
623 BtfType::Int(Int::new(
624 filler_type_name,
625 1,
626 IntEncoding::None,
627 0,
628 )),
629 );
630
631 let filler_var_name = self.add_string("__aya_datasec_filler");
632 add_type(
633 &mut self.header,
634 &mut types,
635 BtfType::Var(Var::new(
636 filler_var_name,
637 filler_type_id,
638 VarLinkage::Static,
639 )),
640 )
641 });
642 let filler_len = section_size.max(1);
643 debug!(
644 "{kind} {name}: injecting filler entry for zero-length DATASEC (len={filler_len})"
645 );
646 entries.push(DataSecEntry {
647 btf_type: filler_var_id,
648 offset: 0,
649 size: filler_len,
650 });
651 if section_size == 0 {
652 section_size = filler_len;
653 }
654 }
655
656 for e in &mut entries {
657 if let BtfType::Var(var) = types.type_by_id(e.btf_type)? {
658 let var_name = self.string_at(var.name_offset)?;
659 if var.linkage == VarLinkage::Static {
660 debug!("{kind} {name}: VAR {var_name}: fixup not required");
661 continue;
662 }
663
664 let Some(offset) = symbol_offsets.get(var_name.as_ref()) else {
665 return Err(BtfError::SymbolOffsetNotFound {
666 symbol_name: var_name.into_owned(),
667 });
668 };
669 e.offset = *offset as u32;
670 debug!("{kind} {name}: VAR {var_name}: fixup offset {offset}");
671 } else {
672 return Err(BtfError::InvalidDatasec);
673 }
674 }
675 let fixed_section = DataSec::new(name_offset, entries, section_size);
676 let new_size = fixed_section.type_info_size();
677 if new_size != old_size {
678 self.header.type_len =
679 self.header.type_len - old_size as u32 + new_size as u32;
680 self.header.str_off = self.header.type_len;
681 }
682
683 let t = &mut types.types[i];
685 *t = BtfType::DataSec(fixed_section);
686 }
687 }
688 BtfType::FuncProto(ty) if features.btf_func => {
690 for (i, param) in ty.params.iter_mut().enumerate() {
691 if param.name_offset == 0 && param.btf_type != 0 {
692 param.name_offset = self.add_string(&format!("param{i}"));
693 }
694 }
695 }
696 BtfType::FuncProto(ty) if !features.btf_func => {
698 debug!("{kind}: not supported. replacing with ENUM");
699 let members: Vec<BtfEnum> = ty
700 .params
701 .iter()
702 .map(|p| BtfEnum {
703 name_offset: p.name_offset,
704 value: p.btf_type,
705 })
706 .collect();
707 let enum_type = BtfType::Enum(Enum::new(ty.name_offset, false, members));
708 *t = enum_type;
709 }
710 BtfType::Func(ty) => {
712 let name = self.string_at(ty.name_offset)?;
713 if !features.btf_func {
715 debug!("{kind}: not supported. replacing with TYPEDEF");
716 *t = BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type));
717 } else if !features.btf_func_global
718 || name == "memset"
719 || name == "memcpy"
720 || name == "memmove"
721 || name == "memcmp"
722 {
723 if ty.linkage() == FuncLinkage::Global {
729 if features.btf_func_global {
730 debug!("changing FUNC {name} linkage to BTF_FUNC_STATIC");
731 } else {
732 debug!(
733 "{kind}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC",
734 );
735 }
736 ty.set_linkage(FuncLinkage::Static);
737 }
738 }
739 }
740 BtfType::Float(ty) if !features.btf_float => {
742 debug!("{kind}: not supported. replacing with STRUCT");
743 *t = BtfType::Struct(Struct::new(0, vec![], ty.size));
744 }
745 BtfType::DeclTag(ty) if !features.btf_decl_tag => {
747 debug!("{kind}: not supported. replacing with INT");
748 *t = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0));
749 }
750 BtfType::TypeTag(ty) if !features.btf_type_tag => {
752 debug!("{kind}: not supported. replacing with CONST");
753 *t = BtfType::Const(Const::new(ty.btf_type));
754 }
755 BtfType::Enum(ty) if !features.btf_enum64 && ty.is_signed() => {
757 debug!("{kind}: signed ENUMs not supported. Marking as unsigned");
758 ty.set_signed(false);
759 }
760 BtfType::Enum64(ty) if !features.btf_enum64 => {
762 debug!("{kind}: not supported. replacing with UNION");
765
766 let is_signed = ty.is_signed();
770 let Enum64 {
771 name_offset,
772 size,
773 variants,
774 ..
775 } = ty;
776 let (name_offset, size, variants) = (*name_offset, *size, mem::take(variants));
777
778 let fallback = Enum64Fallback {
779 signed: is_signed,
780 variants: variants
781 .iter()
782 .copied()
783 .map(
784 |BtfEnum64 {
785 name_offset,
786 value_high,
787 value_low,
788 }| Enum64VariantFallback {
789 name_offset,
790 value: (u64::from(value_high) << 32) | u64::from(value_low),
791 },
792 )
793 .collect(),
794 };
795
796 let placeholder_id = enum64_placeholder_id.get_or_init(|| {
799 let placeholder_name = self.add_string("enum64_placeholder");
800 add_type(
801 &mut self.header,
802 &mut types,
803 BtfType::Int(Int::new(placeholder_name, 1, IntEncoding::None, 0)),
804 )
805 });
806 let members: Vec<BtfMember> = variants
807 .iter()
808 .map(|v| BtfMember {
809 name_offset: v.name_offset,
810 btf_type: *placeholder_id,
811 offset: 0,
812 })
813 .collect();
814
815 let t = &mut types.types[i];
817 *t = BtfType::Union(Union::new(name_offset, size, members, Some(fallback)));
818 }
819 _ => {}
821 }
822 }
823 self.types = types;
824 Ok(())
825 }
826}
827
828impl Default for Btf {
829 fn default() -> Self {
830 Self::new()
831 }
832}
833
834impl Object {
835 pub fn fixup_and_sanitize_btf(
839 &mut self,
840 features: &BtfFeatures,
841 ) -> Result<Option<&Btf>, BtfError> {
842 if let Some(obj_btf) = &mut self.btf {
843 if obj_btf.is_empty() {
844 return Ok(None);
845 }
846 obj_btf.fixup_and_sanitize(
848 &self.section_infos,
849 &self.symbol_offset_by_name,
850 features,
851 )?;
852 Ok(Some(obj_btf))
853 } else {
854 Ok(None)
855 }
856 }
857}
858
859const unsafe fn read_btf_header(data: &[u8]) -> btf_header {
860 unsafe { ptr::read_unaligned(data.as_ptr().cast()) }
862}
863
864#[derive(Debug, Clone)]
866pub struct BtfExt {
867 data: Vec<u8>,
868 _endianness: Endianness,
869 relocations: Vec<(u32, Vec<Relocation>)>,
870 header: btf_ext_header,
871 func_info_rec_size: usize,
872 pub(crate) func_info: FuncInfo,
873 line_info_rec_size: usize,
874 pub(crate) line_info: LineInfo,
875 core_relo_rec_size: usize,
876}
877
878impl BtfExt {
879 pub(crate) fn parse(data: &[u8], endianness: Endianness, btf: &Btf) -> Result<Self, BtfError> {
880 #[repr(C)]
881 #[derive(Debug, Copy, Clone)]
882 struct MinimalHeader {
883 pub magic: u16,
884 pub version: u8,
885 pub flags: u8,
886 pub hdr_len: u32,
887 }
888
889 if data.len() < size_of::<MinimalHeader>() {
890 return Err(BtfError::InvalidHeader);
891 }
892
893 let header = {
894 let minimal_header = unsafe {
897 ptr::read_unaligned::<MinimalHeader>(data.as_ptr().cast::<MinimalHeader>())
898 };
899
900 let len_to_read = minimal_header.hdr_len as usize;
901
902 if data.len() < len_to_read {
904 return Err(BtfError::InvalidHeader);
905 }
906
907 let len_to_read = len_to_read.min(size_of::<btf_ext_header>());
911
912 let mut header = mem::MaybeUninit::<btf_ext_header>::zeroed();
916 unsafe {
921 ptr::copy(data.as_ptr(), header.as_mut_ptr().cast::<u8>(), len_to_read);
922 header.assume_init()
923 }
924 };
925
926 let btf_ext_header {
927 hdr_len,
928 func_info_off,
929 func_info_len,
930 line_info_off,
931 line_info_len,
932 core_relo_off,
933 core_relo_len,
934 ..
935 } = header;
936
937 let rec_size = |offset, len| {
938 let offset = hdr_len as usize + offset as usize;
939 let len = len as usize;
940 if (len > 0 && len < 4) || offset + len > data.len() {
942 return Err(BtfError::InvalidInfo {
943 offset,
944 len,
945 section_len: data.len(),
946 });
947 }
948 let read_u32 = if endianness == Endianness::Little {
949 u32::from_le_bytes
950 } else {
951 u32::from_be_bytes
952 };
953 Ok(if len > 0 {
954 read_u32(data[offset..offset + 4].try_into().unwrap()) as usize
955 } else {
956 0
957 })
958 };
959
960 let mut ext = Self {
961 header,
962 relocations: Vec::new(),
963 func_info: FuncInfo::new(),
964 line_info: LineInfo::new(),
965 func_info_rec_size: rec_size(func_info_off, func_info_len)?,
966 line_info_rec_size: rec_size(line_info_off, line_info_len)?,
967 core_relo_rec_size: rec_size(core_relo_off, core_relo_len)?,
968 data: data.to_vec(),
969 _endianness: endianness,
970 };
971
972 let func_info_rec_size = ext.func_info_rec_size;
973 ext.func_info.data.extend(
974 SecInfoIter::new(ext.func_info_data(), ext.func_info_rec_size, endianness)
975 .map(move |sec| {
976 let name = btf
977 .string_at(sec.name_offset)
978 .ok()
979 .map(String::from)
980 .unwrap();
981 let info = FuncSecInfo::parse(
982 sec.name_offset,
983 sec.num_info,
984 func_info_rec_size,
985 sec.data,
986 endianness,
987 );
988 Ok((name, info))
989 })
990 .collect::<Result<HashMap<_, _>, _>>()?,
991 );
992
993 let line_info_rec_size = ext.line_info_rec_size;
994 ext.line_info.data.extend(
995 SecInfoIter::new(ext.line_info_data(), ext.line_info_rec_size, endianness)
996 .map(move |sec| {
997 let name = btf
998 .string_at(sec.name_offset)
999 .ok()
1000 .map(String::from)
1001 .unwrap();
1002 let info = LineSecInfo::parse(
1003 sec.name_offset,
1004 sec.num_info,
1005 line_info_rec_size,
1006 sec.data,
1007 endianness,
1008 );
1009 Ok((name, info))
1010 })
1011 .collect::<Result<HashMap<_, _>, _>>()?,
1012 );
1013
1014 let rec_size = ext.core_relo_rec_size;
1015 ext.relocations.extend(
1016 SecInfoIter::new(ext.core_relo_data(), ext.core_relo_rec_size, endianness)
1017 .map(move |sec| {
1018 let relos = sec
1019 .data
1020 .chunks(rec_size)
1021 .enumerate()
1022 .map(|(n, rec)| unsafe { Relocation::parse(rec, n) })
1023 .collect::<Result<Vec<_>, _>>()?;
1024 Ok((sec.name_offset, relos))
1025 })
1026 .collect::<Result<Vec<_>, _>>()?,
1027 );
1028
1029 Ok(ext)
1030 }
1031
1032 fn info_data(&self, offset: u32, len: u32) -> &[u8] {
1033 let offset = (self.header.hdr_len + offset) as usize;
1034 let data = &self.data[offset..offset + len as usize];
1035 if len > 0 {
1036 &data[4..]
1038 } else {
1039 data
1040 }
1041 }
1042
1043 fn core_relo_data(&self) -> &[u8] {
1044 self.info_data(self.header.core_relo_off, self.header.core_relo_len)
1045 }
1046
1047 fn func_info_data(&self) -> &[u8] {
1048 self.info_data(self.header.func_info_off, self.header.func_info_len)
1049 }
1050
1051 fn line_info_data(&self) -> &[u8] {
1052 self.info_data(self.header.line_info_off, self.header.line_info_len)
1053 }
1054
1055 pub(crate) const fn relocations(&self) -> &[(u32, Vec<Relocation>)] {
1056 self.relocations.as_slice()
1057 }
1058
1059 pub(crate) const fn func_info_rec_size(&self) -> usize {
1060 self.func_info_rec_size
1061 }
1062
1063 pub(crate) const fn line_info_rec_size(&self) -> usize {
1064 self.line_info_rec_size
1065 }
1066}
1067
1068pub(crate) struct SecInfoIter<'a> {
1069 data: &'a [u8],
1070 offset: usize,
1071 rec_size: usize,
1072 endianness: Endianness,
1073}
1074
1075impl<'a> SecInfoIter<'a> {
1076 const fn new(data: &'a [u8], rec_size: usize, endianness: Endianness) -> Self {
1077 Self {
1078 data,
1079 rec_size,
1080 offset: 0,
1081 endianness,
1082 }
1083 }
1084}
1085
1086impl<'a> Iterator for SecInfoIter<'a> {
1087 type Item = SecInfo<'a>;
1088
1089 fn next(&mut self) -> Option<Self::Item> {
1090 let data = self.data;
1091 if self.offset + 8 >= data.len() {
1092 return None;
1093 }
1094
1095 let read_u32 = if self.endianness == Endianness::Little {
1096 u32::from_le_bytes
1097 } else {
1098 u32::from_be_bytes
1099 };
1100 let name_offset = read_u32(data[self.offset..self.offset + 4].try_into().unwrap());
1101 self.offset += 4;
1102 let num_info = u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap());
1103 self.offset += 4;
1104
1105 let data = &data[self.offset..self.offset + (self.rec_size * num_info as usize)];
1106 self.offset += self.rec_size * num_info as usize;
1107
1108 Some(SecInfo {
1109 name_offset,
1110 num_info,
1111 data,
1112 })
1113 }
1114}
1115
1116#[derive(Debug, Clone)]
1119pub(crate) struct BtfTypes {
1120 pub(crate) types: Vec<BtfType>,
1121}
1122
1123impl Default for BtfTypes {
1124 fn default() -> Self {
1125 Self {
1126 types: vec![BtfType::Unknown],
1127 }
1128 }
1129}
1130
1131impl BtfTypes {
1132 pub(crate) fn to_bytes(&self) -> Vec<u8> {
1133 let mut buf = vec![];
1134 for t in self.types.iter().skip(1) {
1135 let b = t.to_bytes();
1136 buf.extend(b)
1137 }
1138 buf
1139 }
1140
1141 pub(crate) const fn len(&self) -> usize {
1142 self.types.len()
1143 }
1144
1145 pub(crate) fn push(&mut self, value: BtfType) {
1146 self.types.push(value)
1147 }
1148
1149 pub(crate) fn type_by_id(&self, type_id: u32) -> Result<&BtfType, BtfError> {
1150 self.types
1151 .get(type_id as usize)
1152 .ok_or(BtfError::UnknownBtfType { type_id })
1153 }
1154
1155 pub(crate) fn resolve_type(&self, root_type_id: u32) -> Result<u32, BtfError> {
1156 let mut type_id = root_type_id;
1157 for () in core::iter::repeat_n((), MAX_RESOLVE_DEPTH) {
1158 let ty = self.type_by_id(type_id)?;
1159
1160 match ty {
1161 BtfType::Volatile(ty) => {
1162 type_id = ty.btf_type;
1163 }
1164 BtfType::Const(ty) => {
1165 type_id = ty.btf_type;
1166 }
1167 BtfType::Restrict(ty) => {
1168 type_id = ty.btf_type;
1169 }
1170 BtfType::Typedef(ty) => {
1171 type_id = ty.btf_type;
1172 }
1173 BtfType::TypeTag(ty) => {
1174 type_id = ty.btf_type;
1175 }
1176 _ => return Ok(type_id),
1177 }
1178 }
1179
1180 Err(BtfError::MaximumTypeDepthReached {
1181 type_id: root_type_id,
1182 })
1183 }
1184}
1185
1186#[derive(Debug)]
1187pub(crate) struct SecInfo<'a> {
1188 name_offset: u32,
1189 num_info: u32,
1190 data: &'a [u8],
1191}
1192
1193#[cfg(test)]
1194mod tests {
1195 use assert_matches::assert_matches;
1196
1197 use super::*;
1198 use crate::btf::{BtfParam, DeclTag, Float, Func, FuncProto, Ptr, TypeTag};
1199
1200 #[test]
1201 fn test_parse_header() {
1202 let header = btf_header {
1203 magic: 0xeb9f,
1204 version: 0x01,
1205 flags: 0x00,
1206 hdr_len: 0x18,
1207 type_off: 0x00,
1208 type_len: 0x2a5464,
1209 str_off: 0x2a5464,
1210 str_len: 0x1c6410,
1211 };
1212 let data = unsafe { bytes_of::<btf_header>(&header).to_vec() };
1213 let header = unsafe { read_btf_header(&data) };
1214 assert_eq!(header.magic, 0xeb9f);
1215 assert_eq!(header.version, 0x01);
1216 assert_eq!(header.flags, 0x00);
1217 assert_eq!(header.hdr_len, 0x18);
1218 assert_eq!(header.type_off, 0x00);
1219 assert_eq!(header.type_len, 0x2a5464);
1220 assert_eq!(header.str_off, 0x2a5464);
1221 assert_eq!(header.str_len, 0x1c6410);
1222 }
1223
1224 #[test]
1225 fn test_parse_btf() {
1226 let data: &[u8] = if cfg!(target_endian = "little") {
1229 &[
1230 0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01,
1231 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1232 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00,
1233 0x00, 0x04, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1234 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
1235 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
1236 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00,
1237 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
1238 0x03, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00,
1239 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1240 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1241 0x00, 0x0d, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1242 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00,
1243 0x00, 0x01, 0x69, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x00,
1244 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00,
1245 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
1246 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0x00,
1247 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1248 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00,
1249 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
1250 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x78,
1251 0x64, 0x70, 0x5f, 0x6d, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x64, 0x61, 0x74,
1252 0x61, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x65, 0x74,
1253 0x61, 0x00, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66, 0x69, 0x6e,
1254 0x64, 0x65, 0x78, 0x00, 0x72, 0x78, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69,
1255 0x6e, 0x64, 0x65, 0x78, 0x00, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66,
1256 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x5f, 0x5f, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6e,
1257 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x63, 0x74, 0x78,
1258 0x00, 0x69, 0x6e, 0x74, 0x00, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x00,
1259 0x78, 0x64, 0x70, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65,
1260 0x2f, 0x64, 0x61, 0x76, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x62, 0x70, 0x66, 0x64,
1261 0x2f, 0x62, 0x70, 0x66, 0x2f, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x2e,
1262 0x62, 0x70, 0x66, 0x2e, 0x63, 0x00, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
1263 0x72, 0x6e, 0x20, 0x58, 0x44, 0x50, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x3b, 0x00, 0x63,
1264 0x68, 0x61, 0x72, 0x00, 0x5f, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x5f, 0x53, 0x49,
1265 0x5a, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5f, 0x00, 0x5f, 0x6c, 0x69, 0x63,
1266 0x65, 0x6e, 0x73, 0x65, 0x00, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x00,
1267 ]
1268 } else {
1269 &[
1270 0xeb, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1271 0x01, 0x0c, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00,
1272 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
1273 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,
1274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
1275 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40,
1276 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00,
1277 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3f,
1278 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x4e, 0x08, 0x00,
1279 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x00,
1280 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
1281 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x01,
1282 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
1283 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05,
1284 0x00, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
1285 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1286 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1287 0x00, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20,
1288 0x00, 0x00, 0x00, 0xd0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
1289 0x00, 0x01, 0x00, 0x00, 0x00, 0xd9, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1290 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x78,
1291 0x64, 0x70, 0x5f, 0x6d, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x64, 0x61, 0x74,
1292 0x61, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x65, 0x74,
1293 0x61, 0x00, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66, 0x69, 0x6e,
1294 0x64, 0x65, 0x78, 0x00, 0x72, 0x78, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69,
1295 0x6e, 0x64, 0x65, 0x78, 0x00, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66,
1296 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x5f, 0x5f, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6e,
1297 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x63, 0x74, 0x78,
1298 0x00, 0x69, 0x6e, 0x74, 0x00, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x00,
1299 0x78, 0x64, 0x70, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65,
1300 0x2f, 0x64, 0x61, 0x76, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x62, 0x70, 0x66, 0x64,
1301 0x2f, 0x62, 0x70, 0x66, 0x2f, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x2e,
1302 0x62, 0x70, 0x66, 0x2e, 0x63, 0x00, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
1303 0x72, 0x6e, 0x20, 0x58, 0x44, 0x50, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x3b, 0x00, 0x63,
1304 0x68, 0x61, 0x72, 0x00, 0x5f, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x5f, 0x53, 0x49,
1305 0x5a, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5f, 0x00, 0x5f, 0x6c, 0x69, 0x63,
1306 0x65, 0x6e, 0x73, 0x65, 0x00, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x00,
1307 ]
1308 };
1309 assert_eq!(data.len(), 517);
1310 let btf = Btf::parse(data, Endianness::default()).unwrap();
1311 let data2 = btf.to_bytes();
1312 assert_eq!(data2.len(), 517);
1313 assert_eq!(data, data2);
1314
1315 const FUNC_LEN: u32 = 0x14;
1316 const LINE_INFO_LEN: u32 = 0x1c;
1317 const CORE_RELO_LEN: u32 = 0;
1318 const DATA_LEN: u32 = (FUNC_LEN + LINE_INFO_LEN + CORE_RELO_LEN) / 4;
1319 struct TestStruct {
1320 _header: btf_ext_header,
1321 _data: [u32; DATA_LEN as usize],
1322 }
1323 let test_data = TestStruct {
1324 _header: btf_ext_header {
1325 magic: 0xeb9f,
1326 version: 1,
1327 flags: 0,
1328 hdr_len: 0x20,
1329 func_info_off: 0,
1330 func_info_len: FUNC_LEN,
1331 line_info_off: FUNC_LEN,
1332 line_info_len: LINE_INFO_LEN,
1333 core_relo_off: FUNC_LEN + LINE_INFO_LEN,
1334 core_relo_len: CORE_RELO_LEN,
1335 },
1336 _data: [
1337 0x00000008u32,
1338 0x00000072u32,
1339 0x00000001u32,
1340 0x00000000u32,
1341 0x00000007u32,
1342 0x00000010u32,
1343 0x00000072u32,
1344 0x00000001u32,
1345 0x00000000u32,
1346 0x0000007bu32,
1347 0x000000a2u32,
1348 0x00002c05u32,
1349 ],
1350 };
1351 let ext_data = unsafe { bytes_of::<TestStruct>(&test_data).to_vec() };
1352
1353 assert_eq!(ext_data.len(), 80);
1354 let _unused: BtfExt = BtfExt::parse(&ext_data, Endianness::default(), &btf).unwrap();
1355 }
1356
1357 #[test]
1358 fn parsing_older_ext_data() {
1359 const TYPE_LEN: u32 = 0;
1360 const STR_LEN: u32 = 1;
1361 struct BtfTestStruct {
1362 _header: btf_header,
1363 _data: [u8; (TYPE_LEN + STR_LEN) as usize],
1364 }
1365 let btf_test_data = BtfTestStruct {
1366 _header: btf_header {
1367 magic: 0xeb9f,
1368 version: 0x01,
1369 flags: 0x00,
1370 hdr_len: 24,
1371 type_off: 0,
1372 type_len: TYPE_LEN,
1373 str_off: TYPE_LEN,
1374 str_len: TYPE_LEN + STR_LEN,
1375 },
1376 _data: [0x00u8],
1377 };
1378 let btf_data = unsafe { bytes_of::<BtfTestStruct>(&btf_test_data).to_vec() };
1379
1380 const FUNC_INFO_LEN: u32 = 4;
1381 const LINE_INFO_LEN: u32 = 4;
1382 const CORE_RELO_LEN: u32 = 16;
1383 let ext_header = btf_ext_header {
1384 magic: 0xeb9f,
1385 version: 1,
1386 flags: 0,
1387 hdr_len: 24,
1388 func_info_off: 0,
1389 func_info_len: FUNC_INFO_LEN,
1390 line_info_off: FUNC_INFO_LEN,
1391 line_info_len: LINE_INFO_LEN,
1392 core_relo_off: FUNC_INFO_LEN + LINE_INFO_LEN,
1393 core_relo_len: CORE_RELO_LEN,
1394 };
1395 let btf_ext_data = unsafe { bytes_of::<btf_ext_header>(&ext_header).to_vec() };
1396
1397 let btf = Btf::parse(&btf_data, Endianness::default()).unwrap();
1398 let btf_ext = BtfExt::parse(&btf_ext_data, Endianness::default(), &btf).unwrap();
1399 assert_eq!(btf_ext.func_info_rec_size(), 8);
1400 assert_eq!(btf_ext.line_info_rec_size(), 16);
1401 }
1402
1403 #[test]
1404 fn test_write_btf() {
1405 let mut btf = Btf::new();
1406 let name_offset = btf.add_string("int");
1407 let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
1408 btf.add_type(int_type);
1409
1410 let name_offset = btf.add_string("widget");
1411 let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
1412 btf.add_type(int_type);
1413
1414 let btf_bytes = btf.to_bytes();
1415 let raw_btf = btf_bytes.as_slice();
1416
1417 let btf = Btf::parse(raw_btf, Endianness::default()).unwrap();
1418 assert_eq!(btf.string_at(1).unwrap(), "int");
1419 assert_eq!(btf.string_at(5).unwrap(), "widget");
1420 }
1421
1422 #[test]
1423 fn test_fixup_ptr() {
1424 let mut btf = Btf::new();
1425 let name_offset = btf.add_string("int");
1426 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1427 name_offset,
1428 4,
1429 IntEncoding::Signed,
1430 0,
1431 )));
1432
1433 let name_offset = btf.add_string("&mut int");
1434 let ptr_type_id = btf.add_type(BtfType::Ptr(Ptr::new(name_offset, int_type_id)));
1435
1436 let features = Default::default();
1437
1438 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1439 .unwrap();
1440 assert_matches!(btf.type_by_id(ptr_type_id).unwrap(), BtfType::Ptr(fixed) => {
1441 assert_eq!(fixed.name_offset, 0);
1442 });
1443 let raw = btf.to_bytes();
1445 Btf::parse(&raw, Endianness::default()).unwrap();
1446 }
1447
1448 #[test]
1449 fn test_sanitize_var() {
1450 let mut btf = Btf::new();
1451 let name_offset = btf.add_string("int");
1452 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1453 name_offset,
1454 4,
1455 IntEncoding::Signed,
1456 0,
1457 )));
1458
1459 let name_offset = btf.add_string("&mut int");
1460 let var_type_id = btf.add_type(BtfType::Var(Var::new(
1461 name_offset,
1462 int_type_id,
1463 VarLinkage::Static,
1464 )));
1465
1466 let features = BtfFeatures {
1467 btf_datasec: false,
1468 ..Default::default()
1469 };
1470
1471 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1472 .unwrap();
1473 assert_matches!(btf.type_by_id(var_type_id).unwrap(), BtfType::Int(fixed) => {
1474 assert_eq!(fixed.name_offset, name_offset);
1475 });
1476 let raw = btf.to_bytes();
1478 Btf::parse(&raw, Endianness::default()).unwrap();
1479 }
1480
1481 #[test]
1482 fn test_sanitize_datasec() {
1483 let mut btf = Btf::new();
1484 let name_offset = btf.add_string("int");
1485 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1486 name_offset,
1487 4,
1488 IntEncoding::Signed,
1489 0,
1490 )));
1491
1492 let var_name_offset = btf.add_string("foo");
1493 let var_type_id = btf.add_type(BtfType::Var(Var::new(
1494 var_name_offset,
1495 int_type_id,
1496 VarLinkage::Static,
1497 )));
1498
1499 let name_offset = btf.add_string("data");
1500 let variables = vec![DataSecEntry {
1501 btf_type: var_type_id,
1502 offset: 0,
1503 size: 4,
1504 }];
1505 let datasec_type_id =
1506 btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0)));
1507
1508 let features = BtfFeatures {
1509 btf_datasec: false,
1510 ..Default::default()
1511 };
1512
1513 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1514 .unwrap();
1515 assert_matches!(btf.type_by_id(datasec_type_id).unwrap(), BtfType::Struct(fixed) => {
1516 assert_eq!(fixed.name_offset , name_offset);
1517 assert_matches!(*fixed.members, [
1518 BtfMember {
1519 name_offset: name_offset1,
1520 btf_type,
1521 offset: 0,
1522 },
1523 ] => {
1524 assert_eq!(name_offset1, var_name_offset);
1525 assert_eq!(btf_type, var_type_id);
1526 })
1527 });
1528 let raw = btf.to_bytes();
1530 Btf::parse(&raw, Endianness::default()).unwrap();
1531 }
1532
1533 #[test]
1534 fn test_fixup_datasec() {
1535 let mut btf = Btf::new();
1536 let name_offset = btf.add_string("int");
1537 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1538 name_offset,
1539 4,
1540 IntEncoding::Signed,
1541 0,
1542 )));
1543
1544 let name_offset = btf.add_string("foo");
1545 let var_type_id = btf.add_type(BtfType::Var(Var::new(
1546 name_offset,
1547 int_type_id,
1548 VarLinkage::Global,
1549 )));
1550
1551 let name_offset = btf.add_string(".data/foo");
1552 let variables = vec![DataSecEntry {
1553 btf_type: var_type_id,
1554 offset: 0,
1555 size: 4,
1556 }];
1557 let datasec_type_id =
1558 btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0)));
1559
1560 let features = BtfFeatures {
1561 btf_datasec: true,
1562 ..Default::default()
1563 };
1564
1565 btf.fixup_and_sanitize(
1566 &HashMap::from([(".data/foo".to_owned(), (SectionIndex(0), 32u64))]),
1567 &HashMap::from([("foo".to_owned(), 64u64)]),
1568 &features,
1569 )
1570 .unwrap();
1571
1572 assert_matches!(btf.type_by_id(datasec_type_id).unwrap(), BtfType::DataSec(fixed) => {
1573 assert_ne!(fixed.name_offset, name_offset);
1574 assert_eq!(fixed.size, 32);
1575 assert_matches!(*fixed.entries, [
1576 DataSecEntry {
1577 btf_type,
1578 offset,
1579 size,
1580 },
1581 ] => {
1582 assert_eq!(btf_type, var_type_id);
1583 assert_eq!(offset, 64);
1584 assert_eq!(size, 4);
1585 }
1586 );
1587 assert_eq!(btf.string_at(fixed.name_offset).unwrap(), ".data.foo");
1588 });
1589 let raw = btf.to_bytes();
1591 Btf::parse(&raw, Endianness::default()).unwrap();
1592 }
1593
1594 #[test]
1595 fn test_sanitize_func_and_proto() {
1596 let mut btf = Btf::new();
1597 let name_offset = btf.add_string("int");
1598 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1599 name_offset,
1600 4,
1601 IntEncoding::Signed,
1602 0,
1603 )));
1604
1605 let params = vec![
1606 BtfParam {
1607 name_offset: btf.add_string("a"),
1608 btf_type: int_type_id,
1609 },
1610 BtfParam {
1611 name_offset: btf.add_string("b"),
1612 btf_type: int_type_id,
1613 },
1614 ];
1615 let func_proto_type_id =
1616 btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id)));
1617 let inc = btf.add_string("inc");
1618 let func_type_id = btf.add_type(BtfType::Func(Func::new(
1619 inc,
1620 func_proto_type_id,
1621 FuncLinkage::Static,
1622 )));
1623
1624 let features = BtfFeatures {
1625 btf_func: false,
1626 ..Default::default()
1627 };
1628
1629 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1630 .unwrap();
1631 assert_matches!(btf.type_by_id(func_proto_type_id).unwrap(), BtfType::Enum(fixed) => {
1632 assert_eq!(fixed.name_offset, 0);
1633 assert_matches!(*fixed.variants, [
1634 BtfEnum {
1635 name_offset: name_offset1,
1636 value: value1,
1637 },
1638 BtfEnum {
1639 name_offset: name_offset2,
1640 value: value2,
1641 },
1642 ] => {
1643 assert_eq!(btf.string_at(name_offset1).unwrap(), "a");
1644 assert_eq!(value1, int_type_id);
1645 assert_eq!(btf.string_at(name_offset2).unwrap(), "b");
1646 assert_eq!(value2, int_type_id);
1647 }
1648 );
1649 });
1650
1651 assert_matches!(btf.type_by_id(func_type_id).unwrap(), BtfType::Typedef(fixed) => {
1652 assert_eq!(fixed.name_offset, inc);
1653 assert_eq!(fixed.btf_type, func_proto_type_id);
1654 });
1655
1656 let raw = btf.to_bytes();
1658 Btf::parse(&raw, Endianness::default()).unwrap();
1659 }
1660
1661 #[test]
1662 fn test_fixup_func_proto() {
1663 let mut btf = Btf::new();
1664 let name_offset = btf.add_string("int");
1665 let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
1666 let int_type_id = btf.add_type(int_type);
1667
1668 let params = vec![
1669 BtfParam {
1670 name_offset: 0,
1671 btf_type: int_type_id,
1672 },
1673 BtfParam {
1674 name_offset: 0,
1675 btf_type: int_type_id,
1676 },
1677 ];
1678 let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id));
1679 let func_proto_type_id = btf.add_type(func_proto);
1680
1681 let features = BtfFeatures {
1682 btf_func: true,
1683 ..Default::default()
1684 };
1685
1686 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1687 .unwrap();
1688
1689 assert_matches!(btf.type_by_id(func_proto_type_id).unwrap(), BtfType::FuncProto(fixed) => {
1690 assert_matches!(*fixed.params, [
1691 BtfParam {
1692 name_offset: name_offset1,
1693 btf_type: btf_type1,
1694 },
1695 BtfParam {
1696 name_offset: name_offset2,
1697 btf_type: btf_type2,
1698 },
1699 ] => {
1700 assert_eq!(btf.string_at(name_offset1).unwrap(), "param0");
1701 assert_eq!(btf_type1, int_type_id);
1702 assert_eq!(btf.string_at(name_offset2).unwrap(), "param1");
1703 assert_eq!(btf_type2, int_type_id);
1704 }
1705 );
1706 });
1707
1708 let raw = btf.to_bytes();
1710 Btf::parse(&raw, Endianness::default()).unwrap();
1711 }
1712
1713 #[test]
1714 fn test_sanitize_func_global() {
1715 let mut btf = Btf::new();
1716 let name_offset = btf.add_string("int");
1717 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1718 name_offset,
1719 4,
1720 IntEncoding::Signed,
1721 0,
1722 )));
1723
1724 let params = vec![
1725 BtfParam {
1726 name_offset: btf.add_string("a"),
1727 btf_type: int_type_id,
1728 },
1729 BtfParam {
1730 name_offset: btf.add_string("b"),
1731 btf_type: int_type_id,
1732 },
1733 ];
1734 let func_proto_type_id =
1735 btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id)));
1736 let inc = btf.add_string("inc");
1737 let func_type_id = btf.add_type(BtfType::Func(Func::new(
1738 inc,
1739 func_proto_type_id,
1740 FuncLinkage::Global,
1741 )));
1742
1743 let features = BtfFeatures {
1744 btf_func: true,
1745 btf_func_global: false,
1746 ..Default::default()
1747 };
1748
1749 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1750 .unwrap();
1751
1752 assert_matches!(btf.type_by_id(func_type_id).unwrap(), BtfType::Func(fixed) => {
1753 assert_eq!(fixed.linkage(), FuncLinkage::Static);
1754 });
1755
1756 let raw = btf.to_bytes();
1758 Btf::parse(&raw, Endianness::default()).unwrap();
1759 }
1760
1761 #[test]
1762 fn test_sanitize_mem_builtins() {
1763 let mut btf = Btf::new();
1764 let name_offset = btf.add_string("int");
1765 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1766 name_offset,
1767 4,
1768 IntEncoding::Signed,
1769 0,
1770 )));
1771
1772 let params = vec![
1773 BtfParam {
1774 name_offset: btf.add_string("a"),
1775 btf_type: int_type_id,
1776 },
1777 BtfParam {
1778 name_offset: btf.add_string("b"),
1779 btf_type: int_type_id,
1780 },
1781 ];
1782 let func_proto_type_id =
1783 btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id)));
1784
1785 let builtins = ["memset", "memcpy", "memcmp", "memmove"];
1786 for fname in builtins {
1787 let func_name_offset = btf.add_string(fname);
1788 let func_type_id = btf.add_type(BtfType::Func(Func::new(
1789 func_name_offset,
1790 func_proto_type_id,
1791 FuncLinkage::Global,
1792 )));
1793
1794 let features = BtfFeatures {
1795 btf_func: true,
1796 btf_func_global: true, ..Default::default()
1798 };
1799
1800 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1801 .unwrap();
1802
1803 assert_matches!(btf.type_by_id(func_type_id).unwrap(), BtfType::Func(fixed) => {
1804 assert_eq!(fixed.linkage(), FuncLinkage::Static);
1805 });
1806
1807 let raw = btf.to_bytes();
1809 Btf::parse(&raw, Endianness::default()).unwrap();
1810 }
1811 }
1812
1813 #[test]
1814 fn test_sanitize_float() {
1815 let mut btf = Btf::new();
1816 let name_offset = btf.add_string("float");
1817 let float_type_id = btf.add_type(BtfType::Float(Float::new(name_offset, 16)));
1818
1819 let features = BtfFeatures {
1820 btf_float: false,
1821 ..Default::default()
1822 };
1823
1824 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1825 .unwrap();
1826 assert_matches!(btf.type_by_id(float_type_id).unwrap(), BtfType::Struct(fixed) => {
1827 assert_eq!(fixed.name_offset, 0);
1828 assert_eq!(fixed.size, 16);
1829 });
1830
1831 let raw = btf.to_bytes();
1833 Btf::parse(&raw, Endianness::default()).unwrap();
1834 }
1835
1836 #[test]
1837 fn test_sanitize_decl_tag() {
1838 let mut btf = Btf::new();
1839 let name_offset = btf.add_string("int");
1840 let int_type_id = btf.add_type(BtfType::Int(Int::new(
1841 name_offset,
1842 4,
1843 IntEncoding::Signed,
1844 0,
1845 )));
1846
1847 let name_offset = btf.add_string("foo");
1848 let var_type_id = btf.add_type(BtfType::Var(Var::new(
1849 name_offset,
1850 int_type_id,
1851 VarLinkage::Static,
1852 )));
1853
1854 let name_offset = btf.add_string("decl_tag");
1855 let decl_tag_type_id =
1856 btf.add_type(BtfType::DeclTag(DeclTag::new(name_offset, var_type_id, -1)));
1857
1858 let features = BtfFeatures {
1859 btf_decl_tag: false,
1860 ..Default::default()
1861 };
1862
1863 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1864 .unwrap();
1865 assert_matches!(btf.type_by_id(decl_tag_type_id).unwrap(), BtfType::Int(fixed) => {
1866 assert_eq!(fixed.name_offset, name_offset);
1867 assert_eq!(fixed.size, 1);
1868 });
1869
1870 let raw = btf.to_bytes();
1872 Btf::parse(&raw, Endianness::default()).unwrap();
1873 }
1874
1875 #[test]
1876 fn test_sanitize_type_tag() {
1877 let mut btf = Btf::new();
1878
1879 let int_type_id = btf.add_type(BtfType::Int(Int::new(0, 4, IntEncoding::Signed, 0)));
1880
1881 let name_offset = btf.add_string("int");
1882 let type_tag_type = btf.add_type(BtfType::TypeTag(TypeTag::new(name_offset, int_type_id)));
1883 btf.add_type(BtfType::Ptr(Ptr::new(0, type_tag_type)));
1884
1885 let features = BtfFeatures {
1886 btf_type_tag: false,
1887 ..Default::default()
1888 };
1889
1890 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1891 .unwrap();
1892 assert_matches!(btf.type_by_id(type_tag_type).unwrap(), BtfType::Const(fixed) => {
1893 assert_eq!(fixed.btf_type, int_type_id);
1894 });
1895
1896 let raw = btf.to_bytes();
1898 Btf::parse(&raw, Endianness::default()).unwrap();
1899 }
1900
1901 #[test]
1902 #[cfg(feature = "std")]
1903 #[cfg_attr(miri, ignore = "`open` not available when isolation is enabled")]
1904 #[cfg_attr(
1905 target_endian = "big",
1906 ignore = "Not possible to emulate \"/sys/kernel/btf/vmlinux\" as big endian"
1907 )]
1908 fn test_read_btf_from_sys_fs() {
1909 let btf = Btf::parse_file("/sys/kernel/btf/vmlinux", Endianness::default()).unwrap();
1910 let task_struct_id = btf
1911 .id_by_type_name_kind("task_struct", BtfKind::Struct)
1912 .unwrap();
1913 assert!(task_struct_id != 0);
1915
1916 let netif_id = btf
1917 .id_by_type_name_kind("netif_receive_skb", BtfKind::Func)
1918 .unwrap();
1919 assert!(netif_id != 0);
1920
1921 let u32_def = btf.id_by_type_name_kind("__u32", BtfKind::Typedef).unwrap();
1922 assert!(u32_def != 0);
1923
1924 let u32_base = btf.resolve_type(u32_def).unwrap();
1925 assert!(u32_base != 0);
1926
1927 let u32_ty = btf.type_by_id(u32_base).unwrap();
1928 assert_eq!(u32_ty.kind(), BtfKind::Int);
1929 }
1930
1931 #[test]
1932 fn test_sanitize_signed_enum() {
1933 let mut btf = Btf::new();
1934 let name_offset = btf.add_string("signed_enum");
1935 let name_a = btf.add_string("A");
1936 let name_b = btf.add_string("B");
1937 let name_c = btf.add_string("C");
1938 let enum64_type = Enum::new(
1939 name_offset,
1940 true,
1941 vec![
1942 BtfEnum::new(name_a, -1i32 as u32),
1943 BtfEnum::new(name_b, -2i32 as u32),
1944 BtfEnum::new(name_c, -3i32 as u32),
1945 ],
1946 );
1947 let enum_type_id = btf.add_type(BtfType::Enum(enum64_type));
1948
1949 let features = BtfFeatures {
1950 btf_enum64: false,
1951 ..Default::default()
1952 };
1953
1954 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1955 .unwrap();
1956
1957 assert_matches!(btf.type_by_id(enum_type_id).unwrap(), BtfType::Enum(fixed) => {
1958 assert!(!fixed.is_signed());
1959 assert_matches!(fixed.variants[..], [
1960 BtfEnum { name_offset: name1, value: 0xFFFF_FFFF },
1961 BtfEnum { name_offset: name2, value: 0xFFFF_FFFE },
1962 BtfEnum { name_offset: name3, value: 0xFFFF_FFFD },
1963 ] => {
1964 assert_eq!(name1, name_a);
1965 assert_eq!(name2, name_b);
1966 assert_eq!(name3, name_c);
1967 });
1968 });
1969
1970 let raw = btf.to_bytes();
1972 Btf::parse(&raw, Endianness::default()).unwrap();
1973 }
1974
1975 #[test]
1976 fn test_sanitize_enum64() {
1977 let mut btf = Btf::new();
1978 let name_offset = btf.add_string("enum64");
1979 let name_a = btf.add_string("A");
1980 let name_b = btf.add_string("B");
1981 let name_c = btf.add_string("C");
1982 let enum64_type = Enum64::new(
1983 name_offset,
1984 false,
1985 vec![
1986 BtfEnum64::new(name_a, 1),
1987 BtfEnum64::new(name_b, 2),
1988 BtfEnum64::new(name_c, 3),
1989 ],
1990 );
1991 let enum_type_id = btf.add_type(BtfType::Enum64(enum64_type));
1992
1993 let features = BtfFeatures {
1994 btf_enum64: false,
1995 ..Default::default()
1996 };
1997
1998 btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
1999 .unwrap();
2000
2001 assert_matches!(btf.type_by_id(enum_type_id).unwrap(), BtfType::Union(fixed) => {
2002 let placeholder = btf.id_by_type_name_kind("enum64_placeholder", BtfKind::Int)
2003 .expect("enum64_placeholder type not found");
2004 assert_matches!(fixed.members[..], [
2005 BtfMember { name_offset: name_offset1, btf_type: btf_type1, offset: 0 },
2006 BtfMember { name_offset: name_offset2, btf_type: btf_type2, offset: 0 },
2007 BtfMember { name_offset: name_offset3, btf_type: btf_type3, offset: 0 },
2008 ] => {
2009 assert_eq!(name_offset1, name_a);
2010 assert_eq!(btf_type1, placeholder);
2011 assert_eq!(name_offset2, name_b);
2012 assert_eq!(btf_type2, placeholder);
2013 assert_eq!(name_offset3, name_c);
2014 assert_eq!(btf_type3, placeholder);
2015 });
2016 });
2017
2018 let raw = btf.to_bytes();
2020 Btf::parse(&raw, Endianness::default()).unwrap();
2021 }
2022}