xref: /linux/tools/testing/selftests/bpf/prog_tests/usdt.c (revision 8915457146a11d20a6c0786396376afda65eec40)
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 #if defined(__x86_64__) || defined(__i386__)
44 /*
45  * SIB (Scale-Index-Base) addressing format: "size@(base_reg, index_reg, scale)"
46  * - 'size' is the size in bytes of the array element, and its sign indicates
47  *   whether the type is signed (negative) or unsigned (positive).
48  * - 'base_reg' is the register holding the base address, normally rdx or edx
49  * - 'index_reg' is the register holding the index, normally rax or eax
50  * - 'scale' is the scaling factor (typically 1, 2, 4, or 8), which matches the
51  *    size of the element type.
52  *
53  * For example, for an array of 'short' (signed 2-byte elements), the SIB spec would be:
54  * - size: -2 (negative because 'short' is signed)
55  * - scale: 2 (since sizeof(short) == 2)
56  *
57  * The resulting SIB format: "-2@(%%rdx,%%rax,2)" for x86_64, "-2@(%%edx,%%eax,2)" for i386
58  */
59 static volatile short array[] = {-1, -2, -3, -4};
60 
61 #if defined(__x86_64__)
62 #define USDT_SIB_ARG_SPEC -2@(%%rdx,%%rax,2)
63 #else
64 #define USDT_SIB_ARG_SPEC -2@(%%edx,%%eax,2)
65 #endif
66 
67 unsigned short test_usdt_sib_semaphore SEC(".probes");
68 
69 static void trigger_sib_spec(void)
70 {
71 	/*
72 	 * Force SIB addressing with inline assembly.
73 	 *
74 	 * You must compile with -std=gnu99 or -std=c99 to use the
75 	 * STAP_PROBE_ASM macro.
76 	 *
77 	 * The STAP_PROBE_ASM macro generates a quoted string that gets
78 	 * inserted between the surrounding assembly instructions. In this
79 	 * case, USDT_SIB_ARG_SPEC is embedded directly into the instruction
80 	 * stream, creating a probe point between the asm statement boundaries.
81 	 * It works fine with gcc/clang.
82 	 *
83 	 * Register constraints:
84 	 * - "d"(array): Binds the 'array' variable to %rdx or %edx register
85 	 * - "a"(0): Binds the constant 0 to %rax or %eax register
86 	 * These ensure that when USDT_SIB_ARG_SPEC references %%rdx(%edx) and
87 	 * %%rax(%eax), they contain the expected values for SIB addressing.
88 	 *
89 	 * The "memory" clobber prevents the compiler from reordering memory
90 	 * accesses around the probe point, ensuring that the probe behavior
91 	 * is predictable and consistent.
92 	 */
93 	asm volatile(
94 		STAP_PROBE_ASM(test, usdt_sib, USDT_SIB_ARG_SPEC)
95 		:
96 		: "d"(array), "a"(0)
97 		: "memory"
98 	);
99 }
100 #endif
101 
102 static void subtest_basic_usdt(bool optimized)
103 {
104 	LIBBPF_OPTS(bpf_usdt_opts, opts);
105 	struct test_usdt *skel;
106 	struct test_usdt__bss *bss;
107 	int err, i, called;
108 	const __u64 expected_cookie = 0xcafedeadbeeffeed;
109 
110 #define TRIGGER(x) ({			\
111 	trigger_func(x);		\
112 	if (optimized)			\
113 		trigger_func(x);	\
114 	optimized ? 2 : 1;		\
115 	})
116 
117 	skel = test_usdt__open_and_load();
118 	if (!ASSERT_OK_PTR(skel, "skel_open"))
119 		return;
120 
121 	bss = skel->bss;
122 	bss->my_pid = getpid();
123 
124 	err = test_usdt__attach(skel);
125 	if (!ASSERT_OK(err, "skel_attach"))
126 		goto cleanup;
127 
128 	/* usdt0 won't be auto-attached */
129 	opts.usdt_cookie = expected_cookie;
130 	skel->links.usdt0 = bpf_program__attach_usdt(skel->progs.usdt0,
131 						     0 /*self*/, "/proc/self/exe",
132 						     "test", "usdt0", &opts);
133 	if (!ASSERT_OK_PTR(skel->links.usdt0, "usdt0_link"))
134 		goto cleanup;
135 
136 #if defined(__x86_64__) || defined(__i386__)
137 	opts.usdt_cookie = expected_cookie;
138 	skel->links.usdt_sib = bpf_program__attach_usdt(skel->progs.usdt_sib,
139 							 0 /*self*/, "/proc/self/exe",
140 							 "test", "usdt_sib", &opts);
141 	if (!ASSERT_OK_PTR(skel->links.usdt_sib, "usdt_sib_link"))
142 		goto cleanup;
143 #endif
144 
145 	called = TRIGGER(1);
146 
147 	ASSERT_EQ(bss->usdt0_called, called, "usdt0_called");
148 	ASSERT_EQ(bss->usdt3_called, called, "usdt3_called");
149 	ASSERT_EQ(bss->usdt12_called, called, "usdt12_called");
150 
151 	ASSERT_EQ(bss->usdt0_cookie, expected_cookie, "usdt0_cookie");
152 	ASSERT_EQ(bss->usdt0_arg_cnt, 0, "usdt0_arg_cnt");
153 	ASSERT_EQ(bss->usdt0_arg_ret, -ENOENT, "usdt0_arg_ret");
154 	ASSERT_EQ(bss->usdt0_arg_size, -ENOENT, "usdt0_arg_size");
155 
156 	/* auto-attached usdt3 gets default zero cookie value */
157 	ASSERT_EQ(bss->usdt3_cookie, 0, "usdt3_cookie");
158 	ASSERT_EQ(bss->usdt3_arg_cnt, 3, "usdt3_arg_cnt");
159 
160 	ASSERT_EQ(bss->usdt3_arg_rets[0], 0, "usdt3_arg1_ret");
161 	ASSERT_EQ(bss->usdt3_arg_rets[1], 0, "usdt3_arg2_ret");
162 	ASSERT_EQ(bss->usdt3_arg_rets[2], 0, "usdt3_arg3_ret");
163 	ASSERT_EQ(bss->usdt3_args[0], 1, "usdt3_arg1");
164 	ASSERT_EQ(bss->usdt3_args[1], 42, "usdt3_arg2");
165 	ASSERT_EQ(bss->usdt3_args[2], (uintptr_t)&bla, "usdt3_arg3");
166 	ASSERT_EQ(bss->usdt3_arg_sizes[0], 4, "usdt3_arg1_size");
167 	ASSERT_EQ(bss->usdt3_arg_sizes[1], 8, "usdt3_arg2_size");
168 	ASSERT_EQ(bss->usdt3_arg_sizes[2], 8, "usdt3_arg3_size");
169 
170 	/* auto-attached usdt12 gets default zero cookie value */
171 	ASSERT_EQ(bss->usdt12_cookie, 0, "usdt12_cookie");
172 	ASSERT_EQ(bss->usdt12_arg_cnt, 12, "usdt12_arg_cnt");
173 
174 	ASSERT_EQ(bss->usdt12_args[0], 1, "usdt12_arg1");
175 	ASSERT_EQ(bss->usdt12_args[1], 1 + 1, "usdt12_arg2");
176 	ASSERT_EQ(bss->usdt12_args[2], 42, "usdt12_arg3");
177 	ASSERT_EQ(bss->usdt12_args[3], 42 + 1, "usdt12_arg4");
178 	ASSERT_EQ(bss->usdt12_args[4], 5, "usdt12_arg5");
179 	ASSERT_EQ(bss->usdt12_args[5], 42 / 7, "usdt12_arg6");
180 	ASSERT_EQ(bss->usdt12_args[6], bla, "usdt12_arg7");
181 	ASSERT_EQ(bss->usdt12_args[7], (uintptr_t)&bla, "usdt12_arg8");
182 	ASSERT_EQ(bss->usdt12_args[8], -9, "usdt12_arg9");
183 	ASSERT_EQ(bss->usdt12_args[9], nums[1], "usdt12_arg10");
184 	ASSERT_EQ(bss->usdt12_args[10], nums[idx], "usdt12_arg11");
185 	ASSERT_EQ(bss->usdt12_args[11], t1.y, "usdt12_arg12");
186 
187 	int usdt12_expected_arg_sizes[12] = { 4, 4, 8, 8, 4, 8, 8, 8, 4, 2, 2, 1 };
188 
189 	for (i = 0; i < 12; i++)
190 		ASSERT_EQ(bss->usdt12_arg_sizes[i], usdt12_expected_arg_sizes[i], "usdt12_arg_size");
191 
192 	/* trigger_func() is marked __always_inline, so USDT invocations will be
193 	 * inlined in two different places, meaning that each USDT will have
194 	 * at least 2 different places to be attached to. This verifies that
195 	 * bpf_program__attach_usdt() handles this properly and attaches to
196 	 * all possible places of USDT invocation.
197 	 */
198 	called += TRIGGER(2);
199 
200 	ASSERT_EQ(bss->usdt0_called, called, "usdt0_called");
201 	ASSERT_EQ(bss->usdt3_called, called, "usdt3_called");
202 	ASSERT_EQ(bss->usdt12_called, called, "usdt12_called");
203 
204 	/* only check values that depend on trigger_func()'s input value */
205 	ASSERT_EQ(bss->usdt3_args[0], 2, "usdt3_arg1");
206 
207 	ASSERT_EQ(bss->usdt12_args[0], 2, "usdt12_arg1");
208 	ASSERT_EQ(bss->usdt12_args[1], 2 + 1, "usdt12_arg2");
209 	ASSERT_EQ(bss->usdt12_args[3], 42 + 2, "usdt12_arg4");
210 	ASSERT_EQ(bss->usdt12_args[9], nums[2], "usdt12_arg10");
211 
212 	/* detach and re-attach usdt3 */
213 	bpf_link__destroy(skel->links.usdt3);
214 
215 	opts.usdt_cookie = 0xBADC00C51E;
216 	skel->links.usdt3 = bpf_program__attach_usdt(skel->progs.usdt3, -1 /* any pid */,
217 						     "/proc/self/exe", "test", "usdt3", &opts);
218 	if (!ASSERT_OK_PTR(skel->links.usdt3, "usdt3_reattach"))
219 		goto cleanup;
220 
221 	called += TRIGGER(3);
222 
223 	ASSERT_EQ(bss->usdt3_called, called, "usdt3_called");
224 	/* this time usdt3 has custom cookie */
225 	ASSERT_EQ(bss->usdt3_cookie, 0xBADC00C51E, "usdt3_cookie");
226 	ASSERT_EQ(bss->usdt3_arg_cnt, 3, "usdt3_arg_cnt");
227 
228 	ASSERT_EQ(bss->usdt3_arg_rets[0], 0, "usdt3_arg1_ret");
229 	ASSERT_EQ(bss->usdt3_arg_rets[1], 0, "usdt3_arg2_ret");
230 	ASSERT_EQ(bss->usdt3_arg_rets[2], 0, "usdt3_arg3_ret");
231 	ASSERT_EQ(bss->usdt3_args[0], 3, "usdt3_arg1");
232 	ASSERT_EQ(bss->usdt3_args[1], 42, "usdt3_arg2");
233 	ASSERT_EQ(bss->usdt3_args[2], (uintptr_t)&bla, "usdt3_arg3");
234 
235 #if defined(__x86_64__) || defined(__i386__)
236 	trigger_sib_spec();
237 	ASSERT_EQ(bss->usdt_sib_called, 1, "usdt_sib_called");
238 	ASSERT_EQ(bss->usdt_sib_cookie, expected_cookie, "usdt_sib_cookie");
239 	ASSERT_EQ(bss->usdt_sib_arg_cnt, 1, "usdt_sib_arg_cnt");
240 	ASSERT_EQ(bss->usdt_sib_arg, nums[0], "usdt_sib_arg");
241 	ASSERT_EQ(bss->usdt_sib_arg_ret, 0, "usdt_sib_arg_ret");
242 	ASSERT_EQ(bss->usdt_sib_arg_size, sizeof(nums[0]), "usdt_sib_arg_size");
243 #endif
244 
245 cleanup:
246 	test_usdt__destroy(skel);
247 #undef TRIGGER
248 }
249 
250 #ifdef __x86_64__
251 extern void usdt_1(void);
252 extern void usdt_2(void);
253 extern void usdt_red_zone_trigger(void);
254 
255 static unsigned char nop1[1] = { 0x90 };
256 static unsigned char nop1_nop10_combo[11] = { 0x90, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
257 
258 static void *find_instr(void *fn, unsigned char *instr, size_t cnt)
259 {
260 	int i;
261 
262 	for (i = 0; i < 10; i++) {
263 		if (!memcmp(instr, fn + i, cnt))
264 			return fn + i;
265 	}
266 	return NULL;
267 }
268 
269 static void subtest_optimized_attach(void)
270 {
271 	struct test_usdt *skel;
272 	__u8 *addr_1, *addr_2;
273 
274 	/* usdt_1 USDT probe has single nop instruction */
275 	addr_1 = find_instr(usdt_1, nop1_nop10_combo, 11);
276 	if (!ASSERT_NULL(addr_1, "usdt_1_find_nop1_nop10_combo"))
277 		return;
278 
279 	addr_1 = find_instr(usdt_1, nop1, 1);
280 	if (!ASSERT_OK_PTR(addr_1, "usdt_1_find_nop1"))
281 		return;
282 
283 	/* usdt_2 USDT probe has nop,nop10 instructions combo */
284 	addr_2 = find_instr(usdt_2, nop1_nop10_combo, 11);
285 	if (!ASSERT_OK_PTR(addr_2, "usdt_2_find_nop1_nop10_combo"))
286 		return;
287 
288 	skel = test_usdt__open_and_load();
289 	if (!ASSERT_OK_PTR(skel, "test_usdt__open_and_load"))
290 		return;
291 
292 	skel->bss->expected_ip = (unsigned long) addr_1;
293 
294 	/*
295 	 * Attach program on top of usdt_1 which is single nop probe,
296 	 * so the probe won't get optimized.
297 	 */
298 	skel->links.usdt_executed = bpf_program__attach_usdt(skel->progs.usdt_executed,
299 						     0 /*self*/, "/proc/self/exe",
300 						     "optimized_attach", "usdt_1", NULL);
301 	if (!ASSERT_OK_PTR(skel->links.usdt_executed, "bpf_program__attach_usdt"))
302 		goto cleanup;
303 
304 	usdt_1();
305 	usdt_1();
306 
307 	/* int3 is on addr_1 address */
308 	ASSERT_EQ(*addr_1, 0xcc, "int3");
309 	ASSERT_EQ(skel->bss->executed, 2, "executed");
310 
311 	bpf_link__destroy(skel->links.usdt_executed);
312 
313 	/* we expect the nop10 ip */
314 	skel->bss->expected_ip = (unsigned long) addr_2 + 1;
315 
316 	/*
317 	 * Attach program on top of usdt_2 which is probe defined on top
318 	 * of nop1,nop10 combo, so the probe gets optimized on top of nop10.
319 	 */
320 	skel->links.usdt_executed = bpf_program__attach_usdt(skel->progs.usdt_executed,
321 						     0 /*self*/, "/proc/self/exe",
322 						     "optimized_attach", "usdt_2", NULL);
323 	if (!ASSERT_OK_PTR(skel->links.usdt_executed, "bpf_program__attach_usdt"))
324 		goto cleanup;
325 
326 	usdt_2();
327 	usdt_2();
328 
329 	/* nop stays on addr_2 address */
330 	ASSERT_EQ(*addr_2, 0x90, "nop");
331 
332 	/*
333 	 * lea -0x80(%rsp), %rsp
334 	 * call ...
335 	 */
336 	static unsigned char expected[] = { 0x48, 0x8d, 0x64, 0x24, 0x80, 0xe8 };
337 
338 	ASSERT_MEMEQ(addr_2 + 1, expected, sizeof(expected), "lea_and_call");
339 	ASSERT_EQ(skel->bss->executed, 4, "executed");
340 
341 cleanup:
342 	test_usdt__destroy(skel);
343 }
344 
345 /*
346  * Test that USDT arguments survive nop10 optimization in a function where
347  * the compiler places operands in the red zone.
348  *
349  * Signal handlers are prone to having the compiler place USDT argument
350  * operands in the red zone (below rsp).
351  *
352  * The nop5 optimization used CALL (which pushes a return address to
353  * [rsp-8]), the value at -8(%rsp) was overwritten. The nop10 optimization
354  * should escape that by moving stackpointer below the redzone before
355  * doing the CALL.
356  */
357 static void subtest_optimized_red_zone(void)
358 {
359 	struct test_usdt *skel;
360 	int i;
361 
362 	skel = test_usdt__open_and_load();
363 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
364 		return;
365 
366 	skel->bss->expected_arg[0] = 0xDEADBEEF;
367 	skel->bss->expected_arg[1] = 0xCAFEBABE;
368 	skel->bss->expected_arg[2] = 0xFEEDFACE;
369 	skel->bss->expected_pid = getpid();
370 
371 	skel->links.usdt_check_arg = bpf_program__attach_usdt(
372 		skel->progs.usdt_check_arg, 0, "/proc/self/exe",
373 		"optimized_attach", "usdt_red_zone", NULL);
374 	if (!ASSERT_OK_PTR(skel->links.usdt_check_arg, "attach_usdt_red_zone"))
375 		goto cleanup;
376 
377 	for (i = 0; i < 10; i++)
378 		usdt_red_zone_trigger();
379 
380 	ASSERT_EQ(skel->bss->arg_total, 10, "arg_total");
381 	ASSERT_EQ(skel->bss->arg_bad, 0, "arg_bad");
382 	ASSERT_EQ(skel->bss->arg_last[0], 0xDEADBEEF, "arg_last_1");
383 	ASSERT_EQ(skel->bss->arg_last[1], 0xCAFEBABE, "arg_last_2");
384 	ASSERT_EQ(skel->bss->arg_last[2], 0xFEEDFACE, "arg_last_3");
385 
386 cleanup:
387 	test_usdt__destroy(skel);
388 }
389 
390 #endif
391 
392 unsigned short test_usdt_100_semaphore SEC(".probes");
393 unsigned short test_usdt_300_semaphore SEC(".probes");
394 unsigned short test_usdt_400_semaphore SEC(".probes");
395 
396 #define R10(F, X)  F(X+0); F(X+1);F(X+2); F(X+3); F(X+4); \
397 		   F(X+5); F(X+6); F(X+7); F(X+8); F(X+9);
398 #define R100(F, X) R10(F,X+ 0);R10(F,X+10);R10(F,X+20);R10(F,X+30);R10(F,X+40); \
399 		   R10(F,X+50);R10(F,X+60);R10(F,X+70);R10(F,X+80);R10(F,X+90);
400 
401 /* carefully control that we get exactly 100 inlines by preventing inlining */
402 static void __always_inline f100(int x)
403 {
404 	STAP_PROBE1(test, usdt_100, x);
405 }
406 
407 __weak void trigger_100_usdts(void)
408 {
409 	R100(f100, 0);
410 }
411 
412 /* we shouldn't be able to attach to test:usdt2_300 USDT as we don't have as
413  * many slots for specs. It's important that each STAP_PROBE2() invocation
414  * (after untolling) gets different arg spec due to compiler inlining i as
415  * a constant
416  */
417 static void __always_inline f300(int x)
418 {
419 	STAP_PROBE1(test, usdt_300, x);
420 }
421 
422 __weak void trigger_300_usdts(void)
423 {
424 	R100(f300, 0);
425 	R100(f300, 100);
426 	R100(f300, 200);
427 }
428 
429 static void __always_inline f400(int x __attribute__((unused)))
430 {
431 	STAP_PROBE1(test, usdt_400, 400);
432 }
433 
434 /* this time we have 400 different USDT call sites, but they have uniform
435  * argument location, so libbpf's spec string deduplication logic should keep
436  * spec count use very small and so we should be able to attach to all 400
437  * call sites
438  */
439 __weak void trigger_400_usdts(void)
440 {
441 	R100(f400, 0);
442 	R100(f400, 100);
443 	R100(f400, 200);
444 	R100(f400, 300);
445 }
446 
447 static void subtest_multispec_usdt(void)
448 {
449 	LIBBPF_OPTS(bpf_usdt_opts, opts);
450 	struct test_usdt *skel;
451 	struct test_usdt__bss *bss;
452 	int err, i;
453 
454 	skel = test_usdt__open_and_load();
455 	if (!ASSERT_OK_PTR(skel, "skel_open"))
456 		return;
457 
458 	bss = skel->bss;
459 	bss->my_pid = getpid();
460 
461 	err = test_usdt__attach(skel);
462 	if (!ASSERT_OK(err, "skel_attach"))
463 		goto cleanup;
464 
465 	/* usdt_100 is auto-attached and there are 100 inlined call sites,
466 	 * let's validate that all of them are properly attached to and
467 	 * handled from BPF side
468 	 */
469 	trigger_100_usdts();
470 
471 	ASSERT_EQ(bss->usdt_100_called, 100, "usdt_100_called");
472 	ASSERT_EQ(bss->usdt_100_sum, 99 * 100 / 2, "usdt_100_sum");
473 
474 	/* Stress test free spec ID tracking. By default libbpf allows up to
475 	 * 256 specs to be used, so if we don't return free spec IDs back
476 	 * after few detachments and re-attachments we should run out of
477 	 * available spec IDs.
478 	 */
479 	for (i = 0; i < 2; i++) {
480 		bpf_link__destroy(skel->links.usdt_100);
481 
482 		skel->links.usdt_100 = bpf_program__attach_usdt(skel->progs.usdt_100, -1,
483 							        "/proc/self/exe",
484 								"test", "usdt_100", NULL);
485 		if (!ASSERT_OK_PTR(skel->links.usdt_100, "usdt_100_reattach"))
486 			goto cleanup;
487 
488 		bss->usdt_100_sum = 0;
489 		trigger_100_usdts();
490 
491 		ASSERT_EQ(bss->usdt_100_called, (i + 1) * 100 + 100, "usdt_100_called");
492 		ASSERT_EQ(bss->usdt_100_sum, 99 * 100 / 2, "usdt_100_sum");
493 	}
494 
495 	/* Now let's step it up and try to attach USDT that requires more than
496 	 * 256 attach points with different specs for each.
497 	 * Note that we need trigger_300_usdts() only to actually have 300
498 	 * USDT call sites, we are not going to actually trace them.
499 	 */
500 	trigger_300_usdts();
501 
502 	bpf_link__destroy(skel->links.usdt_100);
503 
504 	bss->usdt_100_called = 0;
505 	bss->usdt_100_sum = 0;
506 
507 	/* If built with arm64/clang, there will be much less number of specs
508 	 * for usdt_300 call sites.
509 	 */
510 #if !defined(__aarch64__) || !defined(__clang__)
511 	/* we'll reuse usdt_100 BPF program for usdt_300 test */
512 	skel->links.usdt_100 = bpf_program__attach_usdt(skel->progs.usdt_100, -1, "/proc/self/exe",
513 							"test", "usdt_300", NULL);
514 	err = -errno;
515 	if (!ASSERT_ERR_PTR(skel->links.usdt_100, "usdt_300_bad_attach"))
516 		goto cleanup;
517 	ASSERT_EQ(err, -E2BIG, "usdt_300_attach_err");
518 
519 	/* let's check that there are no "dangling" BPF programs attached due
520 	 * to partial success of the above test:usdt_300 attachment
521 	 */
522 	f300(777); /* this is 301st instance of usdt_300 */
523 
524 	ASSERT_EQ(bss->usdt_100_called, 0, "usdt_301_called");
525 	ASSERT_EQ(bss->usdt_100_sum, 0, "usdt_301_sum");
526 #endif
527 
528 	/* This time we have USDT with 400 inlined invocations, but arg specs
529 	 * should be the same across all sites, so libbpf will only need to
530 	 * use one spec and thus we'll be able to attach 400 uprobes
531 	 * successfully.
532 	 *
533 	 * Again, we are reusing usdt_100 BPF program.
534 	 */
535 	skel->links.usdt_100 = bpf_program__attach_usdt(skel->progs.usdt_100, -1,
536 							"/proc/self/exe",
537 							"test", "usdt_400", NULL);
538 	if (!ASSERT_OK_PTR(skel->links.usdt_100, "usdt_400_attach"))
539 		goto cleanup;
540 
541 	trigger_400_usdts();
542 
543 	ASSERT_EQ(bss->usdt_100_called, 400, "usdt_400_called");
544 	ASSERT_EQ(bss->usdt_100_sum, 400 * 400, "usdt_400_sum");
545 
546 cleanup:
547 	test_usdt__destroy(skel);
548 }
549 
550 static FILE *urand_spawn(int *pid)
551 {
552 	FILE *f;
553 
554 	/* urandom_read's stdout is wired into f */
555 	f = popen("./urandom_read 1 report-pid", "r");
556 	if (!f)
557 		return NULL;
558 
559 	if (fscanf(f, "%d", pid) != 1) {
560 		pclose(f);
561 		errno = EINVAL;
562 		return NULL;
563 	}
564 
565 	return f;
566 }
567 
568 static int urand_trigger(FILE **urand_pipe)
569 {
570 	int exit_code;
571 
572 	/* pclose() waits for child process to exit and returns their exit code */
573 	exit_code = pclose(*urand_pipe);
574 	*urand_pipe = NULL;
575 
576 	return exit_code;
577 }
578 
579 static void subtest_urandom_usdt(bool auto_attach)
580 {
581 	struct test_urandom_usdt *skel;
582 	struct test_urandom_usdt__bss *bss;
583 	struct bpf_link *l;
584 	FILE *urand_pipe = NULL;
585 	int err, urand_pid = 0;
586 
587 	skel = test_urandom_usdt__open_and_load();
588 	if (!ASSERT_OK_PTR(skel, "skel_open"))
589 		return;
590 
591 	urand_pipe = urand_spawn(&urand_pid);
592 	if (!ASSERT_OK_PTR(urand_pipe, "urand_spawn"))
593 		goto cleanup;
594 
595 	bss = skel->bss;
596 	bss->urand_pid = urand_pid;
597 
598 	if (auto_attach) {
599 		err = test_urandom_usdt__attach(skel);
600 		if (!ASSERT_OK(err, "skel_auto_attach"))
601 			goto cleanup;
602 	} else {
603 		l = bpf_program__attach_usdt(skel->progs.urand_read_without_sema,
604 					     urand_pid, "./urandom_read",
605 					     "urand", "read_without_sema", NULL);
606 		if (!ASSERT_OK_PTR(l, "urand_without_sema_attach"))
607 			goto cleanup;
608 		skel->links.urand_read_without_sema = l;
609 
610 		l = bpf_program__attach_usdt(skel->progs.urand_read_with_sema,
611 					     urand_pid, "./urandom_read",
612 					     "urand", "read_with_sema", NULL);
613 		if (!ASSERT_OK_PTR(l, "urand_with_sema_attach"))
614 			goto cleanup;
615 		skel->links.urand_read_with_sema = l;
616 
617 		l = bpf_program__attach_usdt(skel->progs.urandlib_read_without_sema,
618 					     urand_pid, "./liburandom_read.so",
619 					     "urandlib", "read_without_sema", NULL);
620 		if (!ASSERT_OK_PTR(l, "urandlib_without_sema_attach"))
621 			goto cleanup;
622 		skel->links.urandlib_read_without_sema = l;
623 
624 		l = bpf_program__attach_usdt(skel->progs.urandlib_read_with_sema,
625 					     urand_pid, "./liburandom_read.so",
626 					     "urandlib", "read_with_sema", NULL);
627 		if (!ASSERT_OK_PTR(l, "urandlib_with_sema_attach"))
628 			goto cleanup;
629 		skel->links.urandlib_read_with_sema = l;
630 
631 	}
632 
633 	/* trigger urandom_read USDTs */
634 	ASSERT_OK(urand_trigger(&urand_pipe), "urand_exit_code");
635 
636 	ASSERT_EQ(bss->urand_read_without_sema_call_cnt, 1, "urand_wo_sema_cnt");
637 	ASSERT_EQ(bss->urand_read_without_sema_buf_sz_sum, 256, "urand_wo_sema_sum");
638 
639 	ASSERT_EQ(bss->urand_read_with_sema_call_cnt, 1, "urand_w_sema_cnt");
640 	ASSERT_EQ(bss->urand_read_with_sema_buf_sz_sum, 256, "urand_w_sema_sum");
641 
642 	ASSERT_EQ(bss->urandlib_read_without_sema_call_cnt, 1, "urandlib_wo_sema_cnt");
643 	ASSERT_EQ(bss->urandlib_read_without_sema_buf_sz_sum, 256, "urandlib_wo_sema_sum");
644 
645 	ASSERT_EQ(bss->urandlib_read_with_sema_call_cnt, 1, "urandlib_w_sema_cnt");
646 	ASSERT_EQ(bss->urandlib_read_with_sema_buf_sz_sum, 256, "urandlib_w_sema_sum");
647 
648 cleanup:
649 	if (urand_pipe)
650 		pclose(urand_pipe);
651 	test_urandom_usdt__destroy(skel);
652 }
653 
654 void test_usdt(void)
655 {
656 	if (test__start_subtest("basic"))
657 		subtest_basic_usdt(false);
658 #ifdef __x86_64__
659 	if (test__start_subtest("basic_optimized"))
660 		subtest_basic_usdt(true);
661 	if (test__start_subtest("optimized_attach"))
662 		subtest_optimized_attach();
663 	if (test__start_subtest("optimized_red_zone"))
664 		subtest_optimized_red_zone();
665 #endif
666 	if (test__start_subtest("multispec"))
667 		subtest_multispec_usdt();
668 	if (test__start_subtest("urand_auto_attach"))
669 		subtest_urandom_usdt(true /* auto_attach */);
670 	if (test__start_subtest("urand_pid_attach"))
671 		subtest_urandom_usdt(false /* auto_attach */);
672 }
673