diff --git a/aya-obj/Cargo.toml b/aya-obj/Cargo.toml index 79dc47c6..0dc1e2b6 100644 --- a/aya-obj/Cargo.toml +++ b/aya-obj/Cargo.toml @@ -11,3 +11,10 @@ documentation = "https://docs.rs/aya-obj" edition = "2021" [dependencies] +bytes = "1" +log = "0.4" +object = { version = "0.30", default-features = false, features = ["std", "read_core", "elf"] } +thiserror = "1" + +[dev-dependencies] +matches = "0.1.8" diff --git a/aya/src/obj/btf/btf.rs b/aya-obj/src/btf/btf.rs similarity index 97% rename from aya/src/obj/btf/btf.rs rename to aya-obj/src/btf/btf.rs index dc1563f8..e8da97e1 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -16,14 +16,13 @@ use thiserror::Error; use crate::{ generated::{btf_ext_header, btf_header}, - obj::btf::{ + btf::{ info::{FuncSecInfo, LineSecInfo}, relocation::Relocation, Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int, IntEncoding, LineInfo, Struct, Typedef, VarLinkage, }, util::bytes_of, - Features, }; pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32; @@ -158,6 +157,16 @@ pub enum BtfError { InvalidSymbolName, } +#[derive(Default, Debug)] +pub struct BtfFeatures { + pub btf_func: bool, + pub btf_func_global: bool, + pub btf_datasec: bool, + pub btf_float: bool, + pub btf_decl_tag: bool, + pub btf_type_tag: bool, +} + /// Bpf Type Format metadata. /// /// BTF is a kind of debug metadata that allows eBPF programs compiled against one kernel version @@ -175,7 +184,7 @@ pub struct Btf { } impl Btf { - pub(crate) fn new() -> Btf { + pub fn new() -> Btf { Btf { header: btf_header { magic: 0xeb9f, @@ -197,7 +206,7 @@ impl Btf { self.types.types.iter() } - pub(crate) fn add_string(&mut self, name: String) -> u32 { + pub fn add_string(&mut self, name: String) -> u32 { let str = CString::new(name).unwrap(); let name_offset = self.strings.len(); self.strings.extend(str.as_c_str().to_bytes_with_nul()); @@ -205,7 +214,7 @@ impl Btf { name_offset as u32 } - pub(crate) fn add_type(&mut self, btf_type: BtfType) -> u32 { + pub fn add_type(&mut self, btf_type: BtfType) -> u32 { let size = btf_type.type_info_size() as u32; let type_id = self.types.len(); self.types.push(btf_type); @@ -231,7 +240,7 @@ impl Btf { ) } - pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result { + pub fn parse(data: &[u8], endianness: Endianness) -> Result { if data.len() < mem::size_of::() { return Err(BtfError::InvalidHeader); } @@ -324,7 +333,7 @@ impl Btf { self.string_at(ty.name_offset()).ok().map(String::from) } - pub(crate) fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result { + pub fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result { for (type_id, ty) in self.types().enumerate() { if ty.kind() != kind { continue; @@ -370,7 +379,7 @@ impl Btf { }) } - pub(crate) fn to_bytes(&self) -> Vec { + pub fn to_bytes(&self) -> Vec { // Safety: btf_header is POD let mut buf = unsafe { bytes_of::(&self.header).to_vec() }; // Skip the first type since it's always BtfType::Unknown for type_by_id to work @@ -379,11 +388,11 @@ impl Btf { buf } - pub(crate) fn fixup_and_sanitize( + pub fn fixup_and_sanitize( &mut self, section_sizes: &HashMap, symbol_offsets: &HashMap, - features: &Features, + features: &BtfFeatures, ) -> Result<(), BtfError> { let mut types = mem::take(&mut self.types); for i in 0..types.types.len() { @@ -863,7 +872,7 @@ pub(crate) struct SecInfo<'a> { #[cfg(test)] mod tests { - use crate::obj::btf::{ + use crate::btf::{ BtfParam, DataSec, DataSecEntry, DeclTag, Float, Func, FuncProto, Ptr, TypeTag, Var, }; @@ -996,7 +1005,7 @@ mod tests { let name_offset = btf.add_string("&mut int".to_string()); let ptr_type_id = btf.add_type(BtfType::Ptr(Ptr::new(name_offset, int_type_id))); - let features = Features { + let features = BtfFeatures { ..Default::default() }; @@ -1034,7 +1043,7 @@ mod tests { VarLinkage::Static, ))); - let features = Features { + let features = BtfFeatures { btf_datasec: false, ..Default::default() }; @@ -1078,7 +1087,7 @@ mod tests { let datasec_type_id = btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0))); - let features = Features { + let features = BtfFeatures { btf_datasec: false, ..Default::default() }; @@ -1125,7 +1134,7 @@ mod tests { let datasec_type_id = btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0))); - let features = Features { + let features = BtfFeatures { btf_datasec: true, ..Default::default() }; @@ -1186,7 +1195,7 @@ mod tests { FuncLinkage::Static, ))); - let features = Features { + let features = BtfFeatures { btf_func: false, ..Default::default() }; @@ -1235,7 +1244,7 @@ mod tests { let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id)); let func_proto_type_id = btf.add_type(func_proto); - let features = Features { + let features = BtfFeatures { btf_func: true, ..Default::default() }; @@ -1284,7 +1293,7 @@ mod tests { FuncLinkage::Global, ))); - let features = Features { + let features = BtfFeatures { btf_func: true, btf_func_global: false, ..Default::default() @@ -1309,7 +1318,7 @@ mod tests { let name_offset = btf.add_string("float".to_string()); let float_type_id = btf.add_type(BtfType::Float(Float::new(name_offset, 16))); - let features = Features { + let features = BtfFeatures { btf_float: false, ..Default::default() }; @@ -1349,7 +1358,7 @@ mod tests { let decl_tag_type_id = btf.add_type(BtfType::DeclTag(DeclTag::new(name_offset, var_type_id, -1))); - let features = Features { + let features = BtfFeatures { btf_decl_tag: false, ..Default::default() }; @@ -1377,7 +1386,7 @@ mod tests { let type_tag_type = btf.add_type(BtfType::TypeTag(TypeTag::new(name_offset, int_type_id))); btf.add_type(BtfType::Ptr(Ptr::new(0, type_tag_type))); - let features = Features { + let features = BtfFeatures { btf_type_tag: false, ..Default::default() }; diff --git a/aya/src/obj/btf/info.rs b/aya-obj/src/btf/info.rs similarity index 94% rename from aya/src/obj/btf/info.rs rename to aya-obj/src/btf/info.rs index 2e6139ce..d265a3a9 100644 --- a/aya/src/obj/btf/info.rs +++ b/aya-obj/src/btf/info.rs @@ -5,7 +5,7 @@ use object::Endianness; use crate::{ generated::{bpf_func_info, bpf_line_info}, - obj::relocation::INS_SIZE, + relocation::INS_SIZE, util::bytes_of, }; @@ -20,7 +20,7 @@ use crate::{ * ...... */ #[derive(Debug, Clone, Default)] -pub(crate) struct FuncSecInfo { +pub struct FuncSecInfo { pub _sec_name_offset: u32, pub num_info: u32, pub func_info: Vec, @@ -64,7 +64,7 @@ impl FuncSecInfo { } } - pub(crate) fn func_info_bytes(&self) -> Vec { + pub fn func_info_bytes(&self) -> Vec { let mut buf = vec![]; for l in &self.func_info { // Safety: bpf_func_info is POD @@ -73,13 +73,13 @@ impl FuncSecInfo { buf } - pub(crate) fn len(&self) -> usize { + pub fn len(&self) -> usize { self.func_info.len() } } #[derive(Debug, Clone)] -pub(crate) struct FuncInfo { +pub struct FuncInfo { pub data: HashMap, } @@ -99,7 +99,7 @@ impl FuncInfo { } #[derive(Debug, Clone, Default)] -pub(crate) struct LineSecInfo { +pub struct LineSecInfo { // each line info section has a header pub _sec_name_offset: u32, pub num_info: u32, @@ -154,7 +154,7 @@ impl LineSecInfo { } } - pub(crate) fn line_info_bytes(&self) -> Vec { + pub fn line_info_bytes(&self) -> Vec { let mut buf = vec![]; for l in &self.line_info { // Safety: bpf_func_info is POD @@ -163,7 +163,7 @@ impl LineSecInfo { buf } - pub(crate) fn len(&self) -> usize { + pub fn len(&self) -> usize { self.line_info.len() } } diff --git a/aya/src/obj/btf/mod.rs b/aya-obj/src/btf/mod.rs similarity index 77% rename from aya/src/obj/btf/mod.rs rename to aya-obj/src/btf/mod.rs index 8b3ed606..44bf123f 100644 --- a/aya/src/obj/btf/mod.rs +++ b/aya-obj/src/btf/mod.rs @@ -1,3 +1,5 @@ +//! BTF loading, parsing and relocation. + #[allow(clippy::module_inception)] mod btf; mod info; diff --git a/aya/src/obj/btf/relocation.rs b/aya-obj/src/btf/relocation.rs similarity index 94% rename from aya/src/obj/btf/relocation.rs rename to aya-obj/src/btf/relocation.rs index 285c5c03..b3e89d93 100644 --- a/aya/src/obj/btf/relocation.rs +++ b/aya-obj/src/btf/relocation.rs @@ -3,20 +3,27 @@ use std::{collections::HashMap, io, mem, ptr, str::FromStr}; use thiserror::Error; use crate::{ + btf::{ + fields_are_compatible, types_are_compatible, Array, Btf, BtfError, BtfMember, BtfType, + IntEncoding, Struct, Union, MAX_SPEC_LEN, + }, generated::{ bpf_core_relo, bpf_core_relo_kind::*, bpf_insn, BPF_ALU, BPF_ALU64, BPF_B, BPF_DW, BPF_H, BPF_K, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_W, BTF_INT_SIGNED, }, - obj::{ - btf::{ - fields_are_compatible, types_are_compatible, Array, BtfMember, BtfType, IntEncoding, - Struct, Union, MAX_SPEC_LEN, - }, - Btf, BtfError, Object, Program, ProgramSection, - }, - BpfError, + Object, Program, ProgramSection, }; +#[derive(Error, Debug)] +#[error("error relocating `{section}`")] +pub struct BtfRelocationError { + /// The function name + pub section: String, + #[source] + /// The original error + error: RelocationError, +} + #[derive(Error, Debug)] enum RelocationError { #[error(transparent)] @@ -78,6 +85,9 @@ enum RelocationError { type_id: u32, ins_index: usize, }, + + #[error("invalid BTF")] + BtfError(#[from] BtfError), } fn err_type_name(name: &Option) -> String { @@ -154,7 +164,7 @@ impl Relocation { } impl Object { - pub fn relocate_btf(&mut self, target_btf: &Btf) -> Result<(), BpfError> { + pub fn relocate_btf(&mut self, target_btf: &Btf) -> Result<(), BtfRelocationError> { let (local_btf, btf_ext) = match (&self.btf, &self.btf_ext) { (Some(btf), Some(btf_ext)) => (btf, btf_ext), _ => return Ok(()), @@ -162,7 +172,10 @@ impl Object { let mut candidates_cache = HashMap::>::new(); for (sec_name_off, relos) in btf_ext.relocations() { - let section_name = local_btf.string_at(*sec_name_off)?; + let section_name = local_btf.string_at(*sec_name_off).map_err(|e| BtfRelocationError { + section: format!("section@{sec_name_off}"), + error: RelocationError::BtfError(e), + })?; let program_section = match ProgramSection::from_str(§ion_name) { Ok(program) => program, @@ -173,20 +186,17 @@ impl Object { let program = self .programs .get_mut(section_name) - .ok_or(BpfError::RelocationError { - function: section_name.to_owned(), - error: Box::new(RelocationError::ProgramNotFound), + .ok_or(BtfRelocationError { + section: section_name.to_owned(), + error: RelocationError::ProgramNotFound, })?; match relocate_btf_program(program, relos, local_btf, target_btf, &mut candidates_cache) { Ok(_) => {} - Err(ErrorWrapper::BtfError(e)) => return Err(e.into()), - Err(ErrorWrapper::RelocationError(error)) => { - return Err(BpfError::RelocationError { - function: section_name.to_owned(), - error: Box::new(error), - }) - } + Err(error) => return Err(BtfRelocationError { + section: section_name.to_owned(), + error, + }), } } @@ -200,7 +210,7 @@ fn relocate_btf_program<'target>( local_btf: &Btf, target_btf: &'target Btf, candidates_cache: &mut HashMap>>, -) -> Result<(), ErrorWrapper> { +) -> Result<(), RelocationError> { for rel in relos { let instructions = &mut program.function.instructions; let ins_index = rel.ins_offset / std::mem::size_of::(); @@ -209,8 +219,7 @@ fn relocate_btf_program<'target>( index: ins_index, num_instructions: instructions.len(), relocation_number: rel.number, - } - .into()); + }); } let local_ty = local_btf.type_by_id(rel.type_id)?; @@ -266,8 +275,7 @@ fn relocate_btf_program<'target>( return Err(RelocationError::ConflictingCandidates { type_name: local_name.to_string(), candidates: conflicts, - } - .into()); + }); } target_comp_rel } else { @@ -317,7 +325,7 @@ fn find_candidates<'target>( fn match_candidate<'target>( local_spec: &AccessSpec, candidate: &'target Candidate, -) -> Result>, ErrorWrapper> { +) -> Result>, RelocationError> { let mut target_spec = AccessSpec { btf: candidate.btf, root_type_id: candidate.type_id, @@ -419,8 +427,7 @@ fn match_candidate<'target>( if target_spec.parts.len() == MAX_SPEC_LEN { return Err(RelocationError::MaximumNestingLevelReached { type_name: Some(candidate.name.clone()), - } - .into()); + }); } target_spec.parts.push(accessor.index); @@ -446,7 +453,7 @@ fn match_member<'target>( target_btf: &'target Btf, target_id: u32, target_spec: &mut AccessSpec<'target>, -) -> Result, ErrorWrapper> { +) -> Result, RelocationError> { let local_ty = local_btf.type_by_id(local_accessor.type_id)?; let local_member = match local_ty { // this won't panic, bounds are checked when local_spec is built in AccessSpec::new @@ -470,8 +477,7 @@ fn match_member<'target>( let root_ty = target_spec.btf.type_by_id(target_spec.root_type_id)?; return Err(RelocationError::MaximumNestingLevelReached { type_name: target_spec.btf.err_type_name(root_ty), - } - .into()); + }); } // this will not panic as we've already established these are fields types @@ -532,7 +538,7 @@ impl<'a> AccessSpec<'a> { root_type_id: u32, spec: &str, relocation: Relocation, - ) -> Result, ErrorWrapper> { + ) -> Result, RelocationError> { let parts = spec .split(':') .map(|s| s.parse::()) @@ -552,8 +558,7 @@ impl<'a> AccessSpec<'a> { if parts != [0] { return Err(RelocationError::InvalidAccessString { access_str: spec.to_string(), - } - .into()); + }); } AccessSpec { btf, @@ -569,8 +574,7 @@ impl<'a> AccessSpec<'a> { if parts.len() != 1 { return Err(RelocationError::InvalidAccessString { access_str: spec.to_string(), - } - .into()); + }); } let index = parts[0]; if index >= en.variants.len() { @@ -580,8 +584,7 @@ impl<'a> AccessSpec<'a> { index, max_index: en.variants.len(), error: "tried to access nonexistant enum variant".to_string(), - } - .into()); + }); } let accessors = vec![Accessor { type_id, @@ -607,8 +610,7 @@ impl<'a> AccessSpec<'a> { relocation_kind: format!("{:?}", relocation.kind), type_kind: format!("{:?}", ty.kind()), error: "enum relocation on non-enum type".to_string(), - } - .into()) + }) } }, @@ -638,8 +640,7 @@ impl<'a> AccessSpec<'a> { index, max_index: members.len(), error: "out of bounds struct or union access".to_string(), - } - .into()); + }); } let member = &members[index]; @@ -675,8 +676,7 @@ impl<'a> AccessSpec<'a> { index, max_index: array.len as usize, error: "array index out of bounds".to_string(), - } - .into()); + }); } accessors.push(Accessor { type_id, @@ -693,8 +693,7 @@ impl<'a> AccessSpec<'a> { type_kind: format!("{:?}", ty.kind()), error: "field relocation on a type that doesn't have fields" .to_string(), - } - .into()); + }); } }; } @@ -747,7 +746,7 @@ impl ComputedRelocation { rel: &Relocation, local_spec: &AccessSpec, target_spec: Option<&AccessSpec>, - ) -> Result { + ) -> Result { use RelocationKind::*; let ret = match rel.kind { FieldByteOffset | FieldByteSize | FieldExists | FieldSigned | FieldLShift64 @@ -774,7 +773,7 @@ impl ComputedRelocation { rel: &Relocation, local_btf: &Btf, target_btf: &Btf, - ) -> Result<(), ErrorWrapper> { + ) -> Result<(), RelocationError> { let instructions = &mut program.function.instructions; let num_instructions = instructions.len(); let ins_index = rel.ins_offset / std::mem::size_of::(); @@ -799,8 +798,7 @@ impl ComputedRelocation { relocation_number: rel.number, index: ins_index, error: format!("invalid src_reg={src_reg:x} expected {BPF_K:x}"), - } - .into()); + }); } ins.imm = target_value as i32; @@ -811,8 +809,7 @@ impl ComputedRelocation { relocation_number: rel.number, index: ins_index, error: format!("value `{target_value}` overflows 16 bits offset field"), - } - .into()); + }); } ins.off = target_value as i16; @@ -837,8 +834,7 @@ impl ComputedRelocation { err_type_name(&target_btf.err_type_name(target_ty)), self.target.size, ), - } - .into()) + }) } } @@ -852,8 +848,7 @@ impl ComputedRelocation { relocation_number: rel.number, index: ins_index, error: format!("invalid target size {size}"), - } - .into()) + }) } } as u8; ins.code = ins.code & 0xE0 | size | ins.code & 0x07; @@ -876,8 +871,7 @@ impl ComputedRelocation { relocation_number: rel.number, index: ins_index, error: format!("invalid instruction class {class:x}"), - } - .into()) + }) } }; @@ -887,7 +881,7 @@ impl ComputedRelocation { fn compute_enum_relocation( rel: &Relocation, spec: Option<&AccessSpec>, - ) -> Result { + ) -> Result { use RelocationKind::*; let value = match (rel.kind, spec) { (EnumVariantExists, spec) => spec.is_some() as u32, @@ -918,7 +912,7 @@ impl ComputedRelocation { fn compute_field_relocation( rel: &Relocation, spec: Option<&AccessSpec>, - ) -> Result { + ) -> Result { use RelocationKind::*; if let FieldExists = rel.kind { @@ -963,8 +957,7 @@ impl ComputedRelocation { relocation_kind: format!("{rel_kind:?}"), type_kind: format!("{:?}", ty.kind()), error: "invalid relocation kind for array type".to_string(), - } - .into()); + }); } }; } @@ -979,8 +972,7 @@ impl ComputedRelocation { relocation_kind: format!("{:?}", rel.kind), type_kind: format!("{:?}", ty.kind()), error: "field relocation on a type that doesn't have fields".to_string(), - } - .into()); + }); } }; @@ -1055,7 +1047,7 @@ impl ComputedRelocation { rel: &Relocation, local_spec: &AccessSpec, target_spec: Option<&AccessSpec>, - ) -> Result { + ) -> Result { use RelocationKind::*; let value = match (rel.kind, target_spec) { @@ -1081,14 +1073,3 @@ impl ComputedRelocation { }) } } - -// this exists only to simplify propagating errors from relocate_btf() and to associate -// RelocationError(s) with their respective program name -#[derive(Error, Debug)] -enum ErrorWrapper { - #[error(transparent)] - BtfError(#[from] BtfError), - - #[error(transparent)] - RelocationError(#[from] RelocationError), -} diff --git a/aya/src/obj/btf/types.rs b/aya-obj/src/btf/types.rs similarity index 96% rename from aya/src/obj/btf/types.rs rename to aya-obj/src/btf/types.rs index 8f687bb3..f50b6d07 100644 --- a/aya/src/obj/btf/types.rs +++ b/aya-obj/src/btf/types.rs @@ -2,10 +2,10 @@ use std::{fmt::Display, mem, ptr}; use object::Endianness; -use crate::obj::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}; +use crate::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}; #[derive(Clone, Debug)] -pub(crate) enum BtfType { +pub enum BtfType { Unknown, Fwd(Fwd), Const(Const), @@ -29,7 +29,7 @@ pub(crate) enum BtfType { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Fwd { +pub struct Fwd { pub(crate) name_offset: u32, info: u32, _unused: u32, @@ -51,7 +51,7 @@ impl Fwd { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Const { +pub struct Const { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -82,7 +82,7 @@ impl Const { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Volatile { +pub struct Volatile { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -103,7 +103,7 @@ impl Volatile { } #[derive(Clone, Debug)] -pub(crate) struct Restrict { +pub struct Restrict { pub(crate) name_offset: u32, _info: u32, pub(crate) btf_type: u32, @@ -125,7 +125,7 @@ impl Restrict { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Ptr { +pub struct Ptr { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -144,7 +144,7 @@ impl Ptr { mem::size_of::() } - pub(crate) fn new(name_offset: u32, btf_type: u32) -> Self { + pub fn new(name_offset: u32, btf_type: u32) -> Self { let info = (BtfKind::Ptr as u32) << 24; Ptr { name_offset, @@ -156,7 +156,7 @@ impl Ptr { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Typedef { +pub struct Typedef { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -187,7 +187,7 @@ impl Typedef { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Float { +pub struct Float { pub(crate) name_offset: u32, info: u32, pub(crate) size: u32, @@ -205,7 +205,7 @@ impl Float { mem::size_of::() } - pub(crate) fn new(name_offset: u32, size: u32) -> Self { + pub fn new(name_offset: u32, size: u32) -> Self { let info = (BtfKind::Float as u32) << 24; Float { name_offset, @@ -217,7 +217,7 @@ impl Float { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Func { +pub struct Func { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -225,7 +225,7 @@ pub(crate) struct Func { #[repr(u32)] #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum FuncLinkage { +pub enum FuncLinkage { Static = 0, Global = 1, Extern = 2, @@ -255,7 +255,7 @@ impl Func { mem::size_of::() } - pub(crate) fn new(name_offset: u32, proto: u32, linkage: FuncLinkage) -> Self { + pub fn new(name_offset: u32, proto: u32, linkage: FuncLinkage) -> Self { let mut info = (BtfKind::Func as u32) << 24; info |= (linkage as u32) & 0xFFFF; Func { @@ -276,7 +276,7 @@ impl Func { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct TypeTag { +pub struct TypeTag { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -295,7 +295,7 @@ impl TypeTag { mem::size_of::() } - pub(crate) fn new(name_offset: u32, btf_type: u32) -> Self { + pub fn new(name_offset: u32, btf_type: u32) -> Self { let info = (BtfKind::TypeTag as u32) << 24; TypeTag { name_offset, @@ -307,7 +307,7 @@ impl TypeTag { #[repr(u32)] #[derive(Clone, Debug, Eq, PartialEq)] -pub(crate) enum IntEncoding { +pub enum IntEncoding { None, Signed = 1, Char = 2, @@ -329,7 +329,7 @@ impl From for IntEncoding { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Int { +pub struct Int { pub(crate) name_offset: u32, info: u32, pub(crate) size: u32, @@ -353,7 +353,7 @@ impl Int { mem::size_of::() } - pub(crate) fn new(name_offset: u32, size: u32, encoding: IntEncoding, offset: u32) -> Self { + pub fn new(name_offset: u32, size: u32, encoding: IntEncoding, offset: u32) -> Self { let info = (BtfKind::Int as u32) << 24; let mut data = 0u32; data |= (encoding as u32 & 0x0f) << 24; @@ -391,7 +391,7 @@ pub(crate) struct BtfEnum { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Enum { +pub struct Enum { pub(crate) name_offset: u32, info: u32, pub(crate) size: u32, @@ -441,7 +441,7 @@ pub(crate) struct BtfMember { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Struct { +pub struct Struct { pub(crate) name_offset: u32, info: u32, pub(crate) size: u32, @@ -502,7 +502,7 @@ impl Struct { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Union { +pub struct Union { pub(crate) name_offset: u32, info: u32, pub(crate) size: u32, @@ -559,7 +559,7 @@ pub(crate) struct BtfArray { } #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Array { +pub struct Array { pub(crate) name_offset: u32, info: u32, _unused: u32, @@ -602,14 +602,14 @@ impl Array { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct BtfParam { - pub(crate) name_offset: u32, - pub(crate) btf_type: u32, +pub struct BtfParam { + pub name_offset: u32, + pub btf_type: u32, } #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct FuncProto { +pub struct FuncProto { pub(crate) name_offset: u32, info: u32, pub(crate) return_type: u32, @@ -637,7 +637,7 @@ impl FuncProto { mem::size_of::() + mem::size_of::() * self.params.len() } - pub(crate) fn new(params: Vec, return_type: u32) -> Self { + pub fn new(params: Vec, return_type: u32) -> Self { let mut info = (BtfKind::FuncProto as u32) << 24; info |= (params.len() as u32) & 0xFFFF; FuncProto { @@ -651,7 +651,7 @@ impl FuncProto { #[repr(u32)] #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum VarLinkage { +pub enum VarLinkage { Static, Global, Extern, @@ -671,7 +671,7 @@ impl From for VarLinkage { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct Var { +pub struct Var { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -696,7 +696,7 @@ impl Var { mem::size_of::() } - pub(crate) fn new(name_offset: u32, btf_type: u32, linkage: VarLinkage) -> Self { + pub fn new(name_offset: u32, btf_type: u32, linkage: VarLinkage) -> Self { let info = (BtfKind::Var as u32) << 24; Var { name_offset, @@ -709,15 +709,15 @@ impl Var { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct DataSecEntry { - pub(crate) btf_type: u32, - pub(crate) offset: u32, - pub(crate) size: u32, +pub struct DataSecEntry { + pub btf_type: u32, + pub offset: u32, + pub size: u32, } #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct DataSec { +pub struct DataSec { pub(crate) name_offset: u32, info: u32, pub(crate) size: u32, @@ -746,7 +746,7 @@ impl DataSec { mem::size_of::() + mem::size_of::() * self.entries.len() } - pub(crate) fn new(name_offset: u32, entries: Vec, size: u32) -> Self { + pub fn new(name_offset: u32, entries: Vec, size: u32) -> Self { let mut info = (BtfKind::DataSec as u32) << 24; info |= (entries.len() as u32) & 0xFFFF; DataSec { @@ -760,7 +760,7 @@ impl DataSec { #[repr(C)] #[derive(Clone, Debug)] -pub(crate) struct DeclTag { +pub struct DeclTag { pub(crate) name_offset: u32, info: u32, pub(crate) btf_type: u32, @@ -785,7 +785,7 @@ impl DeclTag { mem::size_of::() } - pub(crate) fn new(name_offset: u32, btf_type: u32, component_index: i32) -> Self { + pub fn new(name_offset: u32, btf_type: u32, component_index: i32) -> Self { let info = (BtfKind::DeclTag as u32) << 24; DeclTag { name_offset, @@ -798,7 +798,7 @@ impl DeclTag { #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(u32)] -pub(crate) enum BtfKind { +pub enum BtfKind { Unknown = 0, Int = 1, Ptr = 2, diff --git a/aya-obj/src/generated/mod.rs b/aya-obj/src/generated/mod.rs index 4153c2e8..0a64f088 100644 --- a/aya-obj/src/generated/mod.rs +++ b/aya-obj/src/generated/mod.rs @@ -31,56 +31,3 @@ pub use linux_bindings_aarch64::*; #[cfg(target_arch = "riscv64")] pub use linux_bindings_riscv64::*; - -pub mod maps { - /// Invalid map type encontered - pub struct InvalidMapTypeError { - /// The map type - pub map_type: u32, - } - - impl TryFrom for super::bpf_map_type { - type Error = InvalidMapTypeError; - - fn try_from(map_type: u32) -> Result { - use super::bpf_map_type::*; - Ok(match map_type { - x if x == BPF_MAP_TYPE_UNSPEC as u32 => BPF_MAP_TYPE_UNSPEC, - x if x == BPF_MAP_TYPE_HASH as u32 => BPF_MAP_TYPE_HASH, - x if x == BPF_MAP_TYPE_ARRAY as u32 => BPF_MAP_TYPE_ARRAY, - x if x == BPF_MAP_TYPE_PROG_ARRAY as u32 => BPF_MAP_TYPE_PROG_ARRAY, - x if x == BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32 => BPF_MAP_TYPE_PERF_EVENT_ARRAY, - x if x == BPF_MAP_TYPE_PERCPU_HASH as u32 => BPF_MAP_TYPE_PERCPU_HASH, - x if x == BPF_MAP_TYPE_PERCPU_ARRAY as u32 => BPF_MAP_TYPE_PERCPU_ARRAY, - x if x == BPF_MAP_TYPE_STACK_TRACE as u32 => BPF_MAP_TYPE_STACK_TRACE, - x if x == BPF_MAP_TYPE_CGROUP_ARRAY as u32 => BPF_MAP_TYPE_CGROUP_ARRAY, - x if x == BPF_MAP_TYPE_LRU_HASH as u32 => BPF_MAP_TYPE_LRU_HASH, - x if x == BPF_MAP_TYPE_LRU_PERCPU_HASH as u32 => BPF_MAP_TYPE_LRU_PERCPU_HASH, - x if x == BPF_MAP_TYPE_LPM_TRIE as u32 => BPF_MAP_TYPE_LPM_TRIE, - x if x == BPF_MAP_TYPE_BLOOM_FILTER as u32 => BPF_MAP_TYPE_BLOOM_FILTER, - x if x == BPF_MAP_TYPE_ARRAY_OF_MAPS as u32 => BPF_MAP_TYPE_ARRAY_OF_MAPS, - x if x == BPF_MAP_TYPE_HASH_OF_MAPS as u32 => BPF_MAP_TYPE_HASH_OF_MAPS, - x if x == BPF_MAP_TYPE_DEVMAP as u32 => BPF_MAP_TYPE_DEVMAP, - x if x == BPF_MAP_TYPE_SOCKMAP as u32 => BPF_MAP_TYPE_SOCKMAP, - x if x == BPF_MAP_TYPE_CPUMAP as u32 => BPF_MAP_TYPE_CPUMAP, - x if x == BPF_MAP_TYPE_XSKMAP as u32 => BPF_MAP_TYPE_XSKMAP, - x if x == BPF_MAP_TYPE_SOCKHASH as u32 => BPF_MAP_TYPE_SOCKHASH, - x if x == BPF_MAP_TYPE_CGROUP_STORAGE as u32 => BPF_MAP_TYPE_CGROUP_STORAGE, - x if x == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY as u32 => BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, - x if x == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE as u32 => { - BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE - } - x if x == BPF_MAP_TYPE_QUEUE as u32 => BPF_MAP_TYPE_QUEUE, - x if x == BPF_MAP_TYPE_STACK as u32 => BPF_MAP_TYPE_STACK, - x if x == BPF_MAP_TYPE_SK_STORAGE as u32 => BPF_MAP_TYPE_SK_STORAGE, - x if x == BPF_MAP_TYPE_DEVMAP_HASH as u32 => BPF_MAP_TYPE_DEVMAP_HASH, - x if x == BPF_MAP_TYPE_STRUCT_OPS as u32 => BPF_MAP_TYPE_STRUCT_OPS, - x if x == BPF_MAP_TYPE_RINGBUF as u32 => BPF_MAP_TYPE_RINGBUF, - x if x == BPF_MAP_TYPE_INODE_STORAGE as u32 => BPF_MAP_TYPE_INODE_STORAGE, - x if x == BPF_MAP_TYPE_TASK_STORAGE as u32 => BPF_MAP_TYPE_TASK_STORAGE, - _ => return Err(InvalidMapTypeError { map_type }), - }) - } - } -} - diff --git a/aya-obj/src/lib.rs b/aya-obj/src/lib.rs index 5302fbe6..d145d2aa 100644 --- a/aya-obj/src/lib.rs +++ b/aya-obj/src/lib.rs @@ -1,12 +1,19 @@ //! A library for loading and relocating eBPF object files. -#![no_std] #![doc( html_logo_url = "https://aya-rs.dev/assets/images/crabby.svg", html_favicon_url = "https://aya-rs.dev/assets/images/crabby.svg" )] #![cfg_attr(docsrs, feature(doc_cfg))] -#![deny(clippy::all, missing_docs)] +#![deny(clippy::all)] #![allow(clippy::missing_safety_doc, clippy::len_without_is_empty)] +pub mod btf; pub mod generated; +pub mod maps; +pub mod obj; +pub mod programs; +pub mod relocation; +mod util; + +pub use obj::*; diff --git a/aya-obj/src/maps.rs b/aya-obj/src/maps.rs new file mode 100644 index 00000000..94d0b590 --- /dev/null +++ b/aya-obj/src/maps.rs @@ -0,0 +1,111 @@ +//! Map struct and type bindings. + +use thiserror::Error; + +/// Invalid map type encontered +pub struct InvalidMapTypeError { + /// The map type + pub map_type: u32, +} + +impl TryFrom for crate::generated::bpf_map_type { + type Error = InvalidMapTypeError; + + fn try_from(map_type: u32) -> Result { + use crate::generated::bpf_map_type::*; + Ok(match map_type { + x if x == BPF_MAP_TYPE_UNSPEC as u32 => BPF_MAP_TYPE_UNSPEC, + x if x == BPF_MAP_TYPE_HASH as u32 => BPF_MAP_TYPE_HASH, + x if x == BPF_MAP_TYPE_ARRAY as u32 => BPF_MAP_TYPE_ARRAY, + x if x == BPF_MAP_TYPE_PROG_ARRAY as u32 => BPF_MAP_TYPE_PROG_ARRAY, + x if x == BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32 => BPF_MAP_TYPE_PERF_EVENT_ARRAY, + x if x == BPF_MAP_TYPE_PERCPU_HASH as u32 => BPF_MAP_TYPE_PERCPU_HASH, + x if x == BPF_MAP_TYPE_PERCPU_ARRAY as u32 => BPF_MAP_TYPE_PERCPU_ARRAY, + x if x == BPF_MAP_TYPE_STACK_TRACE as u32 => BPF_MAP_TYPE_STACK_TRACE, + x if x == BPF_MAP_TYPE_CGROUP_ARRAY as u32 => BPF_MAP_TYPE_CGROUP_ARRAY, + x if x == BPF_MAP_TYPE_LRU_HASH as u32 => BPF_MAP_TYPE_LRU_HASH, + x if x == BPF_MAP_TYPE_LRU_PERCPU_HASH as u32 => BPF_MAP_TYPE_LRU_PERCPU_HASH, + x if x == BPF_MAP_TYPE_LPM_TRIE as u32 => BPF_MAP_TYPE_LPM_TRIE, + x if x == BPF_MAP_TYPE_BLOOM_FILTER as u32 => BPF_MAP_TYPE_BLOOM_FILTER, + x if x == BPF_MAP_TYPE_ARRAY_OF_MAPS as u32 => BPF_MAP_TYPE_ARRAY_OF_MAPS, + x if x == BPF_MAP_TYPE_HASH_OF_MAPS as u32 => BPF_MAP_TYPE_HASH_OF_MAPS, + x if x == BPF_MAP_TYPE_DEVMAP as u32 => BPF_MAP_TYPE_DEVMAP, + x if x == BPF_MAP_TYPE_SOCKMAP as u32 => BPF_MAP_TYPE_SOCKMAP, + x if x == BPF_MAP_TYPE_CPUMAP as u32 => BPF_MAP_TYPE_CPUMAP, + x if x == BPF_MAP_TYPE_XSKMAP as u32 => BPF_MAP_TYPE_XSKMAP, + x if x == BPF_MAP_TYPE_SOCKHASH as u32 => BPF_MAP_TYPE_SOCKHASH, + x if x == BPF_MAP_TYPE_CGROUP_STORAGE as u32 => BPF_MAP_TYPE_CGROUP_STORAGE, + x if x == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY as u32 => BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + x if x == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE as u32 => { + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE + } + x if x == BPF_MAP_TYPE_QUEUE as u32 => BPF_MAP_TYPE_QUEUE, + x if x == BPF_MAP_TYPE_STACK as u32 => BPF_MAP_TYPE_STACK, + x if x == BPF_MAP_TYPE_SK_STORAGE as u32 => BPF_MAP_TYPE_SK_STORAGE, + x if x == BPF_MAP_TYPE_DEVMAP_HASH as u32 => BPF_MAP_TYPE_DEVMAP_HASH, + x if x == BPF_MAP_TYPE_STRUCT_OPS as u32 => BPF_MAP_TYPE_STRUCT_OPS, + x if x == BPF_MAP_TYPE_RINGBUF as u32 => BPF_MAP_TYPE_RINGBUF, + x if x == BPF_MAP_TYPE_INODE_STORAGE as u32 => BPF_MAP_TYPE_INODE_STORAGE, + x if x == BPF_MAP_TYPE_TASK_STORAGE as u32 => BPF_MAP_TYPE_TASK_STORAGE, + _ => return Err(InvalidMapTypeError { map_type }), + }) + } +} + +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct BtfMapDef { + pub(crate) map_type: u32, + pub(crate) key_size: u32, + pub(crate) value_size: u32, + pub(crate) max_entries: u32, + pub(crate) map_flags: u32, + pub(crate) pinning: PinningType, + pub btf_key_type_id: u32, + pub btf_value_type_id: u32, +} + +#[repr(u32)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum PinningType { + None = 0, + ByName = 1, +} + +#[derive(Debug, Error)] +pub enum PinningError { + #[error("unsupported pinning type")] + Unsupported, +} + +impl TryFrom for PinningType { + type Error = PinningError; + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(PinningType::None), + 1 => Ok(PinningType::ByName), + _ => Err(PinningError::Unsupported), + } + } +} + +impl Default for PinningType { + fn default() -> Self { + PinningType::None + } +} + +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct bpf_map_def { + // minimum features required by old BPF programs + pub map_type: u32, + pub key_size: u32, + pub value_size: u32, + pub max_entries: u32, + pub map_flags: u32, + // optional features + pub id: u32, + pub pinning: PinningType, +} diff --git a/aya/src/obj/mod.rs b/aya-obj/src/obj.rs similarity index 96% rename from aya/src/obj/mod.rs rename to aya-obj/src/obj.rs index 7dd90d53..46e6b1bf 100644 --- a/aya/src/obj/mod.rs +++ b/aya-obj/src/obj.rs @@ -1,5 +1,4 @@ -pub(crate) mod btf; -mod relocation; +//! Object file loading, parsing, and relocation. use log::debug; use object::{ @@ -15,18 +14,18 @@ use std::{ }; use thiserror::Error; -use relocation::*; +use crate::relocation::*; use crate::{ - bpf_map_def, + maps::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}, programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType}, - BpfError, BtfMapDef, PinningType, + maps::BtfMapDef, maps::PinningType, }; use std::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. @@ -34,25 +33,25 @@ const MINIMUM_MAP_SIZE: usize = mem::size_of::() * 5; #[derive(Clone)] pub struct Object { - pub(crate) endianness: Endianness, + pub endianness: Endianness, pub license: CString, pub kernel_version: KernelVersion, pub btf: Option, pub btf_ext: Option, - pub(crate) maps: HashMap, - pub(crate) programs: HashMap, - pub(crate) functions: HashMap, - pub(crate) relocations: HashMap>, - pub(crate) symbols_by_index: HashMap, - pub(crate) section_sizes: HashMap, + pub maps: HashMap, + pub programs: HashMap, + pub functions: HashMap, + pub relocations: HashMap>, + pub symbols_by_index: HashMap, + pub section_sizes: HashMap, // symbol_offset_by_name caches symbols that could be referenced from a // BTF VAR type so the offsets can be fixed up - pub(crate) symbol_offset_by_name: HashMap, - pub(crate) text_section_index: Option, + pub symbol_offset_by_name: HashMap, + pub text_section_index: Option, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub(crate) enum MapKind { +pub enum MapKind { Bss, Data, Rodata, @@ -80,84 +79,84 @@ pub enum Map { } impl Map { - pub(crate) fn map_type(&self) -> u32 { + pub 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 { + pub 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 { + pub 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 { + pub 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) { + pub 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 { + pub 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 { + pub fn pinning(&self) -> PinningType { match self { Map::Legacy(m) => m.def.pinning, Map::Btf(m) => m.def.pinning, } } - pub(crate) fn data(&self) -> &[u8] { + pub 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 { + pub fn data_mut(&mut self) -> &mut Vec { match self { Map::Legacy(m) => m.data.as_mut(), Map::Btf(m) => m.data.as_mut(), } } - pub(crate) fn kind(&self) -> MapKind { + pub fn kind(&self) -> MapKind { match self { Map::Legacy(m) => m.kind, Map::Btf(m) => m.kind, } } - pub(crate) fn section_index(&self) -> usize { + pub 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 { + pub fn symbol_index(&self) -> usize { match self { Map::Legacy(m) => m.symbol_index, Map::Btf(m) => m.symbol_index, @@ -167,41 +166,41 @@ impl Map { #[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, - pub(crate) kind: MapKind, + pub def: bpf_map_def, + pub section_index: usize, + pub symbol_index: usize, + pub data: Vec, + pub 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, + pub def: BtfMapDef, + pub section_index: usize, + pub symbol_index: usize, + pub kind: MapKind, + pub data: Vec, } #[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 { + pub license: CString, + pub kernel_version: KernelVersion, + pub section: ProgramSection, + pub function: 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, - 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 { + pub address: u64, + pub name: String, + pub section_index: SectionIndex, + pub section_offset: usize, + pub instructions: Vec, + pub func_info: FuncSecInfo, + pub line_info: LineSecInfo, + pub func_info_rec_size: usize, + pub line_info_rec_size: usize, } #[derive(Debug, Clone)] @@ -299,7 +298,7 @@ pub enum ProgramSection { } impl ProgramSection { - fn name(&self) -> &str { + pub fn name(&self) -> &str { match self { ProgramSection::KRetProbe { name } => name, ProgramSection::KProbe { name } => name, @@ -521,7 +520,7 @@ impl FromStr for ProgramSection { } impl Object { - pub(crate) fn parse(data: &[u8]) -> Result { + pub fn parse(data: &[u8]) -> Result { let obj = object::read::File::parse(data).map_err(ParseError::ElfError)?; let endianness = obj.endianness(); @@ -829,9 +828,9 @@ impl Object { &mut self, section: &Section, symbols: HashMap, - ) -> 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 +846,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 +867,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::>(); parts.reverse(); @@ -945,11 +942,14 @@ impl Object { } } -#[derive(Debug, Clone, Error)] +#[derive(Debug, Error)] pub enum ParseError { #[error("error parsing ELF data")] ElfError(#[from] object::read::Error), + #[error("BTF error")] + BtfError(#[from] BtfError), + #[error("invalid license `{data:?}`: missing NULL terminator")] MissingLicenseNullTerminator { data: Vec }, @@ -1005,6 +1005,9 @@ pub enum ParseError { #[error("no symbols found for the maps included in the maps section")] NoSymbolsInMapSection {}, + + #[error("no BTF parsed for object")] + NoBTF, } #[derive(Debug)] @@ -1311,7 +1314,7 @@ 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 { +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 +1353,7 @@ pub(crate) fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map { } } -pub(crate) fn copy_instructions(data: &[u8]) -> Result, ParseError> { +pub fn copy_instructions(data: &[u8]) -> Result, ParseError> { if data.len() % mem::size_of::() > 0 { return Err(ParseError::InvalidProgramCode); } @@ -1367,7 +1370,7 @@ mod tests { 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 +1419,7 @@ mod tests { fn test_parse_generic_error() { assert!(matches!( Object::parse(&b"foo"[..]), - Err(BpfError::ParseError(ParseError::ElfError(_))) + Err(ParseError::ElfError(_)) )) } diff --git a/aya-obj/src/programs/cgroup_sock.rs b/aya-obj/src/programs/cgroup_sock.rs new file mode 100644 index 00000000..d30d269b --- /dev/null +++ b/aya-obj/src/programs/cgroup_sock.rs @@ -0,0 +1,52 @@ +//! Cgroup socket programs. +use thiserror::Error; + +use crate::generated::bpf_attach_type; + +/// Defines where to attach a [`CgroupSock`] program. +#[derive(Copy, Clone, Debug)] +pub enum CgroupSockAttachType { + /// Called after the IPv4 bind events. + PostBind4, + /// Called after the IPv6 bind events. + PostBind6, + /// Attach to IPv4 connect events. + SockCreate, + /// Attach to IPv6 connect events. + SockRelease, +} + +impl Default for CgroupSockAttachType { + // The kernel checks for a 0 attach_type and sets it to sock_create + // We may as well do that here also + fn default() -> Self { + CgroupSockAttachType::SockCreate + } +} + +impl From for bpf_attach_type { + fn from(s: CgroupSockAttachType) -> bpf_attach_type { + match s { + CgroupSockAttachType::PostBind4 => bpf_attach_type::BPF_CGROUP_INET4_POST_BIND, + CgroupSockAttachType::PostBind6 => bpf_attach_type::BPF_CGROUP_INET6_POST_BIND, + CgroupSockAttachType::SockCreate => bpf_attach_type::BPF_CGROUP_INET_SOCK_CREATE, + CgroupSockAttachType::SockRelease => bpf_attach_type::BPF_CGROUP_INET_SOCK_RELEASE, + } + } +} + +#[derive(Debug, Error)] +#[error("{0} is not a valid attach type for a CGROUP_SOCK program")] +pub(crate) struct InvalidAttachType(String); + +impl CgroupSockAttachType { + pub(crate) fn try_from(value: &str) -> Result { + match value { + "post_bind4" => Ok(CgroupSockAttachType::PostBind4), + "post_bind6" => Ok(CgroupSockAttachType::PostBind6), + "sock_create" => Ok(CgroupSockAttachType::SockCreate), + "sock_release" => Ok(CgroupSockAttachType::SockRelease), + _ => Err(InvalidAttachType(value.to_owned())), + } + } +} diff --git a/aya-obj/src/programs/cgroup_sock_addr.rs b/aya-obj/src/programs/cgroup_sock_addr.rs new file mode 100644 index 00000000..61cb33c5 --- /dev/null +++ b/aya-obj/src/programs/cgroup_sock_addr.rs @@ -0,0 +1,76 @@ +//! Cgroup socket address programs. +use thiserror::Error; + +use crate::generated::bpf_attach_type; + +/// Defines where to attach a [`CgroupSockAddr`] program. +#[derive(Copy, Clone, Debug)] +pub enum CgroupSockAddrAttachType { + /// Attach to IPv4 bind events. + Bind4, + /// Attach to IPv6 bind events. + Bind6, + /// Attach to IPv4 connect events. + Connect4, + /// Attach to IPv6 connect events. + Connect6, + /// Attach to IPv4 getpeername events. + GetPeerName4, + /// Attach to IPv6 getpeername events. + GetPeerName6, + /// Attach to IPv4 getsockname events. + GetSockName4, + /// Attach to IPv6 getsockname events. + GetSockName6, + /// Attach to IPv4 udp_sendmsg events. + UDPSendMsg4, + /// Attach to IPv6 udp_sendmsg events. + UDPSendMsg6, + /// Attach to IPv4 udp_recvmsg events. + UDPRecvMsg4, + /// Attach to IPv6 udp_recvmsg events. + UDPRecvMsg6, +} + +impl From for bpf_attach_type { + fn from(s: CgroupSockAddrAttachType) -> bpf_attach_type { + match s { + CgroupSockAddrAttachType::Bind4 => bpf_attach_type::BPF_CGROUP_INET4_BIND, + CgroupSockAddrAttachType::Bind6 => bpf_attach_type::BPF_CGROUP_INET6_BIND, + CgroupSockAddrAttachType::Connect4 => bpf_attach_type::BPF_CGROUP_INET4_CONNECT, + CgroupSockAddrAttachType::Connect6 => bpf_attach_type::BPF_CGROUP_INET6_CONNECT, + CgroupSockAddrAttachType::GetPeerName4 => bpf_attach_type::BPF_CGROUP_INET4_GETPEERNAME, + CgroupSockAddrAttachType::GetPeerName6 => bpf_attach_type::BPF_CGROUP_INET6_GETPEERNAME, + CgroupSockAddrAttachType::GetSockName4 => bpf_attach_type::BPF_CGROUP_INET4_GETSOCKNAME, + CgroupSockAddrAttachType::GetSockName6 => bpf_attach_type::BPF_CGROUP_INET6_GETSOCKNAME, + CgroupSockAddrAttachType::UDPSendMsg4 => bpf_attach_type::BPF_CGROUP_UDP4_SENDMSG, + CgroupSockAddrAttachType::UDPSendMsg6 => bpf_attach_type::BPF_CGROUP_UDP6_SENDMSG, + CgroupSockAddrAttachType::UDPRecvMsg4 => bpf_attach_type::BPF_CGROUP_UDP4_RECVMSG, + CgroupSockAddrAttachType::UDPRecvMsg6 => bpf_attach_type::BPF_CGROUP_UDP6_RECVMSG, + } + } +} + +#[derive(Debug, Error)] +#[error("{0} is not a valid attach type for a CGROUP_SOCK_ADDR program")] +pub(crate) struct InvalidAttachType(String); + +impl CgroupSockAddrAttachType { + pub(crate) fn try_from(value: &str) -> Result { + match value { + "bind4" => Ok(CgroupSockAddrAttachType::Bind4), + "bind6" => Ok(CgroupSockAddrAttachType::Bind6), + "connect4" => Ok(CgroupSockAddrAttachType::Connect4), + "connect6" => Ok(CgroupSockAddrAttachType::Connect6), + "getpeername4" => Ok(CgroupSockAddrAttachType::GetPeerName4), + "getpeername6" => Ok(CgroupSockAddrAttachType::GetPeerName6), + "getsockname4" => Ok(CgroupSockAddrAttachType::GetSockName4), + "getsockname6" => Ok(CgroupSockAddrAttachType::GetSockName6), + "sendmsg4" => Ok(CgroupSockAddrAttachType::UDPSendMsg4), + "sendmsg6" => Ok(CgroupSockAddrAttachType::UDPSendMsg6), + "recvmsg4" => Ok(CgroupSockAddrAttachType::UDPRecvMsg4), + "recvmsg6" => Ok(CgroupSockAddrAttachType::UDPRecvMsg6), + _ => Err(InvalidAttachType(value.to_owned())), + } + } +} diff --git a/aya-obj/src/programs/cgroup_sockopt.rs b/aya-obj/src/programs/cgroup_sockopt.rs new file mode 100644 index 00000000..daa4b250 --- /dev/null +++ b/aya-obj/src/programs/cgroup_sockopt.rs @@ -0,0 +1,36 @@ +//! Cgroup socket option programs. +use thiserror::Error; + +use crate::generated::bpf_attach_type; + +/// Defines where to attach a [`CgroupSockopt`] program. +#[derive(Copy, Clone, Debug)] +pub enum CgroupSockoptAttachType { + /// Attach to GetSockopt. + Get, + /// Attach to SetSockopt. + Set, +} + +impl From for bpf_attach_type { + fn from(s: CgroupSockoptAttachType) -> bpf_attach_type { + match s { + CgroupSockoptAttachType::Get => bpf_attach_type::BPF_CGROUP_GETSOCKOPT, + CgroupSockoptAttachType::Set => bpf_attach_type::BPF_CGROUP_SETSOCKOPT, + } + } +} + +#[derive(Debug, Error)] +#[error("{0} is not a valid attach type for a CGROUP_SOCKOPT program")] +pub(crate) struct InvalidAttachType(String); + +impl CgroupSockoptAttachType { + pub(crate) fn try_from(value: &str) -> Result { + match value { + "getsockopt" => Ok(CgroupSockoptAttachType::Get), + "setsockopt" => Ok(CgroupSockoptAttachType::Set), + _ => Err(InvalidAttachType(value.to_owned())), + } + } +} diff --git a/aya-obj/src/programs/mod.rs b/aya-obj/src/programs/mod.rs new file mode 100644 index 00000000..4f76211a --- /dev/null +++ b/aya-obj/src/programs/mod.rs @@ -0,0 +1,9 @@ +//! Program struct and type bindings. + +pub mod cgroup_sock; +pub mod cgroup_sock_addr; +pub mod cgroup_sockopt; + +pub use cgroup_sock::CgroupSockAttachType; +pub use cgroup_sock_addr::CgroupSockAddrAttachType; +pub use cgroup_sockopt::CgroupSockoptAttachType; diff --git a/aya/src/obj/relocation.rs b/aya-obj/src/relocation.rs similarity index 87% rename from aya/src/obj/relocation.rs rename to aya-obj/src/relocation.rs index 1564084a..6f56eb60 100644 --- a/aya/src/obj/relocation.rs +++ b/aya-obj/src/relocation.rs @@ -9,15 +9,23 @@ use crate::{ bpf_insn, BPF_CALL, BPF_JMP, BPF_K, BPF_PSEUDO_CALL, BPF_PSEUDO_FUNC, BPF_PSEUDO_MAP_FD, BPF_PSEUDO_MAP_VALUE, }, - maps::MapData, - obj::{Function, Object, Program}, - BpfError, + obj::{Function, Object, Program}, Map, }; pub(crate) const INS_SIZE: usize = mem::size_of::(); +#[derive(Error, Debug)] +#[error("error relocating `{function}`")] +pub struct BpfRelocationError { + /// The function name + function: String, + #[source] + /// The original error + error: RelocationError, +} + #[derive(Debug, Error)] -enum RelocationError { +pub enum RelocationError { #[error("unknown symbol, index `{index}`")] UnknownSymbol { index: usize }, @@ -43,7 +51,7 @@ enum RelocationError { } #[derive(Debug, Copy, Clone)] -pub(crate) struct Relocation { +pub struct Relocation { // byte offset of the instruction to be relocated pub(crate) offset: u64, // index of the symbol to relocate to @@ -51,7 +59,7 @@ pub(crate) struct Relocation { } #[derive(Debug, Clone)] -pub(crate) struct Symbol { +pub struct Symbol { pub(crate) index: usize, pub(crate) section_index: Option, pub(crate) name: Option, @@ -62,16 +70,16 @@ pub(crate) struct Symbol { } impl Object { - pub fn relocate_maps(&mut self, maps: &HashMap) -> Result<(), BpfError> { - let maps_by_section = maps - .iter() - .map(|(name, map)| (map.obj.section_index(), (name.as_str(), map))) - .collect::>(); - - let maps_by_symbol = maps - .iter() - .map(|(name, map)| (map.obj.symbol_index(), (name.as_str(), map))) - .collect::>(); + pub fn relocate_maps<'a, I: Iterator, &'a Map)>>( + &mut self, + maps: I, + ) -> Result<(), BpfRelocationError> { + let mut maps_by_section = HashMap::new(); + let mut maps_by_symbol = HashMap::new(); + for (name, fd, map) in maps { + maps_by_section.insert(map.section_index(), (name, fd, map)); + maps_by_symbol.insert(map.symbol_index(), (name, fd, map)); + } let functions = self .programs @@ -89,9 +97,9 @@ impl Object { &self.symbols_by_index, self.text_section_index, ) - .map_err(|error| BpfError::RelocationError { + .map_err(|error| BpfRelocationError { function: function.name.clone(), - error: Box::new(error), + error, })?; } } @@ -99,7 +107,7 @@ impl Object { Ok(()) } - pub fn relocate_calls(&mut self) -> Result<(), BpfError> { + pub fn relocate_calls(&mut self) -> Result<(), BpfRelocationError> { for (name, program) in self.programs.iter_mut() { let linker = FunctionLinker::new( self.text_section_index, @@ -109,9 +117,9 @@ impl Object { ); linker .link(program) - .map_err(|error| BpfError::RelocationError { - function: name.clone(), - error: Box::new(error), + .map_err(|error| BpfRelocationError{ + function: name.to_owned(), + error, })?; } @@ -122,8 +130,8 @@ impl Object { fn relocate_maps<'a, I: Iterator>( fun: &mut Function, relocations: I, - maps_by_section: &HashMap, - maps_by_symbol: &HashMap, + maps_by_section: &HashMap, &Map)>, + maps_by_symbol: &HashMap, &Map)>, symbol_table: &HashMap, text_section_index: Option, ) -> Result<(), RelocationError> { @@ -166,7 +174,7 @@ fn relocate_maps<'a, I: Iterator>( continue; } - let (name, map) = if maps_by_symbol.contains_key(&rel.symbol_index) { + let (name, fd, map) = if maps_by_symbol.contains_key(&rel.symbol_index) { maps_by_symbol .get(&rel.symbol_index) .ok_or(RelocationError::SectionNotFound { @@ -184,12 +192,12 @@ fn relocate_maps<'a, I: Iterator>( })? }; - let map_fd = map.fd.ok_or_else(|| RelocationError::MapNotCreated { + let map_fd = fd.ok_or_else(|| RelocationError::MapNotCreated { name: (*name).into(), section_index, })?; - if !map.obj.data().is_empty() { + if !map.data().is_empty() { instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_VALUE as u8); instructions[ins_index + 1].imm = instructions[ins_index].imm + sym.address as i32; } else { @@ -437,10 +445,9 @@ fn insn_is_call(ins: &bpf_insn) -> bool { #[cfg(test)] mod test { use crate::{ - bpf_map_def, - maps::MapData, + maps::bpf_map_def, obj::{self, BtfMap, LegacyMap, MapKind}, - BtfMapDef, + maps::BtfMapDef, }; use super::*; @@ -461,38 +468,28 @@ mod test { unsafe { std::ptr::read_unaligned(bytes.as_ptr() as *const _) } } - fn fake_legacy_map(fd: i32, symbol_index: usize) -> MapData { - MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - ..Default::default() - }, - section_index: 0, - symbol_index, - data: Vec::new(), - kind: MapKind::Other, - }), - fd: Some(fd), - btf_fd: None, - pinned: false, - } + fn fake_legacy_map(symbol_index: usize) -> Map { + obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + ..Default::default() + }, + section_index: 0, + symbol_index, + data: Vec::new(), + kind: MapKind::Other, + }) } - fn fake_btf_map(fd: i32, symbol_index: usize) -> MapData { - MapData { - obj: obj::Map::Btf(BtfMap { - def: BtfMapDef { - ..Default::default() - }, - section_index: 0, - symbol_index, - data: Vec::new(), - kind: MapKind::Other, - }), - fd: Some(fd), - btf_fd: None, - pinned: false, - } + fn fake_btf_map(symbol_index: usize) -> Map { + obj::Map::Btf(BtfMap { + def: BtfMapDef { + ..Default::default() + }, + section_index: 0, + symbol_index, + data: Vec::new(), + kind: MapKind::Other, + }) } fn fake_func(name: &str, instructions: Vec) -> Function { @@ -527,8 +524,8 @@ mod test { }]; let maps_by_section = HashMap::new(); - let map = fake_legacy_map(1, 1); - let maps_by_symbol = HashMap::from([(1, ("test_map", &map))]); + let map = fake_legacy_map(1); + let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]); relocate_maps( &mut fun, @@ -579,10 +576,10 @@ mod test { ]; let maps_by_section = HashMap::new(); - let map_1 = fake_legacy_map(1, 1); - let map_2 = fake_legacy_map(2, 2); + let map_1 = fake_legacy_map(1); + let map_2 = fake_legacy_map(2); let maps_by_symbol = - HashMap::from([(1, ("test_map_1", &map_1)), (2, ("test_map_2", &map_2))]); + HashMap::from([(1, ("test_map_1", Some(1), &map_1)), (2, ("test_map_2", Some(2), &map_2))]); relocate_maps( &mut fun, @@ -622,8 +619,8 @@ mod test { }]; let maps_by_section = HashMap::new(); - let map = fake_btf_map(1, 1); - let maps_by_symbol = HashMap::from([(1, ("test_map", &map))]); + let map = fake_btf_map(1); + let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]); relocate_maps( &mut fun, @@ -674,10 +671,10 @@ mod test { ]; let maps_by_section = HashMap::new(); - let map_1 = fake_btf_map(1, 1); - let map_2 = fake_btf_map(2, 2); + let map_1 = fake_btf_map(1); + let map_2 = fake_btf_map(2); let maps_by_symbol = - HashMap::from([(1, ("test_map_1", &map_1)), (2, ("test_map_2", &map_2))]); + HashMap::from([(1, ("test_map_1", Some(1), &map_1)), (2, ("test_map_2", Some(2), &map_2))]); relocate_maps( &mut fun, diff --git a/aya-obj/src/util.rs b/aya-obj/src/util.rs new file mode 100644 index 00000000..6c208ec9 --- /dev/null +++ b/aya-obj/src/util.rs @@ -0,0 +1,7 @@ +use core::{mem, slice}; + +/// bytes_of converts a to a byte slice +pub(crate) unsafe fn bytes_of(val: &T) -> &[u8] { + let size = mem::size_of::(); + slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size) +} \ No newline at end of file diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index f9e209c6..d1988f67 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -1,13 +1,13 @@ use std::{ borrow::Cow, collections::{HashMap, HashSet}, - error::Error, ffi::CString, fs, io, os::{raw::c_int, unix::io::RawFd}, path::{Path, PathBuf}, }; +use aya_obj::{btf::{BtfFeatures, BtfRelocationError}, relocation::BpfRelocationError}; use log::debug; use thiserror::Error; @@ -58,75 +58,15 @@ unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64, u128, i128); // It only makes sense that an array of POD types is itself POD unsafe impl Pod for [T; N] {} -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub(crate) struct bpf_map_def { - // minimum features required by old BPF programs - pub(crate) map_type: u32, - pub(crate) key_size: u32, - pub(crate) value_size: u32, - pub(crate) max_entries: u32, - pub(crate) map_flags: u32, - // optional features - pub(crate) id: u32, - pub(crate) pinning: PinningType, -} - -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub(crate) struct BtfMapDef { - pub(crate) map_type: u32, - pub(crate) key_size: u32, - pub(crate) value_size: u32, - pub(crate) max_entries: u32, - pub(crate) map_flags: u32, - pub(crate) pinning: PinningType, - pub(crate) btf_key_type_id: u32, - pub(crate) btf_value_type_id: u32, -} - -#[repr(u32)] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(crate) enum PinningType { - None = 0, - ByName = 1, -} - -#[derive(Debug, Error)] -pub(crate) enum PinningError { - #[error("unsupported pinning type")] - Unsupported, -} - -impl TryFrom for PinningType { - type Error = PinningError; - - fn try_from(value: u32) -> Result { - match value { - 0 => Ok(PinningType::None), - 1 => Ok(PinningType::ByName), - _ => Err(PinningError::Unsupported), - } - } -} - -impl Default for PinningType { - fn default() -> Self { - PinningType::None - } -} +pub use aya_obj::maps::bpf_map_def; +pub use aya_obj::maps::BtfMapDef; +pub use aya_obj::maps::PinningType; // Features implements BPF and BTF feature detection #[derive(Default, Debug)] pub(crate) struct Features { pub bpf_name: bool, - pub btf: bool, - pub btf_func: bool, - pub btf_func_global: bool, - pub btf_datasec: bool, - pub btf_float: bool, - pub btf_decl_tag: bool, - pub btf_type_tag: bool, + pub btf: Option, } impl Features { @@ -134,33 +74,37 @@ impl Features { self.bpf_name = is_prog_name_supported(); debug!("[FEAT PROBE] BPF program name support: {}", self.bpf_name); - self.btf = is_btf_supported(); - debug!("[FEAT PROBE] BTF support: {}", self.btf); + self.btf = if is_btf_supported() { + Some(BtfFeatures::default()) + } else { + None + }; + debug!("[FEAT PROBE] BTF support: {}", self.btf.is_some()); - if self.btf { - self.btf_func = is_btf_func_supported(); - debug!("[FEAT PROBE] BTF func support: {}", self.btf_func); + if let Some(ref mut btf) = self.btf { + btf.btf_func = is_btf_func_supported(); + debug!("[FEAT PROBE] BTF func support: {}", btf.btf_func); - self.btf_func_global = is_btf_func_global_supported(); + btf.btf_func_global = is_btf_func_global_supported(); debug!( "[FEAT PROBE] BTF global func support: {}", - self.btf_func_global + btf.btf_func_global ); - self.btf_datasec = is_btf_datasec_supported(); + btf.btf_datasec = is_btf_datasec_supported(); debug!( "[FEAT PROBE] BTF var and datasec support: {}", - self.btf_datasec + btf.btf_datasec ); - self.btf_float = is_btf_float_supported(); - debug!("[FEAT PROBE] BTF float support: {}", self.btf_float); + btf.btf_float = is_btf_float_supported(); + debug!("[FEAT PROBE] BTF float support: {}", btf.btf_float); - self.btf_decl_tag = is_btf_decl_tag_supported(); - debug!("[FEAT PROBE] BTF decl_tag support: {}", self.btf_decl_tag); + btf.btf_decl_tag = is_btf_decl_tag_supported(); + debug!("[FEAT PROBE] BTF decl_tag support: {}", btf.btf_decl_tag); - self.btf_type_tag = is_btf_type_tag_supported(); - debug!("[FEAT PROBE] BTF type_tag support: {}", self.btf_type_tag); + btf.btf_type_tag = is_btf_type_tag_supported(); + debug!("[FEAT PROBE] BTF type_tag support: {}", btf.btf_type_tag); } } } @@ -413,12 +357,12 @@ impl<'a> BpfLoader<'a> { let mut obj = Object::parse(data)?; obj.patch_map_data(self.globals.clone())?; - let btf_fd = if self.features.btf { + let btf_fd = if let Some(ref btf) = self.features.btf { if let Some(ref mut obj_btf) = obj.btf { // fixup btf let section_data = obj.section_sizes.clone(); let symbol_offsets = obj.symbol_offset_by_name.clone(); - obj_btf.fixup_and_sanitize(§ion_data, &symbol_offsets, &self.features)?; + obj_btf.fixup_and_sanitize(§ion_data, &symbol_offsets, btf)?; // load btf to the kernel let raw_btf = obj_btf.to_bytes(); Some(load_btf(raw_btf)?) @@ -497,7 +441,7 @@ impl<'a> BpfLoader<'a> { maps.insert(name, map); } - obj.relocate_maps(&maps)?; + obj.relocate_maps(maps.iter().map(|(s, data)| (s.as_str(), data.fd, &data.obj)))?; obj.relocate_calls()?; let programs = obj @@ -921,14 +865,12 @@ pub enum BpfError { BtfError(#[from] BtfError), /// Error performing relocations - #[error("error relocating `{function}`")] - RelocationError { - /// The function name - function: String, - #[source] - /// The original error - error: Box, - }, + #[error("error relocating function")] + RelocationError(#[from] BpfRelocationError), + + /// Error performing relocations + #[error("error relocating section")] + BtfRelocationError(#[from] BtfRelocationError), /// No BTF parsed for object #[error("no BTF parsed for object")] diff --git a/aya/src/lib.rs b/aya/src/lib.rs index 8d235095..8d5be4d9 100644 --- a/aya/src/lib.rs +++ b/aya/src/lib.rs @@ -46,9 +46,9 @@ extern crate lazy_static; extern crate bitflags; mod bpf; -use aya_obj::generated as generated; +use aya_obj::generated; pub mod maps; -mod obj; +use aya_obj as obj; pub mod pin; pub mod programs; mod sys; diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index 2a87a91d..4463116c 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -1,7 +1,6 @@ //! Cgroup socket programs. -use thiserror::Error; +pub use aya_obj::programs::CgroupSockAttachType; -use crate::generated::bpf_attach_type; use std::{ hash::Hash, os::unix::prelude::{AsRawFd, RawFd}, @@ -154,51 +153,3 @@ define_link_wrapper!( CgroupSockLinkInner, CgroupSockLinkIdInner ); - -/// Defines where to attach a [`CgroupSock`] program. -#[derive(Copy, Clone, Debug)] -pub enum CgroupSockAttachType { - /// Called after the IPv4 bind events. - PostBind4, - /// Called after the IPv6 bind events. - PostBind6, - /// Attach to IPv4 connect events. - SockCreate, - /// Attach to IPv6 connect events. - SockRelease, -} - -impl Default for CgroupSockAttachType { - // The kernel checks for a 0 attach_type and sets it to sock_create - // We may as well do that here also - fn default() -> Self { - CgroupSockAttachType::SockCreate - } -} - -impl From for bpf_attach_type { - fn from(s: CgroupSockAttachType) -> bpf_attach_type { - match s { - CgroupSockAttachType::PostBind4 => bpf_attach_type::BPF_CGROUP_INET4_POST_BIND, - CgroupSockAttachType::PostBind6 => bpf_attach_type::BPF_CGROUP_INET6_POST_BIND, - CgroupSockAttachType::SockCreate => bpf_attach_type::BPF_CGROUP_INET_SOCK_CREATE, - CgroupSockAttachType::SockRelease => bpf_attach_type::BPF_CGROUP_INET_SOCK_RELEASE, - } - } -} - -#[derive(Debug, Error)] -#[error("{0} is not a valid attach type for a CGROUP_SOCK program")] -pub(crate) struct InvalidAttachType(String); - -impl CgroupSockAttachType { - pub(crate) fn try_from(value: &str) -> Result { - match value { - "post_bind4" => Ok(CgroupSockAttachType::PostBind4), - "post_bind6" => Ok(CgroupSockAttachType::PostBind6), - "sock_create" => Ok(CgroupSockAttachType::SockCreate), - "sock_release" => Ok(CgroupSockAttachType::SockRelease), - _ => Err(InvalidAttachType(value.to_owned())), - } - } -} diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 2f8aac7d..12345b5e 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -1,7 +1,6 @@ //! Cgroup socket address programs. -use thiserror::Error; +pub use aya_obj::programs::CgroupSockAddrAttachType; -use crate::generated::bpf_attach_type; use std::{ hash::Hash, os::unix::prelude::{AsRawFd, RawFd}, @@ -160,75 +159,3 @@ define_link_wrapper!( CgroupSockAddrLinkInner, CgroupSockAddrLinkIdInner ); - -/// Defines where to attach a [`CgroupSockAddr`] program. -#[derive(Copy, Clone, Debug)] -pub enum CgroupSockAddrAttachType { - /// Attach to IPv4 bind events. - Bind4, - /// Attach to IPv6 bind events. - Bind6, - /// Attach to IPv4 connect events. - Connect4, - /// Attach to IPv6 connect events. - Connect6, - /// Attach to IPv4 getpeername events. - GetPeerName4, - /// Attach to IPv6 getpeername events. - GetPeerName6, - /// Attach to IPv4 getsockname events. - GetSockName4, - /// Attach to IPv6 getsockname events. - GetSockName6, - /// Attach to IPv4 udp_sendmsg events. - UDPSendMsg4, - /// Attach to IPv6 udp_sendmsg events. - UDPSendMsg6, - /// Attach to IPv4 udp_recvmsg events. - UDPRecvMsg4, - /// Attach to IPv6 udp_recvmsg events. - UDPRecvMsg6, -} - -impl From for bpf_attach_type { - fn from(s: CgroupSockAddrAttachType) -> bpf_attach_type { - match s { - CgroupSockAddrAttachType::Bind4 => bpf_attach_type::BPF_CGROUP_INET4_BIND, - CgroupSockAddrAttachType::Bind6 => bpf_attach_type::BPF_CGROUP_INET6_BIND, - CgroupSockAddrAttachType::Connect4 => bpf_attach_type::BPF_CGROUP_INET4_CONNECT, - CgroupSockAddrAttachType::Connect6 => bpf_attach_type::BPF_CGROUP_INET6_CONNECT, - CgroupSockAddrAttachType::GetPeerName4 => bpf_attach_type::BPF_CGROUP_INET4_GETPEERNAME, - CgroupSockAddrAttachType::GetPeerName6 => bpf_attach_type::BPF_CGROUP_INET6_GETPEERNAME, - CgroupSockAddrAttachType::GetSockName4 => bpf_attach_type::BPF_CGROUP_INET4_GETSOCKNAME, - CgroupSockAddrAttachType::GetSockName6 => bpf_attach_type::BPF_CGROUP_INET6_GETSOCKNAME, - CgroupSockAddrAttachType::UDPSendMsg4 => bpf_attach_type::BPF_CGROUP_UDP4_SENDMSG, - CgroupSockAddrAttachType::UDPSendMsg6 => bpf_attach_type::BPF_CGROUP_UDP6_SENDMSG, - CgroupSockAddrAttachType::UDPRecvMsg4 => bpf_attach_type::BPF_CGROUP_UDP4_RECVMSG, - CgroupSockAddrAttachType::UDPRecvMsg6 => bpf_attach_type::BPF_CGROUP_UDP6_RECVMSG, - } - } -} - -#[derive(Debug, Error)] -#[error("{0} is not a valid attach type for a CGROUP_SOCK_ADDR program")] -pub(crate) struct InvalidAttachType(String); - -impl CgroupSockAddrAttachType { - pub(crate) fn try_from(value: &str) -> Result { - match value { - "bind4" => Ok(CgroupSockAddrAttachType::Bind4), - "bind6" => Ok(CgroupSockAddrAttachType::Bind6), - "connect4" => Ok(CgroupSockAddrAttachType::Connect4), - "connect6" => Ok(CgroupSockAddrAttachType::Connect6), - "getpeername4" => Ok(CgroupSockAddrAttachType::GetPeerName4), - "getpeername6" => Ok(CgroupSockAddrAttachType::GetPeerName6), - "getsockname4" => Ok(CgroupSockAddrAttachType::GetSockName4), - "getsockname6" => Ok(CgroupSockAddrAttachType::GetSockName6), - "sendmsg4" => Ok(CgroupSockAddrAttachType::UDPSendMsg4), - "sendmsg6" => Ok(CgroupSockAddrAttachType::UDPSendMsg6), - "recvmsg4" => Ok(CgroupSockAddrAttachType::UDPRecvMsg4), - "recvmsg6" => Ok(CgroupSockAddrAttachType::UDPRecvMsg6), - _ => Err(InvalidAttachType(value.to_owned())), - } - } -} diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index 669e4f99..de4c1f43 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -1,5 +1,5 @@ //! Cgroup socket option programs. -use thiserror::Error; +pub use aya_obj::programs::CgroupSockoptAttachType; use std::{ hash::Hash, @@ -9,7 +9,7 @@ use std::{ use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT, programs::{ - bpf_attach_type, define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, + define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, sys::{bpf_link_create, bpf_prog_attach, kernel_version}, @@ -155,35 +155,3 @@ define_link_wrapper!( CgroupSockoptLinkInner, CgroupSockoptLinkIdInner ); - -/// Defines where to attach a [`CgroupSockopt`] program. -#[derive(Copy, Clone, Debug)] -pub enum CgroupSockoptAttachType { - /// Attach to GetSockopt. - Get, - /// Attach to SetSockopt. - Set, -} - -impl From for bpf_attach_type { - fn from(s: CgroupSockoptAttachType) -> bpf_attach_type { - match s { - CgroupSockoptAttachType::Get => bpf_attach_type::BPF_CGROUP_GETSOCKOPT, - CgroupSockoptAttachType::Set => bpf_attach_type::BPF_CGROUP_SETSOCKOPT, - } - } -} - -#[derive(Debug, Error)] -#[error("{0} is not a valid attach type for a CGROUP_SOCKOPT program")] -pub(crate) struct InvalidAttachType(String); - -impl CgroupSockoptAttachType { - pub(crate) fn try_from(value: &str) -> Result { - match value { - "getsockopt" => Ok(CgroupSockoptAttachType::Get), - "setsockopt" => Ok(CgroupSockoptAttachType::Set), - _ => Err(InvalidAttachType(value.to_owned())), - } - } -}