obj: Improve section detection

This commit improves section detection.
Previously, a section named "xdp_metadata" would be interpretted as a
program section, which is incorrect. This commit first attempts to
identify a BPF section by name, then by section.kind() ==
SectionKind::Text (executable code). The computed section kind is
stored in the Section so variants can be easily matched on later.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/125/head
Dave Tucker 3 years ago
parent c0f695c4b6
commit e4d9774bf7

@ -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(&section, name)?);
.insert(section.name.to_string(), parse_map(&section, section.name)?);
}
name if name.starts_with(".text") => self.parse_text_section(section)?,
".BTF" => self.parse_btf(&section)?,
".BTF.ext" => self.parse_btf_ext(&section)?,
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(&section)?,
BpfSectionKind::BtfExt => self.parse_btf_ext(&section)?,
BpfSectionKind::Maps => {
let name = section.name.splitn(2, '/').last().unwrap();
self.maps
.insert(name.to_string(), parse_map(&section, name)?);
}
name if is_program_section(name) => {
BpfSectionKind::Program => {
let program = self.parse_program(&section)?;
self.programs
.insert(program.section.name().to_owned(), program);
@ -413,9 +414,51 @@ pub enum ParseError {
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)]
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<Vec<bpf_insn>, 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())
)),

Loading…
Cancel
Save