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