From: Zecheng Li Date: Mon, 9 Mar 2026 17:55:14 +0000 (-0400) Subject: perf dwarf-aux: Add die_get_pointer_type to get pointer types X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30b2e6fa58f3b9eff86fb851a8926bf814d82dcd;p=thirdparty%2Fkernel%2Flinux.git 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 Signed-off-by: Namhyung Kim --- diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 44fbd41e38451..cda020ea18d52 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -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 @@ again: 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 @@ again: * 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 @@ again: } /* 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; diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 9267af204c7d5..38142062d6e5f 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -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) diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index cd481ec9c5a1c..99d2735122d5f 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -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);