[PAHOLE v5 1/5] btf_loader: Handle decl tag component_idx for parameters

Vineet Gupta <[email protected]> Wed, 17 Jun 2026 17:57:27 -0700
Newsgroups org.kernel.vger.dwarves,org.kernel.vger.bpf
Message-ID <[email protected]>
From: Alan Maguire <[email protected]>

A BTF_KIND_DECL_TAG with a non-negative component_idx applies to a
specific function parameter (or struct/union member), not to the
function itself. btf_loader.c however attached every decl tag to the
type named by btf_type->type, so parameter decl tags were recorded on
the function rather than on the parameter, and pfunct never printed
them with the parameter.

Resolve a non-negative component_idx to the corresponding parameter via
new helpers ftype__parameter()/function__parameter(), and attach the
tag there. Teach the pretty printer to emit a parameter's attributes by
factoring the function-level attribute loop into tag__attributes_fprintf()
and calling it from ftype__fprintf_parms() for each parameter.

Signed-off-by: Alan Maguire <[email protected]>
Signed-off-by: Vineet Gupta <[email protected]>
---
 btf_loader.c      | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 dwarves_fprintf.c | 20 ++++++++++++++++----
 2 files changed, 61 insertions(+), 5 deletions(-)

diff --git a/btf_loader.c b/btf_loader.c
index b591219a245d..9bb52c3c5801 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -477,12 +477,56 @@ static struct attributes *attributes__realloc(struct attributes *attributes, con
 	return result;
 }
 
+static struct tag *ftype__parameter(const struct ftype *ftype, int component_idx)
+{
+	struct parameter *pos;
+	int idx = 0;
+
+	ftype__for_each_parameter(ftype, pos) {
+		if (idx == component_idx)
+			return &pos->tag;
+		++idx;
+	}
+
+	return NULL;
+}
+
+static struct tag *function__parameter(const struct function *func, struct cu *cu,
+				       int component_idx)
+{
+	struct tag *tag;
+
+	if (component_idx < 0)
+		return NULL;
+
+	tag = cu__type(cu, func->proto.tag.type);
+	if (tag == NULL)
+		return NULL;
+
+	return ftype__parameter(tag__ftype(tag), component_idx);
+}
+
 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 attributes *tmp;
 
-	if (tag == NULL)
+	if (component_idx >= 0) {
+		struct tag *func_tag = cu__function(cu, tp->type);
+
+		if (func_tag != NULL) {
+			tag = function__parameter(tag__function(func_tag), cu,
+						  component_idx);
+			if (tag == NULL) {
+				fprintf(stderr, "WARNING: BTF_KIND_DECL_TAG for unknown parameter %d in BTF id %d\n",
+					component_idx, tp->type);
+				return 0;
+			}
+		}
+	}
+
+	if (tag == NULL && component_idx < 0)
 		tag = cu__function(cu, tp->type);
 
 	if (tag == NULL)
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index 1ec478c2a027..54f483244bd2 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -1199,6 +1199,18 @@ const char *function__prototype(const struct function *func,
 					bf, len);
 }
 
+static size_t tag__attributes_fprintf(const struct tag *tag, FILE *fp)
+{
+	size_t printed = 0;
+	int i;
+
+	if (tag->attributes)
+		for (i = 0; i < tag->attributes->cnt; ++i)
+			printed += fprintf(fp, "%s ", tag->attributes->values[i]);
+
+	return printed;
+}
+
 size_t ftype__fprintf_parms(const struct ftype *ftype,
 			    const struct cu *cu, int indent,
 			    const struct conf_fprintf *conf, FILE *fp)
@@ -1240,6 +1252,7 @@ size_t ftype__fprintf_parms(const struct ftype *ftype,
 				if (n)
 					return printed + n;
 				if (ptype->tag == DW_TAG_subroutine_type) {
+					printed += tag__attributes_fprintf(&pos->tag, fp);
 					printed +=
 					     ftype__fprintf(tag__ftype(ptype),
 							    cu, name, 0, 1, 0,
@@ -1248,12 +1261,14 @@ size_t ftype__fprintf_parms(const struct ftype *ftype,
 				}
 			}
 		} else if (type->tag == DW_TAG_subroutine_type) {
+			printed += tag__attributes_fprintf(&pos->tag, fp);
 			printed += ftype__fprintf(tag__ftype(type), cu, name,
 						  true, 0, 0, 0, conf, fp);
 			continue;
 		}
 		stype = tag__name(type, cu, sbf, sizeof(sbf), conf);
 print_it:
+		printed += tag__attributes_fprintf(&pos->tag, fp);
 		printed += fprintf(fp, "%s%s%s", stype, name ? " " : "",
 				   name ?: "");
 	}
@@ -1405,11 +1420,8 @@ 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->attributes)
-		for (i = 0; i < tag->attributes->cnt; ++i)
-			printed += fprintf(fp, "%s ", tag->attributes->values[i]);
+	printed += tag__attributes_fprintf(tag, fp);
 
 	if (func->virtuality == DW_VIRTUALITY_virtual ||
 	    func->virtuality == DW_VIRTUALITY_pure_virtual)
-- 
2.54.0