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