Message ID | 20241211021227.2341735-1-eddyz87@gmail.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | [dwarves,v1,1/2] btf_loader: support for multiple BTF_DECL_TAGs pointing to same tag | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Not a local patch |
On 11/12/2024 02:12, Eduard Zingerman wrote: > btf_loader issues a warning when it sees several BTF_DECL_TAGs > pointing to the same type. Such situation is possible in practice > after patch [0], that marks certain functions with kfunc and > bpf_fastcall tags. E.g.: > > $ pfunct vmlinux -F btf -f bpf_rdonly_cast > WARNING: still unsuported BTF_KIND_DECL_TAG(bpf_fastcall) for bpf_cast_to_kern_ctx already with attribute (bpf_kfunc), ignoring > WARNING: still unsuported BTF_KIND_DECL_TAG(bpf_fastcall) for bpf_rdonly_cast already with attribute (bpf_kfunc), ignoring > bpf_kfunc void * bpf_rdonly_cast(const void * obj__ign, u32 btf_id__k); > > This commit extends 'struct tag' to allow attaching multiple > attributes. Define 'struct attributes' as follows: > > struct attributes { > uint64_t cnt; > const char *values[]; > }; > > In order to avoid adding counter field in 'struct tag', > as not many instances of 'struct tag' would have attributes. > > Same command after this patch: > > $ pfunct vmlinux -F btf -f bpf_rdonly_cast > bpf_kfunc bpf_fastcall void * bpf_rdonly_cast(const void * obj__ign, u32 btf_id__k); > > [0] https://lore.kernel.org/dwarves/094b626d44e817240ae8e44b6f7933b13c26d879.camel@gmail.com/T/#m8a6cb49a99d1b2ba38d616495a540ae8fc5f3a76 > > Reported-by: Arnaldo Carvalho de Melo <acme@kernel.org> > Closes: https://lore.kernel.org/dwarves/Z1dFXVFYmQ-nHSVO@x1/ > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Looks good to me. I _think_ we're safe enough in assuming the tag ordering "bpf_kfunc bpf_fastcall" in the btf_functions.sh test, right? Reviewed-by: Alan Maguire <alan.maguire@oracle.com> Tested-by: Alan Maguire <alan.maguire@oracle.com> > --- > btf_loader.c | 31 +++++++++++++++++++++++-------- > dwarf_loader.c | 2 +- > dwarves.c | 3 +++ > dwarves.h | 8 +++++++- > dwarves_fprintf.c | 6 ++++-- > tests/btf_functions.sh | 2 +- > 6 files changed, 39 insertions(+), 13 deletions(-) > > diff --git a/btf_loader.c b/btf_loader.c > index 4814f29..af9e1db 100644 > --- a/btf_loader.c > +++ b/btf_loader.c > @@ -459,9 +459,28 @@ static int create_new_tag(struct cu *cu, int type, const struct btf_type *tp, ui > return 0; > } > > +static struct attributes *attributes__realloc(struct attributes *attributes, const char *value) > +{ > + struct attributes *result; > + uint64_t cnt; > + size_t sz; > + > + cnt = attributes ? attributes->cnt : 0; > + sz = sizeof(*attributes) + (cnt + 1) * sizeof(*attributes->values); > + result = realloc(attributes, sz); > + if (!result) > + return NULL; > + if (!attributes) > + result->cnt = 0; > + result->values[cnt] = value; > + result->cnt++; > + return result; > +} > + > static int process_decl_tag(struct cu *cu, const struct btf_type *tp) > { > struct tag *tag = cu__type(cu, tp->type); > + struct attributes *tmp; > > if (tag == NULL) > tag = cu__function(cu, tp->type); > @@ -475,15 +494,11 @@ static int process_decl_tag(struct cu *cu, const struct btf_type *tp) > } > > const char *attribute = cu__btf_str(cu, tp->name_off); > + tmp = attributes__realloc(tag->attributes, attribute); > + if (!tmp) > + return -ENOMEM; > > - if (tag->attribute != NULL) { > - char bf[128]; > - > - fprintf(stderr, "WARNING: still unsuported BTF_KIND_DECL_TAG(%s) for %s already with attribute (%s), ignoring\n", > - attribute, tag__name(tag, cu, bf, sizeof(bf), NULL), tag->attribute); > - } else { > - tag->attribute = attribute; > - } > + tag->attributes = tmp; > > return 0; > } > diff --git a/dwarf_loader.c b/dwarf_loader.c > index 598fde4..34376b2 100644 > --- a/dwarf_loader.c > +++ b/dwarf_loader.c > @@ -513,7 +513,7 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die) > > dwarf_tag__set_attr_type(dtag, abstract_origin, die, DW_AT_abstract_origin); > tag->recursivity_level = 0; > - tag->attribute = NULL; > + tag->attributes = NULL; > > if (cu->extra_dbg_info) { > pthread_mutex_lock(&libdw__lock); > diff --git a/dwarves.c b/dwarves.c > index ae512b9..f970dd2 100644 > --- a/dwarves.c > +++ b/dwarves.c > @@ -210,6 +210,9 @@ void tag__delete(struct tag *tag, struct cu *cu) > > assert(list_empty(&tag->node)); > > + if (tag->attributes) > + free(tag->attributes); > + > switch (tag->tag) { > case DW_TAG_union_type: > type__delete(tag__type(tag), cu); break; > diff --git a/dwarves.h b/dwarves.h > index 1cb0d62..0a4d5a2 100644 > --- a/dwarves.h > +++ b/dwarves.h > @@ -516,10 +516,16 @@ int cu__for_all_tags(struct cu *cu, > struct cu *cu, void *cookie), > void *cookie); > > +struct attributes { > + uint64_t cnt; > + const char *values[]; > +}; > + > /** struct tag - basic representation of a debug info element > * @priv - extra data, for instance, DWARF offset, id, decl_{file,line} > * @top_level - > * @shared_tags: used by struct namespace > + * @attributes - attributes specified by BTF_DECL_TAGs targeting this tag > */ > struct tag { > struct list_head node; > @@ -530,7 +536,7 @@ struct tag { > bool has_btf_type_tag:1; > bool shared_tags:1; > uint8_t recursivity_level; > - const char *attribute; > + struct attributes *attributes; > }; > > // To use with things like type->type_enum == perf_event_type+perf_user_event_type > diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c > index e16a6b4..c3e7f3c 100644 > --- a/dwarves_fprintf.c > +++ b/dwarves_fprintf.c > @@ -1405,9 +1405,11 @@ static size_t function__fprintf(const struct tag *tag, const struct cu *cu, > struct ftype *ftype = func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto; > size_t printed = 0; > bool inlined = !conf->strip_inline && function__declared_inline(func); > + int i; > > - if (tag->attribute) > - printed += fprintf(fp, "%s ", tag->attribute); > + if (tag->attributes) > + for (i = 0; i < tag->attributes->cnt; ++i) > + printed += fprintf(fp, "%s ", tag->attributes->values[i]); > > if (func->virtuality == DW_VIRTUALITY_virtual || > func->virtuality == DW_VIRTUALITY_pure_virtual) > diff --git a/tests/btf_functions.sh b/tests/btf_functions.sh > index 61f8a00..c92e5ae 100755 > --- a/tests/btf_functions.sh > +++ b/tests/btf_functions.sh > @@ -66,7 +66,7 @@ pfunct --all --no_parm_names --format_path=dwarf $vmlinux | \ > sort|uniq > $outdir/dwarf.funcs > # all functions from BTF (removing bpf_kfunc prefix where found) > pfunct --all --no_parm_names --format_path=btf $outdir/vmlinux.btf 2>/dev/null|\ > - awk '{ gsub("^bpf_kfunc ",""); print $0}'|sort|uniq > $outdir/btf.funcs > + awk '{ gsub("^(bpf_kfunc |bpf_fastcall )+",""); print $0}'|sort|uniq > $outdir/btf.funcs > > exact=0 > inline=0
On Thu, 2024-12-12 at 20:29 +0000, Alan Maguire wrote: [...] > Looks good to me. I _think_ we're safe enough in assuming the tag > ordering "bpf_kfunc bpf_fastcall" in the btf_functions.sh test, right? For "bpf_kfunc bpf_fastcall" yes, we should be safe. On the other hand, I don't think the below could be simplified with this knowledge: + awk '{ gsub("^(bpf_kfunc |bpf_fastcall )+",""); print $0}'|sort|uniq Because there are situations when only "bpf_kfunc" is present and when both "bpf_kfunc", "bpf_fastcall" are present. [...]
diff --git a/btf_loader.c b/btf_loader.c index 4814f29..af9e1db 100644 --- a/btf_loader.c +++ b/btf_loader.c @@ -459,9 +459,28 @@ static int create_new_tag(struct cu *cu, int type, const struct btf_type *tp, ui return 0; } +static struct attributes *attributes__realloc(struct attributes *attributes, const char *value) +{ + struct attributes *result; + uint64_t cnt; + size_t sz; + + cnt = attributes ? attributes->cnt : 0; + sz = sizeof(*attributes) + (cnt + 1) * sizeof(*attributes->values); + result = realloc(attributes, sz); + if (!result) + return NULL; + if (!attributes) + result->cnt = 0; + result->values[cnt] = value; + result->cnt++; + return result; +} + static int process_decl_tag(struct cu *cu, const struct btf_type *tp) { struct tag *tag = cu__type(cu, tp->type); + struct attributes *tmp; if (tag == NULL) tag = cu__function(cu, tp->type); @@ -475,15 +494,11 @@ static int process_decl_tag(struct cu *cu, const struct btf_type *tp) } const char *attribute = cu__btf_str(cu, tp->name_off); + tmp = attributes__realloc(tag->attributes, attribute); + if (!tmp) + return -ENOMEM; - if (tag->attribute != NULL) { - char bf[128]; - - fprintf(stderr, "WARNING: still unsuported BTF_KIND_DECL_TAG(%s) for %s already with attribute (%s), ignoring\n", - attribute, tag__name(tag, cu, bf, sizeof(bf), NULL), tag->attribute); - } else { - tag->attribute = attribute; - } + tag->attributes = tmp; return 0; } diff --git a/dwarf_loader.c b/dwarf_loader.c index 598fde4..34376b2 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -513,7 +513,7 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die) dwarf_tag__set_attr_type(dtag, abstract_origin, die, DW_AT_abstract_origin); tag->recursivity_level = 0; - tag->attribute = NULL; + tag->attributes = NULL; if (cu->extra_dbg_info) { pthread_mutex_lock(&libdw__lock); diff --git a/dwarves.c b/dwarves.c index ae512b9..f970dd2 100644 --- a/dwarves.c +++ b/dwarves.c @@ -210,6 +210,9 @@ void tag__delete(struct tag *tag, struct cu *cu) assert(list_empty(&tag->node)); + if (tag->attributes) + free(tag->attributes); + switch (tag->tag) { case DW_TAG_union_type: type__delete(tag__type(tag), cu); break; diff --git a/dwarves.h b/dwarves.h index 1cb0d62..0a4d5a2 100644 --- a/dwarves.h +++ b/dwarves.h @@ -516,10 +516,16 @@ int cu__for_all_tags(struct cu *cu, struct cu *cu, void *cookie), void *cookie); +struct attributes { + uint64_t cnt; + const char *values[]; +}; + /** struct tag - basic representation of a debug info element * @priv - extra data, for instance, DWARF offset, id, decl_{file,line} * @top_level - * @shared_tags: used by struct namespace + * @attributes - attributes specified by BTF_DECL_TAGs targeting this tag */ struct tag { struct list_head node; @@ -530,7 +536,7 @@ struct tag { bool has_btf_type_tag:1; bool shared_tags:1; uint8_t recursivity_level; - const char *attribute; + struct attributes *attributes; }; // To use with things like type->type_enum == perf_event_type+perf_user_event_type diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c index e16a6b4..c3e7f3c 100644 --- a/dwarves_fprintf.c +++ b/dwarves_fprintf.c @@ -1405,9 +1405,11 @@ static size_t function__fprintf(const struct tag *tag, const struct cu *cu, struct ftype *ftype = func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto; size_t printed = 0; bool inlined = !conf->strip_inline && function__declared_inline(func); + int i; - if (tag->attribute) - printed += fprintf(fp, "%s ", tag->attribute); + if (tag->attributes) + for (i = 0; i < tag->attributes->cnt; ++i) + printed += fprintf(fp, "%s ", tag->attributes->values[i]); if (func->virtuality == DW_VIRTUALITY_virtual || func->virtuality == DW_VIRTUALITY_pure_virtual) diff --git a/tests/btf_functions.sh b/tests/btf_functions.sh index 61f8a00..c92e5ae 100755 --- a/tests/btf_functions.sh +++ b/tests/btf_functions.sh @@ -66,7 +66,7 @@ pfunct --all --no_parm_names --format_path=dwarf $vmlinux | \ sort|uniq > $outdir/dwarf.funcs # all functions from BTF (removing bpf_kfunc prefix where found) pfunct --all --no_parm_names --format_path=btf $outdir/vmlinux.btf 2>/dev/null|\ - awk '{ gsub("^bpf_kfunc ",""); print $0}'|sort|uniq > $outdir/btf.funcs + awk '{ gsub("^(bpf_kfunc |bpf_fastcall )+",""); print $0}'|sort|uniq > $outdir/btf.funcs exact=0 inline=0
btf_loader issues a warning when it sees several BTF_DECL_TAGs pointing to the same type. Such situation is possible in practice after patch [0], that marks certain functions with kfunc and bpf_fastcall tags. E.g.: $ pfunct vmlinux -F btf -f bpf_rdonly_cast WARNING: still unsuported BTF_KIND_DECL_TAG(bpf_fastcall) for bpf_cast_to_kern_ctx already with attribute (bpf_kfunc), ignoring WARNING: still unsuported BTF_KIND_DECL_TAG(bpf_fastcall) for bpf_rdonly_cast already with attribute (bpf_kfunc), ignoring bpf_kfunc void * bpf_rdonly_cast(const void * obj__ign, u32 btf_id__k); This commit extends 'struct tag' to allow attaching multiple attributes. Define 'struct attributes' as follows: struct attributes { uint64_t cnt; const char *values[]; }; In order to avoid adding counter field in 'struct tag', as not many instances of 'struct tag' would have attributes. Same command after this patch: $ pfunct vmlinux -F btf -f bpf_rdonly_cast bpf_kfunc bpf_fastcall void * bpf_rdonly_cast(const void * obj__ign, u32 btf_id__k); [0] https://lore.kernel.org/dwarves/094b626d44e817240ae8e44b6f7933b13c26d879.camel@gmail.com/T/#m8a6cb49a99d1b2ba38d616495a540ae8fc5f3a76 Reported-by: Arnaldo Carvalho de Melo <acme@kernel.org> Closes: https://lore.kernel.org/dwarves/Z1dFXVFYmQ-nHSVO@x1/ Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> --- btf_loader.c | 31 +++++++++++++++++++++++-------- dwarf_loader.c | 2 +- dwarves.c | 3 +++ dwarves.h | 8 +++++++- dwarves_fprintf.c | 6 ++++-- tests/btf_functions.sh | 2 +- 6 files changed, 39 insertions(+), 13 deletions(-)