[PATCH dwarves 1/2] btf_loader: Attach decl tags to struct and union members

Alan Maguire <[email protected]> Fri, 19 Jun 2026 16:21:02 +0100
Newsgroups org.kernel.vger.dwarves
Message-ID <[email protected]>
BTF_KIND_DECL_TAG with a non-negative component_idx can target either a
function parameter or a struct/union member. The BTF loader only resolved
the function-parameter case, so member decl tags were left attached to the
aggregate type and were not shown by pahole.

Add member lookup by component_idx for struct/union types and print stored
attributes from class_member__fprintf().

Signed-off-by: Alan Maguire <[email protected]>
---
 btf_loader.c      | 35 +++++++++++++++++++++++++++++++++--
 dwarves_fprintf.c |  3 +++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/btf_loader.c b/btf_loader.c
index 92d4832..406ee28 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -506,10 +506,24 @@ static struct tag *function__parameter(const struct function *func, struct cu *c
 	return ftype__parameter(tag__ftype(tag), component_idx);
 }
 
+static struct tag *type__member(struct type *type, int component_idx)
+{
+	struct class_member *member;
+	int idx = 0;
+
+	type__for_each_data_member(type, member) {
+		if (idx == component_idx)
+			return &member->tag;
+		++idx;
+	}
+
+	return NULL;
+}
+
 static int process_decl_tag(struct cu *cu, const struct btf_type *tp)
 {
 	int component_idx = btf_decl_tag(tp)->component_idx;
-	struct tag *tag = cu__type(cu, tp->type);
+	struct tag *tag;
 	struct attributes *tmp;
 
 	tag = cu__function(cu, tp->type);
@@ -522,7 +536,24 @@ static int process_decl_tag(struct cu *cu, const struct btf_type *tp)
 		}
 	}
 
-	if (tag == NULL)
+	if (tag == NULL) {
+		tag = cu__type(cu, tp->type);
+
+		if (component_idx >= 0 && tag != NULL) {
+			if (tag != NULL && (tag__is_struct(tag) || tag__is_union(tag))) {
+				tag = type__member(tag__type(tag), component_idx);
+				if (tag == NULL) {
+					fprintf(stderr, "WARNING: BTF_KIND_DECL_TAG for unknown member %d in BTF id %d\n",
+						component_idx, tp->type);
+					return 0;
+				}
+			} else {
+				tag = NULL;
+			}
+		}
+	}
+
+	if (tag == NULL && component_idx < 0)
 		tag = cu__tag(cu, tp->type);
 
 	if (tag == NULL) {
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index ab1c381..04f6569 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -963,6 +963,7 @@ out_type_not_found:
 static size_t class__fprintf_cacheline_boundary(struct conf_fprintf *conf,
 						uint32_t offset,
 						FILE *fp);
+static size_t tag__attributes_fprintf(const struct tag *tag, FILE *fp);
 
 static size_t class_member__fprintf(struct class_member *member, bool union_member,
 				     struct tag *type, const struct cu *cu,
@@ -996,6 +997,8 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
 	if (member->is_static)
 		printed += fprintf(fp, "static ");
 
+	printed += tag__attributes_fprintf(&member->tag, fp);
+
 	/* For struct-like constructs, the name of the member cannot be
 	 * conflated with the name of its type, otherwise __attribute__ are
 	 * printed in the wrong order.
-- 
2.43.5