aya, aya-obj: refactor map relocations

Clearly split the code between `.maps`, `maps` and data maps (bss, data,
rodata). Sprinkle comments.

Remove MapKind which was effectively only needed since we used to have
one variant - BpfSectionKind::Data - to represent all data maps. Instead
add explicit BpfSectionKind::{Data, Rodata, Bss} variants and match on
those when we initialize maps.
pull/572/head
Alessandro Decina 1 year ago
parent 5c4f1d69a6
commit 401ea5e848

@ -2,7 +2,10 @@
use core::mem; use core::mem;
use crate::thiserror::{self, Error}; use crate::{
thiserror::{self, Error},
BpfSectionKind,
};
use alloc::vec::Vec; use alloc::vec::Vec;
/// Invalid map type encontered /// Invalid map type encontered
@ -139,33 +142,6 @@ pub struct bpf_map_def {
/// The first five __u32 of `bpf_map_def` must be defined. /// The first five __u32 of `bpf_map_def` must be defined.
pub(crate) const MINIMUM_MAP_SIZE: usize = mem::size_of::<u32>() * 5; pub(crate) const MINIMUM_MAP_SIZE: usize = mem::size_of::<u32>() * 5;
/// Kinds of maps
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MapKind {
/// A map holding `.bss` section data
Bss,
/// A map holding `.data` section data
Data,
/// A map holding `.rodata` section data
Rodata,
/// Other maps
Other,
}
impl From<&str> for MapKind {
fn from(s: &str) -> Self {
if s == ".bss" {
MapKind::Bss
} else if s.starts_with(".data") {
MapKind::Data
} else if s.starts_with(".rodata") {
MapKind::Rodata
} else {
MapKind::Other
}
}
}
/// Map data defined in `maps` or `.maps` sections /// Map data defined in `maps` or `.maps` sections
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Map { pub enum Map {
@ -248,14 +224,6 @@ impl Map {
} }
} }
/// Returns the map kind
pub fn kind(&self) -> MapKind {
match self {
Map::Legacy(m) => m.kind,
Map::Btf(m) => m.kind,
}
}
/// Returns the section index /// Returns the section index
pub fn section_index(&self) -> usize { pub fn section_index(&self) -> usize {
match self { match self {
@ -264,11 +232,22 @@ impl Map {
} }
} }
/// Returns the symbol index /// Returns the section kind.
pub fn symbol_index(&self) -> usize { pub fn section_kind(&self) -> BpfSectionKind {
match self {
Map::Legacy(m) => m.section_kind,
Map::Btf(_) => BpfSectionKind::BtfMaps,
}
}
/// Returns the symbol index.
///
/// This is `None` for data maps (.bss, .data and .rodata) since those don't
/// need symbols in order to be relocated.
pub fn symbol_index(&self) -> Option<usize> {
match self { match self {
Map::Legacy(m) => m.symbol_index, Map::Legacy(m) => m.symbol_index,
Map::Btf(m) => m.symbol_index, Map::Btf(m) => Some(m.symbol_index),
} }
} }
} }
@ -283,12 +262,16 @@ pub struct LegacyMap {
pub def: bpf_map_def, pub def: bpf_map_def,
/// The section index /// The section index
pub section_index: usize, pub section_index: usize,
/// The symbol index /// The section kind
pub symbol_index: usize, pub section_kind: BpfSectionKind,
/// The symbol index.
///
/// This is None for data maps (.bss .data and .rodata). We don't need
/// symbols to relocate those since they don't contain multiple maps, but
/// are just a flat array of bytes.
pub symbol_index: Option<usize>,
/// The map data /// The map data
pub data: Vec<u8>, pub data: Vec<u8>,
/// The map kind
pub kind: MapKind,
} }
/// A BTF-defined map, most likely from a `.maps` section. /// A BTF-defined map, most likely from a `.maps` section.
@ -298,6 +281,5 @@ pub struct BtfMap {
pub def: BtfMapDef, pub def: BtfMapDef,
pub(crate) section_index: usize, pub(crate) section_index: usize,
pub(crate) symbol_index: usize, pub(crate) symbol_index: usize,
pub(crate) kind: MapKind,
pub(crate) data: Vec<u8>, pub(crate) data: Vec<u8>,
} }

