|
|
|
@ -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,
|
|
|
|
@ -333,20 +334,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);
|
|
|
|
@ -412,9 +413,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],
|
|
|
|
@ -431,11 +474,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
|
|
|
|
@ -570,39 +624,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;
|
|
|
|
@ -612,9 +633,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,
|
|
|
|
@ -758,7 +780,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 { .. })
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
@ -768,6 +790,7 @@ mod tests {
|
|
|
|
|
assert!(matches!(
|
|
|
|
|
parse_map(
|
|
|
|
|
&fake_section(
|
|
|
|
|
BpfSectionKind::Maps,
|
|
|
|
|
"maps/foo",
|
|
|
|
|
bytes_of(&bpf_map_def {
|
|
|
|
|
map_type: 1,
|
|
|
|
@ -803,6 +826,7 @@ mod tests {
|
|
|
|
|
assert!(matches!(
|
|
|
|
|
parse_map(
|
|
|
|
|
&fake_section(
|
|
|
|
|
BpfSectionKind::Data,
|
|
|
|
|
".bss",
|
|
|
|
|
map_data,
|
|
|
|
|
),
|
|
|
|
@ -837,7 +861,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)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
@ -847,7 +875,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,
|
|
|
|
@ -869,6 +897,7 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
assert_matches!(
|
|
|
|
|
obj.parse_section(fake_section(
|
|
|
|
|
BpfSectionKind::Maps,
|
|
|
|
|
"maps/foo",
|
|
|
|
|
bytes_of(&bpf_map_def {
|
|
|
|
|
map_type: 1,
|
|
|
|
@ -888,31 +917,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());
|
|
|
|
@ -923,7 +956,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!(
|
|
|
|
@ -940,7 +977,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!(
|
|
|
|
@ -957,7 +998,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!(
|
|
|
|
@ -969,7 +1014,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!(
|
|
|
|
@ -986,7 +1035,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!(
|
|
|
|
@ -1003,7 +1056,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!(
|
|
|
|
@ -1020,7 +1077,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!(
|
|
|
|
@ -1032,7 +1093,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!(
|
|
|
|
@ -1049,7 +1114,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!(
|
|
|
|
@ -1066,7 +1135,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!(
|
|
|
|
@ -1083,7 +1156,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!(
|
|
|
|
@ -1101,6 +1178,7 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
assert_matches!(
|
|
|
|
|
obj.parse_section(fake_section(
|
|
|
|
|
BpfSectionKind::Program,
|
|
|
|
|
"sk_skb/stream_parser/my_parser",
|
|
|
|
|
bytes_of(&fake_ins())
|
|
|
|
|
)),
|
|
|
|
|