aya: refactor program section parsing

This renames aya::obj::ProgramKind to aya::obj::ProgramSection and moves
all the program section parsing to ProgramSection::from_str.
pull/14/head
Alessandro Decina 3 years ago
parent 0188622580
commit bb595c4e69

@ -16,7 +16,7 @@ use crate::{
maps::{Map, MapError, MapLock, MapRef, MapRefMut}, maps::{Map, MapError, MapLock, MapRef, MapRefMut},
obj::{ obj::{
btf::{Btf, BtfError}, btf::{Btf, BtfError},
Object, ParseError, ProgramKind, Object, ParseError, ProgramSection,
}, },
programs::{ programs::{
CgroupSkb, CgroupSkbAttachType, KProbe, LircMode2, ProbeKind, Program, ProgramData, CgroupSkb, CgroupSkbAttachType, KProbe, LircMode2, ProbeKind, Program, ProgramData,
@ -148,55 +148,57 @@ impl Bpf {
.programs .programs
.drain() .drain()
.map(|(name, obj)| { .map(|(name, obj)| {
let kind = obj.kind; let section = obj.section.clone();
let data = ProgramData { let data = ProgramData {
obj, obj,
name: name.clone(), name: name.clone(),
fd: None, fd: None,
links: Vec::new(), links: Vec::new(),
}; };
let program = match kind { let program = match section {
ProgramKind::KProbe => Program::KProbe(KProbe { ProgramSection::KProbe { .. } => Program::KProbe(KProbe {
data, data,
kind: ProbeKind::KProbe, kind: ProbeKind::KProbe,
}), }),
ProgramKind::KRetProbe => Program::KProbe(KProbe { ProgramSection::KRetProbe { .. } => Program::KProbe(KProbe {
data, data,
kind: ProbeKind::KRetProbe, kind: ProbeKind::KRetProbe,
}), }),
ProgramKind::UProbe => Program::UProbe(UProbe { ProgramSection::UProbe { .. } => Program::UProbe(UProbe {
data, data,
kind: ProbeKind::UProbe, kind: ProbeKind::UProbe,
}), }),
ProgramKind::URetProbe => Program::UProbe(UProbe { ProgramSection::URetProbe { .. } => Program::UProbe(UProbe {
data, data,
kind: ProbeKind::URetProbe, kind: ProbeKind::URetProbe,
}), }),
ProgramKind::TracePoint => Program::TracePoint(TracePoint { data }), ProgramSection::TracePoint { .. } => Program::TracePoint(TracePoint { data }),
ProgramKind::SocketFilter => Program::SocketFilter(SocketFilter { data }), ProgramSection::SocketFilter { .. } => {
ProgramKind::Xdp => Program::Xdp(Xdp { data }), Program::SocketFilter(SocketFilter { data })
ProgramKind::SkMsg => Program::SkMsg(SkMsg { data }), }
ProgramKind::SkSkbStreamParser => Program::SkSkb(SkSkb { ProgramSection::Xdp { .. } => Program::Xdp(Xdp { data }),
ProgramSection::SkMsg { .. } => Program::SkMsg(SkMsg { data }),
ProgramSection::SkSkbStreamParser { .. } => Program::SkSkb(SkSkb {
data, data,
kind: SkSkbKind::StreamParser, kind: SkSkbKind::StreamParser,
}), }),
ProgramKind::SkSkbStreamVerdict => Program::SkSkb(SkSkb { ProgramSection::SkSkbStreamVerdict { .. } => Program::SkSkb(SkSkb {
data, data,
kind: SkSkbKind::StreamVerdict, kind: SkSkbKind::StreamVerdict,
}), }),
ProgramKind::SockOps => Program::SockOps(SockOps { data }), ProgramSection::SockOps { .. } => Program::SockOps(SockOps { data }),
ProgramKind::SchedClassifier => { ProgramSection::SchedClassifier { .. } => {
Program::SchedClassifier(SchedClassifier { data }) Program::SchedClassifier(SchedClassifier { data })
} }
ProgramKind::CgroupSkbIngress => Program::CgroupSkb(CgroupSkb { ProgramSection::CgroupSkbIngress { .. } => Program::CgroupSkb(CgroupSkb {
data, data,
expected_attach_type: Some(CgroupSkbAttachType::Ingress), expected_attach_type: Some(CgroupSkbAttachType::Ingress),
}), }),
ProgramKind::CgroupSkbEgress => Program::CgroupSkb(CgroupSkb { ProgramSection::CgroupSkbEgress { .. } => Program::CgroupSkb(CgroupSkb {
data, data,
expected_attach_type: Some(CgroupSkbAttachType::Egress), expected_attach_type: Some(CgroupSkbAttachType::Egress),
}), }),
ProgramKind::LircMode2 => Program::LircMode2(LircMode2 { data }), ProgramSection::LircMode2 { .. } => Program::LircMode2(LircMode2 { data }),
}; };
(name, program) (name, program)

@ -51,7 +51,7 @@ pub struct Map {
pub(crate) struct Program { pub(crate) struct Program {
pub(crate) license: CString, pub(crate) license: CString,
pub(crate) kernel_version: KernelVersion, pub(crate) kernel_version: KernelVersion,
pub(crate) kind: ProgramKind, pub(crate) section: ProgramSection,
pub(crate) function: Function, pub(crate) function: Function,
} }
@ -64,49 +64,86 @@ pub(crate) struct Function {
pub(crate) instructions: Vec<bpf_insn>, pub(crate) instructions: Vec<bpf_insn>,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Clone)]
pub enum ProgramKind { pub enum ProgramSection {
KProbe, KRetProbe { name: String },
KRetProbe, KProbe { name: String },
UProbe, UProbe { name: String },
URetProbe, URetProbe { name: String },
TracePoint, TracePoint { name: String },
SocketFilter, SocketFilter { name: String },
Xdp, Xdp { name: String },
SkMsg, SkMsg { name: String },
SkSkbStreamParser, SkSkbStreamParser { name: String },
SkSkbStreamVerdict, SkSkbStreamVerdict { name: String },
SockOps, SockOps { name: String },
SchedClassifier, SchedClassifier { name: String },
CgroupSkbIngress, CgroupSkbIngress { name: String },
CgroupSkbEgress, CgroupSkbEgress { name: String },
LircMode2, LircMode2 { name: String },
} }
impl FromStr for ProgramKind { impl ProgramSection {
fn name(&self) -> &str {
match self {
ProgramSection::KRetProbe { name } => name,
ProgramSection::KProbe { name } => name,
ProgramSection::UProbe { name } => name,
ProgramSection::URetProbe { name } => name,
ProgramSection::TracePoint { name } => name,
ProgramSection::SocketFilter { name } => name,
ProgramSection::Xdp { name } => name,
ProgramSection::SkMsg { name } => name,
ProgramSection::SkSkbStreamParser { name } => name,
ProgramSection::SkSkbStreamVerdict { name } => name,
ProgramSection::SockOps { name } => name,
ProgramSection::SchedClassifier { name } => name,
ProgramSection::CgroupSkbIngress { name } => name,
ProgramSection::CgroupSkbEgress { name } => name,
ProgramSection::LircMode2 { name } => name,
}
}
}
impl FromStr for ProgramSection {
type Err = ParseError; type Err = ParseError;
fn from_str(kind: &str) -> Result<ProgramKind, ParseError> { fn from_str(section: &str) -> Result<ProgramSection, ParseError> {
use ProgramKind::*; use ProgramSection::*;
// parse the common case, eg "xdp/program_name" or
// "sk_skb/stream_verdict/program_name"
let mut parts = section.rsplitn(2, "/").collect::<Vec<_>>();
if parts.len() == 1 {
parts.push(parts[0]);
}
let kind = parts[1];
let name = parts[0].to_owned();
Ok(match kind { Ok(match kind {
"kprobe" => KProbe, "kprobe" => KProbe { name },
"kretprobe" => KRetProbe, "kretprobe" => KRetProbe { name },
"uprobe" => UProbe, "uprobe" => UProbe { name },
"uretprobe" => URetProbe, "uretprobe" => URetProbe { name },
"xdp" => Xdp, "xdp" => Xdp { name },
"tracepoint" => TracePoint, _ if kind.starts_with("tracepoint") || kind.starts_with("tp") => {
"socket_filter" => SocketFilter, // tracepoint sections are named `tracepoint/category/event_name`,
"sk_msg" => SkMsg, // and we want to parse the name as "category/event_name"
"sk_skb/stream_parser" => SkSkbStreamParser, let name = section.splitn(2, "/").last().unwrap().to_owned();
"sk_skb/stream_verdict" => SkSkbStreamVerdict, TracePoint { name }
"sockops" => SockOps, }
"classifier" => SchedClassifier, "socket_filter" => SocketFilter { name },
"cgroup_skb/ingress" => CgroupSkbIngress, "sk_msg" => SkMsg { name },
"cgroup_skb/egress" => CgroupSkbEgress, "sk_skb/stream_parser" => SkSkbStreamParser { name },
"lirc_mode2" => LircMode2, "sk_skb/stream_verdict" => SkSkbStreamVerdict { name },
"sockops" => SockOps { name },
"classifier" => SchedClassifier { name },
"cgroup_skb/ingress" => CgroupSkbIngress { name },
"cgroup_skb/egress" => CgroupSkbEgress { name },
"lirc_mode2" => LircMode2 { name },
_ => { _ => {
return Err(ParseError::InvalidProgramKind { return Err(ParseError::InvalidProgramSection {
kind: kind.to_string(), section: section.to_owned(),
}) })
} }
}) })
@ -181,18 +218,15 @@ impl Object {
Ok(()) Ok(())
} }
fn parse_program( fn parse_program(&self, section: &Section) -> Result<Program, ParseError> {
&self, let prog_sec = ProgramSection::from_str(section.name)?;
section: &Section, let name = prog_sec.name().to_owned();
ty: &str,
name: &str,
) -> Result<Program, ParseError> {
Ok(Program { Ok(Program {
license: self.license.clone(), license: self.license.clone(),
kernel_version: self.kernel_version, kernel_version: self.kernel_version,
kind: ProgramKind::from_str(ty)?, section: prog_sec,
function: Function { function: Function {
name: name.to_owned(), name,
address: section.address, address: section.address,
section_index: section.index, section_index: section.index,
section_offset: 0, section_offset: 0,
@ -276,38 +310,23 @@ impl Object {
} }
} }
match parts.as_slice() { match section.name {
&[name] name if name == ".bss" || name.starts_with(".data") || name.starts_with(".rodata") => {
if name == ".bss" || name.starts_with(".data") || name.starts_with(".rodata") =>
{
self.maps self.maps
.insert(name.to_string(), parse_map(&section, name)?); .insert(name.to_string(), parse_map(&section, name)?);
} }
&[name] if name.starts_with(".text") => self.parse_text_section(section)?, name if name.starts_with(".text") => self.parse_text_section(section)?,
&[".BTF"] => self.parse_btf(&section)?, ".BTF" => self.parse_btf(&section)?,
&[".BTF.ext"] => self.parse_btf_ext(&section)?, ".BTF.ext" => self.parse_btf_ext(&section)?,
&["maps", name] => { map if map.starts_with("maps/") => {
let name = map.splitn(2, "/").last().unwrap();
self.maps self.maps
.insert(name.to_string(), parse_map(&section, name)?); .insert(name.to_string(), parse_map(&section, name)?);
} }
&[ty @ "kprobe", name] name if is_program_section(name) => {
| &[ty @ "kretprobe", name] let program = self.parse_program(&section)?;
| &[ty @ "uprobe", name]
| &[ty @ "uretprobe", name]
| &[ty @ "socket_filter", name]
| &[ty @ "xdp", name]
| &[ty @ "tracepoint", name]
| &[ty @ "sk_msg", name]
| &[ty @ "sk_skb/stream_parser", name]
| &[ty @ "sk_skb/stream_verdict", name]
| &[ty @ "sockops", name]
| &[ty @ "classifier", name]
| &[ty @ "cgroup_skb/ingress", name]
| &[ty @ "cgroup_skb/egress", name]
| &[ty @ "cgroup/skb", name]
| &[ty @ "lirc_mode2", name] => {
self.programs self.programs
.insert(name.to_string(), self.parse_program(&section, ty, name)?); .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,
@ -351,8 +370,8 @@ pub enum ParseError {
#[error("unsupported relocation target")] #[error("unsupported relocation target")]
UnsupportedRelocationTarget, UnsupportedRelocationTarget,
#[error("invalid program kind `{kind}`")] #[error("invalid program section `{section}`")]
InvalidProgramKind { kind: String }, InvalidProgramSection { section: String },
#[error("invalid program code")] #[error("invalid program code")]
InvalidProgramCode, InvalidProgramCode,
@ -516,6 +535,34 @@ fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
Ok(instructions) Ok(instructions)
} }
fn is_program_section(name: &str) -> bool {
for prefix in &[
"classifier",
"cgroup/skb",
"cgroup_skb/egress",
"cgroup_skb/ingress",
"kprobe",
"kretprobe",
"lirc_mode2",
"sk_msg",
"sk_skb/stream_parser",
"sk_skb/stream_verdict",
"socket_filter",
"sockops",
"tp",
"tracepoint",
"uprobe",
"uretprobe",
"xdp",
] {
if name.starts_with(prefix) {
return true;
}
}
false
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use matches::assert_matches; use matches::assert_matches;
@ -723,11 +770,7 @@ mod tests {
let obj = fake_obj(); let obj = fake_obj();
assert_matches!( assert_matches!(
obj.parse_program( obj.parse_program(&fake_section("kprobe/foo", &42u32.to_ne_bytes(),),),
&fake_section("kprobe/foo", &42u32.to_ne_bytes(),),
"kprobe",
"foo"
),
Err(ParseError::InvalidProgramCode) Err(ParseError::InvalidProgramCode)
); );
} }
@ -737,11 +780,11 @@ mod tests {
let obj = fake_obj(); let obj = fake_obj();
assert_matches!( assert_matches!(
obj.parse_program(&fake_section("kprobe/foo", bytes_of(&fake_ins())), "kprobe", "foo"), obj.parse_program(&fake_section("kprobe/foo", bytes_of(&fake_ins()))),
Ok(Program { Ok(Program {
license, license,
kernel_version: KernelVersion::Any, kernel_version: KernelVersion::Any,
kind: ProgramKind::KProbe, section: ProgramSection::KProbe { .. },
function: Function { function: Function {
name, name,
address: 0, address: 0,
@ -820,7 +863,7 @@ mod tests {
assert_matches!( assert_matches!(
obj.programs.get("foo"), obj.programs.get("foo"),
Some(Program { Some(Program {
kind: ProgramKind::KProbe, section: ProgramSection::KProbe { .. },
.. ..
}) })
); );
@ -837,7 +880,7 @@ mod tests {
assert_matches!( assert_matches!(
obj.programs.get("foo"), obj.programs.get("foo"),
Some(Program { Some(Program {
kind: ProgramKind::UProbe, section: ProgramSection::UProbe { .. },
.. ..
}) })
); );
@ -854,7 +897,19 @@ mod tests {
assert_matches!( assert_matches!(
obj.programs.get("foo"), obj.programs.get("foo"),
Some(Program { Some(Program {
kind: ProgramKind::TracePoint, section: ProgramSection::TracePoint { .. },
..
})
);
assert_matches!(
obj.parse_section(fake_section("tp/foo/bar", bytes_of(&fake_ins()))),
Ok(())
);
assert_matches!(
obj.programs.get("foo/bar"),
Some(Program {
section: ProgramSection::TracePoint { .. },
.. ..
}) })
); );
@ -871,7 +926,7 @@ mod tests {
assert_matches!( assert_matches!(
obj.programs.get("foo"), obj.programs.get("foo"),
Some(Program { Some(Program {
kind: ProgramKind::SocketFilter, section: ProgramSection::SocketFilter { .. },
.. ..
}) })
); );
@ -888,7 +943,7 @@ mod tests {
assert_matches!( assert_matches!(
obj.programs.get("foo"), obj.programs.get("foo"),
Some(Program { Some(Program {
kind: ProgramKind::Xdp, section: ProgramSection::Xdp { .. },
.. ..
}) })
); );

Loading…
Cancel
Save