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>
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
* 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);
}
{
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)
#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;
if (!ksyms)
return;
+ free(ksyms->filtered_syms);
+
if (!ksyms->syms) {
free(ksyms);
return;
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;
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)) {
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;
}
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);
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