~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/usdt.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
  3 #include <test_progs.h>
  4 
  5 #define _SDT_HAS_SEMAPHORES 1
  6 #include "../sdt.h"
  7 
  8 #include "test_usdt.skel.h"
  9 #include "test_urandom_usdt.skel.h"
 10 
 11 int lets_test_this(int);
 12 
 13 static volatile int idx = 2;
 14 static volatile __u64 bla = 0xFEDCBA9876543210ULL;
 15 static volatile short nums[] = {-1, -2, -3, -4};
 16 
 17 static volatile struct {
 18         int x;
 19         signed char y;
 20 } t1 = { 1, -127 };
 21 
 22 #define SEC(name) __attribute__((section(name), used))
 23 
 24 unsigned short test_usdt0_semaphore SEC(".probes");
 25 unsigned short test_usdt3_semaphore SEC(".probes");
 26 unsigned short test_usdt12_semaphore SEC(".probes");
 27 
 28 static void __always_inline trigger_func(int x) {
 29         long y = 42;
 30 
 31         if (test_usdt0_semaphore)
 32                 STAP_PROBE(test, usdt0);
 33         if (test_usdt3_semaphore)
 34                 STAP_PROBE3(test, usdt3, x, y, &bla);
 35         if (test_usdt12_semaphore) {
 36                 STAP_PROBE12(test, usdt12,
 37                              x, x + 1, y, x + y, 5,
 38                              y / 7, bla, &bla, -9, nums[x],
 39                              nums[idx], t1.y);
 40         }
 41 }
 42 
 43 static void subtest_basic_usdt(void)
 44 {
 45         LIBBPF_OPTS(bpf_usdt_opts, opts);
 46         struct test_usdt *skel;
 47         struct test_usdt__bss *bss;
 48         int err;
 49 
 50         skel = test_usdt__open_and_load();
 51         if (!ASSERT_OK_PTR(skel, "skel_open"))
 52                 return;
 53 
 54         bss = skel->bss;
 55         bss->my_pid = getpid();
 56 
 57         err = test_usdt__attach(skel);
 58         if (!ASSERT_OK(err, "skel_attach"))
 59                 goto cleanup;
 60 
 61         /* usdt0 won't be auto-attached */
 62         opts.usdt_cookie = 0xcafedeadbeeffeed;
 63         skel->links.usdt0 = bpf_program__attach_usdt(skel->progs.usdt0,
 64                                                      0 /*self*/, "/proc/self/exe",
 65                                                      "test", "usdt0", &opts);
 66         if (!ASSERT_OK_PTR(skel->links.usdt0, "usdt0_link"))
 67                 goto cleanup;
 68 
 69         trigger_func(1);
 70 
 71         ASSERT_EQ(bss->usdt0_called, 1, "usdt0_called");
 72         ASSERT_EQ(bss->usdt3_called, 1, "usdt3_called");
 73         ASSERT_EQ(bss->usdt12_called, 1, "usdt12_called");
 74 
 75         ASSERT_EQ(bss->usdt0_cookie, 0xcafedeadbeeffeed, "usdt0_cookie");
 76         ASSERT_EQ(bss->usdt0_arg_cnt, 0, "usdt0_arg_cnt");
 77         ASSERT_EQ(bss->usdt0_arg_ret, -ENOENT, "usdt0_arg_ret");
 78 
 79         /* auto-attached usdt3 gets default zero cookie value */
 80         ASSERT_EQ(bss->usdt3_cookie, 0, "usdt3_cookie");
 81         ASSERT_EQ(bss->usdt3_arg_cnt, 3, "usdt3_arg_cnt");
 82 
 83         ASSERT_EQ(bss->usdt3_arg_rets[0], 0, "usdt3_arg1_ret");
 84         ASSERT_EQ(bss->usdt3_arg_rets[1], 0, "usdt3_arg2_ret");
 85         ASSERT_EQ(bss->usdt3_arg_rets[2], 0, "usdt3_arg3_ret");
 86         ASSERT_EQ(bss->usdt3_args[0], 1, "usdt3_arg1");
 87         ASSERT_EQ(bss->usdt3_args[1], 42, "usdt3_arg2");
 88         ASSERT_EQ(bss->usdt3_args[2], (uintptr_t)&bla, "usdt3_arg3");
 89 
 90         /* auto-attached usdt12 gets default zero cookie value */
 91         ASSERT_EQ(bss->usdt12_cookie, 0, "usdt12_cookie");
 92         ASSERT_EQ(bss->usdt12_arg_cnt, 12, "usdt12_arg_cnt");
 93 
 94         ASSERT_EQ(bss->usdt12_args[0], 1, "usdt12_arg1");
 95         ASSERT_EQ(bss->usdt12_args[1], 1 + 1, "usdt12_arg2");
 96         ASSERT_EQ(bss->usdt12_args[2], 42, "usdt12_arg3");
 97         ASSERT_EQ(bss->usdt12_args[3], 42 + 1, "usdt12_arg4");
 98         ASSERT_EQ(bss->usdt12_args[4], 5, "usdt12_arg5");
 99         ASSERT_EQ(bss->usdt12_args[5], 42 / 7, "usdt12_arg6");
100         ASSERT_EQ(bss->usdt12_args[6], bla, "usdt12_arg7");
101         ASSERT_EQ(bss->usdt12_args[7], (uintptr_t)&bla, "usdt12_arg8");
102         ASSERT_EQ(bss->usdt12_args[8], -9, "usdt12_arg9");
103         ASSERT_EQ(bss->usdt12_args[9], nums[1], "usdt12_arg10");
104         ASSERT_EQ(bss->usdt12_args[10], nums[idx], "usdt12_arg11");
105         ASSERT_EQ(bss->usdt12_args[11], t1.y, "usdt12_arg12");
106 
107         /* trigger_func() is marked __always_inline, so USDT invocations will be
108          * inlined in two different places, meaning that each USDT will have
109          * at least 2 different places to be attached to. This verifies that
110          * bpf_program__attach_usdt() handles this properly and attaches to
111          * all possible places of USDT invocation.
112          */
113         trigger_func(2);
114 
115         ASSERT_EQ(bss->usdt0_called, 2, "usdt0_called");
116         ASSERT_EQ(bss->usdt3_called, 2, "usdt3_called");
117         ASSERT_EQ(bss->usdt12_called, 2, "usdt12_called");
118 
119         /* only check values that depend on trigger_func()'s input value */
120         ASSERT_EQ(bss->usdt3_args[0], 2, "usdt3_arg1");
121 
122         ASSERT_EQ(bss->usdt12_args[0], 2, "usdt12_arg1");
123         ASSERT_EQ(bss->usdt12_args[1], 2 + 1, "usdt12_arg2");
124         ASSERT_EQ(bss->usdt12_args[3], 42 + 2, "usdt12_arg4");
125         ASSERT_EQ(bss->usdt12_args[9], nums[2], "usdt12_arg10");
126 
127         /* detach and re-attach usdt3 */
128         bpf_link__destroy(skel->links.usdt3);
129 
130         opts.usdt_cookie = 0xBADC00C51E;
131         skel->links.usdt3 = bpf_program__attach_usdt(skel->progs.usdt3, -1 /* any pid */,
132                                                      "/proc/self/exe", "test", "usdt3", &opts);
133         if (!ASSERT_OK_PTR(skel->links.usdt3, "usdt3_reattach"))
134                 goto cleanup;
135 
136         trigger_func(3);
137 
138         ASSERT_EQ(bss->usdt3_called, 3, "usdt3_called");
139         /* this time usdt3 has custom cookie */
140         ASSERT_EQ(bss->usdt3_cookie, 0xBADC00C51E, "usdt3_cookie");
141         ASSERT_EQ(bss->usdt3_arg_cnt, 3, "usdt3_arg_cnt");
142 
143         ASSERT_EQ(bss->usdt3_arg_rets[0], 0, "usdt3_arg1_ret");
144         ASSERT_EQ(bss->usdt3_arg_rets[1], 0, "usdt3_arg2_ret");
145         ASSERT_EQ(bss->usdt3_arg_rets[2], 0, "usdt3_arg3_ret");
146         ASSERT_EQ(bss->usdt3_args[0], 3, "usdt3_arg1");
147         ASSERT_EQ(bss->usdt3_args[1], 42, "usdt3_arg2");
148         ASSERT_EQ(bss->usdt3_args[2], (uintptr_t)&bla, "usdt3_arg3");
149 
150 cleanup:
151         test_usdt__destroy(skel);
152 }
153 
154 unsigned short test_usdt_100_semaphore SEC(".probes");
155 unsigned short test_usdt_300_semaphore SEC(".probes");
156 unsigned short test_usdt_400_semaphore SEC(".probes");
157 
158 #define R10(F, X)  F(X+0); F(X+1);F(X+2); F(X+3); F(X+4); \
159                    F(X+5); F(X+6); F(X+7); F(X+8); F(X+9);
160 #define R100(F, X) R10(F,X+ 0);R10(F,X+10);R10(F,X+20);R10(F,X+30);R10(F,X+40); \
161                    R10(F,X+50);R10(F,X+60);R10(F,X+70);R10(F,X+80);R10(F,X+90);
162 
163 /* carefully control that we get exactly 100 inlines by preventing inlining */
164 static void __always_inline f100(int x)
165 {
166         STAP_PROBE1(test, usdt_100, x);
167 }
168 
169 __weak void trigger_100_usdts(void)
170 {
171         R100(f100, 0);
172 }
173 
174 /* we shouldn't be able to attach to test:usdt2_300 USDT as we don't have as
175  * many slots for specs. It's important that each STAP_PROBE2() invocation
176  * (after untolling) gets different arg spec due to compiler inlining i as
177  * a constant
178  */
179 static void __always_inline f300(int x)
180 {
181         STAP_PROBE1(test, usdt_300, x);
182 }
183 
184 __weak void trigger_300_usdts(void)
185 {
186         R100(f300, 0);
187         R100(f300, 100);
188         R100(f300, 200);
189 }
190 
191 static void __always_inline f400(int x __attribute__((unused)))
192 {
193         STAP_PROBE1(test, usdt_400, 400);
194 }
195 
196 /* this time we have 400 different USDT call sites, but they have uniform
197  * argument location, so libbpf's spec string deduplication logic should keep
198  * spec count use very small and so we should be able to attach to all 400
199  * call sites
200  */
201 __weak void trigger_400_usdts(void)
202 {
203         R100(f400, 0);
204         R100(f400, 100);
205         R100(f400, 200);
206         R100(f400, 300);
207 }
208 
209 static void subtest_multispec_usdt(void)
210 {
211         LIBBPF_OPTS(bpf_usdt_opts, opts);
212         struct test_usdt *skel;
213         struct test_usdt__bss *bss;
214         int err, i;
215 
216         skel = test_usdt__open_and_load();
217         if (!ASSERT_OK_PTR(skel, "skel_open"))
218                 return;
219 
220         bss = skel->bss;
221         bss->my_pid = getpid();
222 
223         err = test_usdt__attach(skel);
224         if (!ASSERT_OK(err, "skel_attach"))
225                 goto cleanup;
226 
227         /* usdt_100 is auto-attached and there are 100 inlined call sites,
228          * let's validate that all of them are properly attached to and
229          * handled from BPF side
230          */
231         trigger_100_usdts();
232 
233         ASSERT_EQ(bss->usdt_100_called, 100, "usdt_100_called");
234         ASSERT_EQ(bss->usdt_100_sum, 99 * 100 / 2, "usdt_100_sum");
235 
236         /* Stress test free spec ID tracking. By default libbpf allows up to
237          * 256 specs to be used, so if we don't return free spec IDs back
238          * after few detachments and re-attachments we should run out of
239          * available spec IDs.
240          */
241         for (i = 0; i < 2; i++) {
242                 bpf_link__destroy(skel->links.usdt_100);
243 
244                 skel->links.usdt_100 = bpf_program__attach_usdt(skel->progs.usdt_100, -1,
245                                                                 "/proc/self/exe",
246                                                                 "test", "usdt_100", NULL);
247                 if (!ASSERT_OK_PTR(skel->links.usdt_100, "usdt_100_reattach"))
248                         goto cleanup;
249 
250                 bss->usdt_100_sum = 0;
251                 trigger_100_usdts();
252 
253                 ASSERT_EQ(bss->usdt_100_called, (i + 1) * 100 + 100, "usdt_100_called");
254                 ASSERT_EQ(bss->usdt_100_sum, 99 * 100 / 2, "usdt_100_sum");
255         }
256 
257         /* Now let's step it up and try to attach USDT that requires more than
258          * 256 attach points with different specs for each.
259          * Note that we need trigger_300_usdts() only to actually have 300
260          * USDT call sites, we are not going to actually trace them.
261          */
262         trigger_300_usdts();
263 
264         /* we'll reuse usdt_100 BPF program for usdt_300 test */
265         bpf_link__destroy(skel->links.usdt_100);
266         skel->links.usdt_100 = bpf_program__attach_usdt(skel->progs.usdt_100, -1, "/proc/self/exe",
267                                                         "test", "usdt_300", NULL);
268         err = -errno;
269         if (!ASSERT_ERR_PTR(skel->links.usdt_100, "usdt_300_bad_attach"))
270                 goto cleanup;
271         ASSERT_EQ(err, -E2BIG, "usdt_300_attach_err");
272 
273         /* let's check that there are no "dangling" BPF programs attached due
274          * to partial success of the above test:usdt_300 attachment
275          */
276         bss->usdt_100_called = 0;
277         bss->usdt_100_sum = 0;
278 
279         f300(777); /* this is 301st instance of usdt_300 */
280 
281         ASSERT_EQ(bss->usdt_100_called, 0, "usdt_301_called");
282         ASSERT_EQ(bss->usdt_100_sum, 0, "usdt_301_sum");
283 
284         /* This time we have USDT with 400 inlined invocations, but arg specs
285          * should be the same across all sites, so libbpf will only need to
286          * use one spec and thus we'll be able to attach 400 uprobes
287          * successfully.
288          *
289          * Again, we are reusing usdt_100 BPF program.
290          */
291         skel->links.usdt_100 = bpf_program__attach_usdt(skel->progs.usdt_100, -1,
292                                                         "/proc/self/exe",
293                                                         "test", "usdt_400", NULL);
294         if (!ASSERT_OK_PTR(skel->links.usdt_100, "usdt_400_attach"))
295                 goto cleanup;
296 
297         trigger_400_usdts();
298 
299         ASSERT_EQ(bss->usdt_100_called, 400, "usdt_400_called");
300         ASSERT_EQ(bss->usdt_100_sum, 400 * 400, "usdt_400_sum");
301 
302 cleanup:
303         test_usdt__destroy(skel);
304 }
305 
306 static FILE *urand_spawn(int *pid)
307 {
308         FILE *f;
309 
310         /* urandom_read's stdout is wired into f */
311         f = popen("./urandom_read 1 report-pid", "r");
312         if (!f)
313                 return NULL;
314 
315         if (fscanf(f, "%d", pid) != 1) {
316                 pclose(f);
317                 errno = EINVAL;
318                 return NULL;
319         }
320 
321         return f;
322 }
323 
324 static int urand_trigger(FILE **urand_pipe)
325 {
326         int exit_code;
327 
328         /* pclose() waits for child process to exit and returns their exit code */
329         exit_code = pclose(*urand_pipe);
330         *urand_pipe = NULL;
331 
332         return exit_code;
333 }
334 
335 static void subtest_urandom_usdt(bool auto_attach)
336 {
337         struct test_urandom_usdt *skel;
338         struct test_urandom_usdt__bss *bss;
339         struct bpf_link *l;
340         FILE *urand_pipe = NULL;
341         int err, urand_pid = 0;
342 
343         skel = test_urandom_usdt__open_and_load();
344         if (!ASSERT_OK_PTR(skel, "skel_open"))
345                 return;
346 
347         urand_pipe = urand_spawn(&urand_pid);
348         if (!ASSERT_OK_PTR(urand_pipe, "urand_spawn"))
349                 goto cleanup;
350 
351         bss = skel->bss;
352         bss->urand_pid = urand_pid;
353 
354         if (auto_attach) {
355                 err = test_urandom_usdt__attach(skel);
356                 if (!ASSERT_OK(err, "skel_auto_attach"))
357                         goto cleanup;
358         } else {
359                 l = bpf_program__attach_usdt(skel->progs.urand_read_without_sema,
360                                              urand_pid, "./urandom_read",
361                                              "urand", "read_without_sema", NULL);
362                 if (!ASSERT_OK_PTR(l, "urand_without_sema_attach"))
363                         goto cleanup;
364                 skel->links.urand_read_without_sema = l;
365 
366                 l = bpf_program__attach_usdt(skel->progs.urand_read_with_sema,
367                                              urand_pid, "./urandom_read",
368                                              "urand", "read_with_sema", NULL);
369                 if (!ASSERT_OK_PTR(l, "urand_with_sema_attach"))
370                         goto cleanup;
371                 skel->links.urand_read_with_sema = l;
372 
373                 l = bpf_program__attach_usdt(skel->progs.urandlib_read_without_sema,
374                                              urand_pid, "./liburandom_read.so",
375                                              "urandlib", "read_without_sema", NULL);
376                 if (!ASSERT_OK_PTR(l, "urandlib_without_sema_attach"))
377                         goto cleanup;
378                 skel->links.urandlib_read_without_sema = l;
379 
380                 l = bpf_program__attach_usdt(skel->progs.urandlib_read_with_sema,
381                                              urand_pid, "./liburandom_read.so",
382                                              "urandlib", "read_with_sema", NULL);
383                 if (!ASSERT_OK_PTR(l, "urandlib_with_sema_attach"))
384                         goto cleanup;
385                 skel->links.urandlib_read_with_sema = l;
386 
387         }
388 
389         /* trigger urandom_read USDTs */
390         ASSERT_OK(urand_trigger(&urand_pipe), "urand_exit_code");
391 
392         ASSERT_EQ(bss->urand_read_without_sema_call_cnt, 1, "urand_wo_sema_cnt");
393         ASSERT_EQ(bss->urand_read_without_sema_buf_sz_sum, 256, "urand_wo_sema_sum");
394 
395         ASSERT_EQ(bss->urand_read_with_sema_call_cnt, 1, "urand_w_sema_cnt");
396         ASSERT_EQ(bss->urand_read_with_sema_buf_sz_sum, 256, "urand_w_sema_sum");
397 
398         ASSERT_EQ(bss->urandlib_read_without_sema_call_cnt, 1, "urandlib_wo_sema_cnt");
399         ASSERT_EQ(bss->urandlib_read_without_sema_buf_sz_sum, 256, "urandlib_wo_sema_sum");
400 
401         ASSERT_EQ(bss->urandlib_read_with_sema_call_cnt, 1, "urandlib_w_sema_cnt");
402         ASSERT_EQ(bss->urandlib_read_with_sema_buf_sz_sum, 256, "urandlib_w_sema_sum");
403 
404 cleanup:
405         if (urand_pipe)
406                 pclose(urand_pipe);
407         test_urandom_usdt__destroy(skel);
408 }
409 
410 void test_usdt(void)
411 {
412         if (test__start_subtest("basic"))
413                 subtest_basic_usdt();
414         if (test__start_subtest("multispec"))
415                 subtest_multispec_usdt();
416         if (test__start_subtest("urand_auto_attach"))
417                 subtest_urandom_usdt(true /* auto_attach */);
418         if (test__start_subtest("urand_pid_attach"))
419                 subtest_urandom_usdt(false /* auto_attach */);
420 }
421 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php