Skip to content

Commit 51ffd0f

Browse files
d-e-s-odanielocfb
authored andcommitted
libbpf-cargo: Add support for custom .data/.bss/.rodata sections
This change adds support for handling of custom .data/.bss/.rodata sections, declared via SEC(".data.xxxx") in the BPF C code. It makes sure that we generate the corresponding Rust types as well as the proper maps getters. Signed-off-by: Daniel Müller <deso@posteo.net>
1 parent 5ba8d69 commit 51ffd0f

File tree

4 files changed

+89
-11
lines changed

4 files changed

+89
-11
lines changed

libbpf-cargo/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Unreleased
33
- Removed `novendor` feature in favor of having disableable default
44
feature
55
- Added support for `struct_ops` shadow objects for generated skeletons
6+
- Added support for handling custom data sections in generated skeletons
67
- Adjusted `SkeletonBuilder::clang_args` to accept an iterator of
78
arguments instead of a string
89
- Added `--clang-args` argument to `make` and `build` sub-commands

libbpf-cargo/src/gen/btf.rs

+1
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ impl struct_ops {{
772772
Some(s) => s.into_owned(),
773773
};
774774
sec_name.remove(0);
775+
let sec_name = sec_name.replace('.', "_");
775776

776777
writeln!(def, r#"#[derive(Debug, Copy, Clone)]"#)?;
777778
writeln!(def, r#"#[repr(C)]"#)?;

libbpf-cargo/src/gen/mod.rs

+31-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ use std::collections::HashSet;
66
use std::ffi::c_void;
77
use std::ffi::CStr;
88
use std::ffi::CString;
9+
use std::fmt::Display;
10+
use std::fmt::Formatter;
11+
use std::fmt::Result as FmtResult;
912
use std::fmt::Write as fmt_write;
1013
use std::fs::File;
1114
use std::io::stdout;
@@ -34,23 +37,28 @@ use crate::metadata::UnprocessedObj;
3437
use self::btf::GenBtf;
3538

3639
#[derive(Debug, PartialEq)]
37-
pub(crate) enum InternalMapType {
40+
pub(crate) enum InternalMapType<'name> {
3841
Data,
42+
CustomData(&'name str),
3943
Rodata,
44+
CustomRodata(&'name str),
4045
Bss,
46+
CustomBss(&'name str),
4147
Kconfig,
4248
StructOps,
4349
}
4450

45-
impl AsRef<str> for InternalMapType {
46-
#[inline]
47-
fn as_ref(&self) -> &'static str {
51+
impl Display for InternalMapType<'_> {
52+
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
4853
match self {
49-
Self::Data => "data",
50-
Self::Rodata => "rodata",
51-
Self::Bss => "bss",
52-
Self::Kconfig => "kconfig",
53-
Self::StructOps => "struct_ops",
54+
Self::Data => write!(f, "data"),
55+
Self::CustomData(name) => write!(f, "data_{}", name),
56+
Self::Rodata => write!(f, "rodata"),
57+
Self::CustomRodata(name) => write!(f, "rodata_{}", name),
58+
Self::Bss => write!(f, "bss"),
59+
Self::CustomBss(name) => write!(f, "bss_{}", name),
60+
Self::Kconfig => write!(f, "kconfig"),
61+
Self::StructOps => write!(f, "struct_ops"),
5462
}
5563
}
5664
}
@@ -193,7 +201,7 @@ fn get_raw_map_name(map: *const libbpf_sys::bpf_map) -> Result<String> {
193201
Ok(unsafe { CStr::from_ptr(name_ptr) }.to_str()?.to_string())
194202
}
195203

196-
pub(crate) fn canonicalize_internal_map_name(s: &str) -> Option<InternalMapType> {
204+
pub(crate) fn canonicalize_internal_map_name(s: &str) -> Option<InternalMapType<'_>> {
197205
if s.ends_with(".data") {
198206
Some(InternalMapType::Data)
199207
} else if s.ends_with(".rodata") {
@@ -208,6 +216,18 @@ pub(crate) fn canonicalize_internal_map_name(s: &str) -> Option<InternalMapType>
208216
// The `*.link` extension really only sets an additional flag in lower
209217
// layers. For our intents and purposes both can be treated similarly.
210218
Some(InternalMapType::StructOps)
219+
// Custom data sections don't prepend bpf_object name, so we can match from
220+
// start of name.
221+
// See https://github.com/libbpf/libbpf/blob/20ea95b4505c477af3b6ff6ce9d19cee868ddc5d/src/libbpf.c#L1789-L1794
222+
} else if s.starts_with(".data.") {
223+
let name = s.get(".data.".len()..).unwrap();
224+
Some(InternalMapType::CustomData(name))
225+
} else if s.starts_with(".rodata.") {
226+
let name = s.get(".rodata.".len()..).unwrap();
227+
Some(InternalMapType::CustomRodata(name))
228+
} else if s.starts_with(".bss.") {
229+
let name = s.get(".bss.".len()..).unwrap();
230+
Some(InternalMapType::CustomBss(name))
211231
} else {
212232
eprintln!("Warning: unrecognized map: {s}");
213233
None
@@ -221,7 +241,7 @@ fn get_map_name(map: *const libbpf_sys::bpf_map) -> Result<Option<String>> {
221241
if unsafe { !libbpf_sys::bpf_map__is_internal(map) } {
222242
Ok(Some(name))
223243
} else {
224-
Ok(canonicalize_internal_map_name(&name).map(|map| map.as_ref().to_string()))
244+
Ok(canonicalize_internal_map_name(&name).map(|map| map.to_string()))
225245
}
226246
}
227247

libbpf-cargo/src/test.rs

+56
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,9 @@ fn test_skeleton_datasec() {
648648
649649
int myglobal = 0;
650650
void * const myconst = 0;
651+
int mycustomdata SEC(".data.custom");
652+
int mycustombss SEC(".bss.custom");
653+
const int mycustomrodata SEC(".rodata.custom") = 43;
651654
652655
SEC("kprobe/foo")
653656
int this_is_my_prog(u64 *ctx)
@@ -715,12 +718,19 @@ fn test_skeleton_datasec() {
715718
// We can always set bss vars
716719
open_skel.bss_mut().myglobal = 42;
717720
721+
open_skel.data_custom_mut().mycustomdata = 1337;
722+
open_skel.bss_custom_mut().mycustombss = 12;
723+
assert_eq!(open_skel.rodata_custom().mycustomrodata, 43);
724+
718725
let mut skel = open_skel
719726
.load()
720727
.expect("failed to load skel");
721728
722729
// We can always set bss vars
723730
skel.bss_mut().myglobal = 24;
731+
skel.data_custom_mut().mycustomdata += 1;
732+
skel.bss_custom_mut().mycustombss += 1;
733+
assert_eq!(skel.rodata_custom().mycustomrodata, 43);
724734
725735
// Read only for rodata after load
726736
let _rodata: &prog_types::rodata = skel.rodata();
@@ -2039,6 +2049,52 @@ pub struct rodata {
20392049
assert_definition(&btf, &rodata, rodata_output);
20402050
}
20412051

2052+
#[test]
2053+
fn test_btf_dump_definition_datasec_custom() {
2054+
let prog_text = r#"
2055+
#include "vmlinux.h"
2056+
#include <bpf/bpf_helpers.h>
2057+
2058+
int bss_array[1] SEC(".bss.custom");
2059+
int data_array[1] SEC(".data.custom");
2060+
const int rodata_array[1] SEC(".rodata.custom");
2061+
"#;
2062+
2063+
let bss_custom_output = r#"
2064+
#[derive(Debug, Copy, Clone)]
2065+
#[repr(C)]
2066+
pub struct bss_custom {
2067+
pub bss_array: [i32; 1],
2068+
}
2069+
"#;
2070+
2071+
let data_custom_output = r#"
2072+
#[derive(Debug, Copy, Clone)]
2073+
#[repr(C)]
2074+
pub struct data_custom {
2075+
pub data_array: [i32; 1],
2076+
}
2077+
"#;
2078+
2079+
let rodata_custom_output = r#"
2080+
#[derive(Debug, Copy, Clone)]
2081+
#[repr(C)]
2082+
pub struct rodata_custom {
2083+
pub rodata_array: [i32; 1],
2084+
}
2085+
"#;
2086+
2087+
let mmap = build_btf_mmap(prog_text);
2088+
let btf = btf_from_mmap(&mmap);
2089+
let bss_custom = find_type_in_btf!(btf, types::DataSec<'_>, ".bss.custom", false);
2090+
let data_custom = find_type_in_btf!(btf, types::DataSec<'_>, ".data.custom", false);
2091+
let rodata_custom = find_type_in_btf!(btf, types::DataSec<'_>, ".rodata.custom", false);
2092+
2093+
assert_definition(&btf, &bss_custom, bss_custom_output);
2094+
assert_definition(&btf, &data_custom, data_custom_output);
2095+
assert_definition(&btf, &rodata_custom, rodata_custom_output);
2096+
}
2097+
20422098
#[test]
20432099
fn test_btf_dump_definition_datasec_long_array() {
20442100
let prog_text = r#"

0 commit comments

Comments
 (0)