From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Alan Maguire <alan.maguire@oracle.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
Clark Williams <williams@redhat.com>,
dwarves@vger.kernel.org,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: [PATCH 03/16] dwarf_loader: Initial support for DW_TAG_subprogram in DW_TAG_enumeration
Date: Mon, 22 Jun 2026 17:24:26 -0300 [thread overview]
Message-ID: <20260622202441.14799-4-acme@kernel.org> (raw)
In-Reply-To: <20260622202441.14799-1-acme@kernel.org>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
In Rust enums can have subprograms, add initial support for it.
Example of a Rust enumeration with a DW_TAG_subprogram tag.
$ pahole -C ProgramKind /tmp/build/perf-tools-next/tests/workloads/code_with_type.a
enum ProgramKind {
PathLookup = 0,
Relative = 1,
Absolute = 2,
enum ProgramKind new(struct &std::ffi::os_str::OsStr),
} __attribute__((__packed__));
$
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
btf_encoder.c | 13 ++++++++----
ctf_encoder.c | 16 +++++++++-----
dwarf_loader.c | 39 +++++++++++++++++++++++++++-------
dwarves.c | 3 +++
dwarves.h | 2 +-
dwarves_emit.c | 10 ++++-----
dwarves_fprintf.c | 54 +++++++++++++++++++++++++++++++++++------------
pahole.c | 9 +++++---
8 files changed, 106 insertions(+), 40 deletions(-)
diff --git a/btf_encoder.c b/btf_encoder.c
index d5af706d7638470d..b6814f6a92899d07 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -1786,7 +1786,7 @@ static uint32_t array_type__nelems(struct tag *tag)
}
static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct tag *tag,
- struct conf_load *conf_load)
+ const struct cu *cu, struct conf_load *conf_load)
{
struct type *etype = tag__type(tag);
struct enumerator *pos;
@@ -1798,6 +1798,11 @@ 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(tag->tag), tag__orig_id(tag, cu));
+ continue;
+ }
name = enumerator__name(pos);
if (btf_encoder__add_enum_val(encoder, name, pos->value, etype, conf_load))
return -1;
@@ -1807,7 +1812,7 @@ static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct ta
}
static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
- struct conf_load *conf_load)
+ const struct cu *cu, struct conf_load *conf_load)
{
/* single out type 0 as it represents special type "void" */
uint32_t ref_type_id = tag->type == 0 ? 0 : encoder->type_id_off + tag->type;
@@ -1847,7 +1852,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
encoder->need_index_type = true;
return btf_encoder__add_array(encoder, ref_type_id, encoder->array_index_id, array_type__nelems(tag));
case DW_TAG_enumeration_type:
- return btf_encoder__add_enum_type(encoder, tag, conf_load);
+ return btf_encoder__add_enum_type(encoder, tag, cu, conf_load);
case DW_TAG_subroutine_type:
return btf_encoder__add_func_proto_for_ftype(encoder, tag__ftype(tag));
case DW_TAG_unspecified_type:
@@ -2906,7 +2911,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
}
cu__for_each_type(cu, core_id, pos) {
- btf_type_id = btf_encoder__encode_tag(encoder, pos, conf_load);
+ btf_type_id = btf_encoder__encode_tag(encoder, pos, cu, conf_load);
if (btf_type_id == 0) {
++skipped_types;
diff --git a/ctf_encoder.c b/ctf_encoder.c
index b761287d45348c59..1c61c76ba20e06bc 100644
--- a/ctf_encoder.c
+++ b/ctf_encoder.c
@@ -142,7 +142,7 @@ static int subroutine_type__encode(struct tag *tag, uint32_t core_id, struct ctf
return 0;
}
-static int enumeration_type__encode(struct tag *tag, uint32_t core_id, struct ctf *ctf)
+static int enumeration_type__encode(struct tag *tag, const struct cu *cu, uint32_t core_id, struct ctf *ctf)
{
struct type *etype = tag__type(tag);
int64_t position;
@@ -154,13 +154,19 @@ static int enumeration_type__encode(struct tag *tag, uint32_t core_id, struct ct
return -1;
struct enumerator *pos;
- type__for_each_enumerator(etype, 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(tag->tag), tag__orig_id(tag, cu));
+ continue;
+ }
ctf__add_enumerator(ctf, pos->name, pos->value, &position);
+ }
return 0;
}
-static void tag__encode_ctf(struct tag *tag, uint32_t core_id, struct ctf *ctf)
+static void tag__encode_ctf(struct tag *tag, const struct cu *cu, uint32_t core_id, struct ctf *ctf)
{
switch (tag->tag) {
case DW_TAG_base_type:
@@ -190,7 +196,7 @@ static void tag__encode_ctf(struct tag *tag, uint32_t core_id, struct ctf *ctf)
subroutine_type__encode(tag, core_id, ctf);
break;
case DW_TAG_enumeration_type:
- enumeration_type__encode(tag, core_id, ctf);
+ enumeration_type__encode(tag, cu, core_id, ctf);
break;
}
}
@@ -253,7 +259,7 @@ int cu__encode_ctf(struct cu *cu, int verbose)
uint32_t id;
struct tag *pos;
cu__for_each_type(cu, id, pos)
- tag__encode_ctf(pos, id, ctf);
+ tag__encode_ctf(pos, cu, id, ctf);
struct hlist_head hash_addr[HASHADDR__SIZE];
diff --git a/dwarf_loader.c b/dwarf_loader.c
index a29caccead6d1eb1..956532bbc5a35410 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -2038,6 +2038,8 @@ out_delete:
return NULL;
}
+static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu, struct conf_load *conf);
+
static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
@@ -2059,18 +2061,39 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, st
die = &child;
do {
- struct enumerator *enumerator;
+ switch (dwarf_tag(die)) {
+ case DW_TAG_enumerator: {
+ struct enumerator *enumerator = enumerator__new(die, cu, conf);
+
+ if (enumerator == NULL)
+ goto out_delete;
+
+ enumeration__add(enumeration, enumerator);
+ cu__hash(cu, &enumerator->tag);
+ }
+ continue;
+ case DW_TAG_subprogram: {
+ struct tag *tag = die__create_new_function(die, cu, conf);
+ uint32_t id;
+
+ if (tag == NULL)
+ goto out_delete;
+
+ if (cu__table_add_tag(cu, tag, &id) < 0) {
+ tag__delete(tag, cu);
+ goto out_delete;
+ }
- if (dwarf_tag(die) != DW_TAG_enumerator) {
+ struct dwarf_tag *dtag = tag__dwarf(tag);
+ dtag->small_id = id;
+ namespace__add_tag(&enumeration->namespace, tag);
+ cu__hash(cu, tag);
+ break;
+ }
+ default:
cu__tag_not_handled(cu, die);
continue;
}
- enumerator = enumerator__new(die, cu, conf);
- if (enumerator == NULL)
- goto out_delete;
-
- enumeration__add(enumeration, enumerator);
- cu__hash(cu, &enumerator->tag);
} while (dwarf_siblingof(die, die) == 0);
out:
return &enumeration->namespace.tag;
diff --git a/dwarves.c b/dwarves.c
index 07acf00aaea42607..e530627073f7352e 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -2017,6 +2017,9 @@ static void enumeration__calc_prefix(struct type *enumeration)
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
+ if (entry->tag.tag != DW_TAG_enumerator)
+ continue;
+
const char *curr_name = enumerator__name(entry);
if (previous_name) {
diff --git a/dwarves.h b/dwarves.h
index 3b6f624716998fd7..638a469b11535061 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -1646,7 +1646,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
void enumeration__delete(struct type *type, struct cu *cu);
void enumeration__add(struct type *type, struct enumerator *enumerator);
-size_t enumeration__fprintf(const struct tag *tag_enum,
+size_t enumeration__fprintf(const struct tag *tag_enum, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
int dwarves__init(void);
diff --git a/dwarves_emit.c b/dwarves_emit.c
index 01b33b7ec41eb947..aaf0f8f9a7ea815a 100644
--- a/dwarves_emit.c
+++ b/dwarves_emit.c
@@ -100,7 +100,7 @@ static struct type *type_emissions__find_fwd_decl(const struct type_emissions *e
return NULL;
}
-static int enumeration__emit_definitions(struct tag *tag,
+static int enumeration__emit_definitions(struct tag *tag, const struct cu *cu,
struct type_emissions *emissions,
const struct conf_fprintf *conf,
FILE *fp)
@@ -121,7 +121,7 @@ static int enumeration__emit_definitions(struct tag *tag,
return 0;
}
- enumeration__fprintf(tag, conf, fp);
+ enumeration__fprintf(tag, cu, conf, fp);
fputs(";\n", fp);
// See comment on enumeration__fprintf(), it seems this happens with DWARF as well
@@ -198,10 +198,10 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
if (type__name(ctype) == NULL) {
fputs("typedef ", fp);
conf.suffix = type__name(def);
- enumeration__emit_definitions(type, emissions, &conf, fp);
+ enumeration__emit_definitions(type, cu, emissions, &conf, fp);
goto out;
} else
- enumeration__emit_definitions(type, emissions, &conf, fp);
+ enumeration__emit_definitions(type, cu, emissions, &conf, fp);
}
break;
case DW_TAG_structure_type:
@@ -380,7 +380,7 @@ next_indirection:
struct conf_fprintf conf = {
.suffix = NULL,
};
- return enumeration__emit_definitions(type, emissions, &conf, fp);
+ return enumeration__emit_definitions(type, cu, emissions, &conf, fp);
}
break;
case DW_TAG_structure_type:
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index ab1c381db64651c6..acbfbc091c9f86dc 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -155,6 +155,8 @@ const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
static size_t union__fprintf(struct type *type, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
+static size_t function__fprintf(const struct tag *tag, const struct cu *cu,
+ const struct conf_fprintf *conf, FILE *fp);
/*
* In dwarves_emit.c we can call type__emit() using a locally setup conf_fprintf for which
@@ -406,7 +408,7 @@ next_type:
struct conf_fprintf tconf = *pconf;
tconf.suffix = type__name(type);
- return printed + enumeration__fprintf(tag_type, &tconf, fp);
+ return printed + enumeration__fprintf(tag_type, cu, &tconf, fp);
}
}
@@ -450,7 +452,15 @@ static int enumeration__max_entry_name_len(struct type *type)
struct enumerator *pos;
type__for_each_enumerator(type, pos) {
- int len = strlen(enumerator__name(pos));
+ int len = 0;
+
+ if (pos->tag.tag == DW_TAG_enumerator)
+ len = strlen(enumerator__name(pos));
+ else if (pos->tag.tag == DW_TAG_subprogram) {
+ const char *fname = function__name(tag__function(&pos->tag));
+ if (fname)
+ len = strlen(fname);
+ }
if (type->max_tag_name_len < len)
type->max_tag_name_len = len;
@@ -459,7 +469,8 @@ out:
return type->max_tag_name_len;
}
-size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
+size_t enumeration__fprintf(const struct tag *tag, const struct cu *cu,
+ const struct conf_fprintf *conf, FILE *fp)
{
struct type *type = tag__type(tag);
struct enumerator *pos;
@@ -480,13 +491,25 @@ size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *co
}
type__for_each_enumerator(type, pos) {
- printed += fprintf(fp, "%.*s\t%-*s = ", indent, tabs,
- max_entry_name_len, enumerator__name(pos));
- if (conf->hex_fmt)
- printed += fprintf(fp, "%#llx", (unsigned long long)pos->value);
- else
- printed += fprintf(fp, type->is_signed_enum ? "%lld" : "%llu",
- (unsigned long long)pos->value);
+ printed += fprintf(fp, "%.*s\t", indent, tabs);
+
+ switch (pos->tag.tag) {
+ case DW_TAG_subprogram:
+ function__fprintf(&pos->tag, cu, conf, fp);
+ break;
+ case DW_TAG_enumerator:
+ printed += fprintf(fp, "%-*s = ", max_entry_name_len, enumerator__name(pos));
+ if (conf->hex_fmt)
+ printed += fprintf(fp, "%#llx", (unsigned long long)pos->value);
+ else
+ printed += fprintf(fp, type->is_signed_enum ? "%lld" : "%llu",
+ (unsigned long long)pos->value);
+ break;
+ default:
+ printed += fprintf(fp, "/* Unexpected %s <%llx> */\n", dwarf_tag_name(tag->tag),
+ tag__orig_id(tag, cu));
+ continue;
+ }
printed += fprintf(fp, ",\n");
}
@@ -586,9 +609,12 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu,
strncpy(bf, name, len);
}
break;
- case DW_TAG_subprogram:
- strncpy(bf, function__name(tag__function(tag)), len);
+ case DW_TAG_subprogram: {
+ const char *fname = function__name(tag__function(tag));
+ if (fname)
+ strncpy(bf, fname, len);
break;
+ }
case DW_TAG_pointer_type:
return tag__ptr_name(tag, cu, bf, len, "*", conf);
case DW_TAG_reference_type:
@@ -937,7 +963,7 @@ print_modifier: {
if (type__name(ctype) != NULL && !expand_types)
printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
else
- printed += enumeration__fprintf(type, &tconf, fp);
+ printed += enumeration__fprintf(type, cu, &tconf, fp);
break;
case DW_TAG_LLVM_annotation:
case DW_TAG_GNU_annotation: {
@@ -2174,7 +2200,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
printed += array_type__fprintf(tag, cu, "array", pconf, fp);
break;
case DW_TAG_enumeration_type:
- printed += enumeration__fprintf(tag, pconf, fp);
+ printed += enumeration__fprintf(tag, cu, pconf, fp);
break;
case DW_TAG_typedef:
printed += typedef__fprintf(tag, cu, pconf, fp);
diff --git a/pahole.c b/pahole.c
index 28d8f8832773520b..765da575f3dab39a 100644
--- a/pahole.c
+++ b/pahole.c
@@ -2155,7 +2155,7 @@ static const char *enumeration__lookup_value(struct type *enumeration, uint64_t
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
- if (entry->value == value)
+ if (entry->tag.tag == DW_TAG_enumerator && entry->value == value)
return enumerator__name(entry);
}
@@ -2180,7 +2180,7 @@ static struct enumerator *enumeration__lookup_entry_from_value(struct type *enum
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
- if (entry->value == value)
+ if (entry->tag.tag == DW_TAG_enumerator && entry->value == value)
return entry;
}
@@ -2206,6 +2206,9 @@ static struct enumerator *enumeration__find_enumerator(struct type *enumeration,
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
+ if (entry->tag.tag != DW_TAG_enumerator)
+ continue;
+
const char *entry_name = enumerator__name(entry);
if (!strcmp(entry_name, name))
@@ -3204,7 +3207,7 @@ static bool print_enumeration_with_enumerator(struct cu *cu, const char *name)
cu__for_each_enumeration(cu, id, enumeration) {
if (enumeration__find_enumerator(enumeration, name) != NULL) {
- enumeration__fprintf(type__tag(enumeration), &conf, stdout);
+ enumeration__fprintf(type__tag(enumeration), cu, &conf, stdout);
fputc('\n', stdout);
return true;
}
--
2.54.0
next prev parent reply other threads:[~2026-06-22 20:24 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-22 20:24 [PATCHES v3 0/7] Initial support for some Rust tags, DW_TAG_imported_unit Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 01/16] dwarf_loader: Initial support for DW_TAG_variant_part Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 02/16] dwarf_loader: Allow forcing the merge of CUs for solving inter CU tag references Arnaldo Carvalho de Melo
2026-06-22 20:24 ` Arnaldo Carvalho de Melo [this message]
2026-06-22 20:24 ` [PATCH 04/16] encoders: Fix diagnostic messages for unexpected tags in enumerations Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 05/16] dwarves_fprintf: Accumulate function__fprintf return value in enumeration printing Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 06/16] dwarves: Use tag__delete for enumeration children Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 07/16] btf_encoder: Fix types__match parameter comparison in BTF_KIND_FUNC_PROTO Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 08/16] encoders: Handle DW_TAG_subprogram in enumerations during BTF/CTF encoding Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 09/16] dwarf_loader: Populate DW_TAG_variant children in DW_TAG_variant_part Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 10/16] btf_encoder: Encode variant parts as union members in BTF Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 11/16] dwarf_loader: Handle DW_FORM_block in attr_numeric for Rust discriminant values Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 12/16] dwarf_loader: Support DW_TAG_imported_unit for same-file partial units Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 13/16] dwarf_loader: Fix cus__merging_cu failing to detect DW_FORM_ref_addr Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 14/16] tests: Add inter-CU type reference comparison test Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 15/16] tests: Guard cleanup() against empty outdir to prevent rm /* Arnaldo Carvalho de Melo
2026-06-22 20:24 ` [PATCH 16/16] tests: Source test_lib.sh via dirname so tests run from any directory Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260622202441.14799-4-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=alan.maguire@oracle.com \
--cc=dwarves@vger.kernel.org \
--cc=jolsa@kernel.org \
--cc=williams@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox