1
1
// SPDX-License-Identifier: GPL-2.0
2
2
3
3
#include <unistd.h>
4
+ #include <pthread.h>
4
5
#include <test_progs.h>
5
6
#include "uprobe_multi.skel.h"
6
7
#include "uprobe_multi_bench.skel.h"
7
8
#include "uprobe_multi_usdt.skel.h"
8
9
#include "bpf/libbpf_internal.h"
9
10
#include "testing_helpers.h"
11
+ #include "../sdt.h"
10
12
11
13
static char test_data [] = "test_data" ;
12
14
@@ -25,9 +27,17 @@ noinline void uprobe_multi_func_3(void)
25
27
asm volatile ("" );
26
28
}
27
29
30
+ noinline void usdt_trigger (void )
31
+ {
32
+ STAP_PROBE (test , pid_filter_usdt );
33
+ }
34
+
28
35
struct child {
29
36
int go [2 ];
37
+ int c2p [2 ]; /* child -> parent channel */
30
38
int pid ;
39
+ int tid ;
40
+ pthread_t thread ;
31
41
};
32
42
33
43
static void release_child (struct child * child )
@@ -38,6 +48,10 @@ static void release_child(struct child *child)
38
48
return ;
39
49
close (child -> go [1 ]);
40
50
close (child -> go [0 ]);
51
+ if (child -> thread )
52
+ pthread_join (child -> thread , NULL );
53
+ close (child -> c2p [0 ]);
54
+ close (child -> c2p [1 ]);
41
55
if (child -> pid > 0 )
42
56
waitpid (child -> pid , & child_status , 0 );
43
57
}
@@ -63,7 +77,7 @@ static struct child *spawn_child(void)
63
77
if (pipe (child .go ))
64
78
return NULL ;
65
79
66
- child .pid = fork ();
80
+ child .pid = child . tid = fork ();
67
81
if (child .pid < 0 ) {
68
82
release_child (& child );
69
83
errno = EINVAL ;
@@ -82,13 +96,75 @@ static struct child *spawn_child(void)
82
96
uprobe_multi_func_1 ();
83
97
uprobe_multi_func_2 ();
84
98
uprobe_multi_func_3 ();
99
+ usdt_trigger ();
85
100
86
101
exit (errno );
87
102
}
88
103
89
104
return & child ;
90
105
}
91
106
107
+ static void * child_thread (void * ctx )
108
+ {
109
+ struct child * child = ctx ;
110
+ int c = 0 , err ;
111
+
112
+ child -> tid = syscall (SYS_gettid );
113
+
114
+ /* let parent know we are ready */
115
+ err = write (child -> c2p [1 ], & c , 1 );
116
+ if (err != 1 )
117
+ pthread_exit (& err );
118
+
119
+ /* wait for parent's kick */
120
+ err = read (child -> go [0 ], & c , 1 );
121
+ if (err != 1 )
122
+ pthread_exit (& err );
123
+
124
+ uprobe_multi_func_1 ();
125
+ uprobe_multi_func_2 ();
126
+ uprobe_multi_func_3 ();
127
+ usdt_trigger ();
128
+
129
+ err = 0 ;
130
+ pthread_exit (& err );
131
+ }
132
+
133
+ static struct child * spawn_thread (void )
134
+ {
135
+ static struct child child ;
136
+ int c , err ;
137
+
138
+ /* pipe to notify child to execute the trigger functions */
139
+ if (pipe (child .go ))
140
+ return NULL ;
141
+ /* pipe to notify parent that child thread is ready */
142
+ if (pipe (child .c2p )) {
143
+ close (child .go [0 ]);
144
+ close (child .go [1 ]);
145
+ return NULL ;
146
+ }
147
+
148
+ child .pid = getpid ();
149
+
150
+ err = pthread_create (& child .thread , NULL , child_thread , & child );
151
+ if (err ) {
152
+ err = - errno ;
153
+ close (child .go [0 ]);
154
+ close (child .go [1 ]);
155
+ close (child .c2p [0 ]);
156
+ close (child .c2p [1 ]);
157
+ errno = - err ;
158
+ return NULL ;
159
+ }
160
+
161
+ err = read (child .c2p [0 ], & c , 1 );
162
+ if (!ASSERT_EQ (err , 1 , "child_thread_ready" ))
163
+ return NULL ;
164
+
165
+ return & child ;
166
+ }
167
+
92
168
static void uprobe_multi_test_run (struct uprobe_multi * skel , struct child * child )
93
169
{
94
170
skel -> bss -> uprobe_multi_func_1_addr = (__u64 ) uprobe_multi_func_1 ;
@@ -103,15 +179,23 @@ static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child
103
179
* passed at the probe attach.
104
180
*/
105
181
skel -> bss -> pid = child ? 0 : getpid ();
182
+ skel -> bss -> expect_pid = child ? child -> pid : 0 ;
183
+
184
+ /* trigger all probes, if we are testing child *process*, just to make
185
+ * sure that PID filtering doesn't let through activations from wrong
186
+ * PIDs; when we test child *thread*, we don't want to do this to
187
+ * avoid double counting number of triggering events
188
+ */
189
+ if (!child || !child -> thread ) {
190
+ uprobe_multi_func_1 ();
191
+ uprobe_multi_func_2 ();
192
+ uprobe_multi_func_3 ();
193
+ usdt_trigger ();
194
+ }
106
195
107
196
if (child )
108
197
kick_child (child );
109
198
110
- /* trigger all probes */
111
- uprobe_multi_func_1 ();
112
- uprobe_multi_func_2 ();
113
- uprobe_multi_func_3 ();
114
-
115
199
/*
116
200
* There are 2 entry and 2 exit probe called for each uprobe_multi_func_[123]
117
201
* function and each slepable probe (6) increments uprobe_multi_sleep_result.
@@ -126,8 +210,12 @@ static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child
126
210
127
211
ASSERT_EQ (skel -> bss -> uprobe_multi_sleep_result , 6 , "uprobe_multi_sleep_result" );
128
212
129
- if (child )
213
+ ASSERT_FALSE (skel -> bss -> bad_pid_seen , "bad_pid_seen" );
214
+
215
+ if (child ) {
130
216
ASSERT_EQ (skel -> bss -> child_pid , child -> pid , "uprobe_multi_child_pid" );
217
+ ASSERT_EQ (skel -> bss -> child_tid , child -> tid , "uprobe_multi_child_tid" );
218
+ }
131
219
}
132
220
133
221
static void test_skel_api (void )
@@ -190,8 +278,24 @@ __test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_mul
190
278
if (!ASSERT_OK_PTR (skel -> links .uprobe_extra , "bpf_program__attach_uprobe_multi" ))
191
279
goto cleanup ;
192
280
281
+ /* Attach (uprobe-backed) USDTs */
282
+ skel -> links .usdt_pid = bpf_program__attach_usdt (skel -> progs .usdt_pid , pid , binary ,
283
+ "test" , "pid_filter_usdt" , NULL );
284
+ if (!ASSERT_OK_PTR (skel -> links .usdt_pid , "attach_usdt_pid" ))
285
+ goto cleanup ;
286
+
287
+ skel -> links .usdt_extra = bpf_program__attach_usdt (skel -> progs .usdt_extra , -1 , binary ,
288
+ "test" , "pid_filter_usdt" , NULL );
289
+ if (!ASSERT_OK_PTR (skel -> links .usdt_extra , "attach_usdt_extra" ))
290
+ goto cleanup ;
291
+
193
292
uprobe_multi_test_run (skel , child );
194
293
294
+ ASSERT_FALSE (skel -> bss -> bad_pid_seen_usdt , "bad_pid_seen_usdt" );
295
+ if (child ) {
296
+ ASSERT_EQ (skel -> bss -> child_pid_usdt , child -> pid , "usdt_multi_child_pid" );
297
+ ASSERT_EQ (skel -> bss -> child_tid_usdt , child -> tid , "usdt_multi_child_tid" );
298
+ }
195
299
cleanup :
196
300
uprobe_multi__destroy (skel );
197
301
}
@@ -210,6 +314,13 @@ test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi
210
314
return ;
211
315
212
316
__test_attach_api (binary , pattern , opts , child );
317
+
318
+ /* pid filter (thread) */
319
+ child = spawn_thread ();
320
+ if (!ASSERT_OK_PTR (child , "spawn_thread" ))
321
+ return ;
322
+
323
+ __test_attach_api (binary , pattern , opts , child );
213
324
}
214
325
215
326
static void test_attach_api_pattern (void )
@@ -397,7 +508,7 @@ static void test_attach_api_fails(void)
397
508
link_fd = bpf_link_create (prog_fd , 0 , BPF_TRACE_UPROBE_MULTI , & opts );
398
509
if (!ASSERT_ERR (link_fd , "link_fd" ))
399
510
goto cleanup ;
400
- ASSERT_EQ (link_fd , - ESRCH , "pid_is_wrong" );
511
+ ASSERT_EQ (link_fd , - EINVAL , "pid_is_wrong" );
401
512
402
513
cleanup :
403
514
if (link_fd >= 0 )
@@ -495,6 +606,13 @@ static void test_link_api(void)
495
606
return ;
496
607
497
608
__test_link_api (child );
609
+
610
+ /* pid filter (thread) */
611
+ child = spawn_thread ();
612
+ if (!ASSERT_OK_PTR (child , "spawn_thread" ))
613
+ return ;
614
+
615
+ __test_link_api (child );
498
616
}
499
617
500
618
static void test_bench_attach_uprobe (void )
0 commit comments