Merge pull request #125 from dave-tucker/btf

obj: Improve section detection
pull/134/head
Alessandro Decina 3 years ago committed by GitHub
commit 26d188c659
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,7 +3,8 @@ mod relocation;
use object::{ use object::{
read::{Object as ElfObject, ObjectSection, Section as ObjSection}, read::{Object as ElfObject, ObjectSection, Section as ObjSection},
Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SymbolKind, Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SectionKind,
SymbolKind,
}; };
use std::{ use std::{
collections::HashMap, collections::HashMap,
@ -333,20 +334,20 @@ impl Object {
parts.push(parts[0]); parts.push(parts[0]);
} }
match section.name { match section.kind {
name if name == ".bss" || name.starts_with(".data") || name.starts_with(".rodata") => { BpfSectionKind::Data => {
self.maps self.maps
.insert(name.to_string(), parse_map(&section, name)?); .insert(section.name.to_string(), parse_map(&section, section.name)?);
} }
name if name.starts_with(".text") => self.parse_text_section(section)?, BpfSectionKind::Text => self.parse_text_section(section)?,
".BTF" => self.parse_btf(&section)?, BpfSectionKind::Btf => self.parse_btf(&section)?,
".BTF.ext" => self.parse_btf_ext(&section)?, BpfSectionKind::BtfExt => self.parse_btf_ext(&section)?,
map if map.starts_with("maps/") => { BpfSectionKind::Maps => {
let name = map.splitn(2, '/').last().unwrap(); let name = section.name.splitn(2, '/').last().unwrap();
self.maps self.maps
.insert(name.to_string(), parse_map(&section, name)?); .insert(name.to_string(), parse_map(&section, name)?);
} }
name if is_program_section(name) => { BpfSectionKind::Program => {
let program = self.parse_program(&section)?; let program = self.parse_program(&section)?;
self.programs self.programs
.insert(program.section.name().to_owned(), program); .insert(program.section.name().to_owned(), program);
@ -412,9 +413,51 @@ pub enum ParseError {
InvalidSymbol { index: usize, name: Option<String> }, InvalidSymbol { index: usize, name: Option<String> },
} }
#[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)] #[derive(Debug)]
struct Section<'a> { struct Section<'a> {
index: SectionIndex, index: SectionIndex,
kind: BpfSectionKind,
address: u64, address: u64,
name: &'a str, name: &'a str,
data: &'a [u8], data: &'a [u8],
@ -431,11 +474,22 @@ impl<'data, 'file, 'a> TryFrom<&'a ObjSection<'data, 'file>> for Section<'a> {
index: index.0, index: index.0,
source, 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 { Ok(Section {
index, index,
kind,
address: section.address(), address: section.address(),
name: section.name().map_err(map_err)?, name,
data: section.data().map_err(map_err)?, data: section.data().map_err(map_err)?,
size: section.size(), size: section.size(),
relocations: section relocations: section
@ -570,39 +624,6 @@ 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",
"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)] #[cfg(test)]
mod tests { mod tests {
use matches::assert_matches; use matches::assert_matches;
@ -612,9 +633,10 @@ mod tests {
use super::*; use super::*;
use crate::PinningType; 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 { Section {
index: SectionIndex(0), index: SectionIndex(0),
kind,
address: 0, address: 0,
name, name,
data, data,
@ -758,7 +780,7 @@ mod tests {
#[test] #[test]
fn test_parse_map_error() { fn test_parse_map_error() {
assert!(matches!( assert!(matches!(
parse_map(&fake_section("maps/foo", &[]), "foo"), parse_map(&fake_section(BpfSectionKind::Maps, "maps/foo", &[]), "foo"),
Err(ParseError::InvalidMapDefinition { .. }) Err(ParseError::InvalidMapDefinition { .. })
)); ));
} }
@ -768,6 +790,7 @@ mod tests {
assert!(matches!( assert!(matches!(
parse_map( parse_map(
&fake_section( &fake_section(
BpfSectionKind::Maps,
"maps/foo", "maps/foo",
bytes_of(&bpf_map_def { bytes_of(&bpf_map_def {
map_type: 1, map_type: 1,
@ -803,6 +826,7 @@ mod tests {
assert!(matches!( assert!(matches!(
parse_map( parse_map(
&fake_section( &fake_section(
BpfSectionKind::Data,
".bss", ".bss",
map_data, map_data,
), ),
@ -837,7 +861,11 @@ mod tests {
let obj = fake_obj(); let obj = fake_obj();
assert_matches!( 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) Err(ParseError::InvalidProgramCode)
); );
} }
@ -847,7 +875,7 @@ 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()))), 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,
@ -869,6 +897,7 @@ mod tests {
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Maps,
"maps/foo", "maps/foo",
bytes_of(&bpf_map_def { bytes_of(&bpf_map_def {
map_type: 1, map_type: 1,
@ -888,31 +917,35 @@ 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(".bss", b"map data"),), obj.parse_section(fake_section(BpfSectionKind::Data, ".bss", b"map data"),),
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(".rodata", b"map data"),), obj.parse_section(fake_section(BpfSectionKind::Data, ".rodata", b"map data"),),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".rodata").is_some()); assert!(obj.maps.get(".rodata").is_some());
assert_matches!( 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(()) 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(".data", b"map data"),), obj.parse_section(fake_section(BpfSectionKind::Data, ".data", b"map data"),),
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(".data.boo", b"map data"),), obj.parse_section(fake_section(BpfSectionKind::Data, ".data.boo", b"map data"),),
Ok(()) Ok(())
); );
assert!(obj.maps.get(".data.boo").is_some()); assert!(obj.maps.get(".data.boo").is_some());
@ -923,7 +956,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -940,7 +977,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -957,7 +998,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -969,7 +1014,11 @@ mod tests {
); );
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -986,7 +1035,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1003,7 +1056,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1020,7 +1077,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1032,7 +1093,11 @@ mod tests {
); );
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1049,7 +1114,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1066,7 +1135,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1083,7 +1156,11 @@ mod tests {
let mut obj = fake_obj(); let mut obj = fake_obj();
assert_matches!( 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(()) Ok(())
); );
assert_matches!( assert_matches!(
@ -1101,6 +1178,7 @@ mod tests {
assert_matches!( assert_matches!(
obj.parse_section(fake_section( obj.parse_section(fake_section(
BpfSectionKind::Program,
"sk_skb/stream_parser/my_parser", "sk_skb/stream_parser/my_parser",
bytes_of(&fake_ins()) bytes_of(&fake_ins())
)), )),

Loading…
Cancel
Save