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