perf dwarf-aux: Add die_get_pointer_type to get pointer types

When a variable type is wrapped in typedef/qualifiers, callers may need
to first resolve it to the underlying DW_TAG_pointer_type or
DW_TAG_array_type. A simple tag check is not enough and directly calling
__die_get_real_type() can stop at the pointer type (e.g. typedef ->
pointer) instead of the pointee type.

Add die_get_pointer_type() helper that follows typedef/qualifier chains
and returns the underlying pointer DIE. Use it in annotate-data.c so
pointer checks and dereference work correctly for typedef'd pointers.

Signed-off-by: Zecheng Li <zli94@ncsu.edu>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Zecheng Li 2026-03-09 13:55:14 -04:00 committed by Namhyung Kim
parent 616cd6047c
commit 30b2e6fa58
3 changed files with 51 additions and 17 deletions

View File

@ -455,13 +455,6 @@ static const char *match_result_str(enum type_match_result tmr)
}
}
static bool is_pointer_type(Dwarf_Die *type_die)
{
int tag = dwarf_tag(type_die);
return tag == DW_TAG_pointer_type || tag == DW_TAG_array_type;
}
static bool is_compound_type(Dwarf_Die *type_die)
{
int tag = dwarf_tag(type_die);
@ -474,19 +467,24 @@ static bool is_better_type(Dwarf_Die *type_a, Dwarf_Die *type_b)
{
Dwarf_Word size_a, size_b;
Dwarf_Die die_a, die_b;
Dwarf_Die ptr_a, ptr_b;
Dwarf_Die *ptr_type_a, *ptr_type_b;
ptr_type_a = die_get_pointer_type(type_a, &ptr_a);
ptr_type_b = die_get_pointer_type(type_b, &ptr_b);
/* pointer type is preferred */
if (is_pointer_type(type_a) != is_pointer_type(type_b))
return is_pointer_type(type_b);
if ((ptr_type_a != NULL) != (ptr_type_b != NULL))
return ptr_type_b != NULL;
if (is_pointer_type(type_b)) {
if (ptr_type_b) {
/*
* We want to compare the target type, but 'void *' can fail to
* get the target type.
*/
if (die_get_real_type(type_a, &die_a) == NULL)
if (die_get_real_type(ptr_type_a, &die_a) == NULL)
return true;
if (die_get_real_type(type_b, &die_b) == NULL)
if (die_get_real_type(ptr_type_b, &die_b) == NULL)
return false;
type_a = &die_a;
@ -539,7 +537,7 @@ static enum type_match_result check_variable(struct data_loc_info *dloc,
* and local variables are accessed directly without a pointer.
*/
if (needs_pointer) {
if (!is_pointer_type(type_die) ||
if (die_get_pointer_type(type_die, type_die) == NULL ||
__die_get_real_type(type_die, type_die) == NULL)
return PERF_TMR_NO_POINTER;
}
@ -880,12 +878,16 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo
continue;
if (var->reg == DWARF_REG_FB || var->reg == fbreg || var->reg == state->stack_reg) {
Dwarf_Die ptr_die;
Dwarf_Die *ptr_type;
int offset = var->offset;
struct type_state_stack *stack;
ptr_type = die_get_pointer_type(&mem_die, &ptr_die);
/* If the reg location holds the pointer value, dereference the type */
if (!var->is_reg_var_addr && is_pointer_type(&mem_die) &&
__die_get_real_type(&mem_die, &mem_die) == NULL)
if (!var->is_reg_var_addr && ptr_type &&
__die_get_real_type(ptr_type, &mem_die) == NULL)
continue;
if (var->reg != DWARF_REG_FB)
@ -1110,7 +1112,9 @@ static enum type_match_result check_matching_type(struct type_state *state,
goto check_non_register;
if (state->regs[reg].kind == TSR_KIND_TYPE) {
Dwarf_Die ptr_die;
Dwarf_Die sized_type;
Dwarf_Die *ptr_type;
struct strbuf sb;
strbuf_init(&sb, 32);
@ -1122,7 +1126,8 @@ static enum type_match_result check_matching_type(struct type_state *state,
* Normal registers should hold a pointer (or array) to
* dereference a memory location.
*/
if (!is_pointer_type(&state->regs[reg].type)) {
ptr_type = die_get_pointer_type(&state->regs[reg].type, &ptr_die);
if (!ptr_type) {
if (dloc->op->offset < 0 && reg != state->stack_reg)
goto check_kernel;
@ -1130,7 +1135,7 @@ static enum type_match_result check_matching_type(struct type_state *state,
}
/* Remove the pointer and get the target type */
if (__die_get_real_type(&state->regs[reg].type, type_die) == NULL)
if (__die_get_real_type(ptr_type, type_die) == NULL)
return PERF_TMR_NO_POINTER;
dloc->type_offset = dloc->op->offset + state->regs[reg].offset;

View File

@ -303,6 +303,33 @@ Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
return vr_die;
}
/**
* die_get_pointer_type - Get a pointer/array type die
* @type_die: a DIE of a type
* @die_mem: where to store a type DIE
*
* Get a pointer/array type DIE from @type_die. If the type is a typedef or
* qualifier (const, volatile, etc.), follow the chain to find the underlying
* pointer type.
*/
Dwarf_Die *die_get_pointer_type(Dwarf_Die *type_die, Dwarf_Die *die_mem)
{
int tag;
do {
tag = dwarf_tag(type_die);
if (tag == DW_TAG_pointer_type || tag == DW_TAG_array_type)
return type_die;
if (tag != DW_TAG_typedef && tag != DW_TAG_const_type &&
tag != DW_TAG_restrict_type && tag != DW_TAG_volatile_type &&
tag != DW_TAG_shared_type)
return NULL;
type_die = die_get_type(type_die, die_mem);
} while (type_die);
return NULL;
}
/* Get attribute and translate it as a udata */
static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
Dwarf_Word *result)

View File

@ -60,6 +60,8 @@ Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
/* Get a type die, but skip qualifiers and typedef */
Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
/* Get a pointer/array type, following typedefs/qualifiers */
Dwarf_Die *die_get_pointer_type(Dwarf_Die *type_die, Dwarf_Die *die_mem);
/* Check whether the DIE is signed or not */
bool die_is_signed_type(Dwarf_Die *tp_die);