aya: Move program's functions to the same map

pull/602/head
Mary 2 years ago
parent 7d88470944
commit 9e1109b3ce

@ -18,7 +18,7 @@ use crate::{
BPF_K, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_W, BTF_INT_SIGNED, BPF_K, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_W, BTF_INT_SIGNED,
}, },
util::HashMap, util::HashMap,
Object, Program, ProgramSection, Function, Object, ProgramSection,
}; };
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
@ -233,15 +233,22 @@ impl Object {
}; };
let section_name = program_section.name(); let section_name = program_section.name();
let program = self let function = self
.programs .programs
.get_mut(section_name) .get_mut(section_name)
.and_then(|x| self.functions.get_mut(&x.function_key()))
.ok_or(BtfRelocationError { .ok_or(BtfRelocationError {
section: section_name.to_owned(), section: section_name.to_owned(),
error: RelocationError::ProgramNotFound, error: RelocationError::ProgramNotFound,
})?; })?;
match relocate_btf_program(program, relos, local_btf, target_btf, &mut candidates_cache)
{ match relocate_btf_function(
function,
relos,
local_btf,
target_btf,
&mut candidates_cache,
) {
Ok(_) => {} Ok(_) => {}
Err(error) => { Err(error) => {
return Err(BtfRelocationError { return Err(BtfRelocationError {
@ -256,15 +263,15 @@ impl Object {
} }
} }
fn relocate_btf_program<'target>( fn relocate_btf_function<'target>(
program: &mut Program, function: &mut Function,
relos: &[Relocation], relos: &[Relocation],
local_btf: &Btf, local_btf: &Btf,
target_btf: &'target Btf, target_btf: &'target Btf,
candidates_cache: &mut HashMap<u32, Vec<Candidate<'target>>>, candidates_cache: &mut HashMap<u32, Vec<Candidate<'target>>>,
) -> Result<(), RelocationError> { ) -> Result<(), RelocationError> {
for rel in relos { for rel in relos {
let instructions = &mut program.function.instructions; let instructions = &mut function.instructions;
let ins_index = rel.ins_offset / mem::size_of::<bpf_insn>(); let ins_index = rel.ins_offset / mem::size_of::<bpf_insn>();
if ins_index >= instructions.len() { if ins_index >= instructions.len() {
return Err(RelocationError::InvalidInstructionIndex { return Err(RelocationError::InvalidInstructionIndex {
@ -337,7 +344,7 @@ fn relocate_btf_program<'target>(
ComputedRelocation::new(rel, &local_spec, None)? ComputedRelocation::new(rel, &local_spec, None)?
}; };
comp_rel.apply(program, rel, local_btf, target_btf)?; comp_rel.apply(function, rel, local_btf, target_btf)?;
} }
Ok(()) Ok(())
@ -847,12 +854,12 @@ impl ComputedRelocation {
fn apply( fn apply(
&self, &self,
program: &mut Program, function: &mut Function,
rel: &Relocation, rel: &Relocation,
local_btf: &Btf, local_btf: &Btf,
target_btf: &Btf, target_btf: &Btf,
) -> Result<(), RelocationError> { ) -> Result<(), RelocationError> {
let instructions = &mut program.function.instructions; let instructions = &mut function.instructions;
let num_instructions = instructions.len(); let num_instructions = instructions.len();
let ins_index = rel.ins_offset / mem::size_of::<bpf_insn>(); let ins_index = rel.ins_offset / mem::size_of::<bpf_insn>();
let ins = let ins =

@ -42,7 +42,8 @@
//! object.relocate_maps(std::iter::empty(), &text_sections).unwrap(); //! object.relocate_maps(std::iter::empty(), &text_sections).unwrap();
//! //!
//! // Run with rbpf //! // Run with rbpf
//! let instructions = &object.programs["prog_name"].function.instructions; //! let function = object.functions.get(&object.programs["prog_name"].function_key()).unwrap();
//! let instructions = &function.instructions;
//! let data = unsafe { //! let data = unsafe {
//! core::slice::from_raw_parts( //! core::slice::from_raw_parts(
//! instructions.as_ptr() as *const u8, //! instructions.as_ptr() as *const u8,

@ -84,8 +84,17 @@ pub struct Program {
pub kernel_version: KernelVersion, pub kernel_version: KernelVersion,
/// The section containing the program /// The section containing the program
pub section: ProgramSection, pub section: ProgramSection,
/// The function /// The section index of the program
pub function: Function, pub section_index: usize,
/// The address of the program
pub address: u64,
}
impl Program {
/// The key used by [Object::functions]
pub fn function_key(&self) -> (usize, u64) {
(self.section_index, self.address)
}
} }
/// An eBPF function /// An eBPF function
@ -646,7 +655,7 @@ impl Object {
Ok(()) Ok(())
} }
fn parse_program(&self, section: &Section) -> Result<Program, ParseError> { fn parse_program(&self, section: &Section) -> Result<(Program, Function), ParseError> {
let prog_sec = ProgramSection::from_str(section.name)?; let prog_sec = ProgramSection::from_str(section.name)?;
let name = prog_sec.name().to_owned(); let name = prog_sec.name().to_owned();
@ -664,11 +673,7 @@ impl Object {
(FuncSecInfo::default(), LineSecInfo::default(), 0, 0) (FuncSecInfo::default(), LineSecInfo::default(), 0, 0)
}; };
Ok(Program { let function = Function {
license: self.license.clone(),
kernel_version: self.kernel_version,
section: prog_sec,
function: Function {
name, name,
address: section.address, address: section.address,
section_index: section.index, section_index: section.index,
@ -678,8 +683,18 @@ impl Object {
line_info, line_info,
func_info_rec_size, func_info_rec_size,
line_info_rec_size, line_info_rec_size,
};
Ok((
Program {
license: self.license.clone(),
kernel_version: self.kernel_version,
section: prog_sec,
section_index: function.section_index.0,
address: function.address,
}, },
}) function,
))
} }
fn parse_text_section(&mut self, section: Section) -> Result<(), ParseError> { fn parse_text_section(&mut self, section: Section) -> Result<(), ParseError> {
@ -875,7 +890,8 @@ impl Object {
res? res?
} }
BpfSectionKind::Program => { BpfSectionKind::Program => {
let program = self.parse_program(&section)?; let (program, function) = self.parse_program(&section)?;
self.functions.insert(program.function_key(), function);
self.programs self.programs
.insert(program.section.name().to_owned(), program); .insert(program.section.name().to_owned(), program);
if !section.relocations.is_empty() { if !section.relocations.is_empty() {
@ -895,10 +911,10 @@ impl Object {
Ok(()) Ok(())
} }
/// Sanitize BPF programs. /// Sanitize BPF functions.
pub fn sanitize_programs(&mut self, features: &Features) { pub fn sanitize_functions(&mut self, features: &Features) {
for program in self.programs.values_mut() { for function in self.functions.values_mut() {
program.sanitize(features); function.sanitize(features);
} }
} }
} }
@ -918,9 +934,9 @@ const BPF_FUNC_PROBE_READ_KERNEL: i32 = 113;
const BPF_FUNC_PROBE_READ_USER_STR: i32 = 114; const BPF_FUNC_PROBE_READ_USER_STR: i32 = 114;
const BPF_FUNC_PROBE_READ_KERNEL_STR: i32 = 115; const BPF_FUNC_PROBE_READ_KERNEL_STR: i32 = 115;
impl Program { impl Function {
fn sanitize(&mut self, features: &Features) { fn sanitize(&mut self, features: &Features) {
for inst in &mut self.function.instructions { for inst in &mut self.instructions {
if !insn_is_helper_call(inst) { if !insn_is_helper_call(inst) {
continue; continue;
} }
@ -1652,17 +1668,17 @@ mod tests {
assert_matches!( assert_matches!(
obj.parse_program(&fake_section(BpfSectionKind::Program,"kprobe/foo", bytes_of(&fake_ins()))), obj.parse_program(&fake_section(BpfSectionKind::Program,"kprobe/foo", bytes_of(&fake_ins()))),
Ok(Program { Ok((Program {
license, license,
kernel_version: KernelVersion::Any, kernel_version: KernelVersion::Any,
section: ProgramSection::KProbe { .. }, section: ProgramSection::KProbe { .. },
function: Function { .. }, Function {
name, name,
address: 0, address: 0,
section_index: SectionIndex(0), section_index: SectionIndex(0),
section_offset: 0, section_offset: 0,
instructions, instructions,
..} }) if license.to_string_lossy() == "GPL" && name == "foo" && instructions.len() == 1 ..})) if license.to_string_lossy() == "GPL" && name == "foo" && instructions.len() == 1
); );
} }

@ -12,7 +12,7 @@ use crate::{
BPF_PSEUDO_MAP_VALUE, BPF_PSEUDO_MAP_VALUE,
}, },
maps::Map, maps::Map,
obj::{Function, Object, Program}, obj::{Function, Object},
util::{HashMap, HashSet}, util::{HashMap, HashSet},
BpfSectionKind, BpfSectionKind,
}; };
@ -64,6 +64,15 @@ pub enum RelocationError {
caller_name: String, caller_name: String,
}, },
/// Unknown function
#[error("program at section {section_index} and address {address:#x} was not found while relocating")]
UnknownProgram {
/// The function section index
section_index: usize,
/// The function address
address: u64,
},
/// Referenced map not created yet /// Referenced map not created yet
#[error("the map `{name}` at section `{section_index}` has not been created")] #[error("the map `{name}` at section `{section_index}` has not been created")]
MapNotCreated { MapNotCreated {
@ -119,13 +128,7 @@ impl Object {
} }
} }
let functions = self for function in self.functions.values_mut() {
.programs
.values_mut()
.map(|p| &mut p.function)
.chain(self.functions.values_mut());
for function in functions {
if let Some(relocations) = self.relocations.get(&function.section_index) { if let Some(relocations) = self.relocations.get(&function.section_index) {
relocate_maps( relocate_maps(
function, function,
@ -150,17 +153,35 @@ impl Object {
&mut self, &mut self,
text_sections: &HashSet<usize>, text_sections: &HashSet<usize>,
) -> Result<(), BpfRelocationError> { ) -> Result<(), BpfRelocationError> {
for (name, program) in self.programs.iter_mut() { for (name, program) in self.programs.iter() {
let linker = FunctionLinker::new( let mut linker = FunctionLinker::new(
&self.functions, &self.functions,
&self.relocations, &self.relocations,
&self.symbol_table, &self.symbol_table,
text_sections, text_sections,
); );
linker.link(program).map_err(|error| BpfRelocationError {
let func_orig =
self.functions
.get(&program.function_key())
.ok_or_else(|| BpfRelocationError {
function: name.clone(),
error: RelocationError::UnknownProgram {
section_index: program.section_index,
address: program.address,
},
})?;
let mut func = func_orig.clone();
linker
.relocate(&mut func, func_orig)
.map_err(|error| BpfRelocationError {
function: name.to_owned(), function: name.to_owned(),
error, error,
})?; })?;
self.functions.insert(program.function_key(), func);
} }
Ok(()) Ok(())
@ -293,19 +314,6 @@ impl<'a> FunctionLinker<'a> {
} }
} }
fn link(mut self, program: &mut Program) -> Result<(), RelocationError> {
let mut fun = program.function.clone();
// relocate calls in the program's main function. As relocation happens,
// it will trigger linking in all the callees.
self.relocate(&mut fun, &program.function)?;
// this now includes the program function plus all the other functions called during
// execution
program.function = fun;
Ok(())
}
fn link_function( fn link_function(
&mut self, &mut self,
program: &mut Function, program: &mut Function,

@ -433,18 +433,21 @@ impl<'a> BpfLoader<'a> {
&text_sections, &text_sections,
)?; )?;
obj.relocate_calls(&text_sections)?; obj.relocate_calls(&text_sections)?;
obj.sanitize_programs(&FEATURES); obj.sanitize_functions(&FEATURES);
let programs = obj let programs = obj
.programs .programs
.drain() .drain()
.map(|(name, obj)| { .map(|(name, prog_obj)| {
let function_obj = obj.functions.get(&prog_obj.function_key()).unwrap().clone();
let prog_name = if FEATURES.bpf_name { let prog_name = if FEATURES.bpf_name {
Some(name.clone()) Some(name.clone())
} else { } else {
None None
}; };
let section = obj.section.clone(); let section = prog_obj.section.clone();
let obj = (prog_obj, function_obj);
let program = if self.extensions.contains(name.as_str()) { let program = if self.extensions.contains(name.as_str()) {
Program::Extension(Extension { Program::Extension(Extension {

@ -405,7 +405,7 @@ impl Program {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ProgramData<T: Link> { pub(crate) struct ProgramData<T: Link> {
pub(crate) name: Option<String>, pub(crate) name: Option<String>,
pub(crate) obj: Option<obj::Program>, pub(crate) obj: Option<(obj::Program, obj::Function)>,
pub(crate) fd: Option<RawFd>, pub(crate) fd: Option<RawFd>,
pub(crate) links: LinkMap<T>, pub(crate) links: LinkMap<T>,
pub(crate) expected_attach_type: Option<bpf_attach_type>, pub(crate) expected_attach_type: Option<bpf_attach_type>,
@ -421,7 +421,7 @@ pub(crate) struct ProgramData<T: Link> {
impl<T: Link> ProgramData<T> { impl<T: Link> ProgramData<T> {
pub(crate) fn new( pub(crate) fn new(
name: Option<String>, name: Option<String>,
obj: obj::Program, obj: (obj::Program, obj::Function),
btf_fd: Option<RawFd>, btf_fd: Option<RawFd>,
verifier_log_level: u32, verifier_log_level: u32,
) -> ProgramData<T> { ) -> ProgramData<T> {
@ -557,8 +557,12 @@ fn load_program<T: Link>(
return Err(ProgramError::AlreadyLoaded); return Err(ProgramError::AlreadyLoaded);
} }
let obj = obj.as_ref().unwrap(); let obj = obj.as_ref().unwrap();
let crate::obj::Program { let (
function: crate::obj::Program {
license,
kernel_version,
..
},
Function { Function {
instructions, instructions,
func_info, func_info,
@ -567,10 +571,7 @@ fn load_program<T: Link>(
line_info_rec_size, line_info_rec_size,
.. ..
}, },
license, ) = obj;
kernel_version,
..
} = obj;
let target_kernel_version = match *kernel_version { let target_kernel_version = match *kernel_version {
KernelVersion::Any => { KernelVersion::Any => {

@ -18,7 +18,11 @@ fn run_with_rbpf() {
)); ));
assert_eq!(object.programs["pass"].section.name(), "pass"); assert_eq!(object.programs["pass"].section.name(), "pass");
let instructions = &object.programs["pass"].function.instructions; let instructions = &object
.functions
.get(&object.programs["pass"].function_key())
.unwrap()
.instructions;
let data = unsafe { let data = unsafe {
from_raw_parts( from_raw_parts(
instructions.as_ptr() as *const u8, instructions.as_ptr() as *const u8,
@ -86,7 +90,11 @@ fn use_map_with_rbpf() {
// Executes the program // Executes the program
assert_eq!(object.programs.len(), 1); assert_eq!(object.programs.len(), 1);
let instructions = &object.programs["tracepoint"].function.instructions; let instructions = &object
.functions
.get(&object.programs["tracepoint"].function_key())
.unwrap()
.instructions;
let data = unsafe { let data = unsafe {
from_raw_parts( from_raw_parts(
instructions.as_ptr() as *const u8, instructions.as_ptr() as *const u8,

Loading…
Cancel
Save