diff mbox series

[dwarves,v1,1/2] btf_loader: support for multiple BTF_DECL_TAGs pointing to same tag

Message ID 20241211021227.2341735-1-eddyz87@gmail.com (mailing list archive)
State New
Headers show
Series [dwarves,v1,1/2] btf_loader: support for multiple BTF_DECL_TAGs pointing to same tag | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Eduard Zingerman Dec. 11, 2024, 2:12 a.m. UTC
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(-)
diff mbox series

Patch

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