@ -15,7 +15,7 @@ use object::{
}; };
use crate::{ use crate::{
maps::{BtfMap, LegacyMap, Map, MapKind, MINIMUM_MAP_SIZE}, maps::{BtfMap, LegacyMap, Map, MINIMUM_MAP_SIZE},
relocation::*, relocation::*,
thiserror::{self, Error}, thiserror::{self, Error},
util::HashMap, util::HashMap,
@ -794,7 +794,6 @@ impl Object {
def, def,
section_index: section.index.0, section_index: section.index.0,
symbol_index, symbol_index,
kind: MapKind::Other,
data: Vec::new(), data: Vec::new(),
}), }),
); );
@ -820,9 +819,9 @@ impl Object {
self.section_sizes self.section_sizes
.insert(section.name.to_owned(), section.size); .insert(section.name.to_owned(), section.size);
match section.kind { match section.kind {
BpfSectionKind::Data => { BpfSectionKind::Data | BpfSectionKind::Rodata | BpfSectionKind::Bss => {
self.maps self.maps
.insert(section.name.to_string(), parse_map(&section, section.name)?); .insert(section.name.to_string(), parse_data_map_section(&section)?);
} }
BpfSectionKind::Text => self.parse_text_section(section)?, BpfSectionKind::Text => self.parse_text_section(section)?,
BpfSectionKind::Btf => self.parse_btf(&section)?, BpfSectionKind::Btf => self.parse_btf(&section)?,
@ -909,16 +908,16 @@ fn parse_maps_section<'a, I: Iterator<Item = &'a Symbol>>(
name.to_string(), name.to_string(),
Map::Legacy(LegacyMap { Map::Legacy(LegacyMap {
section_index: section.index.0, section_index: section.index.0,
symbol_index: sym.index, section_kind: section.kind,
symbol_index: Some(sym.index),
def, def,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}), }),
); );
have_symbols = true; have_symbols = true;
} }
if !have_symbols { if !have_symbols {
return Err(ParseError::NoSymbolsForMapSection); return Err(ParseError::NoSymbolsForMapsSection);
} }
Ok(()) Ok(())
@ -995,17 +994,32 @@ pub enum ParseError {
NoBTF, NoBTF,
} }
#[derive(Debug)] /// The kind of an ELF section.
enum BpfSectionKind { #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BpfSectionKind {
/// Undefined
Undefined, Undefined,
/// `maps`
Maps, Maps,
/// `.maps`
BtfMaps, BtfMaps,
/// A program section
Program, Program,
/// `.data`
Data, Data,
/// `.rodata`
Rodata,
/// `.bss`
Bss,
/// `.text`
Text, Text,
/// `.BTF`
Btf, Btf,
/// `.BTF.ext`
BtfExt, BtfExt,
/// `license`
License, License,
/// `version`
Version, Version,
} }
@ -1172,10 +1186,11 @@ impl From<KernelVersion> for u32 {
} }
} }
fn parse_map(section: &Section, name: &str) -> Result<Map, ParseError> { // Parsed '.bss' '.data' and '.rodata' sections. These sections are arrays of
let kind = MapKind::from(name); // bytes and are relocated based on their section index.
let (def, data) = match kind { fn parse_data_map_section(section: &Section) -> Result<Map, ParseError> {
MapKind::Bss | MapKind::Data | MapKind::Rodata => { let (def, data) = match section.kind {
BpfSectionKind::Bss | BpfSectionKind::Data | BpfSectionKind::Rodata => {
let def = bpf_map_def { let def = bpf_map_def {
map_type: BPF_MAP_TYPE_ARRAY as u32, map_type: BPF_MAP_TYPE_ARRAY as u32,
key_size: mem::size_of::<u32>() as u32, key_size: mem::size_of::<u32>() as u32,
@ -1183,7 +1198,7 @@ fn parse_map(section: &Section, name: &str) -> Result<Map, ParseError> {
// .bss will always have data.len() == 0 // .bss will always have data.len() == 0
value_size: section.size as u32, value_size: section.size as u32,
max_entries: 1, max_entries: 1,
map_flags: if kind == MapKind::Rodata { map_flags: if section.kind == BpfSectionKind::Rodata {
BPF_F_RDONLY_PROG BPF_F_RDONLY_PROG
} else { } else {
0 0
@ -1192,14 +1207,15 @@ fn parse_map(section: &Section, name: &str) -> Result<Map, ParseError> {
}; };
(def, section.data.to_vec()) (def, section.data.to_vec())
} }
MapKind::Other => (parse_map_def(name, section.data)?, Vec::new()), _ => unreachable!(),
}; };
Ok(Map::Legacy(LegacyMap { Ok(Map::Legacy(LegacyMap {
section_index: section.index.0, section_index: section.index.0,
symbol_index: 0, section_kind: section.kind,
// Data maps don't require symbols to be relocated
symbol_index: None,
def, def,
data, data,
kind,
})) }))
} }
@ -1319,8 +1335,6 @@ pub fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
section_index: 0, section_index: 0,
symbol_index: 0, symbol_index: 0,
data: Vec::new(), data: Vec::new(),
// We should never be loading the .bss or .data or .rodata FDs
kind: MapKind::Other,
}) })
} else { } else {
Map::Legacy(LegacyMap { Map::Legacy(LegacyMap {
@ -1334,10 +1348,9 @@ pub fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
id: info.id, id: info.id,
}, },
section_index: 0, section_index: 0,
symbol_index: 0, symbol_index: None,
section_kind: BpfSectionKind::Undefined,
data: Vec::new(), data: Vec::new(),
// We should never be loading the .bss or .data or .rodata FDs
kind: MapKind::Other,
}) })
} }
} }
@ -1523,65 +1536,21 @@ mod tests {
assert_eq!(parse_map_def("foo", &buf).unwrap(), def); assert_eq!(parse_map_def("foo", &buf).unwrap(), def);
} }
#[test]
fn test_parse_map_error() {
assert!(matches!(
parse_map(&fake_section(BpfSectionKind::Maps, "maps/foo", &[]), "foo",),
Err(ParseError::InvalidMapDefinition { .. })
));
}
#[test]
fn test_parse_map() {
assert!(matches!(
parse_map(
&fake_section(
BpfSectionKind::Maps,
"maps/foo",
bytes_of(&bpf_map_def {
map_type: 1,
key_size: 2,
value_size: 3,
max_entries: 4,
map_flags: 5,
id: 0,
pinning: PinningType::None,
})
),
"foo"
),
Ok(Map::Legacy(LegacyMap{
section_index: 0,
def: bpf_map_def {
map_type: 1,
key_size: 2,
value_size: 3,
max_entries: 4,
map_flags: 5,
id: 0,
pinning: PinningType::None,
},
data,
..
})) if data.is_empty()
))
}
#[test] #[test]
fn test_parse_map_data() { fn test_parse_map_data() {
let map_data = b"map data"; let map_data = b"map data";
assert!(matches!( assert!(matches!(
parse_map( parse_data_map_section(
&fake_section( &fake_section(
BpfSectionKind::Data, BpfSectionKind::Data,
".bss", ".bss",
map_data, map_data,
), ),
".bss"
), ),
Ok(Map::Legacy(LegacyMap { Ok(Map::Legacy(LegacyMap {
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Data,
symbol_index: None,
def: bpf_map_def { def: bpf_map_def {
map_type: _map_type, map_type: _map_type,
key_size: 4, key_size: 4,
@ -1592,8 +1561,7 @@ mod tests {
pinning: PinningType::None, pinning: PinningType::None,
}, },
data, data,
kind })) if data == map_data && value_size == map_data.len() as u32
})) if data == map_data && value_size == map_data.len() as u32 && kind == MapKind::Bss
)) ))
} }
@ -2240,9 +2208,9 @@ mod tests {
pinning: PinningType::None, pinning: PinningType::None,
}, },
section_index: 1, section_index: 1,
symbol_index: 1, section_kind: BpfSectionKind::Rodata,
symbol_index: Some(1),
data: vec![0, 0, 0], data: vec![0, 0, 0],
kind: MapKind::Rodata,
}), }),
); );
obj.symbols_by_index.insert( obj.symbols_by_index.insert(

@ -15,6 +15,7 @@ use crate::{
obj::{Function, Object, Program}, obj::{Function, Object, Program},
thiserror::{self, Error}, thiserror::{self, Error},
util::HashMap, util::HashMap,
BpfSectionKind,
}; };
pub(crate) const INS_SIZE: usize = mem::size_of::<bpf_insn>(); pub(crate) const INS_SIZE: usize = mem::size_of::<bpf_insn>();
@ -109,7 +110,9 @@ impl Object {
let mut maps_by_symbol = HashMap::new(); let mut maps_by_symbol = HashMap::new();
for (name, fd, map) in maps { for (name, fd, map) in maps {
maps_by_section.insert(map.section_index(), (name, fd, map)); maps_by_section.insert(map.section_index(), (name, fd, map));
maps_by_symbol.insert(map.symbol_index(), (name, fd, map)); if let Some(index) = map.symbol_index() {
maps_by_symbol.insert(index, (name, fd, map));
}
} }
let functions = self let functions = self
@ -193,10 +196,9 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
index: rel.symbol_index, index: rel.symbol_index,
})?; })?;
let section_index = match sym.section_index { let Some(section_index) = sym.section_index else {
Some(index) => index,
// this is not a map relocation // this is not a map relocation
None => continue, continue;
}; };
// calls and relocation to .text symbols are handled in a separate step // calls and relocation to .text symbols are handled in a separate step
@ -204,23 +206,42 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
continue; continue;
} }
let (name, fd, map) = if maps_by_symbol.contains_key(&rel.symbol_index) { let (name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) {
maps_by_symbol let map = &m.2;
.get(&rel.symbol_index) debug!(
.ok_or(RelocationError::SectionNotFound { "relocating map by symbol index {}, kind {:?}",
symbol_index: rel.symbol_index, map.section_index(),
symbol_name: sym.name.clone(), map.section_kind()
section_index, );
})? debug_assert_eq!(map.symbol_index().unwrap(), rel.symbol_index);
m
} else { } else {
maps_by_section let Some(m) = maps_by_section.get(&section_index) else {
.get(&section_index) debug!(
.ok_or(RelocationError::SectionNotFound { "failed relocating map by section index {}",
section_index
);
return Err(RelocationError::SectionNotFound {
symbol_index: rel.symbol_index, symbol_index: rel.symbol_index,
symbol_name: sym.name.clone(), symbol_name: sym.name.clone(),
section_index, section_index,
})? });
};
let map = &m.2;
debug!(
"relocating map by section index {}, kind {:?}",
map.section_index(),
map.section_kind()
);
debug_assert_eq!(map.symbol_index(), None);
debug_assert!(matches!(
map.section_kind(),
BpfSectionKind::Bss | BpfSectionKind::Data | BpfSectionKind::Rodata
),);
m
}; };
debug_assert_eq!(map.section_index(), section_index);
let map_fd = fd.ok_or_else(|| RelocationError::MapNotCreated { let map_fd = fd.ok_or_else(|| RelocationError::MapNotCreated {
name: (*name).into(), name: (*name).into(),
@ -476,7 +497,10 @@ fn insn_is_call(ins: &bpf_insn) -> bool {
mod test { mod test {
use alloc::{string::ToString, vec, vec::Vec}; use alloc::{string::ToString, vec, vec::Vec};
use crate::maps::{bpf_map_def, BtfMap, BtfMapDef, LegacyMap, Map, MapKind}; use crate::{
maps::{bpf_map_def, BtfMap, BtfMapDef, LegacyMap, Map},
BpfSectionKind,
};
use super::*; use super::*;
@ -498,25 +522,20 @@ mod test {
fn fake_legacy_map(symbol_index: usize) -> Map { fn fake_legacy_map(symbol_index: usize) -> Map {
Map::Legacy(LegacyMap { Map::Legacy(LegacyMap {
def: bpf_map_def { def: Default::default(),
..Default::default()
},
section_index: 0, section_index: 0,
symbol_index, section_kind: BpfSectionKind::Undefined,
symbol_index: Some(symbol_index),
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}) })
} }
fn fake_btf_map(symbol_index: usize) -> Map { fn fake_btf_map(symbol_index: usize) -> Map {
Map::Btf(BtfMap { Map::Btf(BtfMap {
def: BtfMapDef { def: Default::default(),
..Default::default()
},
section_index: 0, section_index: 0,
symbol_index, symbol_index,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}) })
} }

@ -11,6 +11,7 @@ use aya_obj::{
btf::{BtfFeatures, BtfRelocationError}, btf::{BtfFeatures, BtfRelocationError},
generated::BPF_F_XDP_HAS_FRAGS, generated::BPF_F_XDP_HAS_FRAGS,
relocation::BpfRelocationError, relocation::BpfRelocationError,
BpfSectionKind,
}; };
use log::debug; use log::debug;
use thiserror::Error; use thiserror::Error;
@ -23,7 +24,6 @@ use crate::{
maps::{Map, MapData, MapError}, maps::{Map, MapData, MapError},
obj::{ obj::{
btf::{Btf, BtfError}, btf::{Btf, BtfError},
maps::MapKind,
Object, ParseError, ProgramSection, Object, ParseError, ProgramSection,
}, },
programs::{ programs::{
@ -415,14 +415,14 @@ impl<'a> BpfLoader<'a> {
} }
PinningType::None => map.create(&name)?, PinningType::None => map.create(&name)?,
}; };
if !map.obj.data().is_empty() && map.obj.kind() != MapKind::Bss { if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss {
bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0) bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0)
.map_err(|(_, io_error)| MapError::SyscallError { .map_err(|(_, io_error)| MapError::SyscallError {
call: "bpf_map_update_elem".to_owned(), call: "bpf_map_update_elem".to_owned(),
io_error, io_error,
})?; })?;
} }
if map.obj.kind() == MapKind::Rodata { if map.obj.section_kind() == BpfSectionKind::Rodata {
bpf_map_freeze(fd).map_err(|(_, io_error)| MapError::SyscallError { bpf_map_freeze(fd).map_err(|(_, io_error)| MapError::SyscallError {
call: "bpf_map_freeze".to_owned(), call: "bpf_map_freeze".to_owned(),
io_error, io_error,

@ -84,10 +84,7 @@ mod tests {
bpf_map_type::{BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, bpf_map_type::{BPF_MAP_TYPE_BLOOM_FILTER, BPF_MAP_TYPE_PERF_EVENT_ARRAY},
}, },
maps::{Map, MapData}, maps::{Map, MapData},
obj::{ obj::{self, maps::LegacyMap, BpfSectionKind},
self,
maps::{LegacyMap, MapKind},
},
sys::{override_syscall, SysResult, Syscall}, sys::{override_syscall, SysResult, Syscall},
}; };
use libc::{EFAULT, ENOENT}; use libc::{EFAULT, ENOENT};
@ -103,9 +100,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Maps,
symbol_index: None,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}) })
} }
@ -142,9 +139,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Maps,
symbol_index: None,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}), }),
fd: None, fd: None,
pinned: false, pinned: false,

