Message ID | 20210423002646.35043-11-alexei.starovoitov@gmail.com |
---|---|
State | New |
Headers | show |
Series | bpf: syscall program, FD array, loader program, light skeleton. | expand |
On Thu, Apr 22, 2021 at 5:27 PM Alexei Starovoitov <alexei.starovoitov@gmail.com> wrote: > > From: Alexei Starovoitov <ast@kernel.org> > > Add new helper: > > long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > Description > Find given name with given type in BTF pointed to by btf_fd. > If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > Return > Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > --- > include/linux/bpf.h | 1 + > include/uapi/linux/bpf.h | 8 ++++ > kernel/bpf/btf.c | 68 ++++++++++++++++++++++++++++++++++ > kernel/bpf/syscall.c | 2 + > tools/include/uapi/linux/bpf.h | 8 ++++ > 5 files changed, 87 insertions(+) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 0f841bd0cb85..4cf361eb6a80 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1972,6 +1972,7 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto; > extern const struct bpf_func_proto bpf_task_storage_get_proto; > extern const struct bpf_func_proto bpf_task_storage_delete_proto; > extern const struct bpf_func_proto bpf_for_each_map_elem_proto; > +extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto; > > const struct bpf_func_proto *bpf_tracing_func_proto( > enum bpf_func_id func_id, const struct bpf_prog *prog); > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index de58a714ed36..253f5f031f08 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -4748,6 +4748,13 @@ union bpf_attr { > * Execute bpf syscall with given arguments. > * Return > * A syscall result. > + * > + * long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > + * Description > + * Find given name with given type in BTF pointed to by btf_fd. "Find BTF type with given name"? Should the limits on name length be specified? KSYM_NAME_LEN is a pretty arbitrary restriction. Also, would it still work fine if the caller provides a pointer to a much shorter piece of memory? Why not add name_sz right after name, as we do with a lot of other arguments like this? > + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > + * Return > + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. Mention that for vmlinux BTF btf_obj_fd will be zero? Also who "owns" the FD? If the BPF program doesn't close it, when are they going to be cleaned up? > */ > #define __BPF_FUNC_MAPPER(FN) \ > FN(unspec), \ > @@ -4917,6 +4924,7 @@ union bpf_attr { > FN(for_each_map_elem), \ > FN(snprintf), \ > FN(sys_bpf), \ > + FN(btf_find_by_name_kind), \ > /* */ > [...]
On Mon, Apr 26, 2021 at 03:46:29PM -0700, Andrii Nakryiko wrote: > On Thu, Apr 22, 2021 at 5:27 PM Alexei Starovoitov > <alexei.starovoitov@gmail.com> wrote: > > > > From: Alexei Starovoitov <ast@kernel.org> > > > > Add new helper: > > > > long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > > Description > > Find given name with given type in BTF pointed to by btf_fd. > > If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > Return > > Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > > --- > > include/linux/bpf.h | 1 + > > include/uapi/linux/bpf.h | 8 ++++ > > kernel/bpf/btf.c | 68 ++++++++++++++++++++++++++++++++++ > > kernel/bpf/syscall.c | 2 + > > tools/include/uapi/linux/bpf.h | 8 ++++ > > 5 files changed, 87 insertions(+) > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > index 0f841bd0cb85..4cf361eb6a80 100644 > > --- a/include/linux/bpf.h > > +++ b/include/linux/bpf.h > > @@ -1972,6 +1972,7 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto; > > extern const struct bpf_func_proto bpf_task_storage_get_proto; > > extern const struct bpf_func_proto bpf_task_storage_delete_proto; > > extern const struct bpf_func_proto bpf_for_each_map_elem_proto; > > +extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto; > > > > const struct bpf_func_proto *bpf_tracing_func_proto( > > enum bpf_func_id func_id, const struct bpf_prog *prog); > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > > index de58a714ed36..253f5f031f08 100644 > > --- a/include/uapi/linux/bpf.h > > +++ b/include/uapi/linux/bpf.h > > @@ -4748,6 +4748,13 @@ union bpf_attr { > > * Execute bpf syscall with given arguments. > > * Return > > * A syscall result. > > + * > > + * long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > > + * Description > > + * Find given name with given type in BTF pointed to by btf_fd. > > "Find BTF type with given name"? Should the limits on name length be +1 > specified? KSYM_NAME_LEN is a pretty arbitrary restriction. that's implementation detail that shouldn't leak into uapi. > Also, > would it still work fine if the caller provides a pointer to a much > shorter piece of memory? > > Why not add name_sz right after name, as we do with a lot of other > arguments like this? That's an option too, but then the helper will have 5 args and 'flags' would be likely useless. I mean unlikely it will help extending it. I was thinking about ARG_PTR_TO_CONST_STR, but it doesn't work, since blob is writeable by the prog. It's read only from user space. I'm fine with name, name_sz though. > > > + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > + * Return > > + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > Mention that for vmlinux BTF btf_obj_fd will be zero? Also who "owns" > the FD? If the BPF program doesn't close it, when are they going to be > cleaned up? just like bpf_sys_bpf. Who owns returned FD? The program that called the helper, of course. In the current shape of loader prog these btf fds are cleaned up correctly in success and in error case. Not all FDs though. map fds will stay around if bpf_sys_bpf(prog_load) fails to load. Tweaking loader prog to close all FDs in error case is on todo list.
On Mon, Apr 26, 2021 at 8:37 PM Alexei Starovoitov <alexei.starovoitov@gmail.com> wrote: > > On Mon, Apr 26, 2021 at 03:46:29PM -0700, Andrii Nakryiko wrote: > > On Thu, Apr 22, 2021 at 5:27 PM Alexei Starovoitov > > <alexei.starovoitov@gmail.com> wrote: > > > > > > From: Alexei Starovoitov <ast@kernel.org> > > > > > > Add new helper: > > > > > > long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > > > Description > > > Find given name with given type in BTF pointed to by btf_fd. > > > If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > > Return > > > Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > > > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > > > --- > > > include/linux/bpf.h | 1 + > > > include/uapi/linux/bpf.h | 8 ++++ > > > kernel/bpf/btf.c | 68 ++++++++++++++++++++++++++++++++++ > > > kernel/bpf/syscall.c | 2 + > > > tools/include/uapi/linux/bpf.h | 8 ++++ > > > 5 files changed, 87 insertions(+) > > > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > > index 0f841bd0cb85..4cf361eb6a80 100644 > > > --- a/include/linux/bpf.h > > > +++ b/include/linux/bpf.h > > > @@ -1972,6 +1972,7 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto; > > > extern const struct bpf_func_proto bpf_task_storage_get_proto; > > > extern const struct bpf_func_proto bpf_task_storage_delete_proto; > > > extern const struct bpf_func_proto bpf_for_each_map_elem_proto; > > > +extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto; > > > > > > const struct bpf_func_proto *bpf_tracing_func_proto( > > > enum bpf_func_id func_id, const struct bpf_prog *prog); > > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > > > index de58a714ed36..253f5f031f08 100644 > > > --- a/include/uapi/linux/bpf.h > > > +++ b/include/uapi/linux/bpf.h > > > @@ -4748,6 +4748,13 @@ union bpf_attr { > > > * Execute bpf syscall with given arguments. > > > * Return > > > * A syscall result. > > > + * > > > + * long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > > > + * Description > > > + * Find given name with given type in BTF pointed to by btf_fd. > > > > "Find BTF type with given name"? Should the limits on name length be > > +1 > > > specified? KSYM_NAME_LEN is a pretty arbitrary restriction. > > that's implementation detail that shouldn't leak into uapi. > > > Also, > > would it still work fine if the caller provides a pointer to a much > > shorter piece of memory? > > > > Why not add name_sz right after name, as we do with a lot of other > > arguments like this? > > That's an option too, but then the helper will have 5 args and 'flags' > would be likely useless. I mean unlikely it will help extending it. > I was thinking about ARG_PTR_TO_CONST_STR, but it doesn't work, > since blob is writeable by the prog. It's read only from user space. > I'm fine with name, name_sz though. Yeah, I figured ARG_PTR_TO_CONST_STR isn't an option here. By "flags would be useless" you mean that you'd use another parameter if some flags were set? Did we ever do that to existing helpers? We can always add a new helper, if necessary. name + name_sz seems less error-prone, tbh. > > > > > > + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > > + * Return > > > + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > Mention that for vmlinux BTF btf_obj_fd will be zero? Also who "owns" > > the FD? If the BPF program doesn't close it, when are they going to be > > cleaned up? > > just like bpf_sys_bpf. Who owns returned FD? The program that called > the helper, of course. "program" as in the user-space process that did bpf_prog_test_run(), right? In the cover letter you mentioned that BPF_PROG_TYPE_SYSCALL might be called on syscall entry in the future, for that case there is no clear "owning" process, so would be curious to see how that problem gets solved. > In the current shape of loader prog these btf fds are cleaned up correctly > in success and in error case. > Not all FDs though. map fds will stay around if bpf_sys_bpf(prog_load) fails to load. > Tweaking loader prog to close all FDs in error case is on todo list. Ok, good, that seems important.
Alexei Starovoitov wrote: > From: Alexei Starovoitov <ast@kernel.org> > > Add new helper: > > long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > Description > Find given name with given type in BTF pointed to by btf_fd. > If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > Return > Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > --- I'm missing some high-level concept on how this would be used? Where does btf_fd come from and how is it used so that it doesn't break sig-check? A use-case I'm trying to fit into this series is how to pass down a BTF fd/object with the program. I know its not doing CO-RE yet but we would want it to use the BTF object being passed down for CO-RE eventually. Will there be someway to do that here? That looks like the btf_fd here. Thanks, John
John Fastabend wrote: > Alexei Starovoitov wrote: > > From: Alexei Starovoitov <ast@kernel.org> > > > > Add new helper: > > > > long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > > Description > > Find given name with given type in BTF pointed to by btf_fd. > > If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > Return > > Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > > --- > > I'm missing some high-level concept on how this would be used? Where does btf_fd come > from and how is it used so that it doesn't break sig-check? aha as I look through this again it seems btf_fd can be from fd_array[] and sig-check will pan out as well as BTF can come from any valid file. Correct? If so lgtm at high-level.
On Tue, Apr 27, 2021 at 10:45:38AM -0700, Andrii Nakryiko wrote: > > > > > > > + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > > > + * Return > > > > + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > > > Mention that for vmlinux BTF btf_obj_fd will be zero? Also who "owns" > > > the FD? If the BPF program doesn't close it, when are they going to be > > > cleaned up? > > > > just like bpf_sys_bpf. Who owns returned FD? The program that called > > the helper, of course. > > "program" as in the user-space process that did bpf_prog_test_run(), > right? In the cover letter you mentioned that BPF_PROG_TYPE_SYSCALL > might be called on syscall entry in the future, for that case there is > no clear "owning" process, so would be curious to see how that problem > gets solved. well, there is always an owner process. When syscall progs is attached to syscall such FDs will be in the process that doing syscall. It's kinda 'random', but that's the job of the prog to make 'non random'. If it's doing syscalls that will install FDs it should have a reason to do so. Likely there will be limitations on what bpf helpers such syscall prog can do if it's attached to this or that syscall. Currently it's test_run only. I'm not sure whether you're hinting that it all should be FD-less or I'm putting a question in your mouth, but I've considered doing that and figured that it's an overkill. It's possible to convert .*bpf.* do deal with FDs and with some other temporary handle. Instead of map_fd the loader prog would create a map and get a handle back that it will use later in prog_load, etc. But amount of refactoring looks excessive. The generated loader prog should be correct by construction and clean up after itself instead of burdening the kernel cleaning those extra handles.
On Tue, Apr 27, 2021 at 02:00:43PM -0700, John Fastabend wrote: > Alexei Starovoitov wrote: > > From: Alexei Starovoitov <ast@kernel.org> > > > > Add new helper: > > > > long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) > > Description > > Find given name with given type in BTF pointed to by btf_fd. > > If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > Return > > Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > > --- > > I'm missing some high-level concept on how this would be used? Where does btf_fd come > from and how is it used so that it doesn't break sig-check? you mean that one that is being returned or the one passed in? The one that is passed in I only tested locally. No patches use that. Sorry. It's to support PROG_EXT. That btf_fd points to BTF of the prog that is being extended. The signed extension prog will have the name of subprog covered by the signature, but target btf_fd of the prog won't be known at signing time. It will be supplied via struct bpf_prog_desc. That's what attach_prog_fd is there for. I can remove all that stuff for now. The name of target prog doesn't have to be part of the signature. All of these details are to be discussed. We can make signature as tight as we want or more flexible. > A use-case I'm trying to fit into this series is how to pass down a BTF fd/object > with the program. I'm not sure I follow. struct bpf_prog_desc will have more fields that can be populated to tweak particular prog before running the loader. > I know its not doing CO-RE yet but we would want it to use the > BTF object being passed down for CO-RE eventually. Will there be someway to do > that here? That looks like the btf_fd here. I've started hacking on CO-RE. So far I'm thinking to pass spec string to the kernel in another section of btf.ext. Similar to line_info and func_info. As an orthogonal discussion I think CO-RE should be able to relocate against already loaded bpf progs too (and not only kernel and modules).
On Tue, Apr 27, 2021 at 6:55 PM Alexei Starovoitov <alexei.starovoitov@gmail.com> wrote: > > On Tue, Apr 27, 2021 at 10:45:38AM -0700, Andrii Nakryiko wrote: > > > > > > > > > + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. > > > > > + * Return > > > > > + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. > > > > > > > > Mention that for vmlinux BTF btf_obj_fd will be zero? Also who "owns" > > > > the FD? If the BPF program doesn't close it, when are they going to be > > > > cleaned up? > > > > > > just like bpf_sys_bpf. Who owns returned FD? The program that called > > > the helper, of course. > > > > "program" as in the user-space process that did bpf_prog_test_run(), > > right? In the cover letter you mentioned that BPF_PROG_TYPE_SYSCALL > > might be called on syscall entry in the future, for that case there is > > no clear "owning" process, so would be curious to see how that problem > > gets solved. > > well, there is always an owner process. When syscall progs is attached > to syscall such FDs will be in the process that doing syscall. > It's kinda 'random', but that's the job of the prog to make 'non random'. > If it's doing syscalls that will install FDs it should have a reason > to do so. Likely there will be limitations on what bpf helpers such syscall > prog can do if it's attached to this or that syscall. > Currently it's test_run only. > > I'm not sure whether you're hinting that it all should be FD-less or I'm > putting a question in your mouth, but I've considered doing that and > figured that it's an overkill. It's possible to convert .*bpf.* do deal > with FDs and with some other temporary handle. Instead of map_fd the > loader prog would create a map and get a handle back that it will use > later in prog_load, etc. > But amount of refactoring looks excessive. > The generated loader prog should be correct by construction and > clean up after itself instead of burdening the kernel cleaning > those extra handles. That's not really the suggestion or question I had in mind. I was contemplating how the FD handling will happen if such BPF program is running from some other process's context and it seemed (and still seems) very surprising if new FD will just be added to a "random" process. Ignoring all the technical difficulties, I'd say ideally those FDs should be owned by BPF program itself, and when it gets unloaded, just like at the process exit, all still open FDs should be closed. How technically feasible that is is entirely different question. But basically, I wanted to confirm I understand where those new FDs are attached to.
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 0f841bd0cb85..4cf361eb6a80 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1972,6 +1972,7 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto; extern const struct bpf_func_proto bpf_task_storage_get_proto; extern const struct bpf_func_proto bpf_task_storage_delete_proto; extern const struct bpf_func_proto bpf_for_each_map_elem_proto; +extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto; const struct bpf_func_proto *bpf_tracing_func_proto( enum bpf_func_id func_id, const struct bpf_prog *prog); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index de58a714ed36..253f5f031f08 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -4748,6 +4748,13 @@ union bpf_attr { * Execute bpf syscall with given arguments. * Return * A syscall result. + * + * long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) + * Description + * Find given name with given type in BTF pointed to by btf_fd. + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. + * Return + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4917,6 +4924,7 @@ union bpf_attr { FN(for_each_map_elem), \ FN(snprintf), \ FN(sys_bpf), \ + FN(btf_find_by_name_kind), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index fbf6c06a9d62..446c64171464 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6085,3 +6085,71 @@ struct module *btf_try_get_module(const struct btf *btf) return res; } + +BPF_CALL_4(bpf_btf_find_by_name_kind, int, btf_fd, char *, name, u32, kind, int, flags) +{ + char kname[KSYM_NAME_LEN]; + struct btf *btf; + long ret; + + if (flags) + return -EINVAL; + + ret = strncpy_from_kernel_nofault(kname, name, sizeof(kname)); + if (ret < 0) + return ret; + if (btf_fd) + btf = btf_get_by_fd(btf_fd); + else + btf = bpf_get_btf_vmlinux(); + if (IS_ERR(btf)) + return PTR_ERR(btf); + + ret = btf_find_by_name_kind(btf, kname, kind); + /* ret is never zero, since btf_find_by_name_kind returns + * positive btf_id or negative error. + */ + if (btf_fd) + btf_put(btf); + else if (ret < 0) { + struct btf *mod_btf; + int id; + + /* If name is not found in vmlinux's BTF then search in module's BTFs */ + spin_lock_bh(&btf_idr_lock); + idr_for_each_entry(&btf_idr, mod_btf, id) { + if (!btf_is_module(mod_btf)) + continue; + /* linear search could be slow hence unlock/lock + * the IDR to avoiding holding it for too long + */ + btf_get(mod_btf); + spin_unlock_bh(&btf_idr_lock); + ret = btf_find_by_name_kind(mod_btf, kname, kind); + if (ret > 0) { + int btf_obj_fd; + + btf_obj_fd = __btf_new_fd(mod_btf); + if (btf_obj_fd < 0) { + btf_put(mod_btf); + return btf_obj_fd; + } + return ret | (((u64)btf_obj_fd) << 32); + } + spin_lock_bh(&btf_idr_lock); + btf_put(mod_btf); + } + spin_unlock_bh(&btf_idr_lock); + } + return ret; +} + +const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = { + .func = bpf_btf_find_by_name_kind, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, +}; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a81496c5d09f..638c7acad925 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4574,6 +4574,8 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) switch (func_id) { case BPF_FUNC_sys_bpf: return &bpf_sys_bpf_proto; + case BPF_FUNC_btf_find_by_name_kind: + return &bpf_btf_find_by_name_kind_proto; default: return tracing_prog_func_proto(func_id, prog); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 6c8e178d8ffa..5841adb44de6 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -4748,6 +4748,13 @@ union bpf_attr { * Execute bpf syscall with given arguments. * Return * A syscall result. + * + * long bpf_btf_find_by_name_kind(u32 btf_fd, char *name, u32 kind, int flags) + * Description + * Find given name with given type in BTF pointed to by btf_fd. + * If btf_fd is zero look for the name in vmlinux BTF and in module's BTFs. + * Return + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4917,6 +4924,7 @@ union bpf_attr { FN(for_each_map_elem), \ FN(snprintf), \ FN(sys_bpf), \ + FN(btf_find_by_name_kind), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper