Commit 1ebb5e17 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

perf annotate-data: Add get_global_var_type()

Accessing global variable is common when it tracks execution later.
Factor out the common code into a function for later use.

It adds thread and cpumode to struct data_loc_info to find (global)
symbols if needed.  Also remove var_name as it's retrieved in the
helper function.
Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20240319055115.4063940-12-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 4f903455
......@@ -22,6 +22,7 @@
#include "strbuf.h"
#include "symbol.h"
#include "symbol_conf.h"
#include "thread.h"
#define pr_debug_dtp(fmt, ...) \
do { \
......@@ -382,6 +383,50 @@ static struct type_state_stack *findnew_stack_state(struct type_state *state,
return stack;
}
static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc,
u64 ip, u64 var_addr, int *var_offset,
Dwarf_Die *type_die)
{
u64 pc, mem_addr;
int offset;
bool is_pointer = false;
const char *var_name = NULL;
Dwarf_Die var_die;
struct addr_location al;
struct symbol *sym;
/* Try to get the variable by address first */
if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) &&
check_variable(&var_die, type_die, offset, is_pointer) == 0) {
*var_offset = offset;
return true;
}
/* Kernel symbols might be relocated */
mem_addr = var_addr + map__reloc(dloc->ms->map);
addr_location__init(&al);
sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode,
mem_addr, &al);
if (sym) {
var_name = sym->name;
/* Calculate type offset from the start of variable */
*var_offset = mem_addr - map__unmap_ip(al.map, sym->start);
}
addr_location__exit(&al);
if (var_name == NULL)
return false;
pc = map__rip_2objdump(dloc->ms->map, ip);
/* Try to get the name of global variable */
if (die_find_variable_at(cu_die, var_name, pc, &var_die) &&
check_variable(&var_die, type_die, *var_offset, is_pointer) == 0)
return true;
return false;
}
/**
* update_var_state - Update type state using given variables
* @state: type state table
......@@ -637,24 +682,14 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die)
pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die));
if (reg == DWARF_REG_PC) {
if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die,
&offset)) {
ret = check_variable(&var_die, type_die, offset,
/*is_pointer=*/false);
if (get_global_var_type(&cu_die, dloc, dloc->ip, dloc->var_addr,
&offset, type_die)) {
dloc->type_offset = offset;
pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x\n",
dloc->var_addr, offset);
goto out;
}
if (dloc->var_name &&
die_find_variable_at(&cu_die, dloc->var_name, pc, &var_die)) {
ret = check_variable(&var_die, type_die, dloc->type_offset,
/*is_pointer=*/false);
/* dloc->type_offset was updated by the caller */
goto out;
}
}
/* Get a list of nested scopes - i.e. (inlined) functions and blocks. */
......@@ -769,8 +804,7 @@ struct annotated_data_type *find_data_type(struct data_loc_info *dloc)
* The type offset is the same as instruction offset by default.
* But when finding a global variable, the offset won't be valid.
*/
if (dloc->var_name == NULL)
dloc->type_offset = dloc->op->offset;
dloc->type_offset = dloc->op->offset;
dloc->fbreg = -1;
......
......@@ -11,6 +11,7 @@ struct annotated_op_loc;
struct debuginfo;
struct evsel;
struct map_symbol;
struct thread;
/**
* struct annotated_member - Type of member field
......@@ -76,10 +77,11 @@ extern struct annotated_data_type stackop_type;
/**
* struct data_loc_info - Data location information
* @arch: CPU architecture info
* @thread: Thread info
* @ms: Map and Symbol info
* @ip: Instruction address
* @var_addr: Data address (for global variables)
* @var_name: Variable name (for global variables)
* @cpumode: CPU execution mode
* @op: Instruction operand location (regs and offset)
* @di: Debug info
* @fbreg: Frame base register
......@@ -89,10 +91,11 @@ extern struct annotated_data_type stackop_type;
struct data_loc_info {
/* These are input field, should be filled by caller */
struct arch *arch;
struct thread *thread;
struct map_symbol *ms;
u64 ip;
u64 var_addr;
const char *var_name;
u8 cpumode;
struct annotated_op_loc *op;
/* These are used internally */
......
......@@ -3873,9 +3873,11 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
for_each_insn_op_loc(&loc, i, op_loc) {
struct data_loc_info dloc = {
.arch = arch,
.thread = he->thread,
.ms = ms,
/* Recalculate IP for LOCK prefix or insn fusion */
.ip = ms->sym->start + dl->al.offset,
.cpumode = he->cpumode,
.op = op_loc,
};
......@@ -3887,23 +3889,8 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
/* PC-relative addressing */
if (op_loc->reg1 == DWARF_REG_PC) {
struct addr_location al;
struct symbol *var;
u64 map_addr;
dloc.var_addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl);
/* Kernel symbols might be relocated */
map_addr = dloc.var_addr + map__reloc(ms->map);
addr_location__init(&al);
var = thread__find_symbol_fb(he->thread, he->cpumode,
map_addr, &al);
if (var) {
dloc.var_name = var->name;
/* Calculate type offset from the start of variable */
dloc.type_offset = map_addr - map__unmap_ip(al.map, var->start);
}
addr_location__exit(&al);
dloc.var_addr = annotate_calc_pcrel(ms, dloc.ip,
op_loc->offset, dl);
}
mem_type = find_data_type(&dloc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment