Skip to content

Commit 9edaafa

Browse files
Yonghong SongAlexei Starovoitov
authored andcommitted
selftests/bpf: Fix kprobe_multi_bench_attach test failure with LTO kernel
In my locally build clang LTO kernel (enabling CONFIG_LTO and CONFIG_LTO_CLANG_THIN), kprobe_multi_bench_attach/kernel subtest failed like: test_kprobe_multi_bench_attach:PASS:get_syms 0 nsec test_kprobe_multi_bench_attach:PASS:kprobe_multi_empty__open_and_load 0 nsec libbpf: prog 'test_kprobe_empty': failed to attach: No such process test_kprobe_multi_bench_attach:FAIL:bpf_program__attach_kprobe_multi_opts unexpected error: -3 #117/1 kprobe_multi_bench_attach/kernel:FAIL There are multiple symbols in /sys/kernel/debug/tracing/available_filter_functions are renamed in /proc/kallsyms due to cross file inlining. One example is for static function __access_remote_vm in mm/memory.c. In a non-LTO kernel, we have the following call stack: ptrace_access_vm (global, kernel/ptrace.c) access_remote_vm (global, mm/memory.c) __access_remote_vm (static, mm/memory.c) With LTO kernel, it is possible that access_remote_vm() is inlined by ptrace_access_vm(). So we end up with the following call stack: ptrace_access_vm (global, kernel/ptrace.c) __access_remote_vm (static, mm/memory.c) The compiler renames __access_remote_vm to __access_remote_vm.llvm.<hash> to prevent potential name collision. The kernel bpf_kprobe_multi_link_attach() and ftrace_lookup_symbols() try to find addresses based on /proc/kallsyms, hence the current test failed with LTO kenrel. This patch consulted /proc/kallsyms to find the corresponding entries for the ksym and this solved the issue. Signed-off-by: Yonghong Song <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent d1f0258 commit 9edaafa

File tree

1 file changed

+48
-14
lines changed

1 file changed

+48
-14
lines changed

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

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -367,15 +367,49 @@ static bool skip_entry(char *name)
367367
return false;
368368
}
369369

370+
/* Do comparision by ignoring '.llvm.<hash>' suffixes. */
371+
static int compare_name(const char *name1, const char *name2)
372+
{
373+
const char *res1, *res2;
374+
int len1, len2;
375+
376+
res1 = strstr(name1, ".llvm.");
377+
res2 = strstr(name2, ".llvm.");
378+
len1 = res1 ? res1 - name1 : strlen(name1);
379+
len2 = res2 ? res2 - name2 : strlen(name2);
380+
381+
if (len1 == len2)
382+
return strncmp(name1, name2, len1);
383+
if (len1 < len2)
384+
return strncmp(name1, name2, len1) <= 0 ? -1 : 1;
385+
return strncmp(name1, name2, len2) >= 0 ? 1 : -1;
386+
}
387+
388+
static int load_kallsyms_compare(const void *p1, const void *p2)
389+
{
390+
return compare_name(((const struct ksym *)p1)->name, ((const struct ksym *)p2)->name);
391+
}
392+
393+
static int search_kallsyms_compare(const void *p1, const struct ksym *p2)
394+
{
395+
return compare_name(p1, p2->name);
396+
}
397+
370398
static int get_syms(char ***symsp, size_t *cntp, bool kernel)
371399
{
372-
size_t cap = 0, cnt = 0, i;
373-
char *name = NULL, **syms = NULL;
400+
size_t cap = 0, cnt = 0;
401+
char *name = NULL, *ksym_name, **syms = NULL;
374402
struct hashmap *map;
403+
struct ksyms *ksyms;
404+
struct ksym *ks;
375405
char buf[256];
376406
FILE *f;
377407
int err = 0;
378408

409+
ksyms = load_kallsyms_custom_local(load_kallsyms_compare);
410+
if (!ASSERT_OK_PTR(ksyms, "load_kallsyms_custom_local"))
411+
return -EINVAL;
412+
379413
/*
380414
* The available_filter_functions contains many duplicates,
381415
* but other than that all symbols are usable in kprobe multi
@@ -408,7 +442,14 @@ static int get_syms(char ***symsp, size_t *cntp, bool kernel)
408442
if (skip_entry(name))
409443
continue;
410444

411-
err = hashmap__add(map, name, 0);
445+
ks = search_kallsyms_custom_local(ksyms, name, search_kallsyms_compare);
446+
if (!ks) {
447+
err = -EINVAL;
448+
goto error;
449+
}
450+
451+
ksym_name = ks->name;
452+
err = hashmap__add(map, ksym_name, 0);
412453
if (err == -EEXIST) {
413454
err = 0;
414455
continue;
@@ -421,8 +462,7 @@ static int get_syms(char ***symsp, size_t *cntp, bool kernel)
421462
if (err)
422463
goto error;
423464

424-
syms[cnt++] = name;
425-
name = NULL;
465+
syms[cnt++] = ksym_name;
426466
}
427467

428468
*symsp = syms;
@@ -432,11 +472,8 @@ static int get_syms(char ***symsp, size_t *cntp, bool kernel)
432472
free(name);
433473
fclose(f);
434474
hashmap__free(map);
435-
if (err) {
436-
for (i = 0; i < cnt; i++)
437-
free(syms[i]);
475+
if (err)
438476
free(syms);
439-
}
440477
return err;
441478
}
442479

@@ -472,7 +509,7 @@ static void test_kprobe_multi_bench_attach(bool kernel)
472509
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
473510
struct kprobe_multi_empty *skel = NULL;
474511
char **syms = NULL;
475-
size_t cnt = 0, i;
512+
size_t cnt = 0;
476513

477514
if (!ASSERT_OK(get_syms(&syms, &cnt, kernel), "get_syms"))
478515
return;
@@ -488,11 +525,8 @@ static void test_kprobe_multi_bench_attach(bool kernel)
488525

489526
cleanup:
490527
kprobe_multi_empty__destroy(skel);
491-
if (syms) {
492-
for (i = 0; i < cnt; i++)
493-
free(syms[i]);
528+
if (syms)
494529
free(syms);
495-
}
496530
}
497531

498532
static void test_attach_override(void)

0 commit comments

Comments
 (0)