]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / prog_tests / uprobe_multi_test.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <unistd.h>
4 #include <pthread.h>
5 #include <test_progs.h>
6 #include "uprobe_multi.skel.h"
7 #include "uprobe_multi_bench.skel.h"
8 #include "uprobe_multi_usdt.skel.h"
9 #include "uprobe_multi_consumers.skel.h"
10 #include "uprobe_multi_pid_filter.skel.h"
11 #include "uprobe_multi_session.skel.h"
12 #include "uprobe_multi_session_single.skel.h"
13 #include "uprobe_multi_session_cookie.skel.h"
14 #include "uprobe_multi_session_recursive.skel.h"
15 #include "uprobe_multi_verifier.skel.h"
16 #include "bpf/libbpf_internal.h"
17 #include "testing_helpers.h"
18 #include "../sdt.h"
19
20 static char test_data[] = "test_data";
21
22 noinline void uprobe_multi_func_1(void)
23 {
24         asm volatile ("");
25 }
26
27 noinline void uprobe_multi_func_2(void)
28 {
29         asm volatile ("");
30 }
31
32 noinline void uprobe_multi_func_3(void)
33 {
34         asm volatile ("");
35 }
36
37 noinline void usdt_trigger(void)
38 {
39         STAP_PROBE(test, pid_filter_usdt);
40 }
41
42 noinline void uprobe_session_recursive(int i)
43 {
44         if (i)
45                 uprobe_session_recursive(i - 1);
46 }
47
48 struct child {
49         int go[2];
50         int c2p[2]; /* child -> parent channel */
51         int pid;
52         int tid;
53         pthread_t thread;
54         char stack[65536];
55 };
56
57 static void release_child(struct child *child)
58 {
59         int child_status;
60
61         if (!child)
62                 return;
63         close(child->go[1]);
64         close(child->go[0]);
65         if (child->thread)
66                 pthread_join(child->thread, NULL);
67         close(child->c2p[0]);
68         close(child->c2p[1]);
69         if (child->pid > 0)
70                 waitpid(child->pid, &child_status, 0);
71 }
72
73 static void kick_child(struct child *child)
74 {
75         char c = 1;
76
77         if (child) {
78                 write(child->go[1], &c, 1);
79                 release_child(child);
80         }
81         fflush(NULL);
82 }
83
84 static int child_func(void *arg)
85 {
86         struct child *child = arg;
87         int err, c;
88
89         close(child->go[1]);
90
91         /* wait for parent's kick */
92         err = read(child->go[0], &c, 1);
93         if (err != 1)
94                 exit(err);
95
96         uprobe_multi_func_1();
97         uprobe_multi_func_2();
98         uprobe_multi_func_3();
99         usdt_trigger();
100
101         exit(errno);
102 }
103
104 static int spawn_child_flag(struct child *child, bool clone_vm)
105 {
106         /* pipe to notify child to execute the trigger functions */
107         if (pipe(child->go))
108                 return -1;
109
110         if (clone_vm) {
111                 child->pid = child->tid = clone(child_func, child->stack + sizeof(child->stack)/2,
112                                                 CLONE_VM|SIGCHLD, child);
113         } else {
114                 child->pid = child->tid = fork();
115         }
116         if (child->pid < 0) {
117                 release_child(child);
118                 errno = EINVAL;
119                 return -1;
120         }
121
122         /* fork-ed child */
123         if (!clone_vm && child->pid == 0)
124                 child_func(child);
125
126         return 0;
127 }
128
129 static int spawn_child(struct child *child)
130 {
131         return spawn_child_flag(child, false);
132 }
133
134 static void *child_thread(void *ctx)
135 {
136         struct child *child = ctx;
137         int c = 0, err;
138
139         child->tid = sys_gettid();
140
141         /* let parent know we are ready */
142         err = write(child->c2p[1], &c, 1);
143         if (err != 1)
144                 pthread_exit(&err);
145
146         /* wait for parent's kick */
147         err = read(child->go[0], &c, 1);
148         if (err != 1)
149                 pthread_exit(&err);
150
151         uprobe_multi_func_1();
152         uprobe_multi_func_2();
153         uprobe_multi_func_3();
154         usdt_trigger();
155
156         err = 0;
157         pthread_exit(&err);
158 }
159
160 static int spawn_thread(struct child *child)
161 {
162         int c, err;
163
164         /* pipe to notify child to execute the trigger functions */
165         if (pipe(child->go))
166                 return -1;
167         /* pipe to notify parent that child thread is ready */
168         if (pipe(child->c2p)) {
169                 close(child->go[0]);
170                 close(child->go[1]);
171                 return -1;
172         }
173
174         child->pid = getpid();
175
176         err = pthread_create(&child->thread, NULL, child_thread, child);
177         if (err) {
178                 err = -errno;
179                 close(child->go[0]);
180                 close(child->go[1]);
181                 close(child->c2p[0]);
182                 close(child->c2p[1]);
183                 errno = -err;
184                 return -1;
185         }
186
187         err = read(child->c2p[0], &c, 1);
188         if (!ASSERT_EQ(err, 1, "child_thread_ready"))
189                 return -1;
190
191         return 0;
192 }
193
194 static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child)
195 {
196         skel->bss->uprobe_multi_func_1_addr = (__u64) uprobe_multi_func_1;
197         skel->bss->uprobe_multi_func_2_addr = (__u64) uprobe_multi_func_2;
198         skel->bss->uprobe_multi_func_3_addr = (__u64) uprobe_multi_func_3;
199
200         skel->bss->user_ptr = test_data;
201
202         /*
203          * Disable pid check in bpf program if we are pid filter test,
204          * because the probe should be executed only by child->pid
205          * passed at the probe attach.
206          */
207         skel->bss->pid = child ? 0 : getpid();
208         skel->bss->expect_pid = child ? child->pid : 0;
209
210         /* trigger all probes, if we are testing child *process*, just to make
211          * sure that PID filtering doesn't let through activations from wrong
212          * PIDs; when we test child *thread*, we don't want to do this to
213          * avoid double counting number of triggering events
214          */
215         if (!child || !child->thread) {
216                 uprobe_multi_func_1();
217                 uprobe_multi_func_2();
218                 uprobe_multi_func_3();
219                 usdt_trigger();
220         }
221
222         if (child)
223                 kick_child(child);
224
225         /*
226          * There are 2 entry and 2 exit probe called for each uprobe_multi_func_[123]
227          * function and each sleepable probe (6) increments uprobe_multi_sleep_result.
228          */
229         ASSERT_EQ(skel->bss->uprobe_multi_func_1_result, 2, "uprobe_multi_func_1_result");
230         ASSERT_EQ(skel->bss->uprobe_multi_func_2_result, 2, "uprobe_multi_func_2_result");
231         ASSERT_EQ(skel->bss->uprobe_multi_func_3_result, 2, "uprobe_multi_func_3_result");
232
233         ASSERT_EQ(skel->bss->uretprobe_multi_func_1_result, 2, "uretprobe_multi_func_1_result");
234         ASSERT_EQ(skel->bss->uretprobe_multi_func_2_result, 2, "uretprobe_multi_func_2_result");
235         ASSERT_EQ(skel->bss->uretprobe_multi_func_3_result, 2, "uretprobe_multi_func_3_result");
236
237         ASSERT_EQ(skel->bss->uprobe_multi_sleep_result, 6, "uprobe_multi_sleep_result");
238
239         ASSERT_FALSE(skel->bss->bad_pid_seen, "bad_pid_seen");
240
241         if (child) {
242                 ASSERT_EQ(skel->bss->child_pid, child->pid, "uprobe_multi_child_pid");
243                 ASSERT_EQ(skel->bss->child_tid, child->tid, "uprobe_multi_child_tid");
244         }
245 }
246
247 static void test_skel_api(void)
248 {
249         struct uprobe_multi *skel = NULL;
250         int err;
251
252         skel = uprobe_multi__open_and_load();
253         if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
254                 goto cleanup;
255
256         err = uprobe_multi__attach(skel);
257         if (!ASSERT_OK(err, "uprobe_multi__attach"))
258                 goto cleanup;
259
260         uprobe_multi_test_run(skel, NULL);
261
262 cleanup:
263         uprobe_multi__destroy(skel);
264 }
265
266 static void
267 __test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi_opts *opts,
268                   struct child *child)
269 {
270         pid_t pid = child ? child->pid : -1;
271         struct uprobe_multi *skel = NULL;
272
273         skel = uprobe_multi__open_and_load();
274         if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
275                 goto cleanup;
276
277         opts->retprobe = false;
278         skel->links.uprobe = bpf_program__attach_uprobe_multi(skel->progs.uprobe, pid,
279                                                               binary, pattern, opts);
280         if (!ASSERT_OK_PTR(skel->links.uprobe, "bpf_program__attach_uprobe_multi"))
281                 goto cleanup;
282
283         opts->retprobe = true;
284         skel->links.uretprobe = bpf_program__attach_uprobe_multi(skel->progs.uretprobe, pid,
285                                                                  binary, pattern, opts);
286         if (!ASSERT_OK_PTR(skel->links.uretprobe, "bpf_program__attach_uprobe_multi"))
287                 goto cleanup;
288
289         opts->retprobe = false;
290         skel->links.uprobe_sleep = bpf_program__attach_uprobe_multi(skel->progs.uprobe_sleep, pid,
291                                                                     binary, pattern, opts);
292         if (!ASSERT_OK_PTR(skel->links.uprobe_sleep, "bpf_program__attach_uprobe_multi"))
293                 goto cleanup;
294
295         opts->retprobe = true;
296         skel->links.uretprobe_sleep = bpf_program__attach_uprobe_multi(skel->progs.uretprobe_sleep,
297                                                                        pid, binary, pattern, opts);
298         if (!ASSERT_OK_PTR(skel->links.uretprobe_sleep, "bpf_program__attach_uprobe_multi"))
299                 goto cleanup;
300
301         opts->retprobe = false;
302         skel->links.uprobe_extra = bpf_program__attach_uprobe_multi(skel->progs.uprobe_extra, -1,
303                                                                     binary, pattern, opts);
304         if (!ASSERT_OK_PTR(skel->links.uprobe_extra, "bpf_program__attach_uprobe_multi"))
305                 goto cleanup;
306
307         /* Attach (uprobe-backed) USDTs */
308         skel->links.usdt_pid = bpf_program__attach_usdt(skel->progs.usdt_pid, pid, binary,
309                                                         "test", "pid_filter_usdt", NULL);
310         if (!ASSERT_OK_PTR(skel->links.usdt_pid, "attach_usdt_pid"))
311                 goto cleanup;
312
313         skel->links.usdt_extra = bpf_program__attach_usdt(skel->progs.usdt_extra, -1, binary,
314                                                           "test", "pid_filter_usdt", NULL);
315         if (!ASSERT_OK_PTR(skel->links.usdt_extra, "attach_usdt_extra"))
316                 goto cleanup;
317
318         uprobe_multi_test_run(skel, child);
319
320         ASSERT_FALSE(skel->bss->bad_pid_seen_usdt, "bad_pid_seen_usdt");
321         if (child) {
322                 ASSERT_EQ(skel->bss->child_pid_usdt, child->pid, "usdt_multi_child_pid");
323                 ASSERT_EQ(skel->bss->child_tid_usdt, child->tid, "usdt_multi_child_tid");
324         }
325 cleanup:
326         uprobe_multi__destroy(skel);
327 }
328
329 static void
330 test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi_opts *opts)
331 {
332         static struct child child;
333
334         /* no pid filter */
335         __test_attach_api(binary, pattern, opts, NULL);
336
337         /* pid filter */
338         if (!ASSERT_OK(spawn_child(&child), "spawn_child"))
339                 return;
340
341         __test_attach_api(binary, pattern, opts, &child);
342
343         /* pid filter (thread) */
344         if (!ASSERT_OK(spawn_thread(&child), "spawn_thread"))
345                 return;
346
347         __test_attach_api(binary, pattern, opts, &child);
348 }
349
350 static void test_attach_api_pattern(void)
351 {
352         LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
353
354         test_attach_api("/proc/self/exe", "uprobe_multi_func_*", &opts);
355         test_attach_api("/proc/self/exe", "uprobe_multi_func_?", &opts);
356 }
357
358 static void test_attach_api_syms(void)
359 {
360         LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
361         const char *syms[3] = {
362                 "uprobe_multi_func_1",
363                 "uprobe_multi_func_2",
364                 "uprobe_multi_func_3",
365         };
366
367         opts.syms = syms;
368         opts.cnt = ARRAY_SIZE(syms);
369         test_attach_api("/proc/self/exe", NULL, &opts);
370 }
371
372 static void test_attach_api_fails(void)
373 {
374         LIBBPF_OPTS(bpf_link_create_opts, opts);
375         const char *path = "/proc/self/exe";
376         struct uprobe_multi *skel = NULL;
377         int prog_fd, link_fd = -1;
378         unsigned long offset = 0;
379
380         skel = uprobe_multi__open_and_load();
381         if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
382                 goto cleanup;
383
384         prog_fd = bpf_program__fd(skel->progs.uprobe_extra);
385
386         /* abnormal cnt */
387         opts.uprobe_multi.path = path;
388         opts.uprobe_multi.offsets = &offset;
389         opts.uprobe_multi.cnt = INT_MAX;
390         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
391         if (!ASSERT_ERR(link_fd, "link_fd"))
392                 goto cleanup;
393         if (!ASSERT_EQ(link_fd, -E2BIG, "big cnt"))
394                 goto cleanup;
395
396         /* cnt is 0 */
397         LIBBPF_OPTS_RESET(opts,
398                 .uprobe_multi.path = path,
399                 .uprobe_multi.offsets = (unsigned long *) &offset,
400         );
401
402         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
403         if (!ASSERT_ERR(link_fd, "link_fd"))
404                 goto cleanup;
405         if (!ASSERT_EQ(link_fd, -EINVAL, "cnt_is_zero"))
406                 goto cleanup;
407
408         /* negative offset */
409         offset = -1;
410         opts.uprobe_multi.path = path;
411         opts.uprobe_multi.offsets = (unsigned long *) &offset;
412         opts.uprobe_multi.cnt = 1;
413
414         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
415         if (!ASSERT_ERR(link_fd, "link_fd"))
416                 goto cleanup;
417         if (!ASSERT_EQ(link_fd, -EINVAL, "offset_is_negative"))
418                 goto cleanup;
419
420         /* offsets is NULL */
421         LIBBPF_OPTS_RESET(opts,
422                 .uprobe_multi.path = path,
423                 .uprobe_multi.cnt = 1,
424         );
425
426         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
427         if (!ASSERT_ERR(link_fd, "link_fd"))
428                 goto cleanup;
429         if (!ASSERT_EQ(link_fd, -EINVAL, "offsets_is_null"))
430                 goto cleanup;
431
432         /* wrong offsets pointer */
433         LIBBPF_OPTS_RESET(opts,
434                 .uprobe_multi.path = path,
435                 .uprobe_multi.offsets = (unsigned long *) 1,
436                 .uprobe_multi.cnt = 1,
437         );
438
439         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
440         if (!ASSERT_ERR(link_fd, "link_fd"))
441                 goto cleanup;
442         if (!ASSERT_EQ(link_fd, -EFAULT, "offsets_is_wrong"))
443                 goto cleanup;
444
445         /* path is NULL */
446         offset = 1;
447         LIBBPF_OPTS_RESET(opts,
448                 .uprobe_multi.offsets = (unsigned long *) &offset,
449                 .uprobe_multi.cnt = 1,
450         );
451
452         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
453         if (!ASSERT_ERR(link_fd, "link_fd"))
454                 goto cleanup;
455         if (!ASSERT_EQ(link_fd, -EINVAL, "path_is_null"))
456                 goto cleanup;
457
458         /* wrong path pointer  */
459         LIBBPF_OPTS_RESET(opts,
460                 .uprobe_multi.path = (const char *) 1,
461                 .uprobe_multi.offsets = (unsigned long *) &offset,
462                 .uprobe_multi.cnt = 1,
463         );
464
465         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
466         if (!ASSERT_ERR(link_fd, "link_fd"))
467                 goto cleanup;
468         if (!ASSERT_EQ(link_fd, -EFAULT, "path_is_wrong"))
469                 goto cleanup;
470
471         /* wrong path type */
472         LIBBPF_OPTS_RESET(opts,
473                 .uprobe_multi.path = "/",
474                 .uprobe_multi.offsets = (unsigned long *) &offset,
475                 .uprobe_multi.cnt = 1,
476         );
477
478         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
479         if (!ASSERT_ERR(link_fd, "link_fd"))
480                 goto cleanup;
481         if (!ASSERT_EQ(link_fd, -EBADF, "path_is_wrong_type"))
482                 goto cleanup;
483
484         /* wrong cookies pointer */
485         LIBBPF_OPTS_RESET(opts,
486                 .uprobe_multi.path = path,
487                 .uprobe_multi.offsets = (unsigned long *) &offset,
488                 .uprobe_multi.cookies = (__u64 *) 1ULL,
489                 .uprobe_multi.cnt = 1,
490         );
491
492         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
493         if (!ASSERT_ERR(link_fd, "link_fd"))
494                 goto cleanup;
495         if (!ASSERT_EQ(link_fd, -EFAULT, "cookies_is_wrong"))
496                 goto cleanup;
497
498         /* wrong ref_ctr_offsets pointer */
499         LIBBPF_OPTS_RESET(opts,
500                 .uprobe_multi.path = path,
501                 .uprobe_multi.offsets = (unsigned long *) &offset,
502                 .uprobe_multi.cookies = (__u64 *) &offset,
503                 .uprobe_multi.ref_ctr_offsets = (unsigned long *) 1,
504                 .uprobe_multi.cnt = 1,
505         );
506
507         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
508         if (!ASSERT_ERR(link_fd, "link_fd"))
509                 goto cleanup;
510         if (!ASSERT_EQ(link_fd, -EFAULT, "ref_ctr_offsets_is_wrong"))
511                 goto cleanup;
512
513         /* wrong flags */
514         LIBBPF_OPTS_RESET(opts,
515                 .uprobe_multi.flags = 1 << 31,
516         );
517
518         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
519         if (!ASSERT_ERR(link_fd, "link_fd"))
520                 goto cleanup;
521         if (!ASSERT_EQ(link_fd, -EINVAL, "wrong_flags"))
522                 goto cleanup;
523
524         /* wrong pid */
525         LIBBPF_OPTS_RESET(opts,
526                 .uprobe_multi.path = path,
527                 .uprobe_multi.offsets = (unsigned long *) &offset,
528                 .uprobe_multi.cnt = 1,
529                 .uprobe_multi.pid = -2,
530         );
531
532         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
533         if (!ASSERT_ERR(link_fd, "link_fd"))
534                 goto cleanup;
535         ASSERT_EQ(link_fd, -EINVAL, "pid_is_wrong");
536
537 cleanup:
538         if (link_fd >= 0)
539                 close(link_fd);
540         uprobe_multi__destroy(skel);
541 }
542
543 #ifdef __x86_64__
544 noinline void uprobe_multi_error_func(void)
545 {
546         /*
547          * If --fcf-protection=branch is enabled the gcc generates endbr as
548          * first instruction, so marking the exact address of int3 with the
549          * symbol to be used in the attach_uprobe_fail_trap test below.
550          */
551         asm volatile (
552                 ".globl uprobe_multi_error_func_int3;   \n"
553                 "uprobe_multi_error_func_int3:          \n"
554                 "int3                                   \n"
555         );
556 }
557
558 /*
559  * Attaching uprobe on uprobe_multi_error_func results in error
560  * because it already starts with int3 instruction.
561  */
562 static void attach_uprobe_fail_trap(struct uprobe_multi *skel)
563 {
564         LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
565         const char *syms[4] = {
566                 "uprobe_multi_func_1",
567                 "uprobe_multi_func_2",
568                 "uprobe_multi_func_3",
569                 "uprobe_multi_error_func_int3",
570         };
571
572         opts.syms = syms;
573         opts.cnt = ARRAY_SIZE(syms);
574
575         skel->links.uprobe = bpf_program__attach_uprobe_multi(skel->progs.uprobe, -1,
576                                                               "/proc/self/exe", NULL, &opts);
577         if (!ASSERT_ERR_PTR(skel->links.uprobe, "bpf_program__attach_uprobe_multi")) {
578                 bpf_link__destroy(skel->links.uprobe);
579                 skel->links.uprobe = NULL;
580         }
581 }
582 #else
583 static void attach_uprobe_fail_trap(struct uprobe_multi *skel) { }
584 #endif
585
586 short sema_1 __used, sema_2 __used;
587
588 static void attach_uprobe_fail_refctr(struct uprobe_multi *skel)
589 {
590         unsigned long *tmp_offsets = NULL, *tmp_ref_ctr_offsets = NULL;
591         unsigned long offsets[3], ref_ctr_offsets[3];
592         LIBBPF_OPTS(bpf_link_create_opts, opts);
593         const char *path = "/proc/self/exe";
594         const char *syms[3] = {
595                 "uprobe_multi_func_1",
596                 "uprobe_multi_func_2",
597         };
598         const char *sema[3] = {
599                 "sema_1",
600                 "sema_2",
601         };
602         int prog_fd, link_fd, err;
603
604         prog_fd = bpf_program__fd(skel->progs.uprobe_extra);
605
606         err = elf_resolve_syms_offsets("/proc/self/exe", 2, (const char **) &syms,
607                                        &tmp_offsets, STT_FUNC);
608         if (!ASSERT_OK(err, "elf_resolve_syms_offsets_func"))
609                 return;
610
611         err = elf_resolve_syms_offsets("/proc/self/exe", 2, (const char **) &sema,
612                                        &tmp_ref_ctr_offsets, STT_OBJECT);
613         if (!ASSERT_OK(err, "elf_resolve_syms_offsets_sema"))
614                 goto cleanup;
615
616         /*
617          * We attach to 3 uprobes on 2 functions, so 2 uprobes share single function,
618          * but with different ref_ctr_offset which is not allowed and results in fail.
619          */
620         offsets[0] = tmp_offsets[0]; /* uprobe_multi_func_1 */
621         offsets[1] = tmp_offsets[1]; /* uprobe_multi_func_2 */
622         offsets[2] = tmp_offsets[1]; /* uprobe_multi_func_2 */
623
624         ref_ctr_offsets[0] = tmp_ref_ctr_offsets[0]; /* sema_1 */
625         ref_ctr_offsets[1] = tmp_ref_ctr_offsets[1]; /* sema_2 */
626         ref_ctr_offsets[2] = tmp_ref_ctr_offsets[0]; /* sema_1, error */
627
628         opts.uprobe_multi.path = path;
629         opts.uprobe_multi.offsets = (const unsigned long *) &offsets;
630         opts.uprobe_multi.ref_ctr_offsets = (const unsigned long *) &ref_ctr_offsets;
631         opts.uprobe_multi.cnt = 3;
632
633         link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
634         if (!ASSERT_ERR(link_fd, "link_fd"))
635                 close(link_fd);
636
637 cleanup:
638         free(tmp_ref_ctr_offsets);
639         free(tmp_offsets);
640 }
641
642 static void test_attach_uprobe_fails(void)
643 {
644         struct uprobe_multi *skel = NULL;
645
646         skel = uprobe_multi__open_and_load();
647         if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
648                 return;
649
650         /* attach fails due to adding uprobe on trap instruction, x86_64 only */
651         attach_uprobe_fail_trap(skel);
652
653         /* attach fail due to wrong ref_ctr_offs on one of the uprobes */
654         attach_uprobe_fail_refctr(skel);
655
656         uprobe_multi__destroy(skel);
657 }
658
659 static void __test_link_api(struct child *child)
660 {
661         int prog_fd, link1_fd = -1, link2_fd = -1, link3_fd = -1, link4_fd = -1;
662         LIBBPF_OPTS(bpf_link_create_opts, opts);
663         const char *path = "/proc/self/exe";
664         struct uprobe_multi *skel = NULL;
665         unsigned long *offsets = NULL;
666         const char *syms[3] = {
667                 "uprobe_multi_func_1",
668                 "uprobe_multi_func_2",
669                 "uprobe_multi_func_3",
670         };
671         int link_extra_fd = -1;
672         int err;
673
674         err = elf_resolve_syms_offsets(path, 3, syms, (unsigned long **) &offsets, STT_FUNC);
675         if (!ASSERT_OK(err, "elf_resolve_syms_offsets"))
676                 return;
677
678         opts.uprobe_multi.path = path;
679         opts.uprobe_multi.offsets = offsets;
680         opts.uprobe_multi.cnt = ARRAY_SIZE(syms);
681         opts.uprobe_multi.pid = child ? child->pid : 0;
682
683         skel = uprobe_multi__open_and_load();
684         if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
685                 goto cleanup;
686
687         opts.kprobe_multi.flags = 0;
688         prog_fd = bpf_program__fd(skel->progs.uprobe);
689         link1_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
690         if (!ASSERT_GE(link1_fd, 0, "link1_fd"))
691                 goto cleanup;
692
693         opts.kprobe_multi.flags = BPF_F_UPROBE_MULTI_RETURN;
694         prog_fd = bpf_program__fd(skel->progs.uretprobe);
695         link2_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
696         if (!ASSERT_GE(link2_fd, 0, "link2_fd"))
697                 goto cleanup;
698
699         opts.kprobe_multi.flags = 0;
700         prog_fd = bpf_program__fd(skel->progs.uprobe_sleep);
701         link3_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
702         if (!ASSERT_GE(link3_fd, 0, "link3_fd"))
703                 goto cleanup;
704
705         opts.kprobe_multi.flags = BPF_F_UPROBE_MULTI_RETURN;
706         prog_fd = bpf_program__fd(skel->progs.uretprobe_sleep);
707         link4_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
708         if (!ASSERT_GE(link4_fd, 0, "link4_fd"))
709                 goto cleanup;
710
711         opts.kprobe_multi.flags = 0;
712         opts.uprobe_multi.pid = 0;
713         prog_fd = bpf_program__fd(skel->progs.uprobe_extra);
714         link_extra_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
715         if (!ASSERT_GE(link_extra_fd, 0, "link_extra_fd"))
716                 goto cleanup;
717
718         uprobe_multi_test_run(skel, child);
719
720 cleanup:
721         if (link1_fd >= 0)
722                 close(link1_fd);
723         if (link2_fd >= 0)
724                 close(link2_fd);
725         if (link3_fd >= 0)
726                 close(link3_fd);
727         if (link4_fd >= 0)
728                 close(link4_fd);
729         if (link_extra_fd >= 0)
730                 close(link_extra_fd);
731
732         uprobe_multi__destroy(skel);
733         free(offsets);
734 }
735
736 static void test_link_api(void)
737 {
738         static struct child child;
739
740         /* no pid filter */
741         __test_link_api(NULL);
742
743         /* pid filter */
744         if (!ASSERT_OK(spawn_child(&child), "spawn_child"))
745                 return;
746
747         __test_link_api(&child);
748
749         /* pid filter (thread) */
750         if (!ASSERT_OK(spawn_thread(&child), "spawn_thread"))
751                 return;
752
753         __test_link_api(&child);
754 }
755
756 static struct bpf_program *
757 get_program(struct uprobe_multi_consumers *skel, int prog)
758 {
759         switch (prog) {
760         case 0:
761                 return skel->progs.uprobe_0;
762         case 1:
763                 return skel->progs.uprobe_1;
764         case 2:
765                 return skel->progs.uprobe_2;
766         case 3:
767                 return skel->progs.uprobe_3;
768         default:
769                 ASSERT_FAIL("get_program");
770                 return NULL;
771         }
772 }
773
774 static struct bpf_link **
775 get_link(struct uprobe_multi_consumers *skel, int link)
776 {
777         switch (link) {
778         case 0:
779                 return &skel->links.uprobe_0;
780         case 1:
781                 return &skel->links.uprobe_1;
782         case 2:
783                 return &skel->links.uprobe_2;
784         case 3:
785                 return &skel->links.uprobe_3;
786         default:
787                 ASSERT_FAIL("get_link");
788                 return NULL;
789         }
790 }
791
792 static int uprobe_attach(struct uprobe_multi_consumers *skel, int idx, unsigned long offset)
793 {
794         struct bpf_program *prog = get_program(skel, idx);
795         struct bpf_link **link = get_link(skel, idx);
796         LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
797
798         if (!prog || !link)
799                 return -1;
800
801         opts.offsets = &offset;
802         opts.cnt = 1;
803
804         /*
805          * bit/prog: 0 uprobe entry
806          * bit/prog: 1 uprobe return
807          * bit/prog: 2 uprobe session without return
808          * bit/prog: 3 uprobe session with return
809          */
810         opts.retprobe = idx == 1;
811         opts.session  = idx == 2 || idx == 3;
812
813         *link = bpf_program__attach_uprobe_multi(prog, 0, "/proc/self/exe", NULL, &opts);
814         if (!ASSERT_OK_PTR(*link, "bpf_program__attach_uprobe_multi"))
815                 return -1;
816         return 0;
817 }
818
819 static void uprobe_detach(struct uprobe_multi_consumers *skel, int idx)
820 {
821         struct bpf_link **link = get_link(skel, idx);
822
823         bpf_link__destroy(*link);
824         *link = NULL;
825 }
826
827 static bool test_bit(int bit, unsigned long val)
828 {
829         return val & (1 << bit);
830 }
831
832 noinline int
833 uprobe_consumer_test(struct uprobe_multi_consumers *skel,
834                      unsigned long before, unsigned long after,
835                      unsigned long offset)
836 {
837         int idx;
838
839         /* detach uprobe for each unset programs in 'before' state ... */
840         for (idx = 0; idx < 4; idx++) {
841                 if (test_bit(idx, before) && !test_bit(idx, after))
842                         uprobe_detach(skel, idx);
843         }
844
845         /* ... and attach all new programs in 'after' state */
846         for (idx = 0; idx < 4; idx++) {
847                 if (!test_bit(idx, before) && test_bit(idx, after)) {
848                         if (!ASSERT_OK(uprobe_attach(skel, idx, offset), "uprobe_attach_after"))
849                                 return -1;
850                 }
851         }
852         return 0;
853 }
854
855 /*
856  * We generate 16 consumer_testX functions that will have uprobe installed on
857  * and will be called in separate threads. All function pointer are stored in
858  * "consumers" section and each thread will pick one function based on index.
859  */
860
861 extern const void *__start_consumers;
862
863 #define __CONSUMER_TEST(func)                                                   \
864 noinline int func(struct uprobe_multi_consumers *skel, unsigned long before,    \
865                   unsigned long after, unsigned long offset)                    \
866 {                                                                               \
867         return uprobe_consumer_test(skel, before, after, offset);               \
868 }                                                                               \
869 void *__ ## func __used __attribute__((section("consumers"))) = (void *) func;
870
871 #define CONSUMER_TEST(func) __CONSUMER_TEST(func)
872
873 #define C1  CONSUMER_TEST(__PASTE(consumer_test, __COUNTER__))
874 #define C4  C1 C1 C1 C1
875 #define C16 C4 C4 C4 C4
876
877 C16
878
879 typedef int (*test_t)(struct uprobe_multi_consumers *, unsigned long,
880                       unsigned long, unsigned long);
881
882 static int consumer_test(struct uprobe_multi_consumers *skel,
883                          unsigned long before, unsigned long after,
884                          test_t test, unsigned long offset)
885 {
886         int err, idx, ret = -1;
887
888         printf("consumer_test before %lu after %lu\n", before, after);
889
890         /* 'before' is each, we attach uprobe for every set idx */
891         for (idx = 0; idx < 4; idx++) {
892                 if (test_bit(idx, before)) {
893                         if (!ASSERT_OK(uprobe_attach(skel, idx, offset), "uprobe_attach_before"))
894                                 goto cleanup;
895                 }
896         }
897
898         err = test(skel, before, after, offset);
899         if (!ASSERT_EQ(err, 0, "uprobe_consumer_test"))
900                 goto cleanup;
901
902         for (idx = 0; idx < 4; idx++) {
903                 bool uret_stays, uret_survives;
904                 const char *fmt = "BUG";
905                 __u64 val = 0;
906
907                 switch (idx) {
908                 case 0:
909                         /*
910                          * uprobe entry
911                          *   +1 if define in 'before'
912                          */
913                         if (test_bit(idx, before))
914                                 val++;
915                         fmt = "prog 0: uprobe";
916                         break;
917                 case 1:
918                         /*
919                          * To trigger uretprobe consumer, the uretprobe under test either stayed from
920                          * before to after (uret_stays + test_bit) or uretprobe instance survived and
921                          * we have uretprobe active in after (uret_survives + test_bit)
922                          */
923                         uret_stays = before & after & 0b0110;
924                         uret_survives = ((before & 0b0110) && (after & 0b0110) && (before & 0b1001));
925
926                         if ((uret_stays || uret_survives) && test_bit(idx, after))
927                                 val++;
928                         fmt = "prog 1: uretprobe";
929                         break;
930                 case 2:
931                         /*
932                          * session with return
933                          *  +1 if defined in 'before'
934                          *  +1 if defined in 'after'
935                          */
936                         if (test_bit(idx, before)) {
937                                 val++;
938                                 if (test_bit(idx, after))
939                                         val++;
940                         }
941                         fmt = "prog 2: session with return";
942                         break;
943                 case 3:
944                         /*
945                          * session without return
946                          *   +1 if defined in 'before'
947                          */
948                         if (test_bit(idx, before))
949                                 val++;
950                         fmt = "prog 3: session with NO return";
951                         break;
952                 }
953
954                 if (!ASSERT_EQ(skel->bss->uprobe_result[idx], val, fmt))
955                         goto cleanup;
956                 skel->bss->uprobe_result[idx] = 0;
957         }
958
959         ret = 0;
960
961 cleanup:
962         for (idx = 0; idx < 4; idx++)
963                 uprobe_detach(skel, idx);
964         return ret;
965 }
966
967 #define CONSUMER_MAX 16
968
969 /*
970  * Each thread runs 1/16 of the load by running test for single
971  * 'before' number (based on thread index) and full scale of
972  * 'after' numbers.
973  */
974 static void *consumer_thread(void *arg)
975 {
976         unsigned long idx = (unsigned long) arg;
977         struct uprobe_multi_consumers *skel;
978         unsigned long offset;
979         const void *func;
980         int after;
981
982         skel = uprobe_multi_consumers__open_and_load();
983         if (!ASSERT_OK_PTR(skel, "uprobe_multi_consumers__open_and_load"))
984                 return NULL;
985
986         func = *((&__start_consumers) + idx);
987
988         offset = get_uprobe_offset(func);
989         if (!ASSERT_GE(offset, 0, "uprobe_offset"))
990                 goto out;
991
992         for (after = 0; after < CONSUMER_MAX; after++)
993                 if (consumer_test(skel, idx, after, func, offset))
994                         goto out;
995
996 out:
997         uprobe_multi_consumers__destroy(skel);
998         return NULL;
999 }
1000
1001
1002 static void test_consumers(void)
1003 {
1004         pthread_t pt[CONSUMER_MAX];
1005         unsigned long idx;
1006         int err;
1007
1008         /*
1009          * The idea of this test is to try all possible combinations of
1010          * uprobes consumers attached on single function.
1011          *
1012          *  - 1 uprobe entry consumer
1013          *  - 1 uprobe exit consumer
1014          *  - 1 uprobe session with return
1015          *  - 1 uprobe session without return
1016          *
1017          * The test uses 4 uprobes attached on single function, but that
1018          * translates into single uprobe with 4 consumers in kernel.
1019          *
1020          * The before/after values present the state of attached consumers
1021          * before and after the probed function:
1022          *
1023          *  bit/prog 0 : uprobe entry
1024          *  bit/prog 1 : uprobe return
1025          *
1026          * For example for:
1027          *
1028          *   before = 0b01
1029          *   after  = 0b10
1030          *
1031          * it means that before we call 'uprobe_consumer_test' we attach
1032          * uprobes defined in 'before' value:
1033          *
1034          *   - bit/prog 1: uprobe entry
1035          *
1036          * uprobe_consumer_test is called and inside it we attach and detach
1037          * uprobes based on 'after' value:
1038          *
1039          *   - bit/prog 0: is detached
1040          *   - bit/prog 1: is attached
1041          *
1042          * uprobe_consumer_test returns and we check counters values increased
1043          * by bpf programs on each uprobe to match the expected count based on
1044          * before/after bits.
1045          */
1046
1047         for (idx = 0; idx < CONSUMER_MAX; idx++) {
1048                 err = pthread_create(&pt[idx], NULL, consumer_thread, (void *) idx);
1049                 if (!ASSERT_OK(err, "pthread_create"))
1050                         break;
1051         }
1052
1053         while (idx)
1054                 pthread_join(pt[--idx], NULL);
1055 }
1056
1057 static struct bpf_program *uprobe_multi_program(struct uprobe_multi_pid_filter *skel, int idx)
1058 {
1059         switch (idx) {
1060         case 0: return skel->progs.uprobe_multi_0;
1061         case 1: return skel->progs.uprobe_multi_1;
1062         case 2: return skel->progs.uprobe_multi_2;
1063         }
1064         return NULL;
1065 }
1066
1067 #define TASKS 3
1068
1069 static void run_pid_filter(struct uprobe_multi_pid_filter *skel, bool clone_vm, bool retprobe)
1070 {
1071         LIBBPF_OPTS(bpf_uprobe_multi_opts, opts, .retprobe = retprobe);
1072         struct bpf_link *link[TASKS] = {};
1073         struct child child[TASKS] = {};
1074         int i;
1075
1076         memset(skel->bss->test, 0, sizeof(skel->bss->test));
1077
1078         for (i = 0; i < TASKS; i++) {
1079                 if (!ASSERT_OK(spawn_child_flag(&child[i], clone_vm), "spawn_child"))
1080                         goto cleanup;
1081                 skel->bss->pids[i] = child[i].pid;
1082         }
1083
1084         for (i = 0; i < TASKS; i++) {
1085                 link[i] = bpf_program__attach_uprobe_multi(uprobe_multi_program(skel, i),
1086                                                            child[i].pid, "/proc/self/exe",
1087                                                            "uprobe_multi_func_1", &opts);
1088                 if (!ASSERT_OK_PTR(link[i], "bpf_program__attach_uprobe_multi"))
1089                         goto cleanup;
1090         }
1091
1092         for (i = 0; i < TASKS; i++)
1093                 kick_child(&child[i]);
1094
1095         for (i = 0; i < TASKS; i++) {
1096                 ASSERT_EQ(skel->bss->test[i][0], 1, "pid");
1097                 ASSERT_EQ(skel->bss->test[i][1], 0, "unknown");
1098         }
1099
1100 cleanup:
1101         for (i = 0; i < TASKS; i++)
1102                 bpf_link__destroy(link[i]);
1103         for (i = 0; i < TASKS; i++)
1104                 release_child(&child[i]);
1105 }
1106
1107 static void test_pid_filter_process(bool clone_vm)
1108 {
1109         struct uprobe_multi_pid_filter *skel;
1110
1111         skel = uprobe_multi_pid_filter__open_and_load();
1112         if (!ASSERT_OK_PTR(skel, "uprobe_multi_pid_filter__open_and_load"))
1113                 return;
1114
1115         run_pid_filter(skel, clone_vm, false);
1116         run_pid_filter(skel, clone_vm, true);
1117
1118         uprobe_multi_pid_filter__destroy(skel);
1119 }
1120
1121 static void test_session_skel_api(void)
1122 {
1123         struct uprobe_multi_session *skel = NULL;
1124         LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
1125         struct bpf_link *link = NULL;
1126         int err;
1127
1128         skel = uprobe_multi_session__open_and_load();
1129         if (!ASSERT_OK_PTR(skel, "uprobe_multi_session__open_and_load"))
1130                 goto cleanup;
1131
1132         skel->bss->pid = getpid();
1133         skel->bss->user_ptr = test_data;
1134
1135         err = uprobe_multi_session__attach(skel);
1136         if (!ASSERT_OK(err, "uprobe_multi_session__attach"))
1137                 goto cleanup;
1138
1139         /* trigger all probes */
1140         skel->bss->uprobe_multi_func_1_addr = (__u64) uprobe_multi_func_1;
1141         skel->bss->uprobe_multi_func_2_addr = (__u64) uprobe_multi_func_2;
1142         skel->bss->uprobe_multi_func_3_addr = (__u64) uprobe_multi_func_3;
1143
1144         uprobe_multi_func_1();
1145         uprobe_multi_func_2();
1146         uprobe_multi_func_3();
1147
1148         /*
1149          * We expect 2 for uprobe_multi_func_2 because it runs both entry/return probe,
1150          * uprobe_multi_func_[13] run just the entry probe. All expected numbers are
1151          * doubled, because we run extra test for sleepable session.
1152          */
1153         ASSERT_EQ(skel->bss->uprobe_session_result[0], 2, "uprobe_multi_func_1_result");
1154         ASSERT_EQ(skel->bss->uprobe_session_result[1], 4, "uprobe_multi_func_2_result");
1155         ASSERT_EQ(skel->bss->uprobe_session_result[2], 2, "uprobe_multi_func_3_result");
1156
1157         /* We expect increase in 3 entry and 1 return session calls -> 4 */
1158         ASSERT_EQ(skel->bss->uprobe_multi_sleep_result, 4, "uprobe_multi_sleep_result");
1159
1160 cleanup:
1161         bpf_link__destroy(link);
1162         uprobe_multi_session__destroy(skel);
1163 }
1164
1165 static void test_session_single_skel_api(void)
1166 {
1167         struct uprobe_multi_session_single *skel = NULL;
1168         LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
1169         int err;
1170
1171         skel = uprobe_multi_session_single__open_and_load();
1172         if (!ASSERT_OK_PTR(skel, "uprobe_multi_session_single__open_and_load"))
1173                 goto cleanup;
1174
1175         skel->bss->pid = getpid();
1176
1177         err = uprobe_multi_session_single__attach(skel);
1178         if (!ASSERT_OK(err, "uprobe_multi_session_single__attach"))
1179                 goto cleanup;
1180
1181         uprobe_multi_func_1();
1182
1183         /*
1184          * We expect consumer 0 and 2 to trigger just entry handler (value 1)
1185          * and consumer 1 to hit both (value 2).
1186          */
1187         ASSERT_EQ(skel->bss->uprobe_session_result[0], 1, "uprobe_session_result_0");
1188         ASSERT_EQ(skel->bss->uprobe_session_result[1], 2, "uprobe_session_result_1");
1189         ASSERT_EQ(skel->bss->uprobe_session_result[2], 1, "uprobe_session_result_2");
1190
1191 cleanup:
1192         uprobe_multi_session_single__destroy(skel);
1193 }
1194
1195 static void test_session_cookie_skel_api(void)
1196 {
1197         struct uprobe_multi_session_cookie *skel = NULL;
1198         int err;
1199
1200         skel = uprobe_multi_session_cookie__open_and_load();
1201         if (!ASSERT_OK_PTR(skel, "uprobe_multi_session_cookie__open_and_load"))
1202                 goto cleanup;
1203
1204         skel->bss->pid = getpid();
1205
1206         err = uprobe_multi_session_cookie__attach(skel);
1207         if (!ASSERT_OK(err, "uprobe_multi_session_cookie__attach"))
1208                 goto cleanup;
1209
1210         /* trigger all probes */
1211         uprobe_multi_func_1();
1212         uprobe_multi_func_2();
1213         uprobe_multi_func_3();
1214
1215         ASSERT_EQ(skel->bss->test_uprobe_1_result, 1, "test_uprobe_1_result");
1216         ASSERT_EQ(skel->bss->test_uprobe_2_result, 2, "test_uprobe_2_result");
1217         ASSERT_EQ(skel->bss->test_uprobe_3_result, 3, "test_uprobe_3_result");
1218
1219 cleanup:
1220         uprobe_multi_session_cookie__destroy(skel);
1221 }
1222
1223 static void test_session_recursive_skel_api(void)
1224 {
1225         struct uprobe_multi_session_recursive *skel = NULL;
1226         int i, err;
1227
1228         skel = uprobe_multi_session_recursive__open_and_load();
1229         if (!ASSERT_OK_PTR(skel, "uprobe_multi_session_recursive__open_and_load"))
1230                 goto cleanup;
1231
1232         skel->bss->pid = getpid();
1233
1234         err = uprobe_multi_session_recursive__attach(skel);
1235         if (!ASSERT_OK(err, "uprobe_multi_session_recursive__attach"))
1236                 goto cleanup;
1237
1238         for (i = 0; i < ARRAY_SIZE(skel->bss->test_uprobe_cookie_entry); i++)
1239                 skel->bss->test_uprobe_cookie_entry[i] = i + 1;
1240
1241         uprobe_session_recursive(5);
1242
1243         /*
1244          *                                         entry uprobe:
1245          * uprobe_session_recursive(5) {             *cookie = 1, return 0
1246          *   uprobe_session_recursive(4) {           *cookie = 2, return 1
1247          *     uprobe_session_recursive(3) {         *cookie = 3, return 0
1248          *       uprobe_session_recursive(2) {       *cookie = 4, return 1
1249          *         uprobe_session_recursive(1) {     *cookie = 5, return 0
1250          *           uprobe_session_recursive(0) {   *cookie = 6, return 1
1251          *                                          return uprobe:
1252          *           } i = 0                          not executed
1253          *         } i = 1                            test_uprobe_cookie_return[0] = 5
1254          *       } i = 2                              not executed
1255          *     } i = 3                                test_uprobe_cookie_return[1] = 3
1256          *   } i = 4                                  not executed
1257          * } i = 5                                    test_uprobe_cookie_return[2] = 1
1258          */
1259
1260         ASSERT_EQ(skel->bss->idx_entry, 6, "idx_entry");
1261         ASSERT_EQ(skel->bss->idx_return, 3, "idx_return");
1262
1263         ASSERT_EQ(skel->bss->test_uprobe_cookie_return[0], 5, "test_uprobe_cookie_return[0]");
1264         ASSERT_EQ(skel->bss->test_uprobe_cookie_return[1], 3, "test_uprobe_cookie_return[1]");
1265         ASSERT_EQ(skel->bss->test_uprobe_cookie_return[2], 1, "test_uprobe_cookie_return[2]");
1266
1267 cleanup:
1268         uprobe_multi_session_recursive__destroy(skel);
1269 }
1270
1271 static void test_bench_attach_uprobe(void)
1272 {
1273         long attach_start_ns = 0, attach_end_ns = 0;
1274         struct uprobe_multi_bench *skel = NULL;
1275         long detach_start_ns, detach_end_ns;
1276         double attach_delta, detach_delta;
1277         int err;
1278
1279         skel = uprobe_multi_bench__open_and_load();
1280         if (!ASSERT_OK_PTR(skel, "uprobe_multi_bench__open_and_load"))
1281                 goto cleanup;
1282
1283         attach_start_ns = get_time_ns();
1284
1285         err = uprobe_multi_bench__attach(skel);
1286         if (!ASSERT_OK(err, "uprobe_multi_bench__attach"))
1287                 goto cleanup;
1288
1289         attach_end_ns = get_time_ns();
1290
1291         system("./uprobe_multi bench");
1292
1293         ASSERT_EQ(skel->bss->count, 50000, "uprobes_count");
1294
1295 cleanup:
1296         detach_start_ns = get_time_ns();
1297         uprobe_multi_bench__destroy(skel);
1298         detach_end_ns = get_time_ns();
1299
1300         attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
1301         detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
1302
1303         printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
1304         printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
1305 }
1306
1307 static void test_bench_attach_usdt(void)
1308 {
1309         long attach_start_ns = 0, attach_end_ns = 0;
1310         struct uprobe_multi_usdt *skel = NULL;
1311         long detach_start_ns, detach_end_ns;
1312         double attach_delta, detach_delta;
1313
1314         skel = uprobe_multi_usdt__open_and_load();
1315         if (!ASSERT_OK_PTR(skel, "uprobe_multi__open"))
1316                 goto cleanup;
1317
1318         attach_start_ns = get_time_ns();
1319
1320         skel->links.usdt0 = bpf_program__attach_usdt(skel->progs.usdt0, -1, "./uprobe_multi",
1321                                                      "test", "usdt", NULL);
1322         if (!ASSERT_OK_PTR(skel->links.usdt0, "bpf_program__attach_usdt"))
1323                 goto cleanup;
1324
1325         attach_end_ns = get_time_ns();
1326
1327         system("./uprobe_multi usdt");
1328
1329         ASSERT_EQ(skel->bss->count, 50000, "usdt_count");
1330
1331 cleanup:
1332         detach_start_ns = get_time_ns();
1333         uprobe_multi_usdt__destroy(skel);
1334         detach_end_ns = get_time_ns();
1335
1336         attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
1337         detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
1338
1339         printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
1340         printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
1341 }
1342
1343 void test_uprobe_multi_test(void)
1344 {
1345         if (test__start_subtest("skel_api"))
1346                 test_skel_api();
1347         if (test__start_subtest("attach_api_pattern"))
1348                 test_attach_api_pattern();
1349         if (test__start_subtest("attach_api_syms"))
1350                 test_attach_api_syms();
1351         if (test__start_subtest("link_api"))
1352                 test_link_api();
1353         if (test__start_subtest("bench_uprobe"))
1354                 test_bench_attach_uprobe();
1355         if (test__start_subtest("bench_usdt"))
1356                 test_bench_attach_usdt();
1357         if (test__start_subtest("attach_api_fails"))
1358                 test_attach_api_fails();
1359         if (test__start_subtest("attach_uprobe_fails"))
1360                 test_attach_uprobe_fails();
1361         if (test__start_subtest("consumers"))
1362                 test_consumers();
1363         if (test__start_subtest("filter_fork"))
1364                 test_pid_filter_process(false);
1365         if (test__start_subtest("filter_clone_vm"))
1366                 test_pid_filter_process(true);
1367         if (test__start_subtest("session"))
1368                 test_session_skel_api();
1369         if (test__start_subtest("session_single"))
1370                 test_session_single_skel_api();
1371         if (test__start_subtest("session_cookie"))
1372                 test_session_cookie_skel_api();
1373         if (test__start_subtest("session_cookie_recursive"))
1374                 test_session_recursive_skel_api();
1375         RUN_TESTS(uprobe_multi_verifier);
1376 }
This page took 0.142816 seconds and 4 git commands to generate.