|  | @@ -1,47 +1,58 @@
 | 
	
		
			
				|  |  | -pub(crate) mod btf;
 | 
	
		
			
				|  |  | -mod relocation;
 | 
	
		
			
				|  |  | +//! Object file loading, parsing, and relocation.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +use alloc::{
 | 
	
		
			
				|  |  | +    borrow::ToOwned,
 | 
	
		
			
				|  |  | +    ffi::CString,
 | 
	
		
			
				|  |  | +    string::{String, ToString},
 | 
	
		
			
				|  |  | +    vec::Vec,
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +use core::{ffi::CStr, mem, ptr, str::FromStr};
 | 
	
		
			
				|  |  |  use log::debug;
 | 
	
		
			
				|  |  |  use object::{
 | 
	
		
			
				|  |  |      read::{Object as ElfObject, ObjectSection, Section as ObjSection},
 | 
	
		
			
				|  |  |      Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SectionKind,
 | 
	
		
			
				|  |  |      SymbolKind,
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  | -use std::{
 | 
	
		
			
				|  |  | -    collections::HashMap,
 | 
	
		
			
				|  |  | -    ffi::{CStr, CString},
 | 
	
		
			
				|  |  | -    mem, ptr,
 | 
	
		
			
				|  |  | -    str::FromStr,
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -use thiserror::Error;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -use relocation::*;
 | 
	
		
			
				|  |  | +use crate::{
 | 
	
		
			
				|  |  | +    maps::{BtfMap, LegacyMap, Map, MapKind, MINIMUM_MAP_SIZE},
 | 
	
		
			
				|  |  | +    relocation::*,
 | 
	
		
			
				|  |  | +    thiserror::{self, Error},
 | 
	
		
			
				|  |  | +    util::HashMap,
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use crate::{
 | 
	
		
			
				|  |  | -    bpf_map_def,
 | 
	
		
			
				|  |  | +    btf::{Btf, BtfError, BtfExt, BtfType},
 | 
	
		
			
				|  |  |      generated::{bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
 | 
	
		
			
				|  |  | -    obj::btf::{Btf, BtfError, BtfExt, BtfType},
 | 
	
		
			
				|  |  | +    maps::{bpf_map_def, BtfMapDef, PinningType},
 | 
	
		
			
				|  |  |      programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType},
 | 
	
		
			
				|  |  | -    BpfError, BtfMapDef, PinningType,
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  | -use std::slice::from_raw_parts_mut;
 | 
	
		
			
				|  |  | +use core::slice::from_raw_parts_mut;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -use self::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo};
 | 
	
		
			
				|  |  | +use crate::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE;
 | 
	
		
			
				|  |  | -/// The first five __u32 of `bpf_map_def` must be defined.
 | 
	
		
			
				|  |  | -const MINIMUM_MAP_SIZE: usize = mem::size_of::<u32>() * 5;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/// The loaded object file representation
 | 
	
		
			
				|  |  |  #[derive(Clone)]
 | 
	
		
			
				|  |  |  pub struct Object {
 | 
	
		
			
				|  |  | -    pub(crate) endianness: Endianness,
 | 
	
		
			
				|  |  | +    /// The endianness
 | 
	
		
			
				|  |  | +    pub endianness: Endianness,
 | 
	
		
			
				|  |  | +    /// Program license
 | 
	
		
			
				|  |  |      pub license: CString,
 | 
	
		
			
				|  |  | +    /// Kernel version
 | 
	
		
			
				|  |  |      pub kernel_version: KernelVersion,
 | 
	
		
			
				|  |  | +    /// Program BTF
 | 
	
		
			
				|  |  |      pub btf: Option<Btf>,
 | 
	
		
			
				|  |  | +    /// Program BTF.ext
 | 
	
		
			
				|  |  |      pub btf_ext: Option<BtfExt>,
 | 
	
		
			
				|  |  | -    pub(crate) maps: HashMap<String, Map>,
 | 
	
		
			
				|  |  | -    pub(crate) programs: HashMap<String, Program>,
 | 
	
		
			
				|  |  | -    pub(crate) functions: HashMap<u64, Function>,
 | 
	
		
			
				|  |  | +    /// Referenced maps
 | 
	
		
			
				|  |  | +    pub maps: HashMap<String, Map>,
 | 
	
		
			
				|  |  | +    /// A hash map of programs, using the program names parsed
 | 
	
		
			
				|  |  | +    /// in [ProgramSection]s as keys.
 | 
	
		
			
				|  |  | +    pub programs: HashMap<String, Program>,
 | 
	
		
			
				|  |  | +    /// Functions
 | 
	
		
			
				|  |  | +    pub functions: HashMap<u64, Function>,
 | 
	
		
			
				|  |  |      pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
 | 
	
		
			
				|  |  |      pub(crate) symbols_by_index: HashMap<usize, Symbol>,
 | 
	
		
			
				|  |  |      pub(crate) section_sizes: HashMap<String, u64>,
 | 
	
	
		
			
				|  | @@ -51,160 +62,107 @@ pub struct Object {
 | 
	
		
			
				|  |  |      pub(crate) text_section_index: Option<usize>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 | 
	
		
			
				|  |  | -pub(crate) enum MapKind {
 | 
	
		
			
				|  |  | -    Bss,
 | 
	
		
			
				|  |  | -    Data,
 | 
	
		
			
				|  |  | -    Rodata,
 | 
	
		
			
				|  |  | -    Other,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl From<&str> for MapKind {
 | 
	
		
			
				|  |  | -    fn from(s: &str) -> Self {
 | 
	
		
			
				|  |  | -        if s == ".bss" {
 | 
	
		
			
				|  |  | -            MapKind::Bss
 | 
	
		
			
				|  |  | -        } else if s.starts_with(".data") {
 | 
	
		
			
				|  |  | -            MapKind::Data
 | 
	
		
			
				|  |  | -        } else if s.starts_with(".rodata") {
 | 
	
		
			
				|  |  | -            MapKind::Rodata
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -            MapKind::Other
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +/// An eBPF program
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | -pub enum Map {
 | 
	
		
			
				|  |  | -    Legacy(LegacyMap),
 | 
	
		
			
				|  |  | -    Btf(BtfMap),
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl Map {
 | 
	
		
			
				|  |  | -    pub(crate) fn map_type(&self) -> u32 {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.map_type,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.map_type,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn key_size(&self) -> u32 {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.key_size,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.key_size,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn value_size(&self) -> u32 {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.value_size,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.value_size,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn max_entries(&self) -> u32 {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.max_entries,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.max_entries,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn set_max_entries(&mut self, v: u32) {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.max_entries = v,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.max_entries = v,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn map_flags(&self) -> u32 {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.map_flags,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.map_flags,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn pinning(&self) -> PinningType {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.def.pinning,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.def.pinning,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn data(&self) -> &[u8] {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => &m.data,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => &m.data,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn data_mut(&mut self) -> &mut Vec<u8> {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.data.as_mut(),
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.data.as_mut(),
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn kind(&self) -> MapKind {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.kind,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.kind,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn section_index(&self) -> usize {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.section_index,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.section_index,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    pub(crate) fn symbol_index(&self) -> usize {
 | 
	
		
			
				|  |  | -        match self {
 | 
	
		
			
				|  |  | -            Map::Legacy(m) => m.symbol_index,
 | 
	
		
			
				|  |  | -            Map::Btf(m) => m.symbol_index,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | -pub struct LegacyMap {
 | 
	
		
			
				|  |  | -    pub(crate) def: bpf_map_def,
 | 
	
		
			
				|  |  | -    pub(crate) section_index: usize,
 | 
	
		
			
				|  |  | -    pub(crate) symbol_index: usize,
 | 
	
		
			
				|  |  | -    pub(crate) data: Vec<u8>,
 | 
	
		
			
				|  |  | -    pub(crate) kind: MapKind,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | -pub struct BtfMap {
 | 
	
		
			
				|  |  | -    pub(crate) def: BtfMapDef,
 | 
	
		
			
				|  |  | -    pub(crate) section_index: usize,
 | 
	
		
			
				|  |  | -    pub(crate) symbol_index: usize,
 | 
	
		
			
				|  |  | -    pub(crate) kind: MapKind,
 | 
	
		
			
				|  |  | -    pub(crate) data: Vec<u8>,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | -pub(crate) struct Program {
 | 
	
		
			
				|  |  | -    pub(crate) license: CString,
 | 
	
		
			
				|  |  | -    pub(crate) kernel_version: KernelVersion,
 | 
	
		
			
				|  |  | -    pub(crate) section: ProgramSection,
 | 
	
		
			
				|  |  | -    pub(crate) function: Function,
 | 
	
		
			
				|  |  | +pub struct Program {
 | 
	
		
			
				|  |  | +    /// The license
 | 
	
		
			
				|  |  | +    pub license: CString,
 | 
	
		
			
				|  |  | +    /// The kernel version
 | 
	
		
			
				|  |  | +    pub kernel_version: KernelVersion,
 | 
	
		
			
				|  |  | +    /// The section containing the program
 | 
	
		
			
				|  |  | +    pub section: ProgramSection,
 | 
	
		
			
				|  |  | +    /// The function
 | 
	
		
			
				|  |  | +    pub function: Function,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/// An eBPF function
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | -pub(crate) struct Function {
 | 
	
		
			
				|  |  | -    pub(crate) address: u64,
 | 
	
		
			
				|  |  | -    pub(crate) name: String,
 | 
	
		
			
				|  |  | -    pub(crate) section_index: SectionIndex,
 | 
	
		
			
				|  |  | -    pub(crate) section_offset: usize,
 | 
	
		
			
				|  |  | -    pub(crate) instructions: Vec<bpf_insn>,
 | 
	
		
			
				|  |  | -    pub(crate) func_info: FuncSecInfo,
 | 
	
		
			
				|  |  | -    pub(crate) line_info: LineSecInfo,
 | 
	
		
			
				|  |  | -    pub(crate) func_info_rec_size: usize,
 | 
	
		
			
				|  |  | -    pub(crate) line_info_rec_size: usize,
 | 
	
		
			
				|  |  | +pub struct Function {
 | 
	
		
			
				|  |  | +    /// The address
 | 
	
		
			
				|  |  | +    pub address: u64,
 | 
	
		
			
				|  |  | +    /// The function name
 | 
	
		
			
				|  |  | +    pub name: String,
 | 
	
		
			
				|  |  | +    /// The section index
 | 
	
		
			
				|  |  | +    pub section_index: SectionIndex,
 | 
	
		
			
				|  |  | +    /// The section offset
 | 
	
		
			
				|  |  | +    pub section_offset: usize,
 | 
	
		
			
				|  |  | +    /// The eBPF byte code instructions
 | 
	
		
			
				|  |  | +    pub instructions: Vec<bpf_insn>,
 | 
	
		
			
				|  |  | +    /// The function info
 | 
	
		
			
				|  |  | +    pub func_info: FuncSecInfo,
 | 
	
		
			
				|  |  | +    /// The line info
 | 
	
		
			
				|  |  | +    pub line_info: LineSecInfo,
 | 
	
		
			
				|  |  | +    /// Function info record size
 | 
	
		
			
				|  |  | +    pub func_info_rec_size: usize,
 | 
	
		
			
				|  |  | +    /// Line info record size
 | 
	
		
			
				|  |  | +    pub line_info_rec_size: usize,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/// Section types containing eBPF programs
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// # Section Name Parsing
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// Section types are parsed from the section name strings.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// In order for Aya to treat a section as a [ProgramSection],
 | 
	
		
			
				|  |  | +/// there are a few requirements:
 | 
	
		
			
				|  |  | +/// - The section must be an executable code section.
 | 
	
		
			
				|  |  | +/// - The section name must conform to [Program Types and ELF Sections].
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// [Program Types and ELF Sections]: https://docs.kernel.org/bpf/libbpf/program_types.html
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// ## Program Name
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// Each section name is parsed into a section type and a program name.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// Generally speaking,
 | 
	
		
			
				|  |  | +/// - if the section name does not contain any slashes,
 | 
	
		
			
				|  |  | +///   then the program name is just that section name;
 | 
	
		
			
				|  |  | +/// - if there are some slashes, the name is `section_name.rsplitn(2, '/')[0]`,
 | 
	
		
			
				|  |  | +/// - except for tracepoint programs, for which the name is
 | 
	
		
			
				|  |  | +///   `section_name.splitn(2, '/')[1]`.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// ```rust
 | 
	
		
			
				|  |  | +/// use aya_obj::ProgramSection;
 | 
	
		
			
				|  |  | +/// use std::str::FromStr;
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// assert_eq!(
 | 
	
		
			
				|  |  | +///     ProgramSection::from_str("kprobe/do_unlinkat")
 | 
	
		
			
				|  |  | +///             .unwrap().name(),
 | 
	
		
			
				|  |  | +///     "do_unlinkat",
 | 
	
		
			
				|  |  | +/// );
 | 
	
		
			
				|  |  | +/// assert_eq!(
 | 
	
		
			
				|  |  | +///     ProgramSection::from_str("tracepoint/syscalls/sys_enter_openat")
 | 
	
		
			
				|  |  | +///             .unwrap().name(),
 | 
	
		
			
				|  |  | +///     "syscalls/sys_enter_openat",
 | 
	
		
			
				|  |  | +/// );
 | 
	
		
			
				|  |  | +/// ```
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// The program name will be used in [Object] as references to each program.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// # Unsupported Sections
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// Currently, the following section names are not supported yet:
 | 
	
		
			
				|  |  | +/// - `flow_dissector`: `BPF_PROG_TYPE_FLOW_DISSECTOR`
 | 
	
		
			
				|  |  | +/// - `ksyscall+` or `kretsyscall+`
 | 
	
		
			
				|  |  | +/// - `uprobe.s+` or `uretprobe.s+`
 | 
	
		
			
				|  |  | +/// - `usdt+`
 | 
	
		
			
				|  |  | +/// - `kprobe.multi+` or `kretprobe.multi+`: `BPF_TRACE_KPROBE_MULTI`
 | 
	
		
			
				|  |  | +/// - `lsm_cgroup+` or `lsm.s+`
 | 
	
		
			
				|  |  | +/// - `lwt_in`, `lwt_out`, `lwt_seg6local`, `lwt_xmit`
 | 
	
		
			
				|  |  | +/// - `raw_tp.w+`, `raw_tracepoint.w+`
 | 
	
		
			
				|  |  | +/// - `action`
 | 
	
		
			
				|  |  | +/// - `sk_reuseport/migrate`, `sk_reuseport`
 | 
	
		
			
				|  |  | +/// - `syscall`
 | 
	
		
			
				|  |  | +/// - `struct_ops+`
 | 
	
		
			
				|  |  | +/// - `fmod_ret+`, `fmod_ret.s+`
 | 
	
		
			
				|  |  | +/// - `fentry.s+`, `fexit.s+`
 | 
	
		
			
				|  |  | +/// - `iter+`, `iter.s+`
 | 
	
		
			
				|  |  | +/// - `xdp.frags/cpumap`, `xdp/cpumap`
 | 
	
		
			
				|  |  | +/// - `xdp.frags/devmap`, `xdp/devmap`
 | 
	
		
			
				|  |  | +/// - `xdp.frags`
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | +#[allow(missing_docs)]
 | 
	
		
			
				|  |  |  pub enum ProgramSection {
 | 
	
		
			
				|  |  |      KRetProbe {
 | 
	
		
			
				|  |  |          name: String,
 | 
	
	
		
			
				|  | @@ -299,7 +257,8 @@ pub enum ProgramSection {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl ProgramSection {
 | 
	
		
			
				|  |  | -    fn name(&self) -> &str {
 | 
	
		
			
				|  |  | +    /// Returns the program name
 | 
	
		
			
				|  |  | +    pub fn name(&self) -> &str {
 | 
	
		
			
				|  |  |          match self {
 | 
	
		
			
				|  |  |              ProgramSection::KRetProbe { name } => name,
 | 
	
		
			
				|  |  |              ProgramSection::KProbe { name } => name,
 | 
	
	
		
			
				|  | @@ -521,7 +480,8 @@ impl FromStr for ProgramSection {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl Object {
 | 
	
		
			
				|  |  | -    pub(crate) fn parse(data: &[u8]) -> Result<Object, BpfError> {
 | 
	
		
			
				|  |  | +    /// Parses the binary data as an object file into an [Object]
 | 
	
		
			
				|  |  | +    pub fn parse(data: &[u8]) -> Result<Object, ParseError> {
 | 
	
		
			
				|  |  |          let obj = object::read::File::parse(data).map_err(ParseError::ElfError)?;
 | 
	
		
			
				|  |  |          let endianness = obj.endianness();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -604,6 +564,7 @@ impl Object {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /// Patches map data
 | 
	
		
			
				|  |  |      pub fn patch_map_data(&mut self, globals: HashMap<&str, &[u8]>) -> Result<(), ParseError> {
 | 
	
		
			
				|  |  |          let symbols: HashMap<String, &Symbol> = self
 | 
	
		
			
				|  |  |              .symbols_by_index
 | 
	
	
		
			
				|  | @@ -829,9 +790,9 @@ impl Object {
 | 
	
		
			
				|  |  |          &mut self,
 | 
	
		
			
				|  |  |          section: &Section,
 | 
	
		
			
				|  |  |          symbols: HashMap<String, Symbol>,
 | 
	
		
			
				|  |  | -    ) -> Result<(), BpfError> {
 | 
	
		
			
				|  |  | +    ) -> Result<(), ParseError> {
 | 
	
		
			
				|  |  |          if self.btf.is_none() {
 | 
	
		
			
				|  |  | -            return Err(BpfError::NoBTF);
 | 
	
		
			
				|  |  | +            return Err(ParseError::NoBTF);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          let btf = self.btf.as_ref().unwrap();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -847,10 +808,8 @@ impl Object {
 | 
	
		
			
				|  |  |                          let (map_name, def) = parse_btf_map_def(btf, info)?;
 | 
	
		
			
				|  |  |                          let symbol_index = symbols
 | 
	
		
			
				|  |  |                              .get(&map_name)
 | 
	
		
			
				|  |  | -                            .ok_or_else(|| {
 | 
	
		
			
				|  |  | -                                BpfError::ParseError(ParseError::SymbolNotFound {
 | 
	
		
			
				|  |  | -                                    name: map_name.to_string(),
 | 
	
		
			
				|  |  | -                                })
 | 
	
		
			
				|  |  | +                            .ok_or_else(|| ParseError::SymbolNotFound {
 | 
	
		
			
				|  |  | +                                name: map_name.to_string(),
 | 
	
		
			
				|  |  |                              })?
 | 
	
		
			
				|  |  |                              .index;
 | 
	
		
			
				|  |  |                          self.maps.insert(
 | 
	
	
		
			
				|  | @@ -870,7 +829,7 @@ impl Object {
 | 
	
		
			
				|  |  |          Ok(())
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    fn parse_section(&mut self, mut section: Section) -> Result<(), BpfError> {
 | 
	
		
			
				|  |  | +    fn parse_section(&mut self, mut section: Section) -> Result<(), ParseError> {
 | 
	
		
			
				|  |  |          let mut parts = section.name.rsplitn(2, '/').collect::<Vec<_>>();
 | 
	
		
			
				|  |  |          parts.reverse();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -945,10 +904,16 @@ impl Object {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone, Error)]
 | 
	
		
			
				|  |  | +/// Errors caught during parsing the object file
 | 
	
		
			
				|  |  | +#[derive(Debug, Error)]
 | 
	
		
			
				|  |  | +#[allow(missing_docs)]
 | 
	
		
			
				|  |  |  pub enum ParseError {
 | 
	
		
			
				|  |  |      #[error("error parsing ELF data")]
 | 
	
		
			
				|  |  | -    ElfError(#[from] object::read::Error),
 | 
	
		
			
				|  |  | +    ElfError(object::read::Error),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Error parsing BTF object
 | 
	
		
			
				|  |  | +    #[error("BTF error")]
 | 
	
		
			
				|  |  | +    BtfError(#[from] BtfError),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[error("invalid license `{data:?}`: missing NULL terminator")]
 | 
	
		
			
				|  |  |      MissingLicenseNullTerminator { data: Vec<u8> },
 | 
	
	
		
			
				|  | @@ -962,8 +927,7 @@ pub enum ParseError {
 | 
	
		
			
				|  |  |      #[error("error parsing section with index {index}")]
 | 
	
		
			
				|  |  |      SectionError {
 | 
	
		
			
				|  |  |          index: usize,
 | 
	
		
			
				|  |  | -        #[source]
 | 
	
		
			
				|  |  | -        source: object::read::Error,
 | 
	
		
			
				|  |  | +        error: object::read::Error,
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[error("unsupported relocation target")]
 | 
	
	
		
			
				|  | @@ -1005,6 +969,10 @@ pub enum ParseError {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[error("no symbols found for the maps included in the maps section")]
 | 
	
		
			
				|  |  |      NoSymbolsInMapSection {},
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// No BTF parsed for object
 | 
	
		
			
				|  |  | +    #[error("no BTF parsed for object")]
 | 
	
		
			
				|  |  | +    NoBTF,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Debug)]
 | 
	
	
		
			
				|  | @@ -1064,9 +1032,9 @@ impl<'data, 'file, 'a> TryFrom<&'a ObjSection<'data, 'file>> for Section<'a> {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn try_from(section: &'a ObjSection) -> Result<Section<'a>, ParseError> {
 | 
	
		
			
				|  |  |          let index = section.index();
 | 
	
		
			
				|  |  | -        let map_err = |source| ParseError::SectionError {
 | 
	
		
			
				|  |  | +        let map_err = |error| ParseError::SectionError {
 | 
	
		
			
				|  |  |              index: index.0,
 | 
	
		
			
				|  |  | -            source,
 | 
	
		
			
				|  |  | +            error,
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          let name = section.name().map_err(map_err)?;
 | 
	
		
			
				|  |  |          let kind = match BpfSectionKind::from_name(name) {
 | 
	
	
		
			
				|  | @@ -1166,9 +1134,12 @@ fn get_map_field(btf: &Btf, type_id: u32) -> Result<u32, BtfError> {
 | 
	
		
			
				|  |  |      Ok(arr.len)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/// The parsed kernel version
 | 
	
		
			
				|  |  |  #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 | 
	
		
			
				|  |  |  pub enum KernelVersion {
 | 
	
		
			
				|  |  | +    /// Specified version
 | 
	
		
			
				|  |  |      Version(u32),
 | 
	
		
			
				|  |  | +    /// Any version
 | 
	
		
			
				|  |  |      Any,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1311,7 +1282,8 @@ fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDe
 | 
	
		
			
				|  |  |      Ok((map_name.to_string(), map_def))
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -pub(crate) fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
 | 
	
		
			
				|  |  | +/// Parses a [bpf_map_info] into a [Map].
 | 
	
		
			
				|  |  | +pub fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
 | 
	
		
			
				|  |  |      if info.btf_key_type_id != 0 {
 | 
	
		
			
				|  |  |          Map::Btf(BtfMap {
 | 
	
		
			
				|  |  |              def: BtfMapDef {
 | 
	
	
		
			
				|  | @@ -1350,7 +1322,8 @@ pub(crate) fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -pub(crate) fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
 | 
	
		
			
				|  |  | +/// Copies a block of eBPF instructions
 | 
	
		
			
				|  |  | +pub fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
 | 
	
		
			
				|  |  |      if data.len() % mem::size_of::<bpf_insn>() > 0 {
 | 
	
		
			
				|  |  |          return Err(ParseError::InvalidProgramCode);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1363,11 +1336,12 @@ pub(crate) fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[cfg(test)]
 | 
	
		
			
				|  |  |  mod tests {
 | 
	
		
			
				|  |  | +    use alloc::vec;
 | 
	
		
			
				|  |  |      use matches::assert_matches;
 | 
	
		
			
				|  |  |      use object::Endianness;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      use super::*;
 | 
	
		
			
				|  |  | -    use crate::PinningType;
 | 
	
		
			
				|  |  | +    use crate::maps::PinningType;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn fake_section<'a>(kind: BpfSectionKind, name: &'a str, data: &'a [u8]) -> Section<'a> {
 | 
	
		
			
				|  |  |          Section {
 | 
	
	
		
			
				|  | @@ -1416,7 +1390,7 @@ mod tests {
 | 
	
		
			
				|  |  |      fn test_parse_generic_error() {
 | 
	
		
			
				|  |  |          assert!(matches!(
 | 
	
		
			
				|  |  |              Object::parse(&b"foo"[..]),
 | 
	
		
			
				|  |  | -            Err(BpfError::ParseError(ParseError::ElfError(_)))
 | 
	
		
			
				|  |  | +            Err(ParseError::ElfError(_))
 | 
	
		
			
				|  |  |          ))
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 |