[PATCH 1/3] perf dwarf-aux: Add die_is_compound_type() to handle C++ class types

From: Yanbo Zhao

Date: Fri Aug 21 2026 - 01:03:10 EST


Introduce the die_is_compound_type() helper which checks for
DW_TAG_structure_type, DW_TAG_union_type, and DW_TAG_class_type, and
convert all the existing open-coded struct/union tag checks to use it:
- die_get_member_type() in dwarf-aux.c.
- __add_member_cb(), is_compound_type(), and set_stack_state() in
annotate-data.c.

Also accept DW_TAG_inheritance in the member lookup callbacks
(__die_find_member_offset_cb() and __add_member_cb()) so that member
lookup by offset descends into C++ base class subobjects.

This extends the existing member type resolution and data type
profiling state handling to C++ classes with inheritance without
changing behavior for C struct/union types.

Signed-off-by: Yanbo Zhao <yzhao62@xxxxxxxx>
---
tools/perf/util/annotate-data.c | 29 ++++++-----------------------
tools/perf/util/dwarf-aux.c | 17 ++++++++++++-----
tools/perf/util/dwarf-aux.h | 3 +++
3 files changed, 21 insertions(+), 28 deletions(-)

diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 4e4c58764082..ee6bd2d0012d 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -230,9 +230,9 @@ static int __add_member_cb(Dwarf_Die *die, void *arg)
Dwarf_Word size, loc, bit_size = 0;
Dwarf_Attribute attr;
struct strbuf sb;
- int tag;
+ int tag = dwarf_tag(die);

- if (dwarf_tag(die) != DW_TAG_member)
+ if (tag != DW_TAG_member && tag != DW_TAG_inheritance)
return DIE_FIND_CB_SIBLING;

member = zalloc(sizeof(*member));
@@ -292,15 +292,8 @@ static int __add_member_cb(Dwarf_Die *die, void *arg)
INIT_LIST_HEAD(&member->children);
list_add_tail(&member->node, &parent->children);

- tag = dwarf_tag(&die_mem);
- switch (tag) {
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
+ if (die_is_compound_type(&die_mem))
die_find_child(&die_mem, __add_member_cb, member, &die_mem);
- break;
- default:
- break;
- }
return DIE_FIND_CB_SIBLING;
}

@@ -464,9 +457,7 @@ static const char *match_result_str(enum type_match_result tmr)

static bool is_compound_type(Dwarf_Die *type_die)
{
- int tag = dwarf_tag(type_die);
-
- return tag == DW_TAG_structure_type || tag == DW_TAG_union_type;
+ return die_is_compound_type(type_die);
}

/* returns if Type B has better information than Type A */
@@ -584,7 +575,6 @@ struct type_state_stack *find_stack_state(struct type_state *state,
void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
Dwarf_Die *type_die, int ptr_offset)
{
- int tag;
Dwarf_Word size;

if (kind == TSR_KIND_POINTER) {
@@ -605,17 +595,10 @@ void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
return;
}

- tag = dwarf_tag(type_die);
-
- switch (tag) {
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
+ if (die_is_compound_type(type_die))
stack->compound = (kind != TSR_KIND_PERCPU_POINTER);
- break;
- default:
+ else
stack->compound = false;
- break;
- }
}

struct type_state_stack *findnew_stack_state(struct type_state *state,
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index d7160f87ac7d..88ba0ec23a68 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -60,6 +60,14 @@ const char *cu_get_comp_dir(Dwarf_Die *cu_die)
return dwarf_formstring(&attr);
}

+bool die_is_compound_type(Dwarf_Die *type_die)
+{
+ int tag = dwarf_tag(type_die);
+
+ return tag == DW_TAG_structure_type || tag == DW_TAG_union_type ||
+ tag == DW_TAG_class_type;
+}
+
/* Unlike dwarf_getsrc_die(), cu_getsrc_die() only returns statement line */
static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr)
{
@@ -2053,7 +2061,7 @@ static int __die_find_member_offset_cb(Dwarf_Die *die_mem, void *arg)
Dwarf_Word offset = (long)arg;
int tag = dwarf_tag(die_mem);

- if (tag != DW_TAG_member)
+ if (tag != DW_TAG_member && tag != DW_TAG_inheritance)
return DIE_FIND_CB_SIBLING;

/* Unions might not have location */
@@ -2104,7 +2112,7 @@ Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset,

tag = dwarf_tag(type_die);
/* If it's not a compound type, return the type directly */
- if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
+ if (!die_is_compound_type(type_die)) {
Dwarf_Word size;

if (dwarf_aggregate_size(type_die, &size) < 0)
@@ -2119,7 +2127,7 @@ Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset,

mb_type = *type_die;
/* TODO: Handle union types better? */
- while (tag == DW_TAG_structure_type || tag == DW_TAG_union_type) {
+ while (die_is_compound_type(&mb_type)) {
member = die_find_child(&mb_type, __die_find_member_offset_cb,
(void *)(long)offset, die_mem);
if (member == NULL)
@@ -2130,8 +2138,7 @@ Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset,

tag = dwarf_tag(&mb_type);

- if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type ||
- tag == DW_TAG_array_type) {
+ if (die_is_compound_type(&mb_type) || tag == DW_TAG_array_type) {
Dwarf_Word loc;

/* Update offset for the start of the member struct */
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index 161f0bf980b6..855c45fec5bb 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -23,6 +23,9 @@ const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname);
/* Get DW_AT_comp_dir (should be NULL with older gcc) */
const char *cu_get_comp_dir(Dwarf_Die *cu_die);

+/* Check if DIE is a compound type (structure, union, or class) */
+bool die_is_compound_type(Dwarf_Die *type_die);
+
/* Get a line number and file name for given address */
int cu_find_lineinfo(Dwarf_Die *cudie, Dwarf_Addr addr,
const char **fname, int *lineno);
--
2.25.1