Skip to content

Commit ca75690

Browse files
committed
Fix attach_uprobe_multi_with_opts opts
Currently `func_pattern` is mandatory in `attach_uprobe_multi_with_opts` Although in the C api it is optional, and mutually exclusive with some other options. The rust api didn't allow passing null pointer, which made it impossible to use `syms`/`offsets`/`ref_ctr_offsets`/`cookies` from `opts` because of the following check - https://github.com/libbpf/libbpf/blob/3b4f0ef5a6fa247ce1958d909c0e85e760249840/src/libbpf.c#L12172 Change was intentionally made in a way that doesn't break the existing interface - interpret empty `func_pattern` string as non-existant pattern. A more correct fix would probably be using an `Option` as this is truely optional value, or structuring the api in a way that won't allow passing mutually exclusive parameters. Signed-off-by: Omer Kattan <omer.kattan@wiz.io>
1 parent 5453917 commit ca75690

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

libbpf-rs/src/program.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,11 @@ impl<'obj> ProgramMut<'obj> {
11071107
} = opts;
11081108

11091109
let pattern = util::str_to_cstring(func_pattern.as_ref())?;
1110-
let pattern_ptr = pattern.as_ptr();
1110+
let pattern_ptr = if pattern.is_empty() {
1111+
ptr::null()
1112+
} else {
1113+
pattern.as_ptr()
1114+
};
11111115

11121116
let syms_cstrings = syms
11131117
.iter()

libbpf-rs/tests/bin/src/uprobe_multi.bpf.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,20 @@ int handle__uprobe_multi_with_opts(void *ctx)
4242
return 0;
4343
}
4444

45+
SEC("uprobe.multi")
46+
int handle__uprobe_multi_with_non_default_opts(void *ctx)
47+
{
48+
const int key = 1, init_val = 1;
49+
50+
int *val = bpf_map_lookup_elem(&hash_map, &key);
51+
if (val) {
52+
__sync_fetch_and_add(val, 1);
53+
bpf_printk("handle__uprobe_multi_with_non_default_opts: val=%d\n", *val);
54+
} else {
55+
bpf_map_update_elem(&hash_map, &key, &init_val, BPF_ANY);
56+
}
57+
58+
return 0;
59+
}
60+
4561
char LICENSE[] SEC("license") = "GPL";

libbpf-rs/tests/test.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,6 +1987,20 @@ extern "C" fn multi_uprobe_func_with_opts_func_2() -> usize {
19871987
hint::black_box(45)
19881988
}
19891989

1990+
#[inline(never)]
1991+
#[no_mangle]
1992+
extern "C" fn non_default_opts_multi_uprobe_func_with_opts_func_1() -> usize {
1993+
// Use `black_box` here as an additional barrier to inlining.
1994+
hint::black_box(46)
1995+
}
1996+
1997+
#[inline(never)]
1998+
#[no_mangle]
1999+
extern "C" fn non_default_opts_multi_uprobe_func_with_opts_func_2() -> usize {
2000+
// Use `black_box` here as an additional barrier to inlining.
2001+
hint::black_box(47)
2002+
}
2003+
19902004
#[tag(root)]
19912005
#[test]
19922006
fn test_object_uprobe_multi_with_opts() {
@@ -2021,6 +2035,46 @@ fn test_object_uprobe_multi_with_opts() {
20212035
assert_eq!(result, 2);
20222036
}
20232037

2038+
#[tag(root)]
2039+
#[test]
2040+
fn test_object_uprobe_multi_with_non_default_opts() {
2041+
let mut obj = get_test_object("uprobe_multi.bpf.o");
2042+
let prog = get_prog_mut(&mut obj, "handle__uprobe_multi_with_non_default_opts");
2043+
let func_pattern = "";
2044+
2045+
let pid = unsafe { libc::getpid() };
2046+
let path = current_exe().expect("failed to find executable name");
2047+
let opts = UprobeMultiOpts {
2048+
syms: vec![
2049+
"non_default_opts_multi_uprobe_func_with_opts_func_1".to_string(),
2050+
"non_default_opts_multi_uprobe_func_with_opts_func_2".to_string(),
2051+
],
2052+
..Default::default()
2053+
};
2054+
2055+
let _link = prog
2056+
.attach_uprobe_multi_with_opts(pid, path, func_pattern, opts)
2057+
.expect("failed to attach uprobe multi");
2058+
2059+
non_default_opts_multi_uprobe_func_with_opts_func_1();
2060+
non_default_opts_multi_uprobe_func_with_opts_func_2();
2061+
2062+
let map = get_map_mut(&mut obj, "hash_map");
2063+
let result_bytes = map
2064+
.lookup(&(1_u32).to_ne_bytes(), MapFlags::ANY)
2065+
.expect("failed to lookup")
2066+
.expect("failed to find value for key");
2067+
2068+
let result = i32::from_ne_bytes(
2069+
result_bytes
2070+
.as_slice()
2071+
.try_into()
2072+
.expect("invalid value size"),
2073+
);
2074+
2075+
assert_eq!(result, 2);
2076+
}
2077+
20242078
#[tag(root)]
20252079
#[test]
20262080
fn test_object_uprobe_multi() {

0 commit comments

Comments
 (0)