perf annotate-data: Handle this-cpu variables in kernel
On x86, the kernel gets the current task using the current macro like below: #define current get_current() static __always_inline struct task_struct *get_current(void) { return this_cpu_read_stable(pcpu_hot.current_task); } So it returns the current_task field of struct pcpu_hot which is the first member. On my build, it's located at 0x32940. $ nm vmlinux | grep pcpu_hot 0000000000032940 D pcpu_hot And the current macro generates the instructions like below: mov %gs:0x32940, %rcx So the %gs segment register points to the beginning of the per-cpu region of this cpu and it points the variable with a constant. Let's update the instruction location info to have a segment register and handle %gs in kernel to look up a global variable. Pretend it as a global variable by changing the register number to DWARF_REG_PC. Signed-off-by: Namhyung 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-18-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
cbaf89a8c5
commit
02e17ca917
@ -790,7 +790,7 @@ static void delete_var_types(struct die_var_type *var_types)
|
||||
/* It's at the target address, check if it has a matching type */
|
||||
static bool check_matching_type(struct type_state *state,
|
||||
struct data_loc_info *dloc, int reg,
|
||||
Dwarf_Die *type_die)
|
||||
Dwarf_Die *cu_die, Dwarf_Die *type_die)
|
||||
{
|
||||
Dwarf_Word size;
|
||||
u32 insn_offset = dloc->ip - dloc->ms->sym->start;
|
||||
@ -864,6 +864,23 @@ static bool check_matching_type(struct type_state *state,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) {
|
||||
u64 addr;
|
||||
int offset;
|
||||
|
||||
if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm) {
|
||||
pr_debug_dtp(" this-cpu var\n");
|
||||
|
||||
addr = dloc->op->offset;
|
||||
|
||||
if (get_global_var_type(cu_die, dloc, dloc->ip, addr,
|
||||
&offset, type_die)) {
|
||||
dloc->type_offset = offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug_dtp("\n");
|
||||
return false;
|
||||
}
|
||||
@ -897,7 +914,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg,
|
||||
|
||||
if (this_ip == dloc->ip) {
|
||||
found = check_matching_type(&state, dloc, reg,
|
||||
type_die);
|
||||
cu_die, type_die);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -3921,6 +3921,13 @@ retry:
|
||||
op_loc->offset, dl);
|
||||
}
|
||||
|
||||
/* This CPU access in kernel - pretend PC-relative addressing */
|
||||
if (map__dso(ms->map)->kernel && arch__is(arch, "x86") &&
|
||||
op_loc->segment == INSN_SEG_X86_GS && op_loc->imm) {
|
||||
dloc.var_addr = op_loc->offset;
|
||||
op_loc->reg1 = DWARF_REG_PC;
|
||||
}
|
||||
|
||||
mem_type = find_data_type(&dloc);
|
||||
if (mem_type)
|
||||
istat->good++;
|
||||
|
Loading…
x
Reference in New Issue
Block a user