mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 06:31:58 +02:00
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:
parent
616cd6047c
commit
30b2e6fa58
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user