When adding a kfunc prototype to BTF, check for the flags indicating bpf_arena pointers and emit a type tag encoding __attribute__((address_space(1))) for them. This also requires updating BTF type ids in the btf_encoder_func_state, which is done as a side effect in the tagging functions. This feature depends on recent update in libbpf, supporting arbitrarty attribute encoding [1]. [1] https://lore.kernel.org/bpf/20250130201239.1429648-1-ihor.solodrai@xxxxxxxxx/ Signed-off-by: Ihor Solodrai <ihor.solodrai@xxxxxxxxx> Reviewed-by: Alan Maguire <alan.maguire@xxxxxxxxxx> Reviewed-by: Jiri Olsa <jolsa@xxxxxxxxxx> --- btf_encoder.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++- dwarves.h | 1 + 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/btf_encoder.c b/btf_encoder.c index 12a040f..991aba6 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -41,7 +41,13 @@ #define BTF_SET8_KFUNCS (1 << 0) #define BTF_KFUNC_TYPE_TAG "bpf_kfunc" #define BTF_FASTCALL_TAG "bpf_fastcall" -#define KF_FASTCALL (1 << 12) +#define BPF_ARENA_ATTR "address_space(1)" + +/* kfunc flags, see include/linux/btf.h in the kernel source */ +#define KF_FASTCALL (1 << 12) +#define KF_ARENA_RET (1 << 13) +#define KF_ARENA_ARG1 (1 << 14) +#define KF_ARENA_ARG2 (1 << 15) struct btf_id_and_flag { uint32_t id; @@ -718,6 +724,81 @@ static int32_t btf_encoder__tag_type(struct btf_encoder *encoder, uint32_t tag_t return encoder->type_id_off + tag_type; } +static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id) +{ + const struct btf_type *ptr; + int tagged_type_id; + + ptr = btf__type_by_id(btf, ptr_id); + if (!btf_is_ptr(ptr)) + return -EINVAL; + + tagged_type_id = btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr->type); + if (tagged_type_id < 0) + return tagged_type_id; + + return btf__add_ptr(btf, tagged_type_id); +} + +static int btf__tag_bpf_arena_arg(struct btf *btf, struct btf_encoder_func_state *state, int idx) +{ + int id; + + if (state->nr_parms <= idx) + return -EINVAL; + + id = btf__tag_bpf_arena_ptr(btf, state->parms[idx].type_id); + if (id < 0) { + btf__log_err(btf, BTF_KIND_TYPE_TAG, BPF_ARENA_ATTR, true, id, + "Error adding BPF_ARENA_ATTR for an argument of kfunc '%s'", state->elf->name); + return id; + } + state->parms[idx].type_id = id; + + return id; +} + +static int btf__add_bpf_arena_type_tags(struct btf *btf, struct btf_encoder_func_state *state) +{ + uint32_t flags = state->elf->kfunc_flags; + int ret_type_id; + int err; + + if (!btf__add_type_attr) { + fprintf(stderr, "btf__add_type_attr is not available, is libbpf < 1.6?\n"); + return -ENOTSUP; + } + + if (KF_ARENA_RET & flags) { + ret_type_id = btf__tag_bpf_arena_ptr(btf, state->ret_type_id); + if (ret_type_id < 0) { + btf__log_err(btf, BTF_KIND_TYPE_TAG, BPF_ARENA_ATTR, true, ret_type_id, + "Error adding BPF_ARENA_ATTR for return type of kfunc '%s'", state->elf->name); + return ret_type_id; + } + state->ret_type_id = ret_type_id; + } + + if (KF_ARENA_ARG1 & flags) { + err = btf__tag_bpf_arena_arg(btf, state, 0); + if (err < 0) + return err; + } + + if (KF_ARENA_ARG2 & flags) { + err = btf__tag_bpf_arena_arg(btf, state, 1); + if (err < 0) + return err; + } + + return 0; +} + +static inline bool is_kfunc_state(struct btf_encoder_func_state *state) +{ + return state && state->elf && state->elf->kfunc; +} + static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct ftype *ftype, struct btf_encoder_func_state *state) { @@ -731,6 +812,10 @@ static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct f assert(ftype != NULL || state != NULL); + if (is_kfunc_state(state) && encoder->tag_kfuncs) + if (btf__add_bpf_arena_type_tags(encoder->btf, state) < 0) + return -1; + /* add btf_type for func_proto */ if (ftype) { btf = encoder->btf; diff --git a/dwarves.h b/dwarves.h index ab32204..4202dfb 100644 --- a/dwarves.h +++ b/dwarves.h @@ -52,6 +52,7 @@ enum load_steal_kind { struct btf; __weak extern int btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz, bool is_signed); __weak extern int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value); +__weak extern int btf__add_type_attr(struct btf *btf, const char *value, int ref_type_id); __weak extern int btf__distill_base(const struct btf *src_btf, struct btf **new_base_btf, struct btf **new_split_btf); /* -- 2.48.1