1 // SPDX-License-Identifier: GPL-2.0
4 #include <test_progs.h>
5 #include "uprobe_multi.skel.h"
6 #include "uprobe_multi_bench.skel.h"
7 #include "uprobe_multi_usdt.skel.h"
8 #include "bpf/libbpf_internal.h"
9 #include "testing_helpers.h"
11 static char test_data[] = "test_data";
13 noinline void uprobe_multi_func_1(void)
18 noinline void uprobe_multi_func_2(void)
23 noinline void uprobe_multi_func_3(void)
33 static void release_child(struct child *child)
42 waitpid(child->pid, &child_status, 0);
45 static void kick_child(struct child *child)
50 write(child->go[1], &c, 1);
56 static struct child *spawn_child(void)
58 static struct child child;
62 /* pipe to notify child to execute the trigger functions */
68 release_child(&child);
77 /* wait for parent's kick */
78 err = read(child.go[0], &c, 1);
82 uprobe_multi_func_1();
83 uprobe_multi_func_2();
84 uprobe_multi_func_3();
92 static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child)
94 skel->bss->uprobe_multi_func_1_addr = (__u64) uprobe_multi_func_1;
95 skel->bss->uprobe_multi_func_2_addr = (__u64) uprobe_multi_func_2;
96 skel->bss->uprobe_multi_func_3_addr = (__u64) uprobe_multi_func_3;
98 skel->bss->user_ptr = test_data;
101 * Disable pid check in bpf program if we are pid filter test,
102 * because the probe should be executed only by child->pid
103 * passed at the probe attach.
105 skel->bss->pid = child ? 0 : getpid();
110 /* trigger all probes */
111 uprobe_multi_func_1();
112 uprobe_multi_func_2();
113 uprobe_multi_func_3();
116 * There are 2 entry and 2 exit probe called for each uprobe_multi_func_[123]
117 * function and each slepable probe (6) increments uprobe_multi_sleep_result.
119 ASSERT_EQ(skel->bss->uprobe_multi_func_1_result, 2, "uprobe_multi_func_1_result");
120 ASSERT_EQ(skel->bss->uprobe_multi_func_2_result, 2, "uprobe_multi_func_2_result");
121 ASSERT_EQ(skel->bss->uprobe_multi_func_3_result, 2, "uprobe_multi_func_3_result");
123 ASSERT_EQ(skel->bss->uretprobe_multi_func_1_result, 2, "uretprobe_multi_func_1_result");
124 ASSERT_EQ(skel->bss->uretprobe_multi_func_2_result, 2, "uretprobe_multi_func_2_result");
125 ASSERT_EQ(skel->bss->uretprobe_multi_func_3_result, 2, "uretprobe_multi_func_3_result");
127 ASSERT_EQ(skel->bss->uprobe_multi_sleep_result, 6, "uprobe_multi_sleep_result");
130 ASSERT_EQ(skel->bss->child_pid, child->pid, "uprobe_multi_child_pid");
133 static void test_skel_api(void)
135 struct uprobe_multi *skel = NULL;
138 skel = uprobe_multi__open_and_load();
139 if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
142 err = uprobe_multi__attach(skel);
143 if (!ASSERT_OK(err, "uprobe_multi__attach"))
146 uprobe_multi_test_run(skel, NULL);
149 uprobe_multi__destroy(skel);
153 __test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi_opts *opts,
156 pid_t pid = child ? child->pid : -1;
157 struct uprobe_multi *skel = NULL;
159 skel = uprobe_multi__open_and_load();
160 if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
163 opts->retprobe = false;
164 skel->links.uprobe = bpf_program__attach_uprobe_multi(skel->progs.uprobe, pid,
165 binary, pattern, opts);
166 if (!ASSERT_OK_PTR(skel->links.uprobe, "bpf_program__attach_uprobe_multi"))
169 opts->retprobe = true;
170 skel->links.uretprobe = bpf_program__attach_uprobe_multi(skel->progs.uretprobe, pid,
171 binary, pattern, opts);
172 if (!ASSERT_OK_PTR(skel->links.uretprobe, "bpf_program__attach_uprobe_multi"))
175 opts->retprobe = false;
176 skel->links.uprobe_sleep = bpf_program__attach_uprobe_multi(skel->progs.uprobe_sleep, pid,
177 binary, pattern, opts);
178 if (!ASSERT_OK_PTR(skel->links.uprobe_sleep, "bpf_program__attach_uprobe_multi"))
181 opts->retprobe = true;
182 skel->links.uretprobe_sleep = bpf_program__attach_uprobe_multi(skel->progs.uretprobe_sleep,
183 pid, binary, pattern, opts);
184 if (!ASSERT_OK_PTR(skel->links.uretprobe_sleep, "bpf_program__attach_uprobe_multi"))
187 opts->retprobe = false;
188 skel->links.uprobe_extra = bpf_program__attach_uprobe_multi(skel->progs.uprobe_extra, -1,
189 binary, pattern, opts);
190 if (!ASSERT_OK_PTR(skel->links.uprobe_extra, "bpf_program__attach_uprobe_multi"))
193 uprobe_multi_test_run(skel, child);
196 uprobe_multi__destroy(skel);
200 test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi_opts *opts)
205 __test_attach_api(binary, pattern, opts, NULL);
208 child = spawn_child();
209 if (!ASSERT_OK_PTR(child, "spawn_child"))
212 __test_attach_api(binary, pattern, opts, child);
215 static void test_attach_api_pattern(void)
217 LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
219 test_attach_api("/proc/self/exe", "uprobe_multi_func_*", &opts);
220 test_attach_api("/proc/self/exe", "uprobe_multi_func_?", &opts);
223 static void test_attach_api_syms(void)
225 LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
226 const char *syms[3] = {
227 "uprobe_multi_func_1",
228 "uprobe_multi_func_2",
229 "uprobe_multi_func_3",
233 opts.cnt = ARRAY_SIZE(syms);
234 test_attach_api("/proc/self/exe", NULL, &opts);
237 static void test_attach_api_fails(void)
239 LIBBPF_OPTS(bpf_link_create_opts, opts);
240 const char *path = "/proc/self/exe";
241 struct uprobe_multi *skel = NULL;
242 int prog_fd, link_fd = -1;
243 unsigned long offset = 0;
245 skel = uprobe_multi__open_and_load();
246 if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
249 prog_fd = bpf_program__fd(skel->progs.uprobe_extra);
252 opts.uprobe_multi.path = path;
253 opts.uprobe_multi.offsets = &offset;
254 opts.uprobe_multi.cnt = INT_MAX;
255 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
256 if (!ASSERT_ERR(link_fd, "link_fd"))
258 if (!ASSERT_EQ(link_fd, -E2BIG, "big cnt"))
262 LIBBPF_OPTS_RESET(opts,
263 .uprobe_multi.path = path,
264 .uprobe_multi.offsets = (unsigned long *) &offset,
267 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
268 if (!ASSERT_ERR(link_fd, "link_fd"))
270 if (!ASSERT_EQ(link_fd, -EINVAL, "cnt_is_zero"))
273 /* negative offset */
275 opts.uprobe_multi.path = path;
276 opts.uprobe_multi.offsets = (unsigned long *) &offset;
277 opts.uprobe_multi.cnt = 1;
279 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
280 if (!ASSERT_ERR(link_fd, "link_fd"))
282 if (!ASSERT_EQ(link_fd, -EINVAL, "offset_is_negative"))
285 /* offsets is NULL */
286 LIBBPF_OPTS_RESET(opts,
287 .uprobe_multi.path = path,
288 .uprobe_multi.cnt = 1,
291 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
292 if (!ASSERT_ERR(link_fd, "link_fd"))
294 if (!ASSERT_EQ(link_fd, -EINVAL, "offsets_is_null"))
297 /* wrong offsets pointer */
298 LIBBPF_OPTS_RESET(opts,
299 .uprobe_multi.path = path,
300 .uprobe_multi.offsets = (unsigned long *) 1,
301 .uprobe_multi.cnt = 1,
304 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
305 if (!ASSERT_ERR(link_fd, "link_fd"))
307 if (!ASSERT_EQ(link_fd, -EFAULT, "offsets_is_wrong"))
312 LIBBPF_OPTS_RESET(opts,
313 .uprobe_multi.offsets = (unsigned long *) &offset,
314 .uprobe_multi.cnt = 1,
317 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
318 if (!ASSERT_ERR(link_fd, "link_fd"))
320 if (!ASSERT_EQ(link_fd, -EINVAL, "path_is_null"))
323 /* wrong path pointer */
324 LIBBPF_OPTS_RESET(opts,
325 .uprobe_multi.path = (const char *) 1,
326 .uprobe_multi.offsets = (unsigned long *) &offset,
327 .uprobe_multi.cnt = 1,
330 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
331 if (!ASSERT_ERR(link_fd, "link_fd"))
333 if (!ASSERT_EQ(link_fd, -EFAULT, "path_is_wrong"))
336 /* wrong path type */
337 LIBBPF_OPTS_RESET(opts,
338 .uprobe_multi.path = "/",
339 .uprobe_multi.offsets = (unsigned long *) &offset,
340 .uprobe_multi.cnt = 1,
343 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
344 if (!ASSERT_ERR(link_fd, "link_fd"))
346 if (!ASSERT_EQ(link_fd, -EBADF, "path_is_wrong_type"))
349 /* wrong cookies pointer */
350 LIBBPF_OPTS_RESET(opts,
351 .uprobe_multi.path = path,
352 .uprobe_multi.offsets = (unsigned long *) &offset,
353 .uprobe_multi.cookies = (__u64 *) 1ULL,
354 .uprobe_multi.cnt = 1,
357 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
358 if (!ASSERT_ERR(link_fd, "link_fd"))
360 if (!ASSERT_EQ(link_fd, -EFAULT, "cookies_is_wrong"))
363 /* wrong ref_ctr_offsets pointer */
364 LIBBPF_OPTS_RESET(opts,
365 .uprobe_multi.path = path,
366 .uprobe_multi.offsets = (unsigned long *) &offset,
367 .uprobe_multi.cookies = (__u64 *) &offset,
368 .uprobe_multi.ref_ctr_offsets = (unsigned long *) 1,
369 .uprobe_multi.cnt = 1,
372 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
373 if (!ASSERT_ERR(link_fd, "link_fd"))
375 if (!ASSERT_EQ(link_fd, -EFAULT, "ref_ctr_offsets_is_wrong"))
379 LIBBPF_OPTS_RESET(opts,
380 .uprobe_multi.flags = 1 << 31,
383 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
384 if (!ASSERT_ERR(link_fd, "link_fd"))
386 if (!ASSERT_EQ(link_fd, -EINVAL, "wrong_flags"))
390 LIBBPF_OPTS_RESET(opts,
391 .uprobe_multi.path = path,
392 .uprobe_multi.offsets = (unsigned long *) &offset,
393 .uprobe_multi.cnt = 1,
394 .uprobe_multi.pid = -2,
397 link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
398 if (!ASSERT_ERR(link_fd, "link_fd"))
400 ASSERT_EQ(link_fd, -ESRCH, "pid_is_wrong");
405 uprobe_multi__destroy(skel);
408 static void __test_link_api(struct child *child)
410 int prog_fd, link1_fd = -1, link2_fd = -1, link3_fd = -1, link4_fd = -1;
411 LIBBPF_OPTS(bpf_link_create_opts, opts);
412 const char *path = "/proc/self/exe";
413 struct uprobe_multi *skel = NULL;
414 unsigned long *offsets = NULL;
415 const char *syms[3] = {
416 "uprobe_multi_func_1",
417 "uprobe_multi_func_2",
418 "uprobe_multi_func_3",
420 int link_extra_fd = -1;
423 err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets, STT_FUNC);
424 if (!ASSERT_OK(err, "elf_resolve_syms_offsets"))
427 opts.uprobe_multi.path = path;
428 opts.uprobe_multi.offsets = offsets;
429 opts.uprobe_multi.cnt = ARRAY_SIZE(syms);
430 opts.uprobe_multi.pid = child ? child->pid : 0;
432 skel = uprobe_multi__open_and_load();
433 if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
436 opts.kprobe_multi.flags = 0;
437 prog_fd = bpf_program__fd(skel->progs.uprobe);
438 link1_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
439 if (!ASSERT_GE(link1_fd, 0, "link1_fd"))
442 opts.kprobe_multi.flags = BPF_F_UPROBE_MULTI_RETURN;
443 prog_fd = bpf_program__fd(skel->progs.uretprobe);
444 link2_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
445 if (!ASSERT_GE(link2_fd, 0, "link2_fd"))
448 opts.kprobe_multi.flags = 0;
449 prog_fd = bpf_program__fd(skel->progs.uprobe_sleep);
450 link3_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
451 if (!ASSERT_GE(link3_fd, 0, "link3_fd"))
454 opts.kprobe_multi.flags = BPF_F_UPROBE_MULTI_RETURN;
455 prog_fd = bpf_program__fd(skel->progs.uretprobe_sleep);
456 link4_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
457 if (!ASSERT_GE(link4_fd, 0, "link4_fd"))
460 opts.kprobe_multi.flags = 0;
461 opts.uprobe_multi.pid = 0;
462 prog_fd = bpf_program__fd(skel->progs.uprobe_extra);
463 link_extra_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
464 if (!ASSERT_GE(link_extra_fd, 0, "link_extra_fd"))
467 uprobe_multi_test_run(skel, child);
478 if (link_extra_fd >= 0)
479 close(link_extra_fd);
481 uprobe_multi__destroy(skel);
485 static void test_link_api(void)
490 __test_link_api(NULL);
493 child = spawn_child();
494 if (!ASSERT_OK_PTR(child, "spawn_child"))
497 __test_link_api(child);
500 static void test_bench_attach_uprobe(void)
502 long attach_start_ns = 0, attach_end_ns = 0;
503 struct uprobe_multi_bench *skel = NULL;
504 long detach_start_ns, detach_end_ns;
505 double attach_delta, detach_delta;
508 skel = uprobe_multi_bench__open_and_load();
509 if (!ASSERT_OK_PTR(skel, "uprobe_multi_bench__open_and_load"))
512 attach_start_ns = get_time_ns();
514 err = uprobe_multi_bench__attach(skel);
515 if (!ASSERT_OK(err, "uprobe_multi_bench__attach"))
518 attach_end_ns = get_time_ns();
520 system("./uprobe_multi bench");
522 ASSERT_EQ(skel->bss->count, 50000, "uprobes_count");
525 detach_start_ns = get_time_ns();
526 uprobe_multi_bench__destroy(skel);
527 detach_end_ns = get_time_ns();
529 attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
530 detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
532 printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
533 printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
536 static void test_bench_attach_usdt(void)
538 long attach_start_ns = 0, attach_end_ns = 0;
539 struct uprobe_multi_usdt *skel = NULL;
540 long detach_start_ns, detach_end_ns;
541 double attach_delta, detach_delta;
543 skel = uprobe_multi_usdt__open_and_load();
544 if (!ASSERT_OK_PTR(skel, "uprobe_multi__open"))
547 attach_start_ns = get_time_ns();
549 skel->links.usdt0 = bpf_program__attach_usdt(skel->progs.usdt0, -1, "./uprobe_multi",
550 "test", "usdt", NULL);
551 if (!ASSERT_OK_PTR(skel->links.usdt0, "bpf_program__attach_usdt"))
554 attach_end_ns = get_time_ns();
556 system("./uprobe_multi usdt");
558 ASSERT_EQ(skel->bss->count, 50000, "usdt_count");
561 detach_start_ns = get_time_ns();
562 uprobe_multi_usdt__destroy(skel);
563 detach_end_ns = get_time_ns();
565 attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
566 detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
568 printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
569 printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
572 void test_uprobe_multi_test(void)
574 if (test__start_subtest("skel_api"))
576 if (test__start_subtest("attach_api_pattern"))
577 test_attach_api_pattern();
578 if (test__start_subtest("attach_api_syms"))
579 test_attach_api_syms();
580 if (test__start_subtest("link_api"))
582 if (test__start_subtest("bench_uprobe"))
583 test_bench_attach_uprobe();
584 if (test__start_subtest("bench_usdt"))
585 test_bench_attach_usdt();
586 if (test__start_subtest("attach_api_fails"))
587 test_attach_api_fails();