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 */ 6 volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes"))); 7 8 /* uprobe attach point */ 9 static void trigger_func(void) 10 { 11 asm volatile (""); 12 } 13 14 /* attach point for byname uprobe */ 15 static void trigger_func2(void) 16 { 17 asm volatile (""); 18 } 19 20 void 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 kprobe_link = bpf_program__attach_kprobe(skel->progs.handle_kprobe, 59 false /* retprobe */, 60 SYS_NANOSLEEP_KPROBE_NAME); 61 if (!ASSERT_OK_PTR(kprobe_link, "attach_kprobe")) 62 goto cleanup; 63 skel->links.handle_kprobe = kprobe_link; 64 65 kretprobe_link = bpf_program__attach_kprobe(skel->progs.handle_kretprobe, 66 true /* retprobe */, 67 SYS_NANOSLEEP_KPROBE_NAME); 68 if (!ASSERT_OK_PTR(kretprobe_link, "attach_kretprobe")) 69 goto cleanup; 70 skel->links.handle_kretprobe = kretprobe_link; 71 72 if (!legacy) 73 ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_before"); 74 75 uprobe_opts.retprobe = false; 76 uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset; 77 uprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe, 78 0 /* self pid */, 79 "/proc/self/exe", 80 uprobe_offset, 81 &uprobe_opts); 82 if (!ASSERT_OK_PTR(uprobe_link, "attach_uprobe")) 83 goto cleanup; 84 skel->links.handle_uprobe = uprobe_link; 85 86 if (!legacy) 87 ASSERT_GT(uprobe_ref_ctr, 0, "uprobe_ref_ctr_after"); 88 89 /* if uprobe uses ref_ctr, uretprobe has to use ref_ctr as well */ 90 uprobe_opts.retprobe = true; 91 uprobe_opts.ref_ctr_offset = legacy ? 0 : ref_ctr_offset; 92 uretprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe, 93 -1 /* any pid */, 94 "/proc/self/exe", 95 uprobe_offset, &uprobe_opts); 96 if (!ASSERT_OK_PTR(uretprobe_link, "attach_uretprobe")) 97 goto cleanup; 98 skel->links.handle_uretprobe = uretprobe_link; 99 100 /* verify auto-attach fails for old-style uprobe definition */ 101 uprobe_err_link = bpf_program__attach(skel->progs.handle_uprobe_byname); 102 if (!ASSERT_EQ(libbpf_get_error(uprobe_err_link), -EOPNOTSUPP, 103 "auto-attach should fail for old-style name")) 104 goto cleanup; 105 106 uprobe_opts.func_name = "trigger_func2"; 107 uprobe_opts.retprobe = false; 108 uprobe_opts.ref_ctr_offset = 0; 109 skel->links.handle_uprobe_byname = 110 bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname, 111 0 /* this pid */, 112 "/proc/self/exe", 113 0, &uprobe_opts); 114 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname, "attach_uprobe_byname")) 115 goto cleanup; 116 117 /* verify auto-attach works */ 118 skel->links.handle_uretprobe_byname = 119 bpf_program__attach(skel->progs.handle_uretprobe_byname); 120 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname, "attach_uretprobe_byname")) 121 goto cleanup; 122 123 /* test attach by name for a library function, using the library 124 * as the binary argument. libc.so.6 will be resolved via dlopen()/dlinfo(). 125 */ 126 uprobe_opts.func_name = "malloc"; 127 uprobe_opts.retprobe = false; 128 skel->links.handle_uprobe_byname2 = 129 bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe_byname2, 130 0 /* this pid */, 131 "libc.so.6", 132 0, &uprobe_opts); 133 if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname2, "attach_uprobe_byname2")) 134 goto cleanup; 135 136 uprobe_opts.func_name = "free"; 137 uprobe_opts.retprobe = true; 138 skel->links.handle_uretprobe_byname2 = 139 bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe_byname2, 140 -1 /* any pid */, 141 "libc.so.6", 142 0, &uprobe_opts); 143 if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2")) 144 goto cleanup; 145 146 /* trigger & validate kprobe && kretprobe */ 147 usleep(1); 148 149 /* trigger & validate shared library u[ret]probes attached by name */ 150 mem = malloc(1); 151 free(mem); 152 153 /* trigger & validate uprobe & uretprobe */ 154 trigger_func(); 155 156 /* trigger & validate uprobe attached by name */ 157 trigger_func2(); 158 159 ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res"); 160 ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res"); 161 ASSERT_EQ(skel->bss->uprobe_res, 3, "check_uprobe_res"); 162 ASSERT_EQ(skel->bss->uretprobe_res, 4, "check_uretprobe_res"); 163 ASSERT_EQ(skel->bss->uprobe_byname_res, 5, "check_uprobe_byname_res"); 164 ASSERT_EQ(skel->bss->uretprobe_byname_res, 6, "check_uretprobe_byname_res"); 165 ASSERT_EQ(skel->bss->uprobe_byname2_res, 7, "check_uprobe_byname2_res"); 166 ASSERT_EQ(skel->bss->uretprobe_byname2_res, 8, "check_uretprobe_byname2_res"); 167 168 cleanup: 169 test_attach_probe__destroy(skel); 170 ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_cleanup"); 171 } 172