Skip to content

Commit ff94368

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
selftests/bpf: fix uprobe offset calculation in selftests
Fix how selftests determine relative offset of a function that is uprobed. Previously, there was an assumption that uprobed function is always in the first executable region, which is not always the case (libbpf CI hits this case now). So get_base_addr() approach in isolation doesn't work anymore. So teach get_uprobe_offset() to determine correct memory mapping and calculate uprobe offset correctly. While at it, I merged together two implementations of get_uprobe_offset() helper, moving powerpc64-specific logic inside (had to add extra {} block to avoid unused variable error for insn). Also ensured that uprobed functions are never inlined, but are still static (and thus local to each selftest), by using a no-op asm volatile block internally. I didn't want to keep them global __weak, because some tests use uprobe's ref counter offset (to test USDT-like logic) which is not compatible with non-refcounted uprobe. So it's nicer to have each test uprobe target local to the file and guaranteed to not be inlined or skipped by the compiler (which can happen with static functions, especially if compiling selftests with -O2). Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent e5465a9 commit ff94368

File tree

6 files changed

+63
-66
lines changed

6 files changed

+63
-66
lines changed

tools/testing/selftests/bpf/benchs/bench_trigger.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ static void *uprobe_producer_without_nop(void *input)
154154
static void usetup(bool use_retprobe, bool use_nop)
155155
{
156156
size_t uprobe_offset;
157-
ssize_t base_addr;
158157
struct bpf_link *link;
159158

160159
setup_libbpf();
@@ -165,11 +164,10 @@ static void usetup(bool use_retprobe, bool use_nop)
165164
exit(1);
166165
}
167166

168-
base_addr = get_base_addr();
169167
if (use_nop)
170-
uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop, base_addr);
168+
uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop);
171169
else
172-
uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop, base_addr);
170+
uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop);
173171

174172
link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe,
175173
use_retprobe,

tools/testing/selftests/bpf/prog_tests/attach_probe.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
/* this is how USDT semaphore is actually defined, except volatile modifier */
66
volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
77

8-
/* attach point */
9-
static void method(void) {
10-
return ;
8+
/* uprobe attach point */
9+
static void trigger_func(void)
10+
{
11+
asm volatile ("");
1112
}
1213

1314
void test_attach_probe(void)
@@ -17,8 +18,7 @@ void test_attach_probe(void)
1718
struct bpf_link *kprobe_link, *kretprobe_link;
1819
struct bpf_link *uprobe_link, *uretprobe_link;
1920
struct test_attach_probe* skel;
20-
size_t uprobe_offset;
21-
ssize_t base_addr, ref_ctr_offset;
21+
ssize_t uprobe_offset, ref_ctr_offset;
2222
bool legacy;
2323

2424
/* Check if new-style kprobe/uprobe API is supported.
@@ -34,11 +34,9 @@ void test_attach_probe(void)
3434
*/
3535
legacy = access("/sys/bus/event_source/devices/kprobe/type", F_OK) != 0;
3636

37-
base_addr = get_base_addr();
38-
if (CHECK(base_addr < 0, "get_base_addr",
39-
"failed to find base addr: %zd", base_addr))
37+
uprobe_offset = get_uprobe_offset(&trigger_func);
38+
if (!ASSERT_GE(uprobe_offset, 0, "uprobe_offset"))
4039
return;
41-
uprobe_offset = get_uprobe_offset(&method, base_addr);
4240

4341
ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr);
4442
if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
@@ -103,7 +101,7 @@ void test_attach_probe(void)
103101
goto cleanup;
104102

105103
/* trigger & validate uprobe & uretprobe */
106-
method();
104+
trigger_func();
107105

108106
if (CHECK(skel->bss->uprobe_res != 3, "check_uprobe_res",
109107
"wrong uprobe res: %d\n", skel->bss->uprobe_res))

tools/testing/selftests/bpf/prog_tests/bpf_cookie.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
#include <test_progs.h>
99
#include "test_bpf_cookie.skel.h"
1010

11+
/* uprobe attach point */
12+
static void trigger_func(void)
13+
{
14+
asm volatile ("");
15+
}
16+
1117
static void kprobe_subtest(struct test_bpf_cookie *skel)
1218
{
1319
DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
@@ -62,11 +68,11 @@ static void uprobe_subtest(struct test_bpf_cookie *skel)
6268
DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts);
6369
struct bpf_link *link1 = NULL, *link2 = NULL;
6470
struct bpf_link *retlink1 = NULL, *retlink2 = NULL;
65-
size_t uprobe_offset;
66-
ssize_t base_addr;
71+
ssize_t uprobe_offset;
6772

68-
base_addr = get_base_addr();
69-
uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
73+
uprobe_offset = get_uprobe_offset(&trigger_func);
74+
if (!ASSERT_GE(uprobe_offset, 0, "uprobe_offset"))
75+
goto cleanup;
7076

7177
/* attach two uprobes */
7278
opts.bpf_cookie = 0x100;
@@ -99,7 +105,7 @@ static void uprobe_subtest(struct test_bpf_cookie *skel)
99105
goto cleanup;
100106

