[PATCH 29/48] perf annotate-data: Handle PC-relative addressing
From: Namhyung Kim
Date: Wed Oct 11 2023 - 23:54:37 EST
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.
Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
---
tools/perf/util/annotate-data.c | 56 ++++++++++++++++++++++-----------
1 file changed, 38 insertions(+), 18 deletions(-)
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index a4276106e8a8..3d4bd5040782 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -13,6 +13,7 @@
#include "debuginfo.h"
#include "debug.h"
#include "dso.h"
+#include "dwarf-regs.h"
#include "evsel.h"
#include "evlist.h"
#include "map.h"
@@ -210,7 +211,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;
@@ -222,15 +224,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 */
@@ -251,7 +256,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;
@@ -267,21 +272,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;
}
@@ -329,7 +349,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);
--
2.42.0.655.g421f12c284-goog