@ -117,10 +117,7 @@ mod tests {
bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH}, bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH},
}, },
maps::{Map, MapData}, maps::{Map, MapData},
obj::{ obj::{self, maps::LegacyMap, BpfSectionKind},
self,
maps::{LegacyMap, MapKind},
},
sys::{override_syscall, SysResult, Syscall}, sys::{override_syscall, SysResult, Syscall},
}; };
@ -136,9 +133,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
section_kind: BpfSectionKind::Maps,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other, symbol_index: None,
symbol_index: 0,
}) })
} }
@ -267,9 +264,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Maps,
symbol_index: None,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}), }),
fd: Some(42), fd: Some(42),
pinned: false, pinned: false,

@ -247,10 +247,7 @@ mod tests {
bpf_map_type::{BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_PERF_EVENT_ARRAY}, bpf_map_type::{BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_PERF_EVENT_ARRAY},
}, },
maps::{Map, MapData}, maps::{Map, MapData},
obj::{ obj::{self, maps::LegacyMap, BpfSectionKind},
self,
maps::{LegacyMap, MapKind},
},
sys::{override_syscall, SysResult, Syscall}, sys::{override_syscall, SysResult, Syscall},
}; };
use libc::{EFAULT, ENOENT}; use libc::{EFAULT, ENOENT};
@ -266,9 +263,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Maps,
symbol_index: None,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}) })
} }
@ -322,9 +319,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Maps,
symbol_index: None,
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}), }),
fd: None, fd: None,
btf_fd: None, btf_fd: None,

@ -845,7 +845,7 @@ mod tests {
bpf_map_def, bpf_map_def,
generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH}, generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH},
maps::MapData, maps::MapData,
obj::maps::{LegacyMap, MapKind}, obj::{maps::LegacyMap, BpfSectionKind},
sys::{override_syscall, Syscall}, sys::{override_syscall, Syscall},
}; };
@ -861,9 +861,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
section_index: 0, section_index: 0,
symbol_index: 0, section_kind: BpfSectionKind::Maps,
symbol_index: Some(0),
data: Vec::new(), data: Vec::new(),
kind: MapKind::Other,
}) })
} }

Loading…
Cancel
Save