Skip to content

Commit f7a11ee

Browse files
olsajiriAlexei Starovoitov
authored andcommitted
selftests/bpf: Add kprobe_multi attach test
Adding kprobe_multi attach test that uses new fprobe interface to attach kprobe program to multiple functions. The test is attaching programs to bpf_fentry_test* functions and uses single trampoline program bpf_prog_test_run to trigger bpf_fentry_test* functions. Signed-off-by: Jiri Olsa <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent ddc6b04 commit f7a11ee

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
#include "kprobe_multi.skel.h"
4+
#include "trace_helpers.h"
5+
6+
static void kprobe_multi_test_run(struct kprobe_multi *skel)
7+
{
8+
LIBBPF_OPTS(bpf_test_run_opts, topts);
9+
int err, prog_fd;
10+
11+
prog_fd = bpf_program__fd(skel->progs.trigger);
12+
err = bpf_prog_test_run_opts(prog_fd, &topts);
13+
ASSERT_OK(err, "test_run");
14+
ASSERT_EQ(topts.retval, 0, "test_run");
15+
16+
ASSERT_EQ(skel->bss->kprobe_test1_result, 1, "kprobe_test1_result");
17+
ASSERT_EQ(skel->bss->kprobe_test2_result, 1, "kprobe_test2_result");
18+
ASSERT_EQ(skel->bss->kprobe_test3_result, 1, "kprobe_test3_result");
19+
ASSERT_EQ(skel->bss->kprobe_test4_result, 1, "kprobe_test4_result");
20+
ASSERT_EQ(skel->bss->kprobe_test5_result, 1, "kprobe_test5_result");
21+
ASSERT_EQ(skel->bss->kprobe_test6_result, 1, "kprobe_test6_result");
22+
ASSERT_EQ(skel->bss->kprobe_test7_result, 1, "kprobe_test7_result");
23+
ASSERT_EQ(skel->bss->kprobe_test8_result, 1, "kprobe_test8_result");
24+
25+
ASSERT_EQ(skel->bss->kretprobe_test1_result, 1, "kretprobe_test1_result");
26+
ASSERT_EQ(skel->bss->kretprobe_test2_result, 1, "kretprobe_test2_result");
27+
ASSERT_EQ(skel->bss->kretprobe_test3_result, 1, "kretprobe_test3_result");
28+
ASSERT_EQ(skel->bss->kretprobe_test4_result, 1, "kretprobe_test4_result");
29+
ASSERT_EQ(skel->bss->kretprobe_test5_result, 1, "kretprobe_test5_result");
30+
ASSERT_EQ(skel->bss->kretprobe_test6_result, 1, "kretprobe_test6_result");
31+
ASSERT_EQ(skel->bss->kretprobe_test7_result, 1, "kretprobe_test7_result");
32+
ASSERT_EQ(skel->bss->kretprobe_test8_result, 1, "kretprobe_test8_result");
33+
}
34+
35+
static void test_skel_api(void)
36+
{
37+
struct kprobe_multi *skel = NULL;
38+
int err;
39+
40+
skel = kprobe_multi__open_and_load();
41+
if (!ASSERT_OK_PTR(skel, "kprobe_multi__open_and_load"))
42+
goto cleanup;
43+
44+
skel->bss->pid = getpid();
45+
err = kprobe_multi__attach(skel);
46+
if (!ASSERT_OK(err, "kprobe_multi__attach"))
47+
goto cleanup;
48+
49+
kprobe_multi_test_run(skel);
50+
51+
cleanup:
52+
kprobe_multi__destroy(skel);
53+
}
54+
55+
static void test_link_api(struct bpf_link_create_opts *opts)
56+
{
57+
int prog_fd, link1_fd = -1, link2_fd = -1;
58+
struct kprobe_multi *skel = NULL;
59+
60+
skel = kprobe_multi__open_and_load();
61+
if (!ASSERT_OK_PTR(skel, "fentry_raw_skel_load"))
62+
goto cleanup;
63+
64+
skel->bss->pid = getpid();
65+
prog_fd = bpf_program__fd(skel->progs.test_kprobe);
66+
link1_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_KPROBE_MULTI, opts);
67+
if (!ASSERT_GE(link1_fd, 0, "link_fd"))
68+
goto cleanup;
69+
70+
opts->kprobe_multi.flags = BPF_F_KPROBE_MULTI_RETURN;
71+
prog_fd = bpf_program__fd(skel->progs.test_kretprobe);
72+
link2_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_KPROBE_MULTI, opts);
73+
if (!ASSERT_GE(link2_fd, 0, "link_fd"))
74+
goto cleanup;
75+
76+
kprobe_multi_test_run(skel);
77+
78+
cleanup:
79+
if (link1_fd != -1)
80+
close(link1_fd);
81+
if (link2_fd != -1)
82+
close(link2_fd);
83+
kprobe_multi__destroy(skel);
84+
}
85+
86+
#define GET_ADDR(__sym, __addr) ({ \
87+
__addr = ksym_get_addr(__sym); \
88+
if (!ASSERT_NEQ(__addr, 0, "kallsyms load failed for " #__sym)) \
89+
return; \
90+
})
91+
92+
static void test_link_api_addrs(void)
93+
{
94+
LIBBPF_OPTS(bpf_link_create_opts, opts);
95+
unsigned long long addrs[8];
96+
97+
GET_ADDR("bpf_fentry_test1", addrs[0]);
98+
GET_ADDR("bpf_fentry_test2", addrs[1]);
99+
GET_ADDR("bpf_fentry_test3", addrs[2]);
100+
GET_ADDR("bpf_fentry_test4", addrs[3]);
101+
GET_ADDR("bpf_fentry_test5", addrs[4]);
102+
GET_ADDR("bpf_fentry_test6", addrs[5]);
103+
GET_ADDR("bpf_fentry_test7", addrs[6]);
104+
GET_ADDR("bpf_fentry_test8", addrs[7]);
105+
106+
opts.kprobe_multi.addrs = (const unsigned long*) addrs;
107+
opts.kprobe_multi.cnt = ARRAY_SIZE(addrs);
108+
test_link_api(&opts);
109+
}
110+
111+
static void test_link_api_syms(void)
112+
{
113+
LIBBPF_OPTS(bpf_link_create_opts, opts);
114+
const char *syms[8] = {
115+
"bpf_fentry_test1",
116+
"bpf_fentry_test2",
117+
"bpf_fentry_test3",
118+
"bpf_fentry_test4",
119+
"bpf_fentry_test5",
120+
"bpf_fentry_test6",
121+
"bpf_fentry_test7",
122+
"bpf_fentry_test8",
123+
};
124+
125+
opts.kprobe_multi.syms = syms;
126+
opts.kprobe_multi.cnt = ARRAY_SIZE(syms);
127+
test_link_api(&opts);
128+
}
129+
130+
void test_kprobe_multi_test(void)
131+
{
132+
if (!ASSERT_OK(load_kallsyms(), "load_kallsyms"))
133+
return;
134+
135+
if (test__start_subtest("skel_api"))
136+
test_skel_api();
137+
if (test__start_subtest("link_api_addrs"))
138+
test_link_api_syms();
139+
if (test__start_subtest("link_api_syms"))
140+
test_link_api_addrs();
141+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_tracing.h>
5+
#include <stdbool.h>
6+
7+
char _license[] SEC("license") = "GPL";
8+
9+
extern const void bpf_fentry_test1 __ksym;
10+
extern const void bpf_fentry_test2 __ksym;
11+
extern const void bpf_fentry_test3 __ksym;
12+
extern const void bpf_fentry_test4 __ksym;
13+
extern const void bpf_fentry_test5 __ksym;
14+
extern const void bpf_fentry_test6 __ksym;
15+
extern const void bpf_fentry_test7 __ksym;
16+
extern const void bpf_fentry_test8 __ksym;
17+
18+
int pid = 0;
19+
20+
__u64 kprobe_test1_result = 0;
21+
__u64 kprobe_test2_result = 0;
22+
__u64 kprobe_test3_result = 0;
23+
__u64 kprobe_test4_result = 0;
24+
__u64 kprobe_test5_result = 0;
25+
__u64 kprobe_test6_result = 0;
26+
__u64 kprobe_test7_result = 0;
27+
__u64 kprobe_test8_result = 0;
28+
29+
__u64 kretprobe_test1_result = 0;
30+
__u64 kretprobe_test2_result = 0;
31+
__u64 kretprobe_test3_result = 0;
32+
__u64 kretprobe_test4_result = 0;
33+
__u64 kretprobe_test5_result = 0;
34+
__u64 kretprobe_test6_result = 0;
35+
__u64 kretprobe_test7_result = 0;
36+
__u64 kretprobe_test8_result = 0;
37+
38+
static void kprobe_multi_check(void *ctx, bool is_return)
39+
{
40+
if (bpf_get_current_pid_tgid() >> 32 != pid)
41+
return;
42+
43+
__u64 addr = bpf_get_func_ip(ctx);
44+
45+
#define SET(__var, __addr) ({ \
46+
if ((const void *) addr == __addr) \
47+
__var = 1; \
48+
})
49+
50+
if (is_return) {
51+
SET(kretprobe_test1_result, &bpf_fentry_test1);
52+
SET(kretprobe_test2_result, &bpf_fentry_test2);
53+
SET(kretprobe_test3_result, &bpf_fentry_test3);
54+
SET(kretprobe_test4_result, &bpf_fentry_test4);
55+
SET(kretprobe_test5_result, &bpf_fentry_test5);
56+
SET(kretprobe_test6_result, &bpf_fentry_test6);
57+
SET(kretprobe_test7_result, &bpf_fentry_test7);
58+
SET(kretprobe_test8_result, &bpf_fentry_test8);
59+
} else {
60+
SET(kprobe_test1_result, &bpf_fentry_test1);
61+
SET(kprobe_test2_result, &bpf_fentry_test2);
62+
SET(kprobe_test3_result, &bpf_fentry_test3);
63+
SET(kprobe_test4_result, &bpf_fentry_test4);
64+
SET(kprobe_test5_result, &bpf_fentry_test5);
65+
SET(kprobe_test6_result, &bpf_fentry_test6);
66+
SET(kprobe_test7_result, &bpf_fentry_test7);
67+
SET(kprobe_test8_result, &bpf_fentry_test8);
68+
}
69+
70+
#undef SET
71+
}
72+
73+
/*
74+
* No tests in here, just to trigger 'bpf_fentry_test*'
75+
* through tracing test_run
76+
*/
77+
SEC("fentry/bpf_modify_return_test")
78+
int BPF_PROG(trigger)
79+
{
80+
return 0;
81+
}
82+
83+
SEC("kprobe.multi/bpf_fentry_tes??")
84+
int test_kprobe(struct pt_regs *ctx)
85+
{
86+
kprobe_multi_check(ctx, false);
87+
return 0;
88+
}
89+
90+
SEC("kretprobe.multi/bpf_fentry_test*")
91+
int test_kretprobe(struct pt_regs *ctx)
92+
{
93+
kprobe_multi_check(ctx, true);
94+
return 0;
95+
}

tools/testing/selftests/bpf/trace_helpers.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ int load_kallsyms(void)
3434
if (!f)
3535
return -ENOENT;
3636

37+
/*
38+
* This is called/used from multiplace places,
39+
* load symbols just once.
40+
*/
41+
if (sym_cnt)
42+
return 0;
43+
3744
while (fgets(buf, sizeof(buf), f)) {
3845
if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
3946
break;

0 commit comments

Comments
 (0)