Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2#include <test_progs.h>
3#include "test_attach_probe.skel.h"
4
5/* this is how USDT semaphore is actually defined, except volatile modifier */
6volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
7
8/* uprobe attach point */
9static void trigger_func(void)
10{
11 asm volatile ("");
12}
13
14/* attach point for byname uprobe */
15static void trigger_func2(void)
16{
17 asm volatile ("");
18}
19
20void test_attach_probe(void)
21{
22 DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
23 struct bpf_link *kprobe_link, *kretprobe_link;
24 struct bpf_link *uprobe_link, *uretprobe_link;
25 struct test_attach_probe* skel;
26 ssize_t uprobe_offset, ref_ctr_offset;
27 struct bpf_link *uprobe_err_link;
28 bool legacy;
29 char *mem;
30
31 /* Check if new-style kprobe/uprobe API is supported.
32 * Kernels that support new FD-based kprobe and uprobe BPF attachment
33 * through perf_event_open() syscall expose
34 * /sys/bus/event_source/devices/kprobe/type and
35 * /sys/bus/event_source/devices/uprobe/type files, respectively. They
36 * contain magic numbers that are passed as "type" field of
37 * perf_event_attr. Lack of such file in the system indicates legacy
38 * kernel with old-style kprobe/uprobe attach interface through
39 * creating per-probe event through tracefs. For such cases
40 * ref_ctr_offset feature is not supported, so we don't test it.
41 */
42 legacy = access("/sys/bus/event_source/devices/kprobe/type", F_OK) != 0;
43
44 uprobe_offset = get_uprobe_offset(&trigger_func);
45 if (!ASSERT_GE(uprobe_offset, 0, "uprobe_offset"))
46 return;
47
48 ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr);
49 if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
50 return;
51
52 skel = test_attach_probe__open_and_load();
53 if (!ASSERT_OK_PTR(skel, "skel_open"))
54 return;
55 if (!ASSERT_OK_PTR(skel->bss, "check_bss"))
56 goto cleanup;
57
58 /* manual-attach kprobe/kretprobe */
59 kprobe_link = bpf_program__attach_kprobe(skel->progs.handle_kprobe,
60 false /* retprobe */,
61 SYS_NANOSLEEP_KPROBE_NAME);
62 if (!ASSERT_OK_PTR(kprobe_link, "attach_kprobe"))
63 goto cleanup;
64 skel->links.handle_kprobe = kprobe_link;
65
66 kretprobe_link = bpf_program__attach_kprobe(skel->progs.handle_kretprobe,
67 true /* retprobe */,
68 SYS_NANOSLEEP_KPROBE_NAME);
69 if (!ASSERT_OK_PTR(kretprobe_link, "attach_kretprobe"))
70 goto cleanup;
71 skel->links.handle_kretprobe = kretprobe_link;
72
73 /* auto-attachable kprobe and kretprobe */
74 skel->links.handle_kprobe_auto = bpf_program__attach(skel->progs.handle_kprobe_auto);
75 ASSERT_OK_PTR(skel->links.handle_kprobe_auto, "attach_kprobe_auto");
76
77 skel->links.handle_kretprobe_auto = bpf_program__attach(skel->progs.handle_kretprobe_auto);
78 ASSERT_OK_PTR(skel->links.handle_kretprobe_auto, "attach_kretprobe_auto");
79
80 if (!legacy)
81 ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_before");
82
83 uprobe_opts.retprobe = false;
84 uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset;
85 uprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe,
86 0 /* self pid */,
87 "/proc/self/exe",
88 uprobe_offset,
89 &uprobe_opts);
90 if (!ASSERT_OK_PTR(uprobe_link, "attach_uprobe"))
91 goto cleanup;
92 skel->links.handle_uprobe = uprobe_link;
93
94 if (!legacy)
95 ASSERT_GT(uprobe_ref_ctr, 0, "uprobe_ref_ctr_after");
96
97 /* if uprobe uses ref_ctr, uretprobe has to use ref_ctr as well */
98 uprobe_opts.retprobe = true;
99 uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset;
100 uretprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe,
101 -1 /* any pid */,
102 "/proc/self/exe",
103 uprobe_offset, &uprobe_opts);
104 if (!ASSERT_OK_PTR(uretprobe_link, "attach_uretprobe"))
105 goto cleanup;
106 skel->links.handle_uretprobe = uretprobe_link;
107
108 /* verify auto-attach fails for old-style uprobe definition */
109 uprobe_err_link = bpf_program__attach(skel->progs.handle_uprobe_byname);
110 if (!ASSERT_EQ(libbpf_get_error(uprobe_err_link), -EOPNOTSUPP,
111 "auto-attach should fail for old-style name"))
112 goto cleanup;
113
114 uprobe_opts.func_name = "trigger_func2";
115 uprobe_opts.retprobe = false;
116 uprobe_opts.ref_ctr_offset = 0;
117 skel->links.handle_uprobe_byname =
118 bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname,
119 0 /* this pid */,
120 "/proc/self/exe",
121 0, &uprobe_opts);
122 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname, "attach_uprobe_byname"))
123 goto cleanup;
124
125 /* verify auto-attach works */
126 skel->links.handle_uretprobe_byname =
127 bpf_program__attach(skel->progs.handle_uretprobe_byname);
128 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname, "attach_uretprobe_byname"))
129 goto cleanup;
130
131 /* test attach by name for a library function, using the library
132 * as the binary argument. libc.so.6 will be resolved via dlopen()/dlinfo().
133 */
134 uprobe_opts.func_name = "malloc";
135 uprobe_opts.retprobe = false;
136 skel->links.handle_uprobe_byname2 =
137 bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname2,
138 0 /* this pid */,
139 "libc.so.6",
140 0, &uprobe_opts);
141 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname2, "attach_uprobe_byname2"))
142 goto cleanup;
143
144 uprobe_opts.func_name = "free";
145 uprobe_opts.retprobe = true;
146 skel->links.handle_uretprobe_byname2 =
147 bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe_byname2,
148 -1 /* any pid */,
149 "libc.so.6",
150 0, &uprobe_opts);
151 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2"))
152 goto cleanup;
153
154 /* trigger & validate kprobe && kretprobe */
155 usleep(1);
156
157 /* trigger & validate shared library u[ret]probes attached by name */
158 mem = malloc(1);
159 free(mem);
160
161 /* trigger & validate uprobe & uretprobe */
162 trigger_func();
163
164 /* trigger & validate uprobe attached by name */
165 trigger_func2();
166
167 ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res");
168 ASSERT_EQ(skel->bss->kprobe2_res, 11, "check_kprobe_auto_res");
169 ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res");
170 ASSERT_EQ(skel->bss->kretprobe2_res, 22, "check_kretprobe_auto_res");
171 ASSERT_EQ(skel->bss->uprobe_res, 3, "check_uprobe_res");
172 ASSERT_EQ(skel->bss->uretprobe_res, 4, "check_uretprobe_res");
173 ASSERT_EQ(skel->bss->uprobe_byname_res, 5, "check_uprobe_byname_res");
174 ASSERT_EQ(skel->bss->uretprobe_byname_res, 6, "check_uretprobe_byname_res");
175 ASSERT_EQ(skel->bss->uprobe_byname2_res, 7, "check_uprobe_byname2_res");
176 ASSERT_EQ(skel->bss->uretprobe_byname2_res, 8, "check_uretprobe_byname2_res");
177
178cleanup:
179 test_attach_probe__destroy(skel);
180 ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_cleanup");
181}