Skip to content

Commit

Permalink
aya: Support multiple maps in map sections
Browse files Browse the repository at this point in the history
This commit uses the symbol table to discover all maps inside an ELF
section. We then divide the data in to equal sized chunks and parse them
using parse_map_def

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
  • Loading branch information
dave-tucker committed Jan 19, 2022
1 parent 1904aea commit 8536ec8
Showing 1 changed file with 101 additions and 4 deletions.
105 changes: 101 additions & 4 deletions aya/src/obj/mod.rs
Expand Up @@ -494,6 +494,38 @@ impl Object {
Ok(())
}

fn parse_map_section(
&mut self,
section: &Section,
symbols: Vec<Symbol>,
) -> Result<(), ParseError> {
if symbols.is_empty() {
return Err(ParseError::NoSymbolsInMapSection {});
}
let chunk_size = if section.size % symbols.len() as u64 == 0 {
section.size / symbols.len() as u64
} else {
return Err(ParseError::InvalidMapSection {
num_syms: symbols.len(),
});
};
for (i, data) in section.data.chunks(chunk_size as usize).enumerate() {
let s = symbols.get(i).unwrap();
let name = s.name.as_ref().ok_or(ParseError::NoMapName {})?;
let def = parse_map_def(name, data)?;
self.maps.insert(
name.to_string(),
Map {
section_index: section.index.0,
def,
data: data.to_vec(),
kind: MapKind::Other,
},
);
}
Ok(())
}

fn parse_section(&mut self, mut section: Section) -> Result<(), BpfError> {
let mut parts = section.name.rsplitn(2, '/').collect::<Vec<_>>();
parts.reverse();
Expand All @@ -517,9 +549,19 @@ impl Object {
BpfSectionKind::Btf => self.parse_btf(&section)?,
BpfSectionKind::BtfExt => self.parse_btf_ext(&section)?,
BpfSectionKind::Maps => {
let name = section.name.splitn(2, '/').last().unwrap();
self.maps
.insert(name.to_string(), parse_map(&section, name)?);
let symbols = self
.symbols_by_index
.values()
.cloned()
.filter(|s| {
if let Some(idx) = s.section_index {
idx == section.index
} else {
false
}
})
.collect();
self.parse_map_section(&section, symbols)?
}
BpfSectionKind::Program => {
let program = self.parse_program(&section)?;
Expand Down Expand Up @@ -600,6 +642,15 @@ pub enum ParseError {

#[error("map for section with index {index} not found")]
MapNotFound { index: usize },

#[error("map section does not have {num_syms} definitions")]
InvalidMapSection { num_syms: usize },

#[error("no map name provided")]
NoMapName {},

#[error("no symbols in map section")]
NoSymbolsInMapSection {},
}

#[derive(Debug)]
Expand Down Expand Up @@ -848,6 +899,22 @@ mod tests {
}
}

fn fake_sym(obj: &mut Object, section_index: usize, name: &str, size: u64) {
let idx = obj.symbols_by_index.len();
obj.symbols_by_index.insert(
idx + 1,
Symbol {
index: idx + 1,
section_index: Some(SectionIndex(section_index)),
name: Some(name.to_string()),
address: 0,
size,
is_definition: false,
is_text: false,
},
);
}

fn bytes_of<T>(val: &T) -> &[u8] {
// Safety: This is for testing only
unsafe { crate::util::bytes_of(val) }
Expand Down Expand Up @@ -1088,7 +1155,7 @@ mod tests {
#[test]
fn test_parse_section_map() {
let mut obj = fake_obj();

fake_sym(&mut obj, 0, "foo", mem::size_of::<bpf_map_def>() as u64);
assert_matches!(
obj.parse_section(fake_section(
BpfSectionKind::Maps,
Expand All @@ -1107,6 +1174,36 @@ mod tests {
assert!(obj.maps.get("foo").is_some());
}

#[test]
fn test_parse_section_multiple_maps() {
let mut obj = fake_obj();
fake_sym(&mut obj, 0, "foo", mem::size_of::<bpf_map_def>() as u64);
fake_sym(&mut obj, 0, "bar", mem::size_of::<bpf_map_def>() as u64);
fake_sym(&mut obj, 0, "baz", mem::size_of::<bpf_map_def>() as u64);

let map_data = bytes_of(&bpf_map_def {
map_type: 1,
key_size: 2,
value_size: 3,
max_entries: 4,
map_flags: 5,
..Default::default()
})
.to_vec();
let mut buf = vec![];
buf.extend(map_data.iter());
buf.extend(map_data.iter());
buf.extend(map_data.iter());

assert_matches!(
obj.parse_section(fake_section(BpfSectionKind::Maps, "maps", buf.as_slice(),)),
Ok(())
);
assert!(obj.maps.get("foo").is_some());
assert!(obj.maps.get("bar").is_some());
assert!(obj.maps.get("baz").is_some());
}

#[test]
fn test_parse_section_data() {
let mut obj = fake_obj();
Expand Down

0 comments on commit 8536ec8

Please sign in to comment.