Skip to content

Commit

Permalink
perf annotate-data: Handle PC-relative addressing
Browse files Browse the repository at this point in the history
Extend find_data_type_die() to find data type from PC-relative address
using die_find_variable_by_addr().  Users need to pass the address for
the (global) variable.

The offset for the variable should be updated after finding the type
because the offset in the instruction is just to calcuate the address
for the variable.  So it changed to pass a pointer to offset and renamed
it to 'poffset'.

First it searches variables in the CU DIE as it's likely that the global
variables are defined in the file level.  And then it iterates the scope
DIEs to find a local (static) variable.

Reviewed-by: Ian Rogers <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Namhyung Kim <[email protected]>
  • Loading branch information
namhyung committed Jan 22, 2024
1 parent 7a54f1d commit 83bfa06
Showing 1 changed file with 38 additions and 18 deletions.
56 changes: 38 additions & 18 deletions tools/perf/util/annotate-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "debuginfo.h"
#include "debug.h"
#include "dso.h"
#include "dwarf-regs.h"
#include "evsel.h"
#include "evlist.h"
#include "map.h"
Expand Down Expand Up @@ -193,7 +194,8 @@ static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die)
}

/* The type info will be saved in @type_die */
static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset)
static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset,
bool is_pointer)
{
Dwarf_Word size;

Expand All @@ -205,15 +207,18 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset)
}

/*
* It expects a pointer type for a memory access.
* Convert to a real type it points to.
* Usually it expects a pointer type for a memory access.
* Convert to a real type it points to. But global variables
* are accessed directly without a pointer.
*/
if ((dwarf_tag(type_die) != DW_TAG_pointer_type &&
dwarf_tag(type_die) != DW_TAG_array_type) ||
die_get_real_type(type_die, type_die) == NULL) {
pr_debug("no pointer or no type\n");
ann_data_stat.no_typeinfo++;
return -1;
if (is_pointer) {
if ((dwarf_tag(type_die) != DW_TAG_pointer_type &&
dwarf_tag(type_die) != DW_TAG_array_type) ||
die_get_real_type(type_die, type_die) == NULL) {
pr_debug("no pointer or no type\n");
ann_data_stat.no_typeinfo++;
return -1;
}
}

/* Get the size of the actual type */
Expand All @@ -234,7 +239,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset)
}

/* The result will be saved in @type_die */
static int find_data_type_die(struct debuginfo *di, u64 pc,
static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr,
struct annotated_op_loc *loc, Dwarf_Die *type_die)
{
Dwarf_Die cu_die, var_die;
Expand All @@ -250,21 +255,36 @@ static int find_data_type_die(struct debuginfo *di, u64 pc,
return -1;
}

/* Get a list of nested scopes - i.e. (inlined) functions and blocks. */
nr_scopes = die_get_scopes(&cu_die, pc, &scopes);

reg = loc->reg1;
offset = loc->offset;

if (reg == DWARF_REG_PC &&
die_find_variable_by_addr(&cu_die, pc, addr, &var_die, &offset)) {
ret = check_variable(&var_die, type_die, offset,
/*is_pointer=*/false);
goto out;
}

/* Get a list of nested scopes - i.e. (inlined) functions and blocks. */
nr_scopes = die_get_scopes(&cu_die, pc, &scopes);

retry:
/* Search from the inner-most scope to the outer */
for (i = nr_scopes - 1; i >= 0; i--) {
/* Look up variables/parameters in this scope */
if (!die_find_variable_by_reg(&scopes[i], pc, reg, &var_die))
continue;
if (reg == DWARF_REG_PC) {
if (!die_find_variable_by_addr(&scopes[i], pc, addr,
&var_die, &offset))
continue;
} else {
/* Look up variables/parameters in this scope */
if (!die_find_variable_by_reg(&scopes[i], pc, reg,
&var_die))
continue;
}

/* Found a variable, see if it's correct */
ret = check_variable(&var_die, type_die, offset);
ret = check_variable(&var_die, type_die, offset,
reg != DWARF_REG_PC);
goto out;
}

Expand Down Expand Up @@ -312,7 +332,7 @@ struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
* a file address for DWARF processing.
*/
pc = map__rip_2objdump(ms->map, ip);
if (find_data_type_die(di, pc, loc, &type_die) < 0)
if (find_data_type_die(di, pc, 0, loc, &type_die) < 0)
goto out;

result = dso__findnew_data_type(dso, &type_die);
Expand Down

0 comments on commit 83bfa06

Please sign in to comment.