101107
/* trigger uprobe && uretprobe */
102-
get_base_addr();
108+
trigger_func();
103109

104110
ASSERT_EQ(skel->bss->uprobe_res, 0x100 | 0x200, "uprobe_res");
105111
ASSERT_EQ(skel->bss->uretprobe_res, 0x1000 | 0x2000, "uretprobe_res");

tools/testing/selftests/bpf/prog_tests/task_pt_regs.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@
33
#include <test_progs.h>
44
#include "test_task_pt_regs.skel.h"
55

6+
/* uprobe attach point */
7+
static void trigger_func(void)
8+
{
9+
asm volatile ("");
10+
}
11+
612
void test_task_pt_regs(void)
713
{
814
struct test_task_pt_regs *skel;
915
struct bpf_link *uprobe_link;
10-
size_t uprobe_offset;
11-
ssize_t base_addr;
16+
ssize_t uprobe_offset;
1217
bool match;
1318

14-
base_addr = get_base_addr();
15-
if (!ASSERT_GT(base_addr, 0, "get_base_addr"))
19+
uprobe_offset = get_uprobe_offset(&trigger_func);
20+
if (!ASSERT_GE(uprobe_offset, 0, "uprobe_offset"))
1621
return;
17-
uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
1822

1923
skel = test_task_pt_regs__open_and_load();
2024
if (!ASSERT_OK_PTR(skel, "skel_open"))
@@ -32,7 +36,7 @@ void test_task_pt_regs(void)
3236
skel->links.handle_uprobe = uprobe_link;
3337

3438
/* trigger & validate uprobe */
35-
get_base_addr();
39+
trigger_func();
3640

3741
if (!ASSERT_EQ(skel->bss->uprobe_res, 1, "check_uprobe_res"))
3842
goto cleanup;

tools/testing/selftests/bpf/trace_helpers.c

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,36 @@ void read_trace_pipe(void)
138138
}
139139
}
140140

141+
ssize_t get_uprobe_offset(const void *addr)
142+
{
143+
size_t start, end, base;
144+
char buf[256];
145+
bool found;
146+
FILE *f;
147+
148+
f = fopen("/proc/self/maps", "r");
149+
if (!f)
150+
return -errno;
151+
152+
while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
153+
if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
154+
found = true;
155+
break;
156+
}
157+
}
158+
159+
fclose(f);
160+
161+
if (!found)
162+
return -ESRCH;
163+
141164
#if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
142165

143166
#define OP_RT_RA_MASK 0xffff0000UL
144167
#define LIS_R2 0x3c400000UL
145168
#define ADDIS_R2_R12 0x3c4c0000UL
146169
#define ADDI_R2_R2 0x38420000UL
147170

148-
ssize_t get_uprobe_offset(const void *addr, ssize_t base)
149-
{
150-
u32 *insn = (u32 *)(uintptr_t)addr;
151-
152171
/*
153172
* A PPC64 ABIv2 function may have a local and a global entry
154173
* point. We need to use the local entry point when patching
@@ -165,43 +184,16 @@ ssize_t get_uprobe_offset(const void *addr, ssize_t base)
165184
* lis r2,XXXX
166185
* addi r2,r2,XXXX
167186
*/
168-
if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
169-
((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
170-
((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
171-
return (ssize_t)(insn + 2) - base;
172-
else
173-
return (uintptr_t)addr - base;
174-
}
175-
176-
#else
187+
{
188+
const u32 *insn = (const u32 *)(uintptr_t)addr;
177189

178-
ssize_t get_uprobe_offset(const void *addr, ssize_t base)
179-
{
180-
return (uintptr_t)addr - base;
181-
}
182-
183-
#endif
184-
185-
ssize_t get_base_addr(void)
186-
{
187-
size_t start, offset;
188-
char buf[256];
189-
FILE *f;
190-
191-
f = fopen("/proc/self/maps", "r");
192-
if (!f)
193-
return -errno;
194-
195-
while (fscanf(f, "%zx-%*x %s %zx %*[^\n]\n",
196-
&start, buf, &offset) == 3) {
197-
if (strcmp(buf, "r-xp") == 0) {
198-
fclose(f);
199-
return start - offset;
200-
}
190+
if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
191+
((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
192+
((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
193+
return (uintptr_t)(insn + 2) - start + base;
201194
}
202-
203-
fclose(f);
204-
return -EINVAL;
195+
#endif
196+
return (uintptr_t)addr - start + base;
205197
}
206198

207199
ssize_t get_rel_offset(uintptr_t addr)

tools/testing/selftests/bpf/trace_helpers.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ int kallsyms_find(const char *sym, unsigned long long *addr);
1818

1919
void read_trace_pipe(void);
2020

21-
ssize_t get_uprobe_offset(const void *addr, ssize_t base);
22-
ssize_t get_base_addr(void);
21+
ssize_t get_uprobe_offset(const void *addr);
2322
ssize_t get_rel_offset(uintptr_t addr);
2423

2524
#endif

0 commit comments

Comments
 (0)