From: Yonghong Song <yonghong.song@linux.dev>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: bpf@vger.kernel.org, Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
kernel-team@fb.com, Martin KaFai Lau <martin.lau@kernel.org>
Subject: Re: [PATCH bpf-next v2 3/5] libbpf: Handle <orig_name>.llvm.<hash> symbol properly
Date: Fri, 22 Mar 2024 15:09:37 -0700 [thread overview]
Message-ID: <54ce4078-70d4-443a-8bc4-4ffede1d0405@linux.dev> (raw)
In-Reply-To: <CAEf4BzYt==merToZ_3=dkFBRfGBmmULk7OTNOtUvMC5Gweg+9Q@mail.gmail.com>
On 3/22/24 2:50 PM, Andrii Nakryiko wrote:
> On Thu, Mar 21, 2024 at 1:01 PM Yonghong Song <yonghong.song@linux.dev> wrote:
>> With CONFIG_LTO_CLANG_THIN enabled, with some of previous
>> version of kernel code base ([1]), I hit the following
>> error:
>> test_ksyms:PASS:kallsyms_fopen 0 nsec
>> test_ksyms:FAIL:ksym_find symbol 'bpf_link_fops' not found
>> #118 ksyms:FAIL
>>
>> The reason is that 'bpf_link_fops' is renamed to
>> bpf_link_fops.llvm.8325593422554671469
>> Due to cross-file inlining, the static variable 'bpf_link_fops'
>> in syscall.c is used by a function in another file. To avoid
>> potential duplicated names, the llvm added suffix
>> '.llvm.<hash>' ([2]) to 'bpf_link_fops' variable.
>> Such renaming caused a problem in libbpf if 'bpf_link_fops'
>> is used in bpf prog as a ksym as 'bpf_link_fops' does not
>> match any symbol in /proc/kallsyms.
>>
>> To fix this issue, libbpf needs to understand that suffix '.llvm.<hash>'
>> is caused by clang lto kernel and to process such symbols properly.
>>
>> With latest bpf-next code base built with CONFIG_LTO_CLANG_THIN,
>> I cannot reproduce the above failure any more. But such an issue
>> could happen with other symbols.
>>
>> For example, with my current kernel, I got the following from
>> /proc/kallsyms:
>> ffffffff84782154 d __func__.net_ratelimit.llvm.6135436931166841955
>> ffffffff85f0a500 d tk_core.llvm.726630847145216431
>> ffffffff85fdb960 d __fs_reclaim_map.llvm.10487989720912350772
>> ffffffff864c7300 d fake_dst_ops.llvm.54750082607048300
>>
>> I could not easily create a selftest to test newly-added
>> libbpf functionality with a static C test since I do not know
>> which symbol is cross-file inlined. But based on my particular kernel,
>> the following test change can run successfully.
>>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/ksyms.c b/tools/testing/selftests/bpf/prog_tests/ksyms.c
>> index 6a86d1f07800..904a103f7b1d 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/ksyms.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/ksyms.c
>> @@ -42,6 +42,7 @@ void test_ksyms(void)
>> ASSERT_EQ(data->out__bpf_link_fops, link_fops_addr, "bpf_link_fops");
>> ASSERT_EQ(data->out__bpf_link_fops1, 0, "bpf_link_fops1");
>> ASSERT_EQ(data->out__btf_size, btf_size, "btf_size");
>> + ASSERT_NEQ(data->out__fake_dst_ops, 0, "fake_dst_ops");
>> ASSERT_EQ(data->out__per_cpu_start, per_cpu_start_addr, "__per_cpu_start");
>>
>> cleanup:
>> diff --git a/tools/testing/selftests/bpf/progs/test_ksyms.c b/tools/testing/selftests/bpf/progs/test_ksyms.c
>> index 6c9cbb5a3bdf..fe91eef54b66 100644
>> --- a/tools/testing/selftests/bpf/progs/test_ksyms.c
>> +++ b/tools/testing/selftests/bpf/progs/test_ksyms.c
>> @@ -9,11 +9,13 @@ __u64 out__bpf_link_fops = -1;
>> __u64 out__bpf_link_fops1 = -1;
>> __u64 out__btf_size = -1;
>> __u64 out__per_cpu_start = -1;
>> +__u64 out__fake_dst_ops = -1;
>>
>> extern const void bpf_link_fops __ksym;
>> extern const void __start_BTF __ksym;
>> extern const void __stop_BTF __ksym;
>> extern const void __per_cpu_start __ksym;
>> +extern const void fake_dst_ops __ksym;
>> /* non-existing symbol, weak, default to zero */
>> extern const void bpf_link_fops1 __ksym __weak;
>>
>> @@ -23,6 +25,7 @@ int handler(const void *ctx)
>> out__bpf_link_fops = (__u64)&bpf_link_fops;
>> out__btf_size = (__u64)(&__stop_BTF - &__start_BTF);
>> out__per_cpu_start = (__u64)&__per_cpu_start;
>> + out__fake_dst_ops = (__u64)&fake_dst_ops;
>>
>> out__bpf_link_fops1 = (__u64)&bpf_link_fops1;
>>
>> This patch fixed the issue in libbpf such that if clang lto kernel
>> is enabled and the symbol resolution is for ksym's,
>> the suffix '.llvm.<hash>' will be ignored during comparison of
>> bpf prog ksym vs. symbols in /proc/kallsyms, this resolved the issue.
>>
>> Note that currently kernel does not support gcc build with lto.
>>
>> [1] https://lore.kernel.org/bpf/20240302165017.1627295-1-yonghong.song@linux.dev/
>> [2] https://github.com/llvm/llvm-project/blob/release/18.x/llvm/include/llvm/IR/ModuleSummaryIndex.h#L1714-L1719
>>
>> Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
>> ---
>> tools/lib/bpf/libbpf.c | 64 +++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 63 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
>> index a7a89269148c..8c3861192bc8 100644
>> --- a/tools/lib/bpf/libbpf.c
>> +++ b/tools/lib/bpf/libbpf.c
>> @@ -664,6 +664,7 @@ struct bpf_object {
>> bool loaded;
>> bool has_subcalls;
>> bool has_rodata;
>> + bool need_kallsyms;
>>
>> struct bpf_gen *gen_loader;
>>
>> @@ -8016,14 +8017,73 @@ static int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *ctx)
>> return err;
>> }
>>
>> +static int check_lto_kernel(void)
>> +{
>> + static int check_lto = 2;
>> + char buf[PATH_MAX];
>> + struct utsname uts;
>> + gzFile file;
>> + int len;
>> +
>> + if (check_lto != 2)
>> + return check_lto;
>> +
>> + uname(&uts);
>> + len = snprintf(buf, PATH_MAX, "/boot/config-%s", uts.release);
>> + if (len < 0) {
>> + check_lto = -EINVAL;
>> + goto out;
>> + } else if (len >= PATH_MAX) {
>> + check_lto = -ENAMETOOLONG;
>> + goto out;
>> + }
>> +
>> + /* gzopen also accepts uncompressed files. */
>> + file = gzopen(buf, "re");
>> + if (!file)
>> + file = gzopen("/proc/config.gz", "re");
>> +
>> + if (!file) {
>> + check_lto = -ENOENT;
>> + goto out;
>> + }
>> +
>> + check_lto = 0;
>> + while (gzgets(file, buf, sizeof(buf))) {
>> + /* buf also contains '\n', skip it during comparison. */
>> + if (!strncmp(buf, "CONFIG_LTO_CLANG=y", 18)) {
>> + check_lto = 1;
>> + break;
>> + }
>> + }
>> +
>> + gzclose(file);
>> +out:
>> + return check_lto;
>> +}
>> +
>> static int kallsyms_cb(unsigned long long sym_addr, char sym_type,
>> const char *sym_name, void *ctx)
>> {
>> + int lto_enabled = check_lto_kernel();
>> + char orig_name[PATH_MAX], *res;
>> struct bpf_object *obj = ctx;
>> const struct btf_type *t;
>> struct extern_desc *ext;
>>
>> - ext = find_extern_by_name(obj, sym_name);
>> + /* Only check static variables in data sections */
>> + if (sym_type == 'd' && obj->need_kallsyms && lto_enabled == 1) {
>> + strcpy(orig_name, sym_name);
>> + res = strstr(orig_name, ".llvm.");
>> + if (res) {
>> + *res = '\0';
>> + pr_debug("extern (ksym) '%s': use original name '%s' for comparison\n",
>> + sym_name, orig_name);
>> + }
>> + ext = find_extern_by_name(obj, orig_name);
>> + } else {
>> + ext = find_extern_by_name(obj, sym_name);
>> + }
>> if (!ext || ext->type != EXT_KSYM)
>> return 0;
>>
>> @@ -8322,7 +8382,9 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
>> return -EINVAL;
>> }
>> if (need_kallsyms) {
>> + obj->need_kallsyms = true;
>> err = bpf_object__read_kallsyms_file(obj);
>> + obj->need_kallsyms = false;
> I'm not clear on why you need this obj->need_kallsyms? kallsyms_cb is
> used for just this use case, it seems, it should be fine without this
> extra temporary flag.
yes, I realized later so I responded to Alexei's comment that it is okay
to remove it. Originally I thought bpf_object__read_kallsyms_file()
might be an API function hence the above obj->need_kallsyms.
Apparently, it is not.
>
> Ideally we should also switch to the iterator approach for kallsyms,
> just like we did with elf symbols iterator (see elf_sym_iter in
> elf.c), it would be a cleaner approach. Let me know if you are
> interested in doing this as well (it's not mandatory for the changes
> in this patch set, just to be clear).
I will probably finish the core functionality first. I think this
can be a follow-up.
>
>> if (err)
>> return -EINVAL;
>> }
>> --
>> 2.43.0
>>
next prev parent reply other threads:[~2024-03-22 22:09 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-21 20:00 [PATCH bpf-next v2 0/5] bpf: Fix a couple of test failures with LTO kernel Yonghong Song
2024-03-21 20:01 ` [PATCH bpf-next v2 1/5] selftests/bpf: Replace CHECK with ASSERT macros for ksyms test Yonghong Song
2024-03-22 12:38 ` Jiri Olsa
2024-03-22 16:13 ` Andrii Nakryiko
2024-03-22 16:41 ` Yonghong Song
2024-03-22 16:48 ` Andrii Nakryiko
2024-03-22 17:28 ` Yonghong Song
2024-03-21 20:01 ` [PATCH bpf-next v2 2/5] libbpf: Mark libbpf_kallsyms_parse static function Yonghong Song
2024-03-22 12:37 ` Jiri Olsa
2024-03-22 15:37 ` Yonghong Song
2024-03-21 20:01 ` [PATCH bpf-next v2 3/5] libbpf: Handle <orig_name>.llvm.<hash> symbol properly Yonghong Song
2024-03-21 21:54 ` Alexei Starovoitov
2024-03-21 23:55 ` Yonghong Song
2024-03-22 0:02 ` Alexei Starovoitov
2024-03-22 0:17 ` Andrii Nakryiko
2024-03-22 0:32 ` Yonghong Song
2024-03-22 0:18 ` Andrii Nakryiko
2024-03-22 0:34 ` Yonghong Song
2024-03-22 21:50 ` Andrii Nakryiko
2024-03-22 22:09 ` Yonghong Song [this message]
2024-03-21 20:01 ` [PATCH bpf-next v2 4/5] selftests/bpf: Fix kprobe_multi_bench_attach test failure with LTO kernel Yonghong Song
2024-03-22 12:37 ` Jiri Olsa
2024-03-22 16:01 ` Yonghong Song
2024-03-22 21:53 ` Andrii Nakryiko
2024-03-22 22:20 ` Yonghong Song
2024-03-21 20:01 ` [PATCH bpf-next v2 5/5] selftests/bpf: Add a selftest with available_filter_functions_addrs Yonghong Song
2024-03-22 12:26 ` Jiri Olsa
2024-03-22 16:07 ` Yonghong Song
2024-03-22 21:58 ` Andrii Nakryiko
2024-03-22 22:23 ` Yonghong Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54ce4078-70d4-443a-8bc4-4ffede1d0405@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii.nakryiko@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=martin.lau@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.