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 std::fs::File;
use std::io::{BufRead, BufReader};
#[derive(Default)]
pub struct Kprobe {
handler: Option<String>,
function: Option<String>,
}
impl Kprobe {
pub fn new() -> Self {
Default::default()
}
pub fn handler(mut self, name: &str) -> Self {
self.handler = Some(name.to_owned());
self
}
pub fn function(mut self, name: &str) -> Self {
self.function = Some(name.to_owned());
self
}
pub fn attach(self, bpf: &mut BPF) -> Result<(), BccError> {
if self.handler.is_none() {
return Err(BccError::InvalidKprobe {
message: "handler is required".to_string(),
});
}
if self.function.is_none() {
return Err(BccError::InvalidKprobe {
message: "function is required".to_string(),
});
}
let handler = self.handler.unwrap();
let function = self.function.unwrap();
let code_fd = bpf.load(&handler, BPF_PROG_TYPE_KPROBE, 0, 0)?;
let handler = format!("p_{}", &make_alphanumeric(&function));
let kprobe = crate::core::Kprobe::new(&handler, BPF_PROBE_ENTRY, &function, code_fd)?;
bpf.kprobes.insert(kprobe);
Ok(())
}
}
#[derive(Default)]
pub struct Kretprobe {
handler: Option<String>,
function: Option<String>,
}
impl Kretprobe {
pub fn new() -> Self {
Default::default()
}
pub fn handler(mut self, name: &str) -> Self {
self.handler = Some(name.to_owned());
self
}
pub fn function(mut self, name: &str) -> Self {
self.function = Some(name.to_owned());
self
}
pub fn attach(self, bpf: &mut BPF) -> Result<(), BccError> {
if self.handler.is_none() {
return Err(BccError::InvalidKprobe {
message: "handler is required".to_string(),
});
}
if self.function.is_none() {
return Err(BccError::InvalidKprobe {
message: "function is required".to_string(),
});
}
let handler = self.handler.unwrap();
let function = self.function.unwrap();
let code_fd = bpf.load(&handler, BPF_PROG_TYPE_KPROBE, 0, 0)?;
let handler = format!("r_{}", &make_alphanumeric(&function));
let kprobe = crate::core::Kprobe::new(&handler, BPF_PROBE_RETURN, &function, code_fd)?;
bpf.kprobes.insert(kprobe);
Ok(())
}
}
pub fn get_kprobe_functions(event_re: &str) -> Result<Vec<String>, BccError> {
let mut fns: Vec<String> = vec![];
enum Section {
Unmatched,
Begin,
End,
}
let mut in_init_section = Section::Unmatched;
let mut in_irq_section = Section::Unmatched;
let avali = BufReader::new(File::open("/proc/kallsyms").unwrap());
for line in avali.lines() {
let line = line.unwrap();
let cols: Vec<&str> = line.split_whitespace().collect();
let (t, fname) = (cols[1].to_string().to_lowercase(), cols[2]);
match in_init_section {
Section::Unmatched => {
if fname == "__init_begin" {
in_init_section = Section::Begin;
continue;
}
}
Section::Begin => {
if fname == "__init_end" {
in_init_section = Section::End;
}
continue;
}
Section::End => (),
}
match in_irq_section {
Section::Unmatched => {
if fname == "__irqentry_text_start" {
in_irq_section = Section::Begin;
continue;
}
}
Section::Begin => {
if fname == "__irqentry_text_end" {
in_irq_section = Section::End;
}
continue;
}
Section::End => (),
}
if fname.starts_with("_kbl_addr_") {
continue;
}
if fname.starts_with("__perf") || fname.starts_with("perf_") {
continue;
}
if let Some(idx) = fname.find(".cold.") {
if fname[idx + 6..].parse::<usize>().is_ok() {
continue;
}
}
if (t == "t" || t == "w") && fname.contains(event_re) {
fns.push(fname.to_owned());
}
}
Ok(fns)
}