Re: [PATCH 3/4] btf: add dt_btf_func_is_traceable()
Kris Van Hees <[email protected]> Fri, 17 Apr 2026 15:04:11 -0400
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Apr 17, 2026 at 06:07:12PM +0100, Nick Alcock wrote: > On 14 Apr 2026, Kris Van Hees spake thusly: > > > Add a function to determine whether a function (given by BTF id) can be > > traced using BPF fentry/fexit probes. It implements checks inspired by > > btf_distill_func_proto() in kernel/bpf/btf.c. > > ... looks reasonable. > > > Signed-off-by: Kris Van Hees <[email protected]> > > Reviewed-by: Nick Alcock <[email protected]> > > (though you might possibly want to implement the suggestion below, it's > very much optional.) > > > --- > > libdtrace/dt_btf.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ > > libdtrace/dt_btf.h | 2 ++ > > 2 files changed, 67 insertions(+) > > > > diff --git a/libdtrace/dt_btf.c b/libdtrace/dt_btf.c > > index 56eb96a4e..fbf377b4e 100644 > > --- a/libdtrace/dt_btf.c > > +++ b/libdtrace/dt_btf.c > > @@ -1020,3 +1020,68 @@ dt_btf_func_is_void(dtrace_hdl_t *dtp, const dt_btf_t *btf, uint32_t id) > > > > return 0; > > } > > + > > +/* > > + * Return 1 if the function referenced by the BTF id can be traced using the > > + * fprobe/fexit facility. Specifically, that the function is not variadic and > > + * that none of its arguments exceeds the acceptable value size (16 bytes). > > + * (See btf_distill_func_proto() in kernel/bpf/btf.c for reference.) > > + */ > > +#define MAX_BPF_FUNC_REG_REGS 5 > > A shame we need to hardwire this. More of a shame that we need to > hardwire it deep in a .c file where it'll almost certainly be overlooked > when the time comes to change it. Stick it in a suitable header, maybe? It is an internal (non-UAPI) aspect of BPF that is only relevant here, which is why I chose to define it here. I think it would be confusing to have it in a more generic header file. > > +int > > +dt_btf_func_is_traceable(dtrace_hdl_t *dtp, const dt_btf_t *btf, uint32_t id) > > +{ > > + btf_type_t *type = dt_btf_real_type_by_id(dtp, btf, id); > > + int argc; > > + > > + /* If no prototype is found, BPF fprobes do not work. */ > > + if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) > > + return 0; > > + > > + /* If the return type is a struct or union, BPF fprobes do not work. */ > > + if (type->type != 0) { > > + btf_type_t *rtype = dt_btf_real_type_by_id(dtp, btf, type->type); > > + > > + if (rtype == NULL) > > + return 0; > > + > > + switch (BTF_INFO_KIND(rtype->info)) { > > + case BTF_KIND_STRUCT: > > + case BTF_KIND_UNION: > > + return 0; > > + default: > > + /* fall-through */ > > + } > > + } > > + > > + /* > > + * BPF fprobes do not support functions that are variadic or that have > > + * any arguments passed by value that are a struct or union of size > > + * greater than 16. > > + */ > > + argc = BTF_INFO_VLEN(type->info); > > + if (argc > 0) { > > + btf_param_t *args = (btf_param_t *)(type + 1); > > + int i; > > + > > + if (args[argc - 1].type == 0) /* variadic */ > > + return 0; > > + > > + for (i = 0; i < argc; i++) { > > + type = dt_btf_real_type_by_id(dtp, btf, args[i].type); > > + if (type == NULL) > > + return 0; > > + > > + switch (BTF_INFO_KIND(type->info)) { > > + case BTF_KIND_STRUCT: > > + case BTF_KIND_UNION: > > + if (type->size > 16) /* value size > 16 */ > > + return 0; > > + default: > > + /* fall-through */ > > + } > > + } > > + } > > + > > + return 1; > > +} > > diff --git a/libdtrace/dt_btf.h b/libdtrace/dt_btf.h > > index d956ad940..2c921a033 100644 > > --- a/libdtrace/dt_btf.h > > +++ b/libdtrace/dt_btf.h > > @@ -28,6 +28,8 @@ extern int dt_btf_func_argc(dtrace_hdl_t *dtp, const dt_btf_t *btf, > > uint32_t id); > > extern int dt_btf_func_is_void(dtrace_hdl_t *dtp, const dt_btf_t *btf, > > uint32_t id); > > +extern int dt_btf_func_is_traceable(dtrace_hdl_t *dtp, const dt_btf_t *btf, > > + uint32_t id); > > extern int dt_btf_get_module_ids(dtrace_hdl_t *); > > extern int dt_btf_module_fd(const dt_module_t *); > > -- > NULL && (void)