Skip to content

Add CHANGELOG entry for #269 #539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions examples/bpf_query/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ fn prog(args: ProgArgs) {
for prog in query::ProgInfoIter::with_query_opts(opts) {
println!(
"name={:<16} type={:<15} run_count={:<2} runtime_ns={}",
prog.name, prog.ty, prog.run_cnt, prog.run_time_ns
prog.name.to_string_lossy(),
prog.ty,
prog.run_cnt,
prog.run_time_ns
);
if args.disassemble {
#[cfg(target_arch = "x86_64")]
Expand Down Expand Up @@ -56,13 +59,18 @@ fn prog(args: ProgArgs) {

fn map() {
for map in query::MapInfoIter::default() {
println!("name={:<16} type={}", map.name, map.ty);
println!("name={:<16} type={}", map.name.to_string_lossy(), map.ty);
}
}

fn btf() {
for btf in query::BtfInfoIter::default() {
println!("id={:4} name={} size={}", btf.id, btf.name, btf.btf.len());
println!(
"id={:4} name={} size={}",
btf.id,
btf.name.to_string_lossy(),
btf.btf.len()
);
}
}

Expand Down
6 changes: 6 additions & 0 deletions libbpf-rs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Unreleased
----------
- Overhauled `query::ProgramInfo` and `query::ProgInfoIter` to make them more
readily usable


0.21.2
------
- Enabled key iteration on `MapHandle` objects (formerly possible only on `Map`
Expand Down
75 changes: 35 additions & 40 deletions libbpf-rs/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
//!
//! let mut iter = ProgInfoIter::default();
//! for prog in iter {
//! println!("{}", prog.name);
//! println!("{}", prog.name.to_string_lossy());
//! }
//! ```

use core::ffi::c_void;
use std::convert::TryFrom;
use std::ffi::c_void;
use std::ffi::CString;
use std::mem::size_of_val;
use std::os::raw::c_char;
use std::string::String;
use std::time::Duration;

use nix::errno;
Expand Down Expand Up @@ -91,19 +91,6 @@ macro_rules! gen_info_impl {
};
}

fn name_arr_to_string(a: &[c_char], default: &str) -> String {
let converted_arr: Vec<u8> = a
.iter()
.take_while(|x| **x != 0)
.map(|x| *x as u8)
.collect();
if !converted_arr.is_empty() {
String::from_utf8(converted_arr).unwrap_or_else(|_| default.to_string())
} else {
default.to_string()
}
}

/// BTF Line information
#[derive(Clone, Debug)]
pub struct LineInfo {
Expand Down Expand Up @@ -131,17 +118,17 @@ impl From<&libbpf_sys::bpf_line_info> for LineInfo {
}
}

/// Bpf identifier tag
#[derive(Debug, Clone, Default)]
#[repr(C)]
/// Bpf identifier tag
pub struct Tag([u8; 8]);

/// Information about a BPF program
#[derive(Debug, Clone)]
// TODO: Document members.
#[allow(missing_docs)]
pub struct ProgramInfo {
pub name: String,
pub name: CString,
pub ty: ProgramType,
pub tag: Tag,
pub id: u32,
Expand Down Expand Up @@ -169,15 +156,15 @@ pub struct ProgramInfo {
pub run_cnt: u64,
}

#[derive(Default, Debug)]
/// An iterator for the information of loaded bpf programs
#[derive(Default, Debug)]
pub struct ProgInfoIter {
cur_id: u32,
opts: ProgInfoQueryOptions,
}

#[derive(Clone, Default, Debug)]
/// Options to query the program info currently loaded
#[derive(Clone, Default, Debug)]
pub struct ProgInfoQueryOptions {
/// Include the vector of bpf instructions in the result
include_xlated_prog_insns: bool,
Expand Down Expand Up @@ -264,17 +251,19 @@ impl ProgInfoQueryOptions {
self
}

/// Include all
/// Include everything there is in the query results
pub fn include_all(self) -> Self {
self.include_xlated_prog_insns(true)
.include_jited_prog_insns(true)
.include_map_ids(true)
.include_line_info(true)
.include_func_info(true)
.include_jited_line_info(true)
.include_jited_func_lens(true)
.include_prog_tags(true)
.include_jited_ksyms(true)
Self {
include_xlated_prog_insns: true,
include_jited_prog_insns: true,
include_map_ids: true,
include_line_info: true,
include_func_info: true,
include_jited_line_info: true,
include_jited_func_lens: true,
include_prog_tags: true,
include_jited_ksyms: true,
}
}
}

Expand All @@ -299,7 +288,8 @@ impl ProgramInfo {
unsafe { libbpf_sys::bpf_obj_get_info_by_fd(fd, item_ptr as *mut c_void, &mut len) };
util::parse_ret(ret)?;

let name = name_arr_to_string(&item.name, "(?)");
// SANITY: `libbpf` should guarantee NUL termination.
let name = util::c_char_slice_to_cstr(&item.name).unwrap();
let ty = match ProgramType::try_from(item.type_) {
Ok(ty) => ty,
Err(_) => ProgramType::Unknown,
Expand Down Expand Up @@ -379,7 +369,7 @@ impl ProgramInfo {
util::parse_ret(ret)?;

return Ok(ProgramInfo {
name,
name: name.to_owned(),
ty,
tag: Tag(item.tag),
id: item.id,
Expand Down Expand Up @@ -430,7 +420,8 @@ impl Iterator for ProgInfoIter {

match prog {
Ok(p) => return Some(p),
Err(e) => eprintln!("Failed to load program: {}", e),
// TODO: We should consider bubbling up errors properly.
Err(_err) => (),
}
}
}
Expand All @@ -441,7 +432,7 @@ impl Iterator for ProgInfoIter {
// TODO: Document members.
#[allow(missing_docs)]
pub struct MapInfo {
pub name: String,
pub name: CString,
pub ty: MapType,
pub id: u32,
pub key_size: u32,
Expand All @@ -459,14 +450,15 @@ pub struct MapInfo {

impl MapInfo {
fn from_uapi(_fd: i32, s: libbpf_sys::bpf_map_info) -> Option<Self> {
let name = name_arr_to_string(&s.name, "(?)");
// SANITY: `libbpf` should guarantee NUL termination.
let name = util::c_char_slice_to_cstr(&s.name).unwrap();
let ty = match MapType::try_from(s.type_) {
Ok(ty) => ty,
Err(_) => MapType::Unknown,
};

Some(Self {
name,
name: name.to_owned(),
ty,
id: s.id,
key_size: s.key_size,
Expand Down Expand Up @@ -495,10 +487,9 @@ gen_info_impl!(

/// Information about BPF type format
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct BtfInfo {
/// The name associated with this btf information in the kernel
pub name: String,
pub name: CString,
/// The raw btf bytes from the kernel
pub btf: Vec<u8>,
/// The btf id associated with this btf information in the kernel
Expand Down Expand Up @@ -532,7 +523,10 @@ impl BtfInfo {
util::parse_ret(ret)?;

Ok(BtfInfo {
name: String::from_utf8(name).unwrap_or_else(|_| "(?)".to_string()),
// SANITY: Our buffer contained space for a NUL byte and we set its
// contents to 0. Barring a `libbpf` bug a NUL byte will be
// present.
name: CString::from_vec_with_nul(name).unwrap(),
btf,
id: item.id,
})
Expand Down Expand Up @@ -568,7 +562,8 @@ impl Iterator for BtfInfoIter {

match info {
Ok(i) => return Some(i),
Err(e) => eprintln!("Failed to load btf information: {}", e),
// TODO: We should consider bubbling up errors properly.
Err(_err) => (),
}
}
}
Expand Down
40 changes: 40 additions & 0 deletions libbpf-rs/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::ffi::CStr;
use std::ffi::CString;
use std::mem::transmute;
use std::os::raw::c_char;
use std::path::Path;
use std::ptr::NonNull;
Expand Down Expand Up @@ -32,6 +33,22 @@ pub fn c_ptr_to_string(p: *const c_char) -> Result<String> {
.to_owned())
}

/// Convert a `[c_char]` into a `CStr`.
pub fn c_char_slice_to_cstr(s: &[c_char]) -> Option<&CStr> {
// TODO: Switch to using `CStr::from_bytes_until_nul` once we require
// Rust 1.69.0.
let nul_idx = s
.iter()
.enumerate()
.find_map(|(idx, b)| (*b == 0).then_some(idx))?;
let cstr =
// SAFETY: `c_char` and `u8` are both just one byte plain old data
// types.
CStr::from_bytes_with_nul(unsafe { transmute::<&[c_char], &[u8]>(&s[0..=nul_idx]) })
.unwrap();
Some(cstr)
}

/// Round up a number to the next multiple of `r`
pub fn roundup(num: usize, r: usize) -> usize {
((num + (r - 1)) / r) * r
Expand Down Expand Up @@ -129,4 +146,27 @@ mod tests {
let num = num_possible_cpus().unwrap();
assert!(num > 0);
}

/// Check that we can convert a `[c_char]` into a `CStr`.
#[test]
fn c_char_slice_conversion() {
let slice = [];
assert_eq!(c_char_slice_to_cstr(&slice), None);

let slice = [0];
assert_eq!(
c_char_slice_to_cstr(&slice).unwrap(),
CStr::from_bytes_with_nul(b"\0").unwrap()
);

let slice = ['a' as _, 'b' as _, 'c' as _, 0 as _];
assert_eq!(
c_char_slice_to_cstr(&slice).unwrap(),
CStr::from_bytes_with_nul(b"abc\0").unwrap()
);

// Missing terminating NUL byte.
let slice = ['a' as _, 'b' as _, 'c' as _];
assert_eq!(c_char_slice_to_cstr(&slice), None);
}
}