[PATCH 08/16] encoders: Handle DW_TAG_subprogram in enumerations during BTF/CTF encoding

Arnaldo Carvalho de Melo <[email protected]> Mon, 22 Jun 2026 17:24:31 -0300
Newsgroups org.kernel.vger.dwarves
Message-ID <[email protected]>
From: Arnaldo Carvalho de Melo <[email protected]>

Since commit 5c0162ee40f06c95 ("dwarf_loader: Initial support for
DW_TAG_subprogram in DW_TAG_enumeration"), Rust enumerations with
associated functions (impl blocks) are loaded with DW_TAG_subprogram
children in their namespace.

However, the BTF and CTF encoders were not aware of this and treated
these subprogram tags as unexpected, producing noisy warnings:

  Unexpected DW_TAG_subprogram <0>, skipping it...

This was problematic for real Rust binaries.  For instance, BTF encoding
the sashiko-cli Rust binary produced 653 such warnings from enumerations
like Ordering (137), ChunkedState (106), TlsState (20), and others.
Even the Rust standard library object produced 8 warnings.

Since BTF and CTF have no representation for subprograms inside
enumerations, we should skip them, but inform the user about it rather
than warn about an unexpected tag.

Switch the enumerator iteration in both encoders from an if/continue
pattern to a proper switch statement:

  - DW_TAG_enumerator: processed normally
  - DW_TAG_subprogram: silently skipped (BTF logs it in verbose mode)
  - anything else: still warned about with the enumeration name for
    better diagnostics

Before:

  $ pahole --btf_encode sashiko-cli 2>&1 | grep -c subprogram
  653

After:

  $ pahole --btf_encode sashiko-cli 2>&1 | grep -c subprogram
  0

  $ pahole -V --btf_encode sashiko-cli 2>&1 | grep -c 'subprogram in enumeration'
  653

Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
 btf_encoder.c | 22 +++++++++++++++-------
 ctf_encoder.c | 15 ++++++++++-----
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index 82dd5f27138c2949..dc1e18a986605d04 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -1798,14 +1798,22 @@ static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct ta
 		return type_id;
 
 	type__for_each_enumerator(etype, pos) {
-		if (pos->tag.tag != DW_TAG_enumerator) {
-			fprintf(stderr, "Unexpected DW_TAG_%s <%llx>, skipping it...\n",
-				dwarf_tag_name(pos->tag.tag), tag__orig_id(&pos->tag, cu));
-			continue;
+		switch (pos->tag.tag) {
+		case DW_TAG_enumerator:
+			name = enumerator__name(pos);
+			if (btf_encoder__add_enum_val(encoder, name, pos->value, etype, conf_load))
+				return -1;
+			break;
+		case DW_TAG_subprogram:
+			if (encoder->verbose)
+				fprintf(stderr, "BTF: DW_TAG_subprogram in enumeration '%s' not supported, skipping\n",
+					type__name(etype) ?: "(anonymous)");
+			break;
+		default:
+			fprintf(stderr, "BTF: unexpected DW_TAG_%s in enumeration '%s', skipping\n",
+				dwarf_tag_name(pos->tag.tag), type__name(etype) ?: "(anonymous)");
+			break;
 		}
-		name = enumerator__name(pos);
-		if (btf_encoder__add_enum_val(encoder, name, pos->value, etype, conf_load))
-			return -1;
 	}
 
 	return type_id;
diff --git a/ctf_encoder.c b/ctf_encoder.c
index f2c63c2b039026f8..f9e75a5821ce4e83 100644
--- a/ctf_encoder.c
+++ b/ctf_encoder.c
@@ -155,12 +155,17 @@ static int enumeration_type__encode(struct tag *tag, const struct cu *cu, uint32
 
 	struct enumerator *pos;
 	type__for_each_enumerator(etype, pos) {
-		if (pos->tag.tag != DW_TAG_enumerator) {
-			fprintf(stderr, "Unexpected DW_TAG_%s <%llx>, skipping it...\n",
-				dwarf_tag_name(pos->tag.tag), tag__orig_id(&pos->tag, cu));
-			continue;
+		switch (pos->tag.tag) {
+		case DW_TAG_enumerator:
+			ctf__add_enumerator(ctf, pos->name, pos->value, &position);
+			break;
+		case DW_TAG_subprogram:
+			break;
+		default:
+			fprintf(stderr, "CTF: unexpected DW_TAG_%s in enumeration '%s', skipping\n",
+				dwarf_tag_name(pos->tag.tag), type__name(etype) ?: "(anonymous)");
+			break;
 		}
-		ctf__add_enumerator(ctf, pos->name, pos->value, &position);
 	}
 
 	return 0;
-- 
2.54.0