mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-26 04:16:39 +00:00
selftests/bpf: Add tests for symbol versioning for uprobe
This exercises the newly added dynsym symbol versioning logics. Now we accept symbols in form of func, func@LIB_VERSION or func@@LIB_VERSION. The test rely on liburandom_read.so. For liburandom_read.so, we have: $ nm -D liburandom_read.so w __cxa_finalize@GLIBC_2.17 w __gmon_start__ w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000000000 A LIBURANDOM_READ_1.0.0 0000000000000000 A LIBURANDOM_READ_2.0.0 000000000000081c T urandlib_api@@LIBURANDOM_READ_2.0.0 0000000000000814 T urandlib_api@LIBURANDOM_READ_1.0.0 0000000000000824 T urandlib_api_sameoffset@LIBURANDOM_READ_1.0.0 0000000000000824 T urandlib_api_sameoffset@@LIBURANDOM_READ_2.0.0 000000000000082c T urandlib_read_without_sema@@LIBURANDOM_READ_1.0.0 00000000000007c4 T urandlib_read_with_sema@@LIBURANDOM_READ_1.0.0 0000000000011018 D urandlib_read_with_sema_semaphore@@LIBURANDOM_READ_1.0.0 For `urandlib_api`, specifying `urandlib_api` will cause a conflict because there are two symbols named urandlib_api and both are global bind. For `urandlib_api_sameoffset`, there are also two symbols in the .so, but both are at the same offset and essentially they refer to the same function so no conflict. Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Reviewed-by: Alan Maguire <alan.maguire@oracle.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/bpf/20230918024813.237475-4-hengqi.chen@gmail.com
This commit is contained in:
parent
bb7fa09399
commit
7089f85a9e
6 changed files with 209 additions and 4 deletions
|
@ -196,11 +196,12 @@ endif
|
|||
|
||||
# Filter out -static for liburandom_read.so and its dependent targets so that static builds
|
||||
# do not fail. Static builds leave urandom_read relying on system-wide shared libraries.
|
||||
$(OUTPUT)/liburandom_read.so: urandom_read_lib1.c urandom_read_lib2.c
|
||||
$(OUTPUT)/liburandom_read.so: urandom_read_lib1.c urandom_read_lib2.c liburandom_read.map
|
||||
$(call msg,LIB,,$@)
|
||||
$(Q)$(CLANG) $(filter-out -static,$(CFLAGS) $(LDFLAGS)) \
|
||||
$^ $(filter-out -static,$(LDLIBS)) \
|
||||
$(filter %.c,$^) $(filter-out -static,$(LDLIBS)) \
|
||||
-fuse-ld=$(LLD) -Wl,-znoseparate-code -Wl,--build-id=sha1 \
|
||||
-Wl,--version-script=liburandom_read.map \
|
||||
-fPIC -shared -o $@
|
||||
|
||||
$(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_read.so
|
||||
|
|
15
tools/testing/selftests/bpf/liburandom_read.map
Normal file
15
tools/testing/selftests/bpf/liburandom_read.map
Normal file
|
@ -0,0 +1,15 @@
|
|||
LIBURANDOM_READ_1.0.0 {
|
||||
global:
|
||||
urandlib_api;
|
||||
urandlib_api_sameoffset;
|
||||
urandlib_read_without_sema;
|
||||
urandlib_read_with_sema;
|
||||
urandlib_read_with_sema_semaphore;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
LIBURANDOM_READ_2.0.0 {
|
||||
global:
|
||||
urandlib_api;
|
||||
} LIBURANDOM_READ_1.0.0;
|
95
tools/testing/selftests/bpf/prog_tests/uprobe.c
Normal file
95
tools/testing/selftests/bpf/prog_tests/uprobe.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2023 Hengqi Chen */
|
||||
|
||||
#include <test_progs.h>
|
||||
#include "test_uprobe.skel.h"
|
||||
|
||||
static FILE *urand_spawn(int *pid)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
/* urandom_read's stdout is wired into f */
|
||||
f = popen("./urandom_read 1 report-pid", "r");
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
if (fscanf(f, "%d", pid) != 1) {
|
||||
pclose(f);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static int urand_trigger(FILE **urand_pipe)
|
||||
{
|
||||
int exit_code;
|
||||
|
||||
/* pclose() waits for child process to exit and returns their exit code */
|
||||
exit_code = pclose(*urand_pipe);
|
||||
*urand_pipe = NULL;
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
void test_uprobe(void)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
|
||||
struct test_uprobe *skel;
|
||||
FILE *urand_pipe = NULL;
|
||||
int urand_pid = 0, err;
|
||||
|
||||
skel = test_uprobe__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open"))
|
||||
return;
|
||||
|
||||
urand_pipe = urand_spawn(&urand_pid);
|
||||
if (!ASSERT_OK_PTR(urand_pipe, "urand_spawn"))
|
||||
goto cleanup;
|
||||
|
||||
skel->bss->my_pid = urand_pid;
|
||||
|
||||
/* Manual attach uprobe to urandlib_api
|
||||
* There are two `urandlib_api` symbols in .dynsym section:
|
||||
* - urandlib_api@LIBURANDOM_READ_1.0.0
|
||||
* - urandlib_api@@LIBURANDOM_READ_2.0.0
|
||||
* Both are global bind and would cause a conflict if user
|
||||
* specify the symbol name without a version suffix
|
||||
*/
|
||||
uprobe_opts.func_name = "urandlib_api";
|
||||
skel->links.test4 = bpf_program__attach_uprobe_opts(skel->progs.test4,
|
||||
urand_pid,
|
||||
"./liburandom_read.so",
|
||||
0 /* offset */,
|
||||
&uprobe_opts);
|
||||
if (!ASSERT_ERR_PTR(skel->links.test4, "urandlib_api_attach_conflict"))
|
||||
goto cleanup;
|
||||
|
||||
uprobe_opts.func_name = "urandlib_api@LIBURANDOM_READ_1.0.0";
|
||||
skel->links.test4 = bpf_program__attach_uprobe_opts(skel->progs.test4,
|
||||
urand_pid,
|
||||
"./liburandom_read.so",
|
||||
0 /* offset */,
|
||||
&uprobe_opts);
|
||||
if (!ASSERT_OK_PTR(skel->links.test4, "urandlib_api_attach_ok"))
|
||||
goto cleanup;
|
||||
|
||||
/* Auto attach 3 u[ret]probes to urandlib_api_sameoffset */
|
||||
err = test_uprobe__attach(skel);
|
||||
if (!ASSERT_OK(err, "skel_attach"))
|
||||
goto cleanup;
|
||||
|
||||
/* trigger urandom_read */
|
||||
ASSERT_OK(urand_trigger(&urand_pipe), "urand_exit_code");
|
||||
|
||||
ASSERT_EQ(skel->bss->test1_result, 1, "urandlib_api_sameoffset");
|
||||
ASSERT_EQ(skel->bss->test2_result, 1, "urandlib_api_sameoffset@v1");
|
||||
ASSERT_EQ(skel->bss->test3_result, 3, "urandlib_api_sameoffset@@v2");
|
||||
ASSERT_EQ(skel->bss->test4_result, 1, "urandlib_api");
|
||||
|
||||
cleanup:
|
||||
if (urand_pipe)
|
||||
pclose(urand_pipe);
|
||||
test_uprobe__destroy(skel);
|
||||
}
|
61
tools/testing/selftests/bpf/progs/test_uprobe.c
Normal file
61
tools/testing/selftests/bpf/progs/test_uprobe.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2023 Hengqi Chen */
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
pid_t my_pid = 0;
|
||||
|
||||
int test1_result = 0;
|
||||
int test2_result = 0;
|
||||
int test3_result = 0;
|
||||
int test4_result = 0;
|
||||
|
||||
SEC("uprobe/./liburandom_read.so:urandlib_api_sameoffset")
|
||||
int BPF_UPROBE(test1)
|
||||
{
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
|
||||
if (pid != my_pid)
|
||||
return 0;
|
||||
|
||||
test1_result = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uprobe/./liburandom_read.so:urandlib_api_sameoffset@LIBURANDOM_READ_1.0.0")
|
||||
int BPF_UPROBE(test2)
|
||||
{
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
|
||||
if (pid != my_pid)
|
||||
return 0;
|
||||
|
||||
test2_result = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uretprobe/./liburandom_read.so:urandlib_api_sameoffset@@LIBURANDOM_READ_2.0.0")
|
||||
int BPF_URETPROBE(test3, int ret)
|
||||
{
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
|
||||
if (pid != my_pid)
|
||||
return 0;
|
||||
|
||||
test3_result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("uprobe")
|
||||
int BPF_UPROBE(test4)
|
||||
{
|
||||
pid_t pid = bpf_get_current_pid_tgid() >> 32;
|
||||
|
||||
if (pid != my_pid)
|
||||
return 0;
|
||||
|
||||
test4_result = 1;
|
||||
return 0;
|
||||
}
|
|
@ -11,6 +11,9 @@
|
|||
#define _SDT_HAS_SEMAPHORES 1
|
||||
#include "sdt.h"
|
||||
|
||||
#define SHARED 1
|
||||
#include "bpf/libbpf_internal.h"
|
||||
|
||||
#define SEC(name) __attribute__((section(name), used))
|
||||
|
||||
#define BUF_SIZE 256
|
||||
|
@ -21,10 +24,14 @@ void urand_read_without_sema(int iter_num, int iter_cnt, int read_sz);
|
|||
void urandlib_read_with_sema(int iter_num, int iter_cnt, int read_sz);
|
||||
void urandlib_read_without_sema(int iter_num, int iter_cnt, int read_sz);
|
||||
|
||||
int urandlib_api(void);
|
||||
COMPAT_VERSION(urandlib_api_old, urandlib_api, LIBURANDOM_READ_1.0.0)
|
||||
int urandlib_api_old(void);
|
||||
int urandlib_api_sameoffset(void);
|
||||
|
||||
unsigned short urand_read_with_sema_semaphore SEC(".probes");
|
||||
|
||||
static __attribute__((noinline))
|
||||
void urandom_read(int fd, int count)
|
||||
static noinline void urandom_read(int fd, int count)
|
||||
{
|
||||
char buf[BUF_SIZE];
|
||||
int i;
|
||||
|
@ -83,6 +90,10 @@ int main(int argc, char *argv[])
|
|||
|
||||
urandom_read(fd, count);
|
||||
|
||||
urandlib_api();
|
||||
urandlib_api_old();
|
||||
urandlib_api_sameoffset();
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#define _SDT_HAS_SEMAPHORES 1
|
||||
#include "sdt.h"
|
||||
|
||||
#define SHARED 1
|
||||
#include "bpf/libbpf_internal.h"
|
||||
|
||||
#define SEC(name) __attribute__((section(name), used))
|
||||
|
||||
unsigned short urandlib_read_with_sema_semaphore SEC(".probes");
|
||||
|
@ -11,3 +14,22 @@ void urandlib_read_with_sema(int iter_num, int iter_cnt, int read_sz)
|
|||
{
|
||||
STAP_PROBE3(urandlib, read_with_sema, iter_num, iter_cnt, read_sz);
|
||||
}
|
||||
|
||||
COMPAT_VERSION(urandlib_api_v1, urandlib_api, LIBURANDOM_READ_1.0.0)
|
||||
int urandlib_api_v1(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEFAULT_VERSION(urandlib_api_v2, urandlib_api, LIBURANDOM_READ_2.0.0)
|
||||
int urandlib_api_v2(void)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
COMPAT_VERSION(urandlib_api_sameoffset, urandlib_api_sameoffset, LIBURANDOM_READ_1.0.0)
|
||||
DEFAULT_VERSION(urandlib_api_sameoffset, urandlib_api_sameoffset, LIBURANDOM_READ_2.0.0)
|
||||
int urandlib_api_sameoffset(void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue