Commit 02e17ca9 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

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: 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-18-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent cbaf89a8
...@@ -790,7 +790,7 @@ static void delete_var_types(struct die_var_type *var_types) ...@@ -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 */ /* It's at the target address, check if it has a matching type */
static bool check_matching_type(struct type_state *state, static bool check_matching_type(struct type_state *state,
struct data_loc_info *dloc, int reg, struct data_loc_info *dloc, int reg,
Dwarf_Die *type_die) Dwarf_Die *cu_die, Dwarf_Die *type_die)
{ {
Dwarf_Word size; Dwarf_Word size;
u32 insn_offset = dloc->ip - dloc->ms->sym->start; u32 insn_offset = dloc->ip - dloc->ms->sym->start;
...@@ -864,6 +864,23 @@ static bool check_matching_type(struct type_state *state, ...@@ -864,6 +864,23 @@ static bool check_matching_type(struct type_state *state,
return true; 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"); pr_debug_dtp("\n");
return false; return false;
} }
...@@ -897,7 +914,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, ...@@ -897,7 +914,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg,
if (this_ip == dloc->ip) { if (this_ip == dloc->ip) {
found = check_matching_type(&state, dloc, reg, found = check_matching_type(&state, dloc, reg,
type_die); cu_die, type_die);
goto out; goto out;
} }
......
...@@ -3921,6 +3921,13 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) ...@@ -3921,6 +3921,13 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
op_loc->offset, dl); 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); mem_type = find_data_type(&dloc);
if (mem_type) if (mem_type)
istat->good++; istat->good++;
......
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