diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs index 810cc83b..3e08e3ad 100644 --- a/aya/src/obj/mod.rs +++ b/aya/src/obj/mod.rs @@ -3,7 +3,8 @@ mod relocation; use object::{ read::{Object as ElfObject, ObjectSection, Section as ObjSection}, - Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SymbolKind, + Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SectionKind, + SymbolKind, }; use std::{ collections::HashMap, @@ -334,20 +335,20 @@ impl Object { parts.push(parts[0]); } - match section.name { - name if name == ".bss" || name.starts_with(".data") || name.starts_with(".rodata") => { + match section.kind { + BpfSectionKind::Data => { self.maps - .insert(name.to_string(), parse_map(§ion, name)?); + .insert(section.name.to_string(), parse_map(§ion, section.name)?); } - name if name.starts_with(".text") => self.parse_text_section(section)?, - ".BTF" => self.parse_btf(§ion)?, - ".BTF.ext" => self.parse_btf_ext(§ion)?, - map if map.starts_with("maps/") => { - let name = map.splitn(2, '/').last().unwrap(); + BpfSectionKind::Text => self.parse_text_section(section)?, + BpfSectionKind::Btf => self.parse_btf(§ion)?, + BpfSectionKind::BtfExt => self.parse_btf_ext(§ion)?, + BpfSectionKind::Maps => { + let name = section.name.splitn(2, '/').last().unwrap(); self.maps .insert(name.to_string(), parse_map(§ion, name)?); } - name if is_program_section(name) => { + BpfSectionKind::Program => { let program = self.parse_program(§ion)?; self.programs .insert(program.section.name().to_owned(), program); @@ -413,9 +414,51 @@ pub enum ParseError { InvalidSymbol { index: usize, name: Option }, } +#[derive(Debug)] +enum BpfSectionKind { + Undefined, + Maps, + BtfMaps, + Program, + Data, + Text, + Btf, + BtfExt, + License, + Version, +} + +impl BpfSectionKind { + fn from_name(name: &str) -> BpfSectionKind { + if name.starts_with("license") { + BpfSectionKind::License + } else if name.starts_with("version") { + BpfSectionKind::Version + } else if name.starts_with("maps") { + BpfSectionKind::Maps + } else if name.starts_with(".maps") { + BpfSectionKind::BtfMaps + } else if name.starts_with(".text") { + BpfSectionKind::Text + } else if name.starts_with(".bss") + || name.starts_with(".data") + || name.starts_with(".rodata") + { + BpfSectionKind::Data + } else if name == ".BTF" { + BpfSectionKind::Btf + } else if name == ".BTF.ext" { + BpfSectionKind::BtfExt + } else { + BpfSectionKind::Undefined + } + } +} + #[derive(Debug)] struct Section<'a> { index: SectionIndex, + kind: BpfSectionKind, address: u64, name: &'a str, data: &'a [u8], @@ -432,11 +475,22 @@ impl<'data, 'file, 'a> TryFrom<&'a ObjSection<'data, 'file>> for Section<'a> { index: index.0, source, }; - + let name = section.name().map_err(map_err)?; + let kind = match BpfSectionKind::from_name(name) { + BpfSectionKind::Undefined => { + if section.kind() == SectionKind::Text && section.size() > 0 { + BpfSectionKind::Program + } else { + BpfSectionKind::Undefined + } + } + k => k, + }; Ok(Section { index, + kind, address: section.address(), - name: section.name().map_err(map_err)?, + name, data: section.data().map_err(map_err)?, size: section.size(), relocations: section @@ -572,39 +626,6 @@ fn copy_instructions(data: &[u8]) -> Result, ParseError> { 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", - "perf_event", - "sk_msg", - "sk_skb/stream_parser", - "sk_skb/stream_verdict", - "socket_filter", - "sockops", - "tp", - "tracepoint", - "uprobe", - "uretprobe", - "xdp", - "raw_tp", - "raw_tracepoint", - "lsm", - "tp_btf", - ] { - if name.starts_with(prefix) { - return true; - } - } - - false -} - #[cfg(test)] mod tests { use matches::assert_matches; @@ -614,9 +635,10 @@ mod tests { use super::*; use crate::PinningType; - fn fake_section<'a>(name: &'a str, data: &'a [u8]) -> Section<'a> { + fn fake_section<'a>(kind: BpfSectionKind, name: &'a str, data: &'a [u8]) -> Section<'a> { Section { index: SectionIndex(0), + kind, address: 0, name, data, @@ -760,7 +782,7 @@ mod tests { #[test] fn test_parse_map_error() { assert!(matches!( - parse_map(&fake_section("maps/foo", &[]), "foo"), + parse_map(&fake_section(BpfSectionKind::Maps, "maps/foo", &[]), "foo"), Err(ParseError::InvalidMapDefinition { .. }) )); } @@ -770,6 +792,7 @@ mod tests { assert!(matches!( parse_map( &fake_section( + BpfSectionKind::Maps, "maps/foo", bytes_of(&bpf_map_def { map_type: 1, @@ -806,6 +829,7 @@ mod tests { assert!(matches!( parse_map( &fake_section( + BpfSectionKind::Data, ".bss", map_data, ), @@ -841,7 +865,11 @@ mod tests { let obj = fake_obj(); assert_matches!( - obj.parse_program(&fake_section("kprobe/foo", &42u32.to_ne_bytes(),),), + obj.parse_program(&fake_section( + BpfSectionKind::Program, + "kprobe/foo", + &42u32.to_ne_bytes(), + ),), Err(ParseError::InvalidProgramCode) ); } @@ -851,7 +879,7 @@ mod tests { let obj = fake_obj(); assert_matches!( - obj.parse_program(&fake_section("kprobe/foo", bytes_of(&fake_ins()))), + obj.parse_program(&fake_section(BpfSectionKind::Program,"kprobe/foo", bytes_of(&fake_ins()))), Ok(Program { license, kernel_version: KernelVersion::Any, @@ -873,6 +901,7 @@ mod tests { assert_matches!( obj.parse_section(fake_section( + BpfSectionKind::Maps, "maps/foo", bytes_of(&bpf_map_def { map_type: 1, @@ -892,31 +921,35 @@ mod tests { fn test_parse_section_data() { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section(".bss", b"map data"),), + obj.parse_section(fake_section(BpfSectionKind::Data, ".bss", b"map data"),), Ok(()) ); assert!(obj.maps.get(".bss").is_some()); assert_matches!( - obj.parse_section(fake_section(".rodata", b"map data"),), + obj.parse_section(fake_section(BpfSectionKind::Data, ".rodata", b"map data"),), Ok(()) ); assert!(obj.maps.get(".rodata").is_some()); assert_matches!( - obj.parse_section(fake_section(".rodata.boo", b"map data"),), + obj.parse_section(fake_section( + BpfSectionKind::Data, + ".rodata.boo", + b"map data" + ),), Ok(()) ); assert!(obj.maps.get(".rodata.boo").is_some()); assert_matches!( - obj.parse_section(fake_section(".data", b"map data"),), + obj.parse_section(fake_section(BpfSectionKind::Data, ".data", b"map data"),), Ok(()) ); assert!(obj.maps.get(".data").is_some()); assert_matches!( - obj.parse_section(fake_section(".data.boo", b"map data"),), + obj.parse_section(fake_section(BpfSectionKind::Data, ".data.boo", b"map data"),), Ok(()) ); assert!(obj.maps.get(".data.boo").is_some()); @@ -927,7 +960,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("kprobe/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "kprobe/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -944,7 +981,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("uprobe/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "uprobe/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -961,7 +1002,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("tracepoint/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "tracepoint/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -973,7 +1018,11 @@ mod tests { ); assert_matches!( - obj.parse_section(fake_section("tp/foo/bar", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "tp/foo/bar", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -990,7 +1039,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("socket_filter/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "socket_filter/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1007,7 +1060,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("xdp/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "xdp/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1024,7 +1081,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("raw_tp/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "raw_tp/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1036,7 +1097,11 @@ mod tests { ); assert_matches!( - obj.parse_section(fake_section("raw_tracepoint/bar", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "raw_tracepoint/bar", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1053,7 +1118,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("lsm/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "lsm/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1070,7 +1139,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("tp_btf/foo", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "tp_btf/foo", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1087,7 +1160,11 @@ mod tests { let mut obj = fake_obj(); assert_matches!( - obj.parse_section(fake_section("sk_skb/stream_parser", bytes_of(&fake_ins()))), + obj.parse_section(fake_section( + BpfSectionKind::Program, + "sk_skb/stream_parser", + bytes_of(&fake_ins()) + )), Ok(()) ); assert_matches!( @@ -1105,6 +1182,7 @@ mod tests { assert_matches!( obj.parse_section(fake_section( + BpfSectionKind::Program, "sk_skb/stream_parser/my_parser", bytes_of(&fake_ins()) )),