use crate::core::make_alphanumeric;
use crate::core::BPF;
use crate::error::BccError;
use bcc_sys::bccapi::bpf_probe_attach_type_BPF_PROBE_ENTRY as BPF_PROBE_ENTRY;
use bcc_sys::bccapi::bpf_probe_attach_type_BPF_PROBE_RETURN as BPF_PROBE_RETURN;
use bcc_sys::bccapi::bpf_prog_type_BPF_PROG_TYPE_KPROBE as BPF_PROG_TYPE_KPROBE;
use bcc_sys::bccapi::pid_t;
use std::path::{Path, PathBuf};
#[derive(Default)]
pub struct Uprobe {
binary: Option<PathBuf>,
handler: Option<String>,
pid: Option<pid_t>,
symbol: Option<String>,
addr: Option<u64>,
ref_ctr_offset: u32,
}
impl Uprobe {
pub fn new() -> Self {
Default::default()
}
pub fn handler(mut self, name: &str) -> Self {
self.handler = Some(name.to_owned());
self
}
pub fn binary<T: AsRef<Path>>(mut self, path: T) -> Self {
self.binary = Some(PathBuf::from(path.as_ref()));
self
}
pub fn symbol(mut self, symbol: &str) -> Self {
self.symbol = Some(symbol.to_owned());
self
}
pub fn address(mut self, addr: u64) -> Self {
self.addr = Some(addr);
self
}
pub fn pid(mut self, pid: Option<pid_t>) -> Self {
self.pid = pid;
self
}
pub fn ref_ctr_offset(mut self, offset: u32) -> Self {
self.ref_ctr_offset = offset;
self
}
pub fn attach(self, bpf: &mut BPF) -> Result<(), BccError> {
if self.handler.is_none() {
return Err(BccError::InvalidUprobe {
message: "handler is required".to_string(),
});
}
if self.binary.is_none() {
return Err(BccError::InvalidUprobe {
message: "binary is required".to_string(),
});
}
let binary = self.binary.unwrap().to_str().map(|v| v.to_owned());
if binary.is_none() {
return Err(BccError::InvalidUprobe {
message: "binary path is invalid".to_string(),
});
}
let binary = binary.unwrap();
let symbol = self.symbol.as_deref().unwrap_or("");
let pid = self.pid.unwrap_or(-1);
let handler = self.handler.unwrap();
let addr = self.addr;
let (path, addr) =
crate::symbol::resolve_symbol_path(&binary, &symbol, addr.unwrap_or(0x0), pid)?;
let alpha_path = make_alphanumeric(&path);
let ev_name = format!("p_{}_0x{:x}", &alpha_path, addr);
let code_fd = bpf.load(&handler, BPF_PROG_TYPE_KPROBE, 0, 0)?;
#[cfg(any(
feature = "v0_4_0",
feature = "v0_5_0",
feature = "v0_6_0",
feature = "v0_6_1",
feature = "v0_7_0",
feature = "v0_8_0",
feature = "v0_9_0",
feature = "v0_10_0",
feature = "v0_11_0",
feature = "v0_12_0",
feature = "v0_13_0",
feature = "v0_14_0",
feature = "v0_15_0",
feature = "v0_16_0",
))]
let uprobe =
crate::core::Uprobe::new(&ev_name, BPF_PROBE_ENTRY, &path, addr, code_fd, pid)?;
#[cfg(not(any(
feature = "v0_4_0",
feature = "v0_5_0",
feature = "v0_6_0",
feature = "v0_6_1",
feature = "v0_7_0",
feature = "v0_8_0",
feature = "v0_9_0",
feature = "v0_10_0",
feature = "v0_11_0",
feature = "v0_12_0",
feature = "v0_13_0",
feature = "v0_14_0",
feature = "v0_15_0",
feature = "v0_16_0",
)))]
let uprobe = crate::core::Uprobe::new(
&ev_name,
BPF_PROBE_ENTRY,
&path,
addr,
code_fd,
pid,
self.ref_ctr_offset,
)?;
bpf.uprobes.insert(uprobe);
Ok(())
}
}
#[derive(Default)]
pub struct Uretprobe {
binary: Option<PathBuf>,
handler: Option<String>,
pid: Option<pid_t>,
symbol: Option<String>,
ref_ctr_offset: u32,
}
impl Uretprobe {
pub fn new() -> Self {
Default::default()
}
pub fn handler(mut self, name: &str) -> Self {
self.handler = Some(name.to_owned());
self
}
pub fn binary<T: AsRef<Path>>(mut self, path: T) -> Self {
self.binary = Some(PathBuf::from(path.as_ref()));
self
}
pub fn symbol(mut self, symbol: &str) -> Self {
self.symbol = Some(symbol.to_owned());
self
}
pub fn pid(mut self, pid: Option<pid_t>) -> Self {
self.pid = pid;
self
}
pub fn ref_ctr_offset(mut self, offset: u32) -> Self {
self.ref_ctr_offset = offset;
self
}
pub fn attach(self, bpf: &mut BPF) -> Result<(), BccError> {
if self.handler.is_none() {
return Err(BccError::InvalidUprobe {
message: "handler is required".to_string(),
});
}
if self.binary.is_none() {
return Err(BccError::InvalidUprobe {
message: "binary is required".to_string(),
});
}
let binary = self.binary.unwrap().to_str().map(|v| v.to_owned());
if binary.is_none() {
return Err(BccError::InvalidUprobe {
message: "binary path is invalid".to_string(),
});
}
if self.symbol.is_none() {
return Err(BccError::InvalidUprobe {
message: "symbol is required".to_string(),
});
}
let binary = binary.unwrap();
let symbol = self.symbol.unwrap();
let pid = self.pid.unwrap_or(-1);
let handler = self.handler.unwrap();
let (path, addr) = crate::symbol::resolve_symbol_path(&binary, &symbol, 0x0, pid)?;
let alpha_path = make_alphanumeric(&path);
let ev_name = format!("r_{}_0x{:x}", &alpha_path, addr);
let code_fd = bpf.load(&handler, BPF_PROG_TYPE_KPROBE, 0, 0)?;
#[cfg(any(
feature = "v0_4_0",
feature = "v0_5_0",
feature = "v0_6_0",
feature = "v0_6_1",
feature = "v0_7_0",
feature = "v0_8_0",
feature = "v0_9_0",
feature = "v0_10_0",
feature = "v0_11_0",
feature = "v0_12_0",
feature = "v0_13_0",
feature = "v0_14_0",
feature = "v0_15_0",
feature = "v0_16_0",
))]
let uprobe =
crate::core::Uprobe::new(&ev_name, BPF_PROBE_RETURN, &path, addr, code_fd, pid)?;
#[cfg(not(any(
feature = "v0_4_0",
feature = "v0_5_0",
feature = "v0_6_0",
feature = "v0_6_1",
feature = "v0_7_0",
feature = "v0_8_0",
feature = "v0_9_0",
feature = "v0_10_0",
feature = "v0_11_0",
feature = "v0_12_0",
feature = "v0_13_0",
feature = "v0_14_0",
feature = "v0_15_0",
feature = "v0_16_0",
)))]
let uprobe = crate::core::Uprobe::new(
&ev_name,
BPF_PROBE_RETURN,
&path,
addr,
code_fd,
pid,
self.ref_ctr_offset,
)?;
bpf.uprobes.insert(uprobe);
Ok(())
}
}