mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
selftests/bpf: Refactor bpf_get_ksyms() trace helper
ASAN reported a memory leak in bpf_get_ksyms(): it allocates a struct ksyms internally and never frees it. Move struct ksyms to trace_helpers.h and return it from the bpf_get_ksyms(), giving ownership to the caller. Add filtered_syms and filtered_cnt fields to the ksyms to hold the filtered array of symbols, previously returned by bpf_get_ksyms(). Fixup the call sites: kprobe_multi_test and bench_trigger. Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20260223190736.649171-10-ihor.solodrai@linux.dev Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
committed by
Alexei Starovoitov
parent
45897ced3c
commit
a1a771bd64
@@ -230,8 +230,8 @@ static void trigger_fentry_setup(void)
|
||||
static void attach_ksyms_all(struct bpf_program *empty, bool kretprobe)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
|
||||
char **syms = NULL;
|
||||
size_t cnt = 0;
|
||||
struct bpf_link *link = NULL;
|
||||
struct ksyms *ksyms = NULL;
|
||||
|
||||
/* Some recursive functions will be skipped in
|
||||
* bpf_get_ksyms -> skip_entry, as they can introduce sufficient
|
||||
@@ -241,16 +241,18 @@ static void attach_ksyms_all(struct bpf_program *empty, bool kretprobe)
|
||||
* So, don't run the kprobe-multi-all and kretprobe-multi-all on
|
||||
* a debug kernel.
|
||||
*/
|
||||
if (bpf_get_ksyms(&syms, &cnt, true)) {
|
||||
if (bpf_get_ksyms(&ksyms, true)) {
|
||||
fprintf(stderr, "failed to get ksyms\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
opts.syms = (const char **) syms;
|
||||
opts.cnt = cnt;
|
||||
opts.syms = (const char **)ksyms->filtered_syms;
|
||||
opts.cnt = ksyms->filtered_cnt;
|
||||
opts.retprobe = kretprobe;
|
||||
/* attach empty to all the kernel functions except bpf_get_numa_node_id. */
|
||||
if (!bpf_program__attach_kprobe_multi_opts(empty, NULL, &opts)) {
|
||||
link = bpf_program__attach_kprobe_multi_opts(empty, NULL, &opts);
|
||||
free_kallsyms_local(ksyms);
|
||||
if (!link) {
|
||||
fprintf(stderr, "failed to attach bpf_program__attach_kprobe_multi_opts to all\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -456,25 +456,23 @@ static void test_kprobe_multi_bench_attach(bool kernel)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
|
||||
struct kprobe_multi_empty *skel = NULL;
|
||||
char **syms = NULL;
|
||||
size_t cnt = 0;
|
||||
struct ksyms *ksyms = NULL;
|
||||
|
||||
if (!ASSERT_OK(bpf_get_ksyms(&syms, &cnt, kernel), "bpf_get_ksyms"))
|
||||
if (!ASSERT_OK(bpf_get_ksyms(&ksyms, kernel), "bpf_get_ksyms"))
|
||||
return;
|
||||
|
||||
skel = kprobe_multi_empty__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load"))
|
||||
goto cleanup;
|
||||
|
||||
opts.syms = (const char **) syms;
|
||||
opts.cnt = cnt;
|
||||
opts.syms = (const char **)ksyms->filtered_syms;
|
||||
opts.cnt = ksyms->filtered_cnt;
|
||||
|
||||
do_bench_test(skel, &opts);
|
||||
|
||||
cleanup:
|
||||
kprobe_multi_empty__destroy(skel);
|
||||
if (syms)
|
||||
free(syms);
|
||||
free_kallsyms_local(ksyms);
|
||||
}
|
||||
|
||||
static void test_kprobe_multi_bench_attach_addr(bool kernel)
|
||||
|
||||
@@ -24,12 +24,6 @@
|
||||
#define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe"
|
||||
#define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe"
|
||||
|
||||
struct ksyms {
|
||||
struct ksym *syms;
|
||||
size_t sym_cap;
|
||||
size_t sym_cnt;
|
||||
};
|
||||
|
||||
static struct ksyms *ksyms;
|
||||
static pthread_mutex_t ksyms_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
@@ -54,6 +48,8 @@ void free_kallsyms_local(struct ksyms *ksyms)
|
||||
if (!ksyms)
|
||||
return;
|
||||
|
||||
free(ksyms->filtered_syms);
|
||||
|
||||
if (!ksyms->syms) {
|
||||
free(ksyms);
|
||||
return;
|
||||
@@ -610,7 +606,7 @@ static int search_kallsyms_compare(const void *p1, const struct ksym *p2)
|
||||
return compare_name(p1, p2->name);
|
||||
}
|
||||
|
||||
int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
|
||||
int bpf_get_ksyms(struct ksyms **ksymsp, bool kernel)
|
||||
{
|
||||
size_t cap = 0, cnt = 0;
|
||||
char *name = NULL, *ksym_name, **syms = NULL;
|
||||
@@ -637,8 +633,10 @@ int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
|
||||
else
|
||||
f = fopen("/sys/kernel/debug/tracing/available_filter_functions", "r");
|
||||
|
||||
if (!f)
|
||||
if (!f) {
|
||||
free_kallsyms_local(ksyms);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map = hashmap__new(symbol_hash, symbol_equal, NULL);
|
||||
if (IS_ERR(map)) {
|
||||
@@ -679,15 +677,18 @@ int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
|
||||
syms[cnt++] = ksym_name;
|
||||
}
|
||||
|
||||
*symsp = syms;
|
||||
*cntp = cnt;
|
||||
ksyms->filtered_syms = syms;
|
||||
ksyms->filtered_cnt = cnt;
|
||||
*ksymsp = ksyms;
|
||||
|
||||
error:
|
||||
free(name);
|
||||
fclose(f);
|
||||
hashmap__free(map);
|
||||
if (err)
|
||||
if (err) {
|
||||
free(syms);
|
||||
free_kallsyms_local(ksyms);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,14 @@ struct ksym {
|
||||
long addr;
|
||||
char *name;
|
||||
};
|
||||
struct ksyms;
|
||||
|
||||
struct ksyms {
|
||||
struct ksym *syms;
|
||||
size_t sym_cap;
|
||||
size_t sym_cnt;
|
||||
char **filtered_syms;
|
||||
size_t filtered_cnt;
|
||||
};
|
||||
|
||||
typedef int (*ksym_cmp_t)(const void *p1, const void *p2);
|
||||
typedef int (*ksym_search_cmp_t)(const void *p1, const struct ksym *p2);
|
||||
@@ -53,7 +60,7 @@ ssize_t get_rel_offset(uintptr_t addr);
|
||||
|
||||
int read_build_id(const char *path, char *build_id, size_t size);
|
||||
|
||||
int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel);
|
||||
int bpf_get_ksyms(struct ksyms **ksymsp, bool kernel);
|
||||
int bpf_get_addrs(unsigned long **addrsp, size_t *cntp, bool kernel);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user