Skip to content

Commit

Permalink
libbpf: Add unique_match option for multi kprobe
Browse files Browse the repository at this point in the history
Jordan reported an issue in Meta production environment where func
try_to_wake_up() is renamed to try_to_wake_up.llvm.<hash>() by clang
compiler at lto mode. The original 'kprobe/try_to_wake_up' does not
work any more since try_to_wake_up() does not match the actual func
name in /proc/kallsyms.

There are a couple of ways to resolve this issue. For example, in
attach_kprobe(), we could do lookup in /proc/kallsyms so try_to_wake_up()
can be replaced by try_to_wake_up.llvm.<hach>(). Or we can force users
to use bpf_program__attach_kprobe() where they need to lookup
/proc/kallsyms to find out try_to_wake_up.llvm.<hach>(). But these two
approaches requires extra work by either libbpf or user.

Luckily, suggested by Andrii, multi kprobe already supports wildcard ('*')
for symbol matching. In the above example, 'try_to_wake_up*' can match
to try_to_wake_up() or try_to_wake_up.llvm.<hash>() and this allows
bpf prog works for different kernels as some kernels may have
try_to_wake_up() and some others may have try_to_wake_up.llvm.<hash>().

The original intention is to kprobe try_to_wake_up() only, so an optional
field unique_match is added to struct bpf_kprobe_multi_opts. If the
field is set to true, the number of matched functions must be one.
Otherwise, the attachment will fail. In the above case, multi kprobe
with 'try_to_wake_up*' and unique_match preserves user functionality.

Reported-by: Jordan Rome <[email protected]>
Suggested-by: Andrii Nakryiko <[email protected]>
Signed-off-by: Yonghong Song <[email protected]>
Signed-off-by: Andrii Nakryiko <[email protected]>
Link: https://lore.kernel.org/bpf/[email protected]
  • Loading branch information
Yonghong Song authored and anakryiko committed Jan 10, 2025
1 parent e8ec1c9 commit e2b0bda
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
13 changes: 12 additions & 1 deletion tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -11534,7 +11534,7 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
struct bpf_link *link = NULL;
const unsigned long *addrs;
int err, link_fd, prog_fd;
bool retprobe, session;
bool retprobe, session, unique_match;
const __u64 *cookies;
const char **syms;
size_t cnt;
Expand All @@ -11553,13 +11553,16 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
addrs = OPTS_GET(opts, addrs, false);
cnt = OPTS_GET(opts, cnt, false);
cookies = OPTS_GET(opts, cookies, false);
unique_match = OPTS_GET(opts, unique_match, false);

if (!pattern && !addrs && !syms)
return libbpf_err_ptr(-EINVAL);
if (pattern && (addrs || syms || cookies || cnt))
return libbpf_err_ptr(-EINVAL);
if (!pattern && !cnt)
return libbpf_err_ptr(-EINVAL);
if (!pattern && unique_match)
return libbpf_err_ptr(-EINVAL);
if (addrs && syms)
return libbpf_err_ptr(-EINVAL);

Expand All @@ -11570,6 +11573,14 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
err = libbpf_available_kallsyms_parse(&res);
if (err)
goto error;

if (unique_match && res.cnt != 1) {
pr_warn("prog '%s': failed to find a unique match for '%s' (%zu matches)\n",
prog->name, pattern, res.cnt);
err = -EINVAL;
goto error;
}

addrs = res.addrs;
cnt = res.cnt;
}
Expand Down
4 changes: 3 additions & 1 deletion tools/lib/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,10 +552,12 @@ struct bpf_kprobe_multi_opts {
bool retprobe;
/* create session kprobes */
bool session;
/* enforce unique match */
bool unique_match;
size_t :0;
};

#define bpf_kprobe_multi_opts__last_field session
#define bpf_kprobe_multi_opts__last_field unique_match

LIBBPF_API struct bpf_link *
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
Expand Down

0 comments on commit e2b0bda

Please sign in to comment.