aya-obj: add documentation on program names

This commit adds documentation on how program names are parsed from
section names, as is used by `aya_obj::Object.programs` as HashMap keys,
and updates the examples into using program names.
pull/475/head
Shenghui Ye 2 years ago
parent 9ec3447e89
commit 772af170ae

@ -27,8 +27,7 @@ object.relocate_calls().unwrap();
object.relocate_maps(std::iter::empty()).unwrap();
// Run with rbpf
let program = object.programs.iter().next().unwrap().1;
let instructions = &program.function.instructions;
let instructions = &object.programs["prog_name"].function.instructions;
let data = unsafe {
core::slice::from_raw_parts(
instructions.as_ptr() as *const u8,

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

@ -48,7 +48,8 @@ pub struct Object {
pub btf_ext: Option<BtfExt>,
/// Referenced maps
pub maps: HashMap<String, Map>,
/// Programs
/// A hash map of programs, using the program names parsed
/// in [ProgramSection]s as keys.
pub programs: HashMap<String, Program>,
/// Functions
pub functions: HashMap<u64, Function>,
@ -97,7 +98,69 @@ pub struct Function {
pub line_info_rec_size: usize,
}
/// Sections containing eBPF programs
/// Section types containing eBPF programs
///
/// # Section Name Parsing
///
/// Section types are parsed from the section name strings.
///
/// In order for Aya to treat a section as a [ProgramSection],
/// there are a few requirements:
/// - The section must be an executable code section.
/// - The section name must conform to [Program Types and ELF Sections].
///
/// [Program Types and ELF Sections]: https://docs.kernel.org/bpf/libbpf/program_types.html
///
/// ## Program Name
///
/// Each section name is parsed into a section type and a program name.
///
/// Generally speaking,
/// - if the section name does not contain any slashes,
/// then the program name is just that section name;
/// - if there are some slashes, the name is `section_name.rsplitn(2, '/')[0]`,
/// - except for tracepoint programs, for which the name is
/// `section_name.splitn(2, '/')[1]`.
///
/// ```rust
/// use aya_obj::ProgramSection;
/// use std::str::FromStr;
///
/// assert_eq!(
/// ProgramSection::from_str("kprobe/do_unlinkat")
/// .unwrap().name(),
/// "do_unlinkat",
/// );
/// assert_eq!(
/// ProgramSection::from_str("tracepoint/syscalls/sys_enter_openat")
/// .unwrap().name(),
/// "syscalls/sys_enter_openat",
/// );
/// ```
///
/// The program name will be used in [Object] as references to each program.
///
/// ## Unsupported Sections
///
/// Currently, the following section names are not supported yet:
/// - `flow_dissector`: `BPF_PROG_TYPE_FLOW_DISSECTOR`
/// - `ksyscall+` or `kretsyscall+`
/// - `uprobe.s+` or `uretprobe.s+`
/// - `usdt+`
/// - `kprobe.multi+` or `kretprobe.multi+`: `BPF_TRACE_KPROBE_MULTI`
/// - `lsm_cgroup+` or `lsm.s+`
/// - `lwt_in`, `lwt_out`, `lwt_seg6local`, `lwt_xmit`
/// - `raw_tp.w+`, `raw_tracepoint.w+`
/// - `action`
/// - `sk_reuseport/migrate`, `sk_reuseport`
/// - `syscall`
/// - `struct_ops+`
/// - `fmod_ret+`, `fmod_ret.s+`
/// - `fentry.s+`, `fexit.s+`
/// - `iter+`, `iter.s+`
/// - `xdp.frags/cpumap`, `xdp/cpumap`
/// - `xdp.frags/devmap`, `xdp/devmap`
/// - `xdp.frags`
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum ProgramSection {

@ -2,7 +2,7 @@ use core::{mem::size_of, ptr::null_mut, slice::from_raw_parts};
use std::collections::HashMap;
use aya::include_bytes_aligned;
use aya_obj::{generated::bpf_insn, Object};
use aya_obj::{generated::bpf_insn, Object, ProgramSection};
use super::{integration_test, IntegrationTest};
@ -10,7 +10,14 @@ use super::{integration_test, IntegrationTest};
fn run_with_rbpf() {
let bytes = include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/pass");
let object = Object::parse(bytes).unwrap();
assert_eq!(object.programs.len(), 1);
assert!(matches!(
object.programs["pass"].section,
ProgramSection::Xdp { .. }
));
assert_eq!(object.programs["pass"].section.name(), "pass");
let instructions = &object.programs["pass"].function.instructions;
let data = unsafe {
from_raw_parts(
@ -31,26 +38,34 @@ fn use_map_with_rbpf() {
let bytes =
include_bytes_aligned!("../../../../target/bpfel-unknown-none/debug/multimap-btf.bpf.o");
let mut object = Object::parse(bytes).unwrap();
let mut maps = HashMap::new();
// Initializes maps:
// - fd: 0xCAFE00 or 0xCAFE01,
assert_eq!(object.programs.len(), 1);
assert!(matches!(
object.programs["tracepoint"].section,
ProgramSection::TracePoint { .. }
));
assert_eq!(object.programs["tracepoint"].section.name(), "tracepoint");
// Initialize maps:
// - fd: 0xCAFE00 or 0xCAFE01 (the 0xCAFE00 part is used to distinguish fds from indices),
// - Note that rbpf does not convert fds into real pointers,
// so we keeps the pointers to our maps in MULTIMAP_MAPS, to be used in helpers.
let mut map_instances = Vec::new();
for (map_id, (name, map)) in object.maps.iter().enumerate() {
maps.insert(name.to_owned(), (map_id as i32 | 0xCAFE00, map.clone()));
let mut maps = HashMap::new();
let mut map_instances = vec![vec![0u64], vec![0u64]];
for (name, map) in object.maps.iter() {
assert_eq!(map.key_size(), size_of::<u32>() as u32);
assert_eq!(map.value_size(), size_of::<u64>() as u32);
assert_eq!(
map.map_type(),
aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_ARRAY as u32
);
map_instances.push(vec![0u64]);
let map_id = if name == "map_1" { 0 } else { 1 };
let fd = map_id as i32 | 0xCAFE00;
maps.insert(name.to_owned(), (fd, map.clone()));
unsafe {
MULTIMAP_MAPS[if name == "map_1" { 0 } else { 1 }] =
&mut map_instances[map_id] as *mut _;
MULTIMAP_MAPS[map_id] = &mut map_instances[map_id] as *mut _;
}
}
@ -60,7 +75,7 @@ fn use_map_with_rbpf() {
.map(|(s, (fd, map))| (s.as_ref() as &str, Some(*fd), map)),
)
.expect("Relocation failed");
// Actually there is no call involved.
// Actually there is no local function call involved.
object.relocate_calls().unwrap();
// Executes the program

Loading…
Cancel
Save