[PATCH 3/4] btf: add dt_btf_func_is_traceable()
Kris Van Hees <[email protected]> Tue, 14 Apr 2026 02:27:47 -0400
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <IA0PR10MB7325F8591942AB9F13EC9EE5C2252@IA0PR10MB7325.namprd10.prod.outlook.com> |
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. Signed-off-by: Kris Van Hees <[email protected]> --- 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 +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 *); -- 2.53.0