|
|
@ -3,7 +3,7 @@ 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, SectionIndex, SymbolIndex,
|
|
|
|
Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use std::{
|
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
collections::HashMap,
|
|
|
@ -14,7 +14,7 @@ use std::{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use thiserror::Error;
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
|
|
|
pub use relocation::*;
|
|
|
|
use relocation::*;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
use crate::{
|
|
|
|
bpf_map_def,
|
|
|
|
bpf_map_def,
|
|
|
@ -34,8 +34,9 @@ pub struct Object {
|
|
|
|
pub btf_ext: Option<BtfExt>,
|
|
|
|
pub btf_ext: Option<BtfExt>,
|
|
|
|
pub(crate) maps: HashMap<String, Map>,
|
|
|
|
pub(crate) maps: HashMap<String, Map>,
|
|
|
|
pub(crate) programs: HashMap<String, Program>,
|
|
|
|
pub(crate) programs: HashMap<String, Program>,
|
|
|
|
pub(crate) relocations: HashMap<SectionIndex, Vec<Relocation>>,
|
|
|
|
pub(crate) functions: HashMap<u64, Function>,
|
|
|
|
pub(crate) symbols_by_index: HashMap<SymbolIndex, Symbol>,
|
|
|
|
pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
|
|
|
|
|
|
|
|
pub(crate) symbols_by_index: HashMap<usize, Symbol>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
@ -50,9 +51,17 @@ 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) instructions: Vec<bpf_insn>,
|
|
|
|
|
|
|
|
pub(crate) kind: ProgramKind,
|
|
|
|
pub(crate) kind: ProgramKind,
|
|
|
|
|
|
|
|
pub(crate) function: Function,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
|
|
pub(crate) struct Function {
|
|
|
|
|
|
|
|
pub(crate) address: u64,
|
|
|
|
|
|
|
|
pub(crate) name: String,
|
|
|
|
pub(crate) section_index: SectionIndex,
|
|
|
|
pub(crate) section_index: SectionIndex,
|
|
|
|
|
|
|
|
pub(crate) section_offset: usize,
|
|
|
|
|
|
|
|
pub(crate) instructions: Vec<bpf_insn>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
@ -107,23 +116,26 @@ impl Object {
|
|
|
|
|
|
|
|
|
|
|
|
let mut bpf_obj = Object::new(endianness, license, kernel_version);
|
|
|
|
let mut bpf_obj = Object::new(endianness, license, kernel_version);
|
|
|
|
|
|
|
|
|
|
|
|
for s in obj.sections() {
|
|
|
|
|
|
|
|
bpf_obj.parse_section(Section::try_from(&s)?)?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(symbol_table) = obj.symbol_table() {
|
|
|
|
if let Some(symbol_table) = obj.symbol_table() {
|
|
|
|
for symbol in symbol_table.symbols() {
|
|
|
|
for symbol in symbol_table.symbols() {
|
|
|
|
bpf_obj.symbols_by_index.insert(
|
|
|
|
let sym = Symbol {
|
|
|
|
symbol.index(),
|
|
|
|
index: symbol.index().0,
|
|
|
|
Symbol {
|
|
|
|
name: symbol.name().ok().map(String::from),
|
|
|
|
name: symbol.name().ok().map(String::from),
|
|
|
|
section_index: symbol.section().index(),
|
|
|
|
section_index: symbol.section().index(),
|
|
|
|
address: symbol.address(),
|
|
|
|
address: symbol.address(),
|
|
|
|
size: symbol.size(),
|
|
|
|
},
|
|
|
|
is_definition: symbol.is_definition(),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
bpf_obj
|
|
|
|
|
|
|
|
.symbols_by_index
|
|
|
|
|
|
|
|
.insert(symbol.index().0, sym.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for s in obj.sections() {
|
|
|
|
|
|
|
|
bpf_obj.parse_section(Section::try_from(&s)?)?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Ok(bpf_obj);
|
|
|
|
return Ok(bpf_obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -136,46 +148,105 @@ impl Object {
|
|
|
|
btf_ext: None,
|
|
|
|
btf_ext: None,
|
|
|
|
maps: HashMap::new(),
|
|
|
|
maps: HashMap::new(),
|
|
|
|
programs: HashMap::new(),
|
|
|
|
programs: HashMap::new(),
|
|
|
|
|
|
|
|
functions: HashMap::new(),
|
|
|
|
relocations: HashMap::new(),
|
|
|
|
relocations: HashMap::new(),
|
|
|
|
symbols_by_index: HashMap::new(),
|
|
|
|
symbols_by_index: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_program(&self, section: &Section, ty: &str) -> Result<Program, ParseError> {
|
|
|
|
fn parse_btf(&mut self, section: &Section) -> Result<(), BtfError> {
|
|
|
|
let num_instructions = section.data.len() / mem::size_of::<bpf_insn>();
|
|
|
|
self.btf = Some(Btf::parse(section.data, self.endianness)?);
|
|
|
|
if section.data.len() % mem::size_of::<bpf_insn>() > 0 {
|
|
|
|
|
|
|
|
return Err(ParseError::InvalidProgramCode);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let instructions = (0..num_instructions)
|
|
|
|
|
|
|
|
.map(|i| unsafe {
|
|
|
|
|
|
|
|
ptr::read_unaligned(
|
|
|
|
|
|
|
|
(section.data.as_ptr() as usize + i * mem::size_of::<bpf_insn>())
|
|
|
|
|
|
|
|
as *const bpf_insn,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_btf_ext(&mut self, section: &Section) -> Result<(), BtfError> {
|
|
|
|
|
|
|
|
self.btf_ext = Some(BtfExt::parse(section.data, self.endianness)?);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_program(
|
|
|
|
|
|
|
|
&self,
|
|
|
|
|
|
|
|
section: &Section,
|
|
|
|
|
|
|
|
ty: &str,
|
|
|
|
|
|
|
|
name: &str,
|
|
|
|
|
|
|
|
) -> Result<Program, ParseError> {
|
|
|
|
Ok(Program {
|
|
|
|
Ok(Program {
|
|
|
|
section_index: section.index,
|
|
|
|
|
|
|
|
license: self.license.clone(),
|
|
|
|
license: self.license.clone(),
|
|
|
|
kernel_version: self.kernel_version,
|
|
|
|
kernel_version: self.kernel_version,
|
|
|
|
instructions,
|
|
|
|
|
|
|
|
kind: ProgramKind::from_str(ty)?,
|
|
|
|
kind: ProgramKind::from_str(ty)?,
|
|
|
|
|
|
|
|
function: Function {
|
|
|
|
|
|
|
|
name: name.to_owned(),
|
|
|
|
|
|
|
|
address: section.address,
|
|
|
|
|
|
|
|
section_index: section.index,
|
|
|
|
|
|
|
|
section_offset: 0,
|
|
|
|
|
|
|
|
instructions: copy_instructions(section.data)?,
|
|
|
|
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_btf(&mut self, section: &Section) -> Result<(), BtfError> {
|
|
|
|
fn parse_text_section(&mut self, mut section: Section) -> Result<(), ParseError> {
|
|
|
|
self.btf = Some(Btf::parse(section.data, self.endianness)?);
|
|
|
|
let mut symbols_by_address = HashMap::new();
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
for sym in self.symbols_by_index.values() {
|
|
|
|
}
|
|
|
|
if sym.is_definition && sym.section_index == Some(section.index) {
|
|
|
|
|
|
|
|
if symbols_by_address.contains_key(&sym.address) {
|
|
|
|
|
|
|
|
return Err(ParseError::SymbolTableConflict {
|
|
|
|
|
|
|
|
section_index: section.index.0,
|
|
|
|
|
|
|
|
address: sym.address,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbols_by_address.insert(sym.address, sym);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut offset = 0;
|
|
|
|
|
|
|
|
while offset < section.data.len() {
|
|
|
|
|
|
|
|
let address = section.address + offset as u64;
|
|
|
|
|
|
|
|
let sym = symbols_by_address
|
|
|
|
|
|
|
|
.get(&address)
|
|
|
|
|
|
|
|
.ok_or(ParseError::UnknownSymbol {
|
|
|
|
|
|
|
|
section_index: section.index.0,
|
|
|
|
|
|
|
|
address,
|
|
|
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
if sym.size == 0 {
|
|
|
|
|
|
|
|
return Err(ParseError::InvalidSymbol {
|
|
|
|
|
|
|
|
index: sym.index,
|
|
|
|
|
|
|
|
name: sym.name.clone(),
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.functions.insert(
|
|
|
|
|
|
|
|
sym.address,
|
|
|
|
|
|
|
|
Function {
|
|
|
|
|
|
|
|
address,
|
|
|
|
|
|
|
|
name: sym.name.clone().unwrap(),
|
|
|
|
|
|
|
|
section_index: section.index,
|
|
|
|
|
|
|
|
section_offset: offset,
|
|
|
|
|
|
|
|
instructions: copy_instructions(
|
|
|
|
|
|
|
|
§ion.data[offset..offset + sym.size as usize],
|
|
|
|
|
|
|
|
)?,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
offset += sym.size as usize;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if !section.relocations.is_empty() {
|
|
|
|
|
|
|
|
self.relocations.insert(
|
|
|
|
|
|
|
|
section.index,
|
|
|
|
|
|
|
|
section
|
|
|
|
|
|
|
|
.relocations
|
|
|
|
|
|
|
|
.drain(..)
|
|
|
|
|
|
|
|
.map(|rel| (rel.offset, rel))
|
|
|
|
|
|
|
|
.collect(),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_btf_ext(&mut self, section: &Section) -> Result<(), BtfError> {
|
|
|
|
|
|
|
|
self.btf_ext = Some(BtfExt::parse(section.data, self.endianness)?);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_section(&mut self, section: Section) -> Result<(), BpfError> {
|
|
|
|
fn parse_section(&mut self, mut section: Section) -> Result<(), BpfError> {
|
|
|
|
let parts = section.name.split("/").collect::<Vec<_>>();
|
|
|
|
let parts = section.name.split("/").collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
|
|
match parts.as_slice() {
|
|
|
|
match parts.as_slice() {
|
|
|
@ -185,6 +256,7 @@ impl Object {
|
|
|
|
self.maps
|
|
|
|
self.maps
|
|
|
|
.insert(name.to_string(), parse_map(§ion, name)?);
|
|
|
|
.insert(name.to_string(), parse_map(§ion, name)?);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&[".text"] => self.parse_text_section(section)?,
|
|
|
|
&[".BTF"] => self.parse_btf(§ion)?,
|
|
|
|
&[".BTF"] => self.parse_btf(§ion)?,
|
|
|
|
&[".BTF.ext"] => self.parse_btf_ext(§ion)?,
|
|
|
|
&[".BTF.ext"] => self.parse_btf_ext(§ion)?,
|
|
|
|
&["maps", name] => {
|
|
|
|
&["maps", name] => {
|
|
|
@ -199,9 +271,16 @@ impl Object {
|
|
|
|
| &[ty @ "xdp", name]
|
|
|
|
| &[ty @ "xdp", name]
|
|
|
|
| &[ty @ "trace_point", name] => {
|
|
|
|
| &[ty @ "trace_point", name] => {
|
|
|
|
self.programs
|
|
|
|
self.programs
|
|
|
|
.insert(name.to_string(), self.parse_program(§ion, ty)?);
|
|
|
|
.insert(name.to_string(), self.parse_program(§ion, ty, name)?);
|
|
|
|
if !section.relocations.is_empty() {
|
|
|
|
if !section.relocations.is_empty() {
|
|
|
|
self.relocations.insert(section.index, section.relocations);
|
|
|
|
self.relocations.insert(
|
|
|
|
|
|
|
|
section.index,
|
|
|
|
|
|
|
|
section
|
|
|
|
|
|
|
|
.relocations
|
|
|
|
|
|
|
|
.drain(..)
|
|
|
|
|
|
|
|
.map(|rel| (rel.offset, rel))
|
|
|
|
|
|
|
|
.collect(),
|
|
|
|
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -233,8 +312,8 @@ pub enum ParseError {
|
|
|
|
source: object::read::Error,
|
|
|
|
source: object::read::Error,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
#[error("unsupported relocation")]
|
|
|
|
#[error("unsupported relocation target")]
|
|
|
|
UnsupportedRelocationKind,
|
|
|
|
UnsupportedRelocationTarget,
|
|
|
|
|
|
|
|
|
|
|
|
#[error("invalid program kind `{kind}`")]
|
|
|
|
#[error("invalid program kind `{kind}`")]
|
|
|
|
InvalidProgramKind { kind: String },
|
|
|
|
InvalidProgramKind { kind: String },
|
|
|
@ -244,10 +323,21 @@ pub enum ParseError {
|
|
|
|
|
|
|
|
|
|
|
|
#[error("error parsing map `{name}`")]
|
|
|
|
#[error("error parsing map `{name}`")]
|
|
|
|
InvalidMapDefinition { name: String },
|
|
|
|
InvalidMapDefinition { name: String },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[error("two or more symbols in section `{section_index}` have the same address {address:x}")]
|
|
|
|
|
|
|
|
SymbolTableConflict { section_index: usize, address: u64 },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[error("unknown symbol in section `{section_index}` at address {address:x}")]
|
|
|
|
|
|
|
|
UnknownSymbol { section_index: usize, address: u64 },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[error("invalid symbol, index `{index}` name: {}", .name.as_ref().unwrap_or(&"[unknown]".into()))]
|
|
|
|
|
|
|
|
InvalidSymbol { index: usize, name: Option<String> },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct Section<'a> {
|
|
|
|
struct Section<'a> {
|
|
|
|
index: SectionIndex,
|
|
|
|
index: SectionIndex,
|
|
|
|
|
|
|
|
address: u64,
|
|
|
|
name: &'a str,
|
|
|
|
name: &'a str,
|
|
|
|
data: &'a [u8],
|
|
|
|
data: &'a [u8],
|
|
|
|
relocations: Vec<Relocation>,
|
|
|
|
relocations: Vec<Relocation>,
|
|
|
@ -262,19 +352,24 @@ impl<'data, 'file, 'a> TryFrom<&'a ObjSection<'data, 'file>> for Section<'a> {
|
|
|
|
index: index.0,
|
|
|
|
index: index.0,
|
|
|
|
source,
|
|
|
|
source,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Section {
|
|
|
|
Ok(Section {
|
|
|
|
index,
|
|
|
|
index,
|
|
|
|
|
|
|
|
address: section.address(),
|
|
|
|
name: section.name().map_err(map_err)?,
|
|
|
|
name: section.name().map_err(map_err)?,
|
|
|
|
data: section.data().map_err(map_err)?,
|
|
|
|
data: section.data().map_err(map_err)?,
|
|
|
|
relocations: section
|
|
|
|
relocations: section
|
|
|
|
.relocations()
|
|
|
|
.relocations()
|
|
|
|
.map(|(offset, r)| Relocation {
|
|
|
|
.map(|(offset, r)| {
|
|
|
|
kind: r.kind(),
|
|
|
|
Ok(Relocation {
|
|
|
|
target: r.target(),
|
|
|
|
symbol_index: match r.target() {
|
|
|
|
addend: r.addend(),
|
|
|
|
RelocationTarget::Symbol(index) => index.0,
|
|
|
|
offset,
|
|
|
|
_ => return Err(ParseError::UnsupportedRelocationTarget),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
offset,
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -367,6 +462,22 @@ fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
|
|
|
|
Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
|
|
|
|
Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
|
|
|
|
|
|
|
|
if data.len() % mem::size_of::<bpf_insn>() > 0 {
|
|
|
|
|
|
|
|
return Err(ParseError::InvalidProgramCode);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let num_instructions = data.len() / mem::size_of::<bpf_insn>();
|
|
|
|
|
|
|
|
let instructions = (0..num_instructions)
|
|
|
|
|
|
|
|
.map(|i| unsafe {
|
|
|
|
|
|
|
|
ptr::read_unaligned(
|
|
|
|
|
|
|
|
(data.as_ptr() as usize + i * mem::size_of::<bpf_insn>()) as *const bpf_insn,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(instructions)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
mod tests {
|
|
|
|
use matches::assert_matches;
|
|
|
|
use matches::assert_matches;
|
|
|
@ -378,6 +489,7 @@ mod tests {
|
|
|
|
fn fake_section<'a>(name: &'a str, data: &'a [u8]) -> Section<'a> {
|
|
|
|
fn fake_section<'a>(name: &'a str, data: &'a [u8]) -> Section<'a> {
|
|
|
|
Section {
|
|
|
|
Section {
|
|
|
|
index: SectionIndex(0),
|
|
|
|
index: SectionIndex(0),
|
|
|
|
|
|
|
|
address: 0,
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
data,
|
|
|
|
data,
|
|
|
|
relocations: Vec::new(),
|
|
|
|
relocations: Vec::new(),
|
|
|
@ -563,7 +675,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(),), "kprobe"),
|
|
|
|
obj.parse_program(
|
|
|
|
|
|
|
|
&fake_section("kprobe/foo", &42u32.to_ne_bytes(),),
|
|
|
|
|
|
|
|
"kprobe",
|
|
|
|
|
|
|
|
"foo"
|
|
|
|
|
|
|
|
),
|
|
|
|
Err(ParseError::InvalidProgramCode)
|
|
|
|
Err(ParseError::InvalidProgramCode)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -573,14 +689,19 @@ 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"),
|
|
|
|
obj.parse_program(&fake_section("kprobe/foo", bytes_of(&fake_ins())), "kprobe", "foo"),
|
|
|
|
Ok(Program {
|
|
|
|
Ok(Program {
|
|
|
|
license,
|
|
|
|
license,
|
|
|
|
kernel_version,
|
|
|
|
kernel_version: KernelVersion::Any,
|
|
|
|
kind: ProgramKind::KProbe,
|
|
|
|
kind: ProgramKind::KProbe,
|
|
|
|
section_index: SectionIndex(0),
|
|
|
|
function: Function {
|
|
|
|
instructions
|
|
|
|
name,
|
|
|
|
}) if license.to_string_lossy() == "GPL" && kernel_version == KernelVersion::Any && instructions.len() == 1
|
|
|
|
address: 0,
|
|
|
|
|
|
|
|
section_index: SectionIndex(0),
|
|
|
|
|
|
|
|
section_offset: 0,
|
|
|
|
|
|
|
|
instructions
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}) if license.to_string_lossy() == "GPL" && name == "foo" && instructions.len() == 1
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|