Browse Source

aya-obj: migrate aya::obj into a separate crate

To split the crate into two, several changes were made:
1. Most `pub(crate)` are now `pub` to allow access from Aya;
2. Parts of BpfError are merged into, for example, RelocationError;
3. BTF part of Features is moved into the new crate;
4. `#![deny(missing_docs)]` is removed temporarily;
5. Some other code gets moved into the new crate, mainly:
   - aya::{bpf_map_def, BtfMapDef, PinningType},
   - aya::programs::{CgroupSock*AttachType},

The new crate is currenly allowing missing_docs. Member visibility
will be adjusted later to minimize exposure of implementation details.

Refs: #473
Shenghui Ye 2 years ago
parent
commit
ac49827e20

+ 7 - 0
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"

+ 30 - 21
aya/src/obj/btf/btf.rs → 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<Btf, BtfError> {
+    pub fn parse(data: &[u8], endianness: Endianness) -> Result<Btf, BtfError> {
         if data.len() < mem::size_of::<btf_header>() {
             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<u32, BtfError> {
+    pub fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result<u32, BtfError> {
         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<u8> {
+    pub fn to_bytes(&self) -> Vec<u8> {
         // Safety: btf_header is POD
         let mut buf = unsafe { bytes_of::<btf_header>(&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<String, u64>,
         symbol_offsets: &HashMap<String, u64>,
-        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()
         };

+ 8 - 8
aya/src/obj/btf/info.rs → 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<bpf_func_info>,
@@ -64,7 +64,7 @@ impl FuncSecInfo {
         }
     }
 
-    pub(crate) fn func_info_bytes(&self) -> Vec<u8> {
+    pub fn func_info_bytes(&self) -> Vec<u8> {
         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<String, FuncSecInfo>,
 }
 
@@ -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<u8> {
+    pub fn line_info_bytes(&self) -> Vec<u8> {
         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()
     }
 }

+ 2 - 0
aya/src/obj/btf/mod.rs → aya-obj/src/btf/mod.rs

@@ -1,3 +1,5 @@
+//! BTF loading, parsing and relocation.
+
 #[allow(clippy::module_inception)]
 mod btf;
 mod info;

+ 57 - 76
aya/src/obj/btf/relocation.rs → 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>) -> 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::<u32, Vec<Candidate>>::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(&section_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<u32, Vec<Candidate<'target>>>,
-) -> Result<(), ErrorWrapper> {
+) -> Result<(), RelocationError> {
     for rel in relos {
         let instructions = &mut program.function.instructions;
         let ins_index = rel.ins_offset / std::mem::size_of::<bpf_insn>();
@@ -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<Option<AccessSpec<'target>>, ErrorWrapper> {
+) -> Result<Option<AccessSpec<'target>>, 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<Option<u32>, ErrorWrapper> {
+) -> Result<Option<u32>, 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<AccessSpec<'a>, ErrorWrapper> {
+    ) -> Result<AccessSpec<'a>, RelocationError> {
         let parts = spec
             .split(':')
             .map(|s| s.parse::<usize>())
@@ -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<ComputedRelocation, ErrorWrapper> {
+    ) -> Result<ComputedRelocation, RelocationError> {
         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::<bpf_insn>();
@@ -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<ComputedRelocationValue, ErrorWrapper> {
+    ) -> Result<ComputedRelocationValue, RelocationError> {
         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<ComputedRelocationValue, ErrorWrapper> {
+    ) -> Result<ComputedRelocationValue, RelocationError> {
         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<ComputedRelocationValue, ErrorWrapper> {
+    ) -> Result<ComputedRelocationValue, RelocationError> {
         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),
-}

+ 40 - 40
aya/src/obj/btf/types.rs → 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::<Self>()
     }
 
-    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::<Self>()
     }
 
-    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::<Self>()
     }
 
-    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::<Self>()
     }
 
-    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<u32> 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::<Self>()
     }
 
-    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::<Fwd>() + mem::size_of::<BtfParam>() * self.params.len()
     }
 
-    pub(crate) fn new(params: Vec<BtfParam>, return_type: u32) -> Self {
+    pub fn new(params: Vec<BtfParam>, 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<u32> 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::<Self>()
     }
 
-    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::<Fwd>() + mem::size_of::<DataSecEntry>() * self.entries.len()
     }
 
-    pub(crate) fn new(name_offset: u32, entries: Vec<DataSecEntry>, size: u32) -> Self {
+    pub fn new(name_offset: u32, entries: Vec<DataSecEntry>, 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::<Self>()
     }
 
-    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,

+ 0 - 53
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<u32> for super::bpf_map_type {
-        type Error = InvalidMapTypeError;
-
-        fn try_from(map_type: u32) -> Result<Self, Self::Error> {
-            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 }),
-            })
-        }
-    }
-}
-

+ 9 - 2
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::*;

+ 111 - 0
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<u32> for crate::generated::bpf_map_type {
+    type Error = InvalidMapTypeError;
+
+    fn try_from(map_type: u32) -> Result<Self, Self::Error> {
+        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<u32> for PinningType {
+    type Error = PinningError;
+
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        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,
+}

+ 71 - 68
aya/src/obj/mod.rs → 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::<u32>() * 5;
 
 #[derive(Clone)]
 pub struct Object {
-    pub(crate) endianness: Endianness,
+    pub endianness: Endianness,
     pub license: CString,
     pub kernel_version: KernelVersion,
     pub btf: Option<Btf>,
     pub btf_ext: Option<BtfExt>,
-    pub(crate) maps: HashMap<String, Map>,
-    pub(crate) programs: HashMap<String, Program>,
-    pub(crate) 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>,
+    pub maps: HashMap<String, Map>,
+    pub programs: HashMap<String, Program>,
+    pub functions: HashMap<u64, Function>,
+    pub relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
+    pub symbols_by_index: HashMap<usize, Symbol>,
+    pub section_sizes: HashMap<String, u64>,
     // 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<String, u64>,
-    pub(crate) text_section_index: Option<usize>,
+    pub symbol_offset_by_name: HashMap<String, u64>,
+    pub text_section_index: Option<usize>,
 }
 
 #[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<u8> {
+    pub 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 {
+    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<u8>,
-    pub(crate) kind: MapKind,
+    pub def: bpf_map_def,
+    pub section_index: usize,
+    pub symbol_index: usize,
+    pub data: Vec<u8>,
+    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<u8>,
+    pub def: BtfMapDef,
+    pub section_index: usize,
+    pub symbol_index: usize,
+    pub kind: MapKind,
+    pub 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 {
+    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<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 {
+    pub address: u64,
+    pub name: String,
+    pub section_index: SectionIndex,
+    pub section_offset: usize,
+    pub instructions: Vec<bpf_insn>,
+    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<Object, BpfError> {
+    pub fn parse(data: &[u8]) -> Result<Object, ParseError> {
         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<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 +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::<Vec<_>>();
         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<u8> },
 
@@ -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<Vec<bpf_insn>, ParseError> {
+pub fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
     if data.len() % mem::size_of::<bpf_insn>() > 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(_))
         ))
     }
 

+ 52 - 0
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<CgroupSockAttachType> 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<CgroupSockAttachType, InvalidAttachType> {
+        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())),
+        }
+    }
+}

+ 76 - 0
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<CgroupSockAddrAttachType> 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<CgroupSockAddrAttachType, InvalidAttachType> {
+        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())),
+        }
+    }
+}

+ 36 - 0
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<CgroupSockoptAttachType> 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<CgroupSockoptAttachType, InvalidAttachType> {
+        match value {
+            "getsockopt" => Ok(CgroupSockoptAttachType::Get),
+            "setsockopt" => Ok(CgroupSockoptAttachType::Set),
+            _ => Err(InvalidAttachType(value.to_owned())),
+        }
+    }
+}

+ 9 - 0
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;

+ 67 - 70
aya/src/obj/relocation.rs → 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::<bpf_insn>();
 
+#[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<usize>,
     pub(crate) name: Option<String>,
@@ -62,16 +70,16 @@ pub(crate) struct Symbol {
 }
 
 impl Object {
-    pub fn relocate_maps(&mut self, maps: &HashMap<String, MapData>) -> Result<(), BpfError> {
-        let maps_by_section = maps
-            .iter()
-            .map(|(name, map)| (map.obj.section_index(), (name.as_str(), map)))
-            .collect::<HashMap<_, _>>();
-
-        let maps_by_symbol = maps
-            .iter()
-            .map(|(name, map)| (map.obj.symbol_index(), (name.as_str(), map)))
-            .collect::<HashMap<_, _>>();
+    pub fn relocate_maps<'a, I: Iterator<Item = (&'a str, Option<i32>, &'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<Item = &'a Relocation>>(
     fun: &mut Function,
     relocations: I,
-    maps_by_section: &HashMap<usize, (&str, &MapData)>,
-    maps_by_symbol: &HashMap<usize, (&str, &MapData)>,
+    maps_by_section: &HashMap<usize, (&str, Option<i32>, &Map)>,
+    maps_by_symbol: &HashMap<usize, (&str, Option<i32>, &Map)>,
     symbol_table: &HashMap<usize, Symbol>,
     text_section_index: Option<usize>,
 ) -> Result<(), RelocationError> {
@@ -166,7 +174,7 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
             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<Item = &'a Relocation>>(
                 })?
         };
 
-        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<bpf_insn>) -> 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,

+ 7 - 0
aya-obj/src/util.rs

@@ -0,0 +1,7 @@
+use core::{mem, slice};
+
+/// bytes_of converts a <T> to a byte slice
+pub(crate) unsafe fn bytes_of<T>(val: &T) -> &[u8] {
+    let size = mem::size_of::<T>();
+    slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size)
+}

+ 33 - 91
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<T: Pod, const N: usize> 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<u32> for PinningType {
-    type Error = PinningError;
-
-    fn try_from(value: u32) -> Result<Self, Self::Error> {
-        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<BtfFeatures>,
 }
 
 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(&section_data, &symbol_offsets, &self.features)?;
+                obj_btf.fixup_and_sanitize(&section_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<dyn Error + Send + Sync>,
-    },
+    #[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")]

+ 2 - 2
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;

+ 1 - 50
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<CgroupSockAttachType> 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<CgroupSockAttachType, InvalidAttachType> {
-        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())),
-        }
-    }
-}

+ 1 - 74
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<CgroupSockAddrAttachType> 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<CgroupSockAddrAttachType, InvalidAttachType> {
-        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())),
-        }
-    }
-}

+ 2 - 34
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<CgroupSockoptAttachType> 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<CgroupSockoptAttachType, InvalidAttachType> {
-        match value {
-            "getsockopt" => Ok(CgroupSockoptAttachType::Get),
-            "setsockopt" => Ok(CgroupSockoptAttachType::Set),
-            _ => Err(InvalidAttachType(value.to_owned())),
-        }
-    }
-}