use std::ffi::CStr;
use std::ffi::OsStr;
use std::os::fd::AsRawFd as _;
use std::os::unix::ffi::OsStrExt as _;
use crate::Error;
use crate::ErrorExt as _;
use crate::Result;
use super::sys;
#[derive(Debug)]
pub(crate) struct Btf {
data: Vec<u8>,
header: sys::btf_header,
}
impl Btf {
pub fn load_from_id(btf_id: u32) -> Result<Option<Btf>> {
if btf_id == 0 {
return Ok(None)
}
let btf_fd = sys::bpf_btf_get_fd_from_id(btf_id)
.with_context(|| format!("failed to retrieve BTF file descriptor for ID {btf_id}"))?;
let mut btf_info = sys::bpf_btf_info::default();
let () = sys::bpf_btf_get_info_from_fd(btf_fd.as_raw_fd(), &mut btf_info)
.with_context(|| format!("failed to retrieve BTF information for ID {btf_id}"))?;
let mut btf_data = Vec::<u8>::with_capacity(btf_info.btf_size as _);
let () = unsafe { btf_data.set_len(btf_data.capacity()) };
let mut btf_info = sys::bpf_btf_info {
btf: btf_data.as_mut_ptr() as _,
btf_size: btf_data.capacity() as _,
..Default::default()
};
let () = sys::bpf_btf_get_info_from_fd(btf_fd.as_raw_fd(), &mut btf_info)
.with_context(|| format!("failed to retrieve BTF information for ID {btf_id}"))?;
let header = unsafe {
btf_data
.as_mut_ptr()
.cast::<sys::btf_header>()
.read_unaligned()
};
if header.magic != 0xeb9f {
return Err(Error::with_unsupported(format!(
"encountered unsupported BTF magic number ({:#x})",
header.magic
)))
}
if header.version != 1 {
return Err(Error::with_unsupported(format!(
"encountered unsupported BTF version ({})",
header.version
)))
}
let slf = Self {
data: btf_data,
header,
};
Ok(Some(slf))
}
fn raw_strs(&self) -> &[u8] {
let start = self.header.hdr_len as usize + self.header.str_off as usize;
let end = start + self.header.str_len as usize;
self.data.get(start..end).unwrap()
}
pub fn name(&self, offset: u32) -> Option<&OsStr> {
let name = self.raw_strs().get(offset as _..)?;
let name = CStr::from_bytes_until_nul(name).unwrap();
Some(OsStr::from_bytes(name.to_bytes()))
}
}
#[cfg(test)]
mod tests {
use super::*;
use blazesym_dev::prog_mut;
use blazesym_dev::test_object;
use blazesym_dev::TracepointCategory;
use test_tag::tag;
#[tag(miri)]
#[test]
#[cfg(target_endian = "little")]
fn btf_name_query() {
let btf = Btf {
data: vec![
159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 96, 2, 0, 0, 96, 2, 0, 0, 18, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 32, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0,
0, 0, 0, 1, 4, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0,
0, 0, 0, 0, 0, 4, 0, 0, 4, 32, 0, 0, 0, 25, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 30, 0,
0, 0, 5, 0, 0, 0, 64, 0, 0, 0, 42, 0, 0, 0, 7, 0, 0, 0, 128, 0, 0, 0, 51, 0, 0, 0,
7, 0, 0, 0, 192, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 14, 9, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 12, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 64, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 13, 2, 0, 0, 0, 95, 0, 0, 0, 11, 0, 0, 0, 99, 0, 0, 0, 1, 0, 0,
12, 13, 0, 0, 0, 9, 1, 0, 0, 5, 0, 0, 4, 32, 0, 0, 0, 21, 1, 0, 0, 16, 0, 0, 0, 0,
0, 0, 0, 27, 1, 0, 0, 18, 0, 0, 0, 64, 0, 0, 0, 31, 1, 0, 0, 16, 0, 0, 0, 128, 0,
0, 0, 46, 1, 0, 0, 20, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 192, 0, 0,
0, 58, 1, 0, 0, 0, 0, 0, 8, 17, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 32,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 28, 0, 0, 0,
77, 1, 0, 0, 4, 0, 0, 6, 4, 0, 0, 0, 93, 1, 0, 0, 0, 0, 0, 0, 110, 1, 0, 0, 1, 0,
0, 0, 128, 1, 0, 0, 2, 0, 0, 0, 147, 1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 5,
4, 0, 0, 0, 164, 1, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 171, 1, 0, 0, 22, 0, 0, 0, 0, 0,
0, 0, 176, 1, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 236, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
8, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 23, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0,
0, 241, 1, 0, 0, 0, 0, 0, 14, 24, 0, 0, 0, 1, 0, 0, 0, 249, 1, 0, 0, 1, 0, 0, 15,
32, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 255, 1, 0, 0, 1, 0, 0, 15, 4, 0,
0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 7, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0,
105, 110, 116, 0, 95, 95, 65, 82, 82, 65, 89, 95, 83, 73, 90, 69, 95, 84, 89, 80,
69, 95, 95, 0, 116, 121, 112, 101, 0, 109, 97, 120, 95, 101, 110, 116, 114, 105,
101, 115, 0, 107, 101, 121, 95, 115, 105, 122, 101, 0, 118, 97, 108, 117, 101, 95,
115, 105, 122, 101, 0, 104, 105, 100, 95, 106, 109, 112, 95, 116, 97, 98, 108, 101,
0, 117, 110, 115, 105, 103, 110, 101, 100, 32, 108, 111, 110, 103, 32, 108, 111,
110, 103, 0, 99, 116, 120, 0, 104, 105, 100, 95, 116, 97, 105, 108, 95, 99, 97,
108, 108, 0, 102, 109, 111, 100, 95, 114, 101, 116, 47, 95, 95, 104, 105, 100, 95,
98, 112, 102, 95, 116, 97, 105, 108, 95, 99, 97, 108, 108, 0, 47, 104, 111, 109,
101, 47, 98, 116, 105, 115, 115, 111, 105, 114, 47, 83, 114, 99, 47, 104, 105, 100,
47, 100, 114, 105, 118, 101, 114, 115, 47, 104, 105, 100, 47, 98, 112, 102, 47,
101, 110, 116, 114, 121, 112, 111, 105, 110, 116, 115, 47, 101, 110, 116, 114, 121,
112, 111, 105, 110, 116, 115, 46, 98, 112, 102, 46, 99, 0, 105, 110, 116, 32, 66,
80, 70, 95, 80, 82, 79, 71, 40, 104, 105, 100, 95, 116, 97, 105, 108, 95, 99, 97,
108, 108, 44, 32, 115, 116, 114, 117, 99, 116, 32, 104, 105, 100, 95, 98, 112, 102,
95, 99, 116, 120, 32, 42, 104, 99, 116, 120, 41, 0, 104, 105, 100, 95, 98, 112,
102, 95, 99, 116, 120, 0, 105, 110, 100, 101, 120, 0, 104, 105, 100, 0, 97, 108,
108, 111, 99, 97, 116, 101, 100, 95, 115, 105, 122, 101, 0, 114, 101, 112, 111,
114, 116, 95, 116, 121, 112, 101, 0, 95, 95, 117, 51, 50, 0, 117, 110, 115, 105,
103, 110, 101, 100, 32, 105, 110, 116, 0, 104, 105, 100, 95, 114, 101, 112, 111,
114, 116, 95, 116, 121, 112, 101, 0, 72, 73, 68, 95, 73, 78, 80, 85, 84, 95, 82,
69, 80, 79, 82, 84, 0, 72, 73, 68, 95, 79, 85, 84, 80, 85, 84, 95, 82, 69, 80, 79,
82, 84, 0, 72, 73, 68, 95, 70, 69, 65, 84, 85, 82, 69, 95, 82, 69, 80, 79, 82, 84,
0, 72, 73, 68, 95, 82, 69, 80, 79, 82, 84, 95, 84, 89, 80, 69, 83, 0, 114, 101,
116, 118, 97, 108, 0, 115, 105, 122, 101, 0, 95, 95, 115, 51, 50, 0, 48, 58, 48, 0,
9, 98, 112, 102, 95, 116, 97, 105, 108, 95, 99, 97, 108, 108, 40, 99, 116, 120, 44,
32, 38, 104, 105, 100, 95, 106, 109, 112, 95, 116, 97, 98, 108, 101, 44, 32, 104,
99, 116, 120, 45, 62, 105, 110, 100, 101, 120, 41, 59, 0, 99, 104, 97, 114, 0, 76,
73, 67, 69, 78, 83, 69, 0, 46, 109, 97, 112, 115, 0, 108, 105, 99, 101, 110, 115,
101, 0, 104, 105, 100, 95, 100, 101, 118, 105, 99, 101, 0,
],
header: sys::btf_header {
magic: 60319,
version: 1,
flags: 0,
hdr_len: 24,
type_off: 0,
type_len: 608,
str_off: 608,
str_len: 530,
},
};
assert_eq!(btf.name(1).unwrap(), OsStr::new("int"));
}
#[test]
fn btf_loading() {
let mut obj = test_object("getpid.bpf.o");
let prog = prog_mut(&mut obj, "handle__getpid");
let _link = prog
.attach_tracepoint(TracepointCategory::Syscalls, "sys_enter_getpid")
.expect("failed to attach prog");
let prog_id = 0;
let prog_id = sys::bpf_prog_get_next_id(prog_id).unwrap();
let fd = sys::bpf_prog_get_fd_from_id(prog_id).unwrap();
let mut info = sys::bpf_prog_info::default();
let () = sys::bpf_prog_get_info_from_fd(fd.as_raw_fd(), &mut info).unwrap();
let _btf = Btf::load_from_id(info.btf_id).unwrap();
}
}