aya: Find programs using the symbol table

This makes a few changes to the way that Aya reads the ELF object
files.

1. To find programs in a section, we use the symbols table. This allows
   for cases where multiple programs could appear in the same section.
2. When parsing our ELF file we build symbols_by_section_index as an
   optimization as we use it for legacy maps, BTF maps and now programs.

As a result of theses changes the "NAME" used in `bpf.prog_mut("NAME")`
is now ALWAYS the same as the function name in the eBPF code, making the
user experience more consistent.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/413/head
Dave Tucker 2 years ago
parent f705eabe66
commit bf7fdff1ce

@ -123,6 +123,7 @@ pub struct Object {
pub functions: BTreeMap<(usize, u64), Function>, pub functions: BTreeMap<(usize, u64), Function>,
pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>, pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
pub(crate) symbol_table: HashMap<usize, Symbol>, pub(crate) symbol_table: HashMap<usize, Symbol>,
pub(crate) symbols_by_section: HashMap<SectionIndex, Vec<usize>>,
pub(crate) section_infos: HashMap<String, (SectionIndex, u64)>, pub(crate) section_infos: HashMap<String, (SectionIndex, u64)>,
// symbol_offset_by_name caches symbols that could be referenced from a // symbol_offset_by_name caches symbols that could be referenced from a
// BTF VAR type so the offsets can be fixed up // BTF VAR type so the offsets can be fixed up
@ -600,7 +601,13 @@ impl Object {
kind: symbol.kind(), kind: symbol.kind(),
}; };
bpf_obj.symbol_table.insert(symbol.index().0, sym); bpf_obj.symbol_table.insert(symbol.index().0, sym);
if let Some(section_idx) = symbol.section().index() {
bpf_obj
.symbols_by_section
.entry(section_idx)
.or_default()
.push(symbol.index().0);
}
if symbol.is_global() || symbol.kind() == SymbolKind::Data { if symbol.is_global() || symbol.kind() == SymbolKind::Data {
bpf_obj.symbol_offset_by_name.insert(name, symbol.address()); bpf_obj.symbol_offset_by_name.insert(name, symbol.address());
} }
@ -642,6 +649,7 @@ impl Object {
functions: BTreeMap::new(), functions: BTreeMap::new(),
relocations: HashMap::new(), relocations: HashMap::new(),
symbol_table: HashMap::new(), symbol_table: HashMap::new(),
symbols_by_section: HashMap::new(),
section_infos: HashMap::new(), section_infos: HashMap::new(),
symbol_offset_by_name: HashMap::new(), symbol_offset_by_name: HashMap::new(),
} }
@ -711,10 +719,42 @@ impl Object {
Ok(()) Ok(())
} }
fn parse_program(&self, section: &Section) -> Result<(Program, Function), ParseError> { fn parse_programs(&mut self, section: &Section) -> Result<(), ParseError> {
let prog_sec = ProgramSection::from_str(section.name)?; let program_section = ProgramSection::from_str(section.name)?;
let name = prog_sec.name().to_owned(); let syms =
self.symbols_by_section
.get(&section.index)
.ok_or(ParseError::NoSymbolsForSection {
section_name: section.name.to_string(),
})?;
for symbol_index in syms {
let symbol = self
.symbol_table
.get(symbol_index)
.expect("all symbols in symbols_by_section are also in symbol_table");
let Some(name) = symbol.name.as_ref() else {
continue;
};
if name.is_empty() {
continue;
}
let (p, f) =
self.parse_program(section, program_section.clone(), name.to_string(), symbol)?;
let key = p.function_key();
self.programs.insert(f.name.clone(), p);
self.functions.insert(key, f);
}
Ok(())
}
fn parse_program(
&self,
section: &Section,
program_section: ProgramSection,
name: String,
symbol: &Symbol,
) -> Result<(Program, Function), ParseError> {
let (func_info, line_info, func_info_rec_size, line_info_rec_size) = let (func_info, line_info, func_info_rec_size, line_info_rec_size) =
if let Some(btf_ext) = &self.btf_ext { if let Some(btf_ext) = &self.btf_ext {
let func_info = btf_ext.func_info.get(section.name); let func_info = btf_ext.func_info.get(section.name);
@ -729,12 +769,15 @@ impl Object {
(FuncSecInfo::default(), LineSecInfo::default(), 0, 0) (FuncSecInfo::default(), LineSecInfo::default(), 0, 0)
}; };
let start = symbol.address as usize;
let end = (symbol.address + symbol.size) as usize;
let function = Function { let function = Function {
name, name: name.to_owned(),
address: section.address, address: symbol.address,
section_index: section.index, section_index: section.index,
section_offset: 0, section_offset: start,
instructions: copy_instructions(section.data)?, instructions: copy_instructions(&section.data[start..end])?,
func_info, func_info,
line_info, line_info,
func_info_rec_size, func_info_rec_size,
@ -745,9 +788,9 @@ impl Object {
Program { Program {
license: self.license.clone(), license: self.license.clone(),
kernel_version: self.kernel_version, kernel_version: self.kernel_version,
section: prog_sec, section: program_section.clone(),
section_index: function.section_index.0, section_index: section.index.0,
address: function.address, address: symbol.address,
}, },
function, function,
)) ))
@ -845,15 +888,23 @@ impl Object {
Ok(()) Ok(())
} }
fn parse_btf_maps( fn parse_btf_maps(&mut self, section: &Section) -> Result<(), ParseError> {
&mut self,
section: &Section,
symbols: HashMap<String, Symbol>,
) -> Result<(), ParseError> {
if self.btf.is_none() { if self.btf.is_none() {
return Err(ParseError::NoBTF); return Err(ParseError::NoBTF);
} }
let btf = self.btf.as_ref().unwrap(); let btf = self.btf.as_ref().unwrap();
let maps: HashMap<&String, usize> = self
.symbols_by_section
.get(&section.index)
.ok_or(ParseError::NoSymbolsForSection {
section_name: section.name.to_owned(),
})?
.iter()
.filter_map(|s| {
let symbol = self.symbol_table.get(s).unwrap();
symbol.name.as_ref().map(|name| (name, symbol.index))
})
.collect();
for t in btf.types() { for t in btf.types() {
if let BtfType::DataSec(datasec) = &t { if let BtfType::DataSec(datasec) = &t {
@ -865,18 +916,17 @@ impl Object {
// each btf_var_secinfo contains a map // each btf_var_secinfo contains a map
for info in &datasec.entries { for info in &datasec.entries {
let (map_name, def) = parse_btf_map_def(btf, info)?; let (map_name, def) = parse_btf_map_def(btf, info)?;
let symbol_index = symbols let symbol_index =
.get(&map_name) maps.get(&map_name)
.ok_or_else(|| ParseError::SymbolNotFound { .ok_or_else(|| ParseError::SymbolNotFound {
name: map_name.to_string(), name: map_name.to_string(),
})? })?;
.index;
self.maps.insert( self.maps.insert(
map_name, map_name,
Map::Btf(BtfMap { Map::Btf(BtfMap {
def, def,
section_index: section.index.0, section_index: section.index.0,
symbol_index, symbol_index: *symbol_index,
data: Vec::new(), data: Vec::new(),
}), }),
); );
@ -887,6 +937,50 @@ impl Object {
Ok(()) Ok(())
} }
// Parses multiple map definition contained in a single `maps` section (which is
// different from `.maps` which is used for BTF). We can tell where each map is
// based on the symbol table.
fn parse_maps_section<'a, I: Iterator<Item = &'a usize>>(
&self,
maps: &mut HashMap<String, Map>,
section: &Section,
symbols: I,
) -> Result<(), ParseError> {
let mut have_symbols = false;
// each symbol in the section is a separate map
for i in symbols {
let sym = self.symbol_table.get(i).ok_or(ParseError::SymbolNotFound {
name: i.to_string(),
})?;
let start = sym.address as usize;
let end = start + sym.size as usize;
let data = &section.data[start..end];
let name = sym
.name
.as_ref()
.ok_or(ParseError::MapSymbolNameNotFound { i: *i })?;
let def = parse_map_def(name, data)?;
maps.insert(
name.to_string(),
Map::Legacy(LegacyMap {
section_index: section.index.0,
section_kind: section.kind,
symbol_index: Some(sym.index),
def,
data: Vec::new(),
}),
);
have_symbols = true;
}
if !have_symbols {
return Err(ParseError::NoSymbolsForSection {
section_name: section.name.to_owned(),
});
}
Ok(())
}
fn parse_section(&mut self, section: Section) -> Result<(), ParseError> { fn parse_section(&mut self, section: Section) -> Result<(), ParseError> {
self.section_infos self.section_infos
.insert(section.name.to_owned(), (section.index, section.size)); .insert(section.name.to_owned(), (section.index, section.size));
@ -898,22 +992,7 @@ impl Object {
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)?,
BpfSectionKind::BtfExt => self.parse_btf_ext(&section)?, BpfSectionKind::BtfExt => self.parse_btf_ext(&section)?,
BpfSectionKind::BtfMaps => { BpfSectionKind::BtfMaps => self.parse_btf_maps(&section)?,
let symbols: HashMap<String, Symbol> = self
.symbol_table
.values()
.filter(|s| {
if let Some(idx) = s.section_index {
idx == section.index.0 && s.name.is_some()
} else {
false
}
})
.cloned()
.map(|s| (s.name.as_ref().unwrap().to_string(), s))
.collect();
self.parse_btf_maps(&section, symbols)?
}
BpfSectionKind::Maps => { BpfSectionKind::Maps => {
// take out self.maps so we can borrow the iterator below // take out self.maps so we can borrow the iterator below
// without cloning or collecting // without cloning or collecting
@ -921,13 +1000,15 @@ impl Object {
// extract the symbols for the .maps section, we'll need them // extract the symbols for the .maps section, we'll need them
// during parsing // during parsing
let symbols = self.symbol_table.values().filter(|s| { let symbols = self
s.section_index .symbols_by_section
.map(|idx| idx == section.index.0) .get(&section.index)
.unwrap_or(false) .ok_or(ParseError::NoSymbolsForSection {
}); section_name: section.name.to_owned(),
})?
.iter();
let res = parse_maps_section(&mut maps, &section, symbols); let res = self.parse_maps_section(&mut maps, &section, symbols);
// put the maps back // put the maps back
self.maps = maps; self.maps = maps;
@ -935,10 +1016,7 @@ impl Object {
res? res?
} }
BpfSectionKind::Program => { BpfSectionKind::Program => {
let (program, function) = self.parse_program(&section)?; self.parse_programs(&section)?;
self.functions.insert(program.function_key(), function);
self.programs
.insert(program.section.name().to_owned(), program);
if !section.relocations.is_empty() { if !section.relocations.is_empty() {
self.relocations.insert( self.relocations.insert(
section.index, section.index,
@ -1003,45 +1081,6 @@ impl Function {
} }
} }
// Parses multiple map definition contained in a single `maps` section (which is
// different from `.maps` which is used for BTF). We can tell where each map is
// based on the symbol table.
fn parse_maps_section<'a, I: Iterator<Item = &'a Symbol>>(
maps: &mut HashMap<String, Map>,
section: &Section,
symbols: I,
) -> Result<(), ParseError> {
let mut have_symbols = false;
// each symbol in the section is a separate map
for (i, sym) in symbols.enumerate() {
let start = sym.address as usize;
let end = start + sym.size as usize;
let data = &section.data[start..end];
let name = sym
.name
.as_ref()
.ok_or(ParseError::MapSymbolNameNotFound { i })?;
let def = parse_map_def(name, data)?;
maps.insert(
name.to_string(),
Map::Legacy(LegacyMap {
section_index: section.index.0,
section_kind: section.kind,
symbol_index: Some(sym.index),
def,
data: Vec::new(),
}),
);
have_symbols = true;
}
if !have_symbols {
return Err(ParseError::NoSymbolsForMapsSection);
}
Ok(())
}
/// Errors caught during parsing the object file /// Errors caught during parsing the object file
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
#[allow(missing_docs)] #[allow(missing_docs)]
@ -1105,8 +1144,8 @@ pub enum ParseError {
#[error("the map number {i} in the `maps` section doesn't have a symbol name")] #[error("the map number {i} in the `maps` section doesn't have a symbol name")]
MapSymbolNameNotFound { i: usize }, MapSymbolNameNotFound { i: usize },
#[error("no symbols for `maps` section, can't parse maps")] #[error("no symbols found in the {section_name} section")]
NoSymbolsForMapsSection, NoSymbolsForSection { section_name: String },
/// No BTF parsed for object /// No BTF parsed for object
#[error("no BTF parsed for object")] #[error("no BTF parsed for object")]
@ -1480,9 +1519,17 @@ mod tests {
use super::*; use super::*;
use crate::maps::PinningType; use crate::maps::PinningType;
fn fake_section<'a>(kind: BpfSectionKind, name: &'a str, data: &'a [u8]) -> Section<'a> { const FAKE_INS_LEN: u64 = 8;
fn fake_section<'a>(
kind: BpfSectionKind,
name: &'a str,
data: &'a [u8],
index: Option<usize>,
) -> Section<'a> {
let idx = index.unwrap_or(0);
Section { Section {
index: SectionIndex(0), index: SectionIndex(idx),
kind, kind,
address: 0, address: 0,
name, name,
@ -1513,9 +1560,13 @@ mod tests {
address, address,
size, size,
is_definition: false, is_definition: false,
kind: SymbolKind::Data, kind: SymbolKind::Text,
}, },
); );
obj.symbols_by_section
.entry(SectionIndex(section_index))
.or_default()
.push(idx + 1);
} }
fn bytes_of<T>(val: &T) -> &[u8] { fn bytes_of<T>(val: &T) -> &[u8] {
@ -1637,6 +1688,7 @@ mod tests {
BpfSectionKind::Data, BpfSectionKind::Data,
".bss", ".bss",
map_data, map_data,
None,
), ),
), ),
Ok(Map::Legacy(LegacyMap { Ok(Map::Legacy(LegacyMap {
@ -1670,6 +1722,7 @@ mod tests {
&[ &[
159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
], ],
None,
)) ))
.unwrap(); .unwrap();
obj.parse_section(fake_section( obj.parse_section(fake_section(
@ -1679,6 +1732,7 @@ mod tests {
159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0,
0, 0, 16, 0, 0, 0, 0, 0, 16, 0, 0, 0,
], ],
None,
)) ))
.unwrap(); .unwrap();
@ -1688,36 +1742,54 @@ mod tests {
#[test] #[test]
fn test_parse_program_error() { fn test_parse_program_error() {
let obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", 1);
assert_matches!( assert_matches!(
obj.parse_program(&fake_section( obj.parse_programs(&fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"kprobe/foo", "kprobe/foo",
&42u32.to_ne_bytes(), &42u32.to_ne_bytes(),
)), None,
),),
Err(ParseError::InvalidProgramCode) Err(ParseError::InvalidProgramCode)
); );
} }
#[test] #[test]
fn test_parse_program() { fn test_parse_program() {
let obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
obj.parse_programs(&fake_section(
BpfSectionKind::Program,
"kprobe/foo",
bytes_of(&fake_ins()),
None,
))
.unwrap();
let prog_foo = obj.programs.get("foo").unwrap();
assert_matches!( assert_matches!(
obj.parse_program(&fake_section(BpfSectionKind::Program,"kprobe/foo", bytes_of(&fake_ins()))), prog_foo,
Ok((Program { Program {
license, license,
kernel_version: None, kernel_version: None,
section: ProgramSection::KProbe { .. }, section: ProgramSection::KProbe { .. },
.. }, Function { ..
name, } if license.to_str().unwrap() == "GPL"
address: 0,
section_index: SectionIndex(0),
section_offset: 0,
instructions,
..})) if license.to_string_lossy() == "GPL" && name == "foo" && instructions.len() == 1
); );
assert_matches!(
obj.functions.get(&prog_foo.function_key()),
Some(Function {
name,
address: 0,
section_index: SectionIndex(0),
section_offset: 0,
instructions,
..}) if name == "foo" && instructions.len() == 1
)
} }
#[test] #[test]
@ -1735,13 +1807,72 @@ mod tests {
max_entries: 4, max_entries: 4,
map_flags: 5, map_flags: 5,
..Default::default() ..Default::default()
}) }),
None,
)), )),
Ok(()) Ok(())
); );
assert!(obj.maps.get("foo").is_some()); assert!(obj.maps.get("foo").is_some());
} }
#[test]
fn test_parse_multiple_program_in_same_section() {
let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
fake_sym(&mut obj, 0, FAKE_INS_LEN, "bar", FAKE_INS_LEN);
let insns = [fake_ins(), fake_ins()];
let data = bytes_of(&insns);
obj.parse_programs(&fake_section(BpfSectionKind::Program, "kprobe", data, None))
.unwrap();
let prog_foo = obj.programs.get("foo").unwrap();
let function_foo = obj.functions.get(&prog_foo.function_key()).unwrap();
let prog_bar = obj.programs.get("bar").unwrap();
let function_bar = obj.functions.get(&prog_bar.function_key()).unwrap();
assert_matches!(prog_foo,
Program {
license,
kernel_version: None,
section: ProgramSection::KProbe { .. },
..
} if license.to_string_lossy() == "GPL"
);
assert_matches!(
function_foo,
Function {
name,
address: 0,
section_index: SectionIndex(0),
section_offset: 0,
instructions,
..
} if name == "foo" && instructions.len() == 1
);
assert_matches!(prog_bar,
Program {
license,
kernel_version: None,
section: ProgramSection::KProbe { .. },
..
} if license.to_string_lossy() == "GPL"
);
assert_matches!(
function_bar,
Function {
name,
address: 8,
section_index: SectionIndex(0),
section_offset: 8,
instructions,
..
} if name == "bar" && instructions.len() == 1
);
}
#[test] #[test]
fn test_parse_section_multiple_maps() { fn test_parse_section_multiple_maps() {
let mut obj = fake_obj(); let mut obj = fake_obj();
@ -1764,7 +1895,12 @@ mod tests {
buf.extend([0, 0, 0, 0]); buf.extend([0, 0, 0, 0]);
buf.extend(&map_data); buf.extend(&map_data);
assert_matches!( assert_matches!(
obj.parse_section(fake_section(BpfSectionKind::Maps, "maps", buf.as_slice(),)), obj.parse_section(fake_section(
BpfSectionKind::Maps,
"maps",
buf.as_slice(),
None
)),
Ok(()) Ok(())
); );
assert!(obj.maps.get("foo").is_some()); assert!(obj.maps.get("foo").is_some());
@ -1783,13 +1919,23 @@ mod tests {
fn test_parse_section_data() { fn test_parse_section_data() {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( assert_matches!(
obj.parse_section(fake_section(BpfSectionKind::Data, ".bss", b"map data")), obj.parse_section(fake_section(
BpfSectionKind::Data,
".bss",
b"map data",
None
)),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".bss").is_some()); assert!(obj.maps.get(".bss").is_some());
assert_matches!( assert_matches!(
obj.parse_section(fake_section(BpfSectionKind::Data, ".rodata", b"map data")), obj.parse_section(fake_section(
BpfSectionKind::Data,
".rodata",
b"map data",
None
)),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".rodata").is_some()); assert!(obj.maps.get(".rodata").is_some());
@ -1798,20 +1944,31 @@ mod tests {
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Data, BpfSectionKind::Data,
".rodata.boo", ".rodata.boo",
b"map data" b"map data",
None
)), )),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".rodata.boo").is_some()); assert!(obj.maps.get(".rodata.boo").is_some());
assert_matches!( assert_matches!(
obj.parse_section(fake_section(BpfSectionKind::Data, ".data", b"map data")), obj.parse_section(fake_section(
BpfSectionKind::Data,
".data",
b"map data",
None
)),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".data").is_some()); assert!(obj.maps.get(".data").is_some());
assert_matches!( assert_matches!(
obj.parse_section(fake_section(BpfSectionKind::Data, ".data.boo", b"map data")), obj.parse_section(fake_section(
BpfSectionKind::Data,
".data.boo",
b"map data",
None
)),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".data.boo").is_some()); assert!(obj.maps.get(".data.boo").is_some());
@ -1820,12 +1977,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_kprobe() { fn test_parse_section_kprobe() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"kprobe/foo", "kprobe/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1841,12 +2000,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_uprobe() { fn test_parse_section_uprobe() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"uprobe/foo", "uprobe/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1862,12 +2023,15 @@ mod tests {
#[test] #[test]
fn test_parse_section_trace_point() { fn test_parse_section_trace_point() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
fake_sym(&mut obj, 1, 0, "bar", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"tracepoint/foo", "tracepoint/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1883,12 +2047,13 @@ mod tests {
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"tp/foo/bar", "tp/foo/bar",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
Some(1),
)), )),
Ok(()) Ok(())
); );
assert_matches!( assert_matches!(
obj.programs.get("foo/bar"), obj.programs.get("bar"),
Some(Program { Some(Program {
section: ProgramSection::TracePoint { .. }, section: ProgramSection::TracePoint { .. },
.. ..
@ -1899,12 +2064,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_socket_filter() { fn test_parse_section_socket_filter() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"socket/foo", "socket/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1920,12 +2087,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_xdp() { fn test_parse_section_xdp() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"xdp/foo", "xdp/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1941,12 +2110,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_xdp_frags() { fn test_parse_section_xdp_frags() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"xdp.frags/foo", "xdp.frags/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1962,12 +2133,15 @@ mod tests {
#[test] #[test]
fn test_parse_section_raw_tp() { fn test_parse_section_raw_tp() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
fake_sym(&mut obj, 1, 0, "bar", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"raw_tp/foo", "raw_tp/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -1983,7 +2157,8 @@ mod tests {
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"raw_tracepoint/bar", "raw_tracepoint/bar",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
Some(1)
)), )),
Ok(()) Ok(())
); );
@ -1999,12 +2174,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_lsm() { fn test_parse_section_lsm() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"lsm/foo", "lsm/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2023,12 +2200,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_lsm_sleepable() { fn test_parse_section_lsm_sleepable() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"lsm.s/foo", "lsm.s/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2047,12 +2226,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_btf_tracepoint() { fn test_parse_section_btf_tracepoint() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"tp_btf/foo", "tp_btf/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2068,12 +2249,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_skskb_unnamed() { fn test_parse_section_skskb_unnamed() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "stream_parser", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"sk_skb/stream_parser", "sk_skb/stream_parser",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2089,12 +2272,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_skskb_named() { fn test_parse_section_skskb_named() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "my_parser", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"sk_skb/stream_parser/my_parser", "sk_skb/stream_parser/my_parser",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2110,12 +2295,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_fentry() { fn test_parse_section_fentry() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"fentry/foo", "fentry/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2131,12 +2318,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_fexit() { fn test_parse_section_fexit() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"fexit/foo", "fexit/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2152,12 +2341,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_cgroup_skb_ingress_unnamed() { fn test_parse_section_cgroup_skb_ingress_unnamed() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "ingress", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup_skb/ingress", "cgroup_skb/ingress",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2173,12 +2364,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_cgroup_skb_ingress_named() { fn test_parse_section_cgroup_skb_ingress_named() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup_skb/ingress/foo", "cgroup_skb/ingress/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2194,12 +2387,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_cgroup_skb_no_direction_unamed() { fn test_parse_section_cgroup_skb_no_direction_unamed() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "skb", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup/skb", "cgroup/skb",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2215,12 +2410,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_cgroup_skb_no_direction_named() { fn test_parse_section_cgroup_skb_no_direction_named() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup/skb/foo", "cgroup/skb/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2236,12 +2433,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_sock_addr_named() { fn test_parse_section_sock_addr_named() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup/connect4/foo", "cgroup/connect4/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2260,12 +2459,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_sock_addr_unnamed() { fn test_parse_section_sock_addr_unnamed() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "connect4", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup/connect4", "cgroup/connect4",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2284,12 +2485,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_sockopt_named() { fn test_parse_section_sockopt_named() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup/getsockopt/foo", "cgroup/getsockopt/foo",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2308,12 +2511,14 @@ mod tests {
#[test] #[test]
fn test_parse_section_sockopt_unnamed() { fn test_parse_section_sockopt_unnamed() {
let mut obj = fake_obj(); let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "getsockopt", FAKE_INS_LEN);
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program, BpfSectionKind::Program,
"cgroup/getsockopt", "cgroup/getsockopt",
bytes_of(&fake_ins()) bytes_of(&fake_ins()),
None
)), )),
Ok(()) Ok(())
); );
@ -2455,10 +2660,10 @@ mod tests {
0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00, 0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
]; ];
let btf_section = fake_section(BpfSectionKind::Btf, ".BTF", data); let btf_section = fake_section(BpfSectionKind::Btf, ".BTF", data, None);
obj.parse_section(btf_section).unwrap(); obj.parse_section(btf_section).unwrap();
let map_section = fake_section(BpfSectionKind::BtfMaps, ".maps", &[]); let map_section = fake_section(BpfSectionKind::BtfMaps, ".maps", &[], None);
obj.parse_section(map_section).unwrap(); obj.parse_section(map_section).unwrap();
let map = obj.maps.get("map_1").unwrap(); let map = obj.maps.get("map_1").unwrap();

@ -3,7 +3,7 @@
use aya_bpf::{bindings::xdp_action, macros::xdp, programs::XdpContext}; use aya_bpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
#[xdp(name = "ihaveaverylongname")] #[xdp]
pub fn ihaveaverylongname(ctx: XdpContext) -> u32 { pub fn ihaveaverylongname(ctx: XdpContext) -> u32 {
match unsafe { try_pass(ctx) } { match unsafe { try_pass(ctx) } {
Ok(ret) => ret, Ok(ret) => ret,

@ -1,7 +1,7 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
SEC("xdp/drop") SEC("xdp")
int xdp_drop(struct xdp_md *ctx) int xdp_drop(struct xdp_md *ctx)
{ {
return XDP_DROP; return XDP_DROP;

@ -1,7 +1,7 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
SEC("xdp/pass") SEC("xdp")
int xdp_pass(struct xdp_md *ctx) int xdp_pass(struct xdp_md *ctx)
{ {
return XDP_PASS; return XDP_PASS;

@ -36,7 +36,7 @@ fn multiple_btf_maps() {
let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap(); let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap();
let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap(); let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap();
let prog: &mut TracePoint = bpf.program_mut("tracepoint").unwrap().try_into().unwrap(); let prog: &mut TracePoint = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
prog.attach("sched", "sched_switch").unwrap(); prog.attach("sched", "sched_switch").unwrap();
@ -110,26 +110,26 @@ macro_rules! assert_loaded {
#[test] #[test]
fn unload_xdp() { fn unload_xdp() {
let mut bpf = Bpf::load(crate::TEST).unwrap(); let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut Xdp = bpf.program_mut("test_xdp").unwrap().try_into().unwrap(); let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_xdp", true); assert_loaded!("pass", true);
let link = prog.attach("lo", XdpFlags::default()).unwrap(); let link = prog.attach("lo", XdpFlags::default()).unwrap();
{ {
let _link_owned = prog.take_link(link).unwrap(); let _link_owned = prog.take_link(link).unwrap();
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded_and_linked!("test_xdp", true); assert_loaded_and_linked!("pass", true);
}; };
assert_loaded!("test_xdp", false); assert_loaded!("pass", false);
prog.load().unwrap(); prog.load().unwrap();
assert_loaded!("test_xdp", true); assert_loaded!("pass", true);
prog.attach("lo", XdpFlags::default()).unwrap(); prog.attach("lo", XdpFlags::default()).unwrap();
assert_loaded!("test_xdp", true); assert_loaded!("pass", true);
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_xdp", false); assert_loaded!("pass", false);
} }
#[test] #[test]
@ -224,26 +224,26 @@ fn pin_link() {
} }
let mut bpf = Bpf::load(crate::TEST).unwrap(); let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut Xdp = bpf.program_mut("test_xdp").unwrap().try_into().unwrap(); let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
let link_id = prog.attach("lo", XdpFlags::default()).unwrap(); let link_id = prog.attach("lo", XdpFlags::default()).unwrap();
let link = prog.take_link(link_id).unwrap(); let link = prog.take_link(link_id).unwrap();
assert_loaded!("test_xdp", true); assert_loaded!("pass", true);
let fd_link: FdLink = link.try_into().unwrap(); let fd_link: FdLink = link.try_into().unwrap();
let pinned = fd_link.pin("/sys/fs/bpf/aya-xdp-test-lo").unwrap(); let pinned = fd_link.pin("/sys/fs/bpf/aya-xdp-test-lo").unwrap();
// because of the pin, the program is still attached // because of the pin, the program is still attached
prog.unload().unwrap(); prog.unload().unwrap();
assert_loaded!("test_xdp", true); assert_loaded!("pass", true);
// delete the pin, but the program is still attached // delete the pin, but the program is still attached
let new_link = pinned.unpin().unwrap(); let new_link = pinned.unpin().unwrap();
assert_loaded!("test_xdp", true); assert_loaded!("pass", true);
// finally when new_link is dropped we're detached // finally when new_link is dropped we're detached
drop(new_link); drop(new_link);
assert_loaded!("test_xdp", false); assert_loaded!("pass", false);
} }
#[test] #[test]

@ -36,10 +36,10 @@ fn use_map_with_rbpf() {
assert_eq!(object.programs.len(), 1); assert_eq!(object.programs.len(), 1);
assert_matches::assert_matches!( assert_matches::assert_matches!(
object.programs["tracepoint"].section, object.programs["bpf_prog"].section,
ProgramSection::TracePoint { .. } ProgramSection::TracePoint { .. }
); );
assert_eq!(object.programs["tracepoint"].section.name(), "tracepoint"); assert_eq!(object.programs["bpf_prog"].section.name(), "tracepoint");
// Initialize maps: // Initialize maps:
// - fd: 0xCAFE00 or 0xCAFE01 (the 0xCAFE00 part is used to distinguish fds from indices), // - fd: 0xCAFE00 or 0xCAFE01 (the 0xCAFE00 part is used to distinguish fds from indices),
@ -83,7 +83,7 @@ fn use_map_with_rbpf() {
assert_eq!(object.programs.len(), 1); assert_eq!(object.programs.len(), 1);
let instructions = &object let instructions = &object
.functions .functions
.get(&object.programs["tracepoint"].function_key()) .get(&object.programs["bpf_prog"].function_key())
.unwrap() .unwrap()
.instructions; .instructions;
let data = unsafe { let data = unsafe {

@ -32,11 +32,14 @@ fn extension() {
return; return;
} }
let mut bpf = Bpf::load(crate::MAIN).unwrap(); let mut bpf = Bpf::load(crate::MAIN).unwrap();
let pass: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); let pass: &mut Xdp = bpf.program_mut("xdp_pass").unwrap().try_into().unwrap();
pass.load().unwrap(); pass.load().unwrap();
pass.attach("lo", XdpFlags::default()).unwrap(); pass.attach("lo", XdpFlags::default()).unwrap();
let mut bpf = BpfLoader::new().extension("drop").load(crate::EXT).unwrap(); let mut bpf = BpfLoader::new()
let drop_: &mut Extension = bpf.program_mut("drop").unwrap().try_into().unwrap(); .extension("xdp_drop")
.load(crate::EXT)
.unwrap();
let drop_: &mut Extension = bpf.program_mut("xdp_drop").unwrap().try_into().unwrap();
drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap(); drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap();
} }

@ -5764,7 +5764,8 @@ pub aya_obj::obj::ParseError::MapSymbolNameNotFound::i: usize
pub aya_obj::obj::ParseError::MissingLicenseNullTerminator pub aya_obj::obj::ParseError::MissingLicenseNullTerminator
pub aya_obj::obj::ParseError::MissingLicenseNullTerminator::data: alloc::vec::Vec<u8> pub aya_obj::obj::ParseError::MissingLicenseNullTerminator::data: alloc::vec::Vec<u8>
pub aya_obj::obj::ParseError::NoBTF pub aya_obj::obj::ParseError::NoBTF
pub aya_obj::obj::ParseError::NoSymbolsForMapsSection pub aya_obj::obj::ParseError::NoSymbolsForSection
pub aya_obj::obj::ParseError::NoSymbolsForSection::section_name: alloc::string::String
pub aya_obj::obj::ParseError::SectionError pub aya_obj::obj::ParseError::SectionError
pub aya_obj::obj::ParseError::SectionError::error: object::read::Error pub aya_obj::obj::ParseError::SectionError::error: object::read::Error
pub aya_obj::obj::ParseError::SectionError::index: usize pub aya_obj::obj::ParseError::SectionError::index: usize
@ -6511,7 +6512,8 @@ pub aya_obj::ParseError::MapSymbolNameNotFound::i: usize
pub aya_obj::ParseError::MissingLicenseNullTerminator pub aya_obj::ParseError::MissingLicenseNullTerminator
pub aya_obj::ParseError::MissingLicenseNullTerminator::data: alloc::vec::Vec<u8> pub aya_obj::ParseError::MissingLicenseNullTerminator::data: alloc::vec::Vec<u8>
pub aya_obj::ParseError::NoBTF pub aya_obj::ParseError::NoBTF
pub aya_obj::ParseError::NoSymbolsForMapsSection pub aya_obj::ParseError::NoSymbolsForSection
pub aya_obj::ParseError::NoSymbolsForSection::section_name: alloc::string::String
pub aya_obj::ParseError::SectionError pub aya_obj::ParseError::SectionError
pub aya_obj::ParseError::SectionError::error: object::read::Error pub aya_obj::ParseError::SectionError::error: object::read::Error
pub aya_obj::ParseError::SectionError::index: usize pub aya_obj::ParseError::SectionError::index: usize

Loading…
Cancel
Save