lkml.org 
[lkml]   [2023]   [Nov]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 50/52] perf annotate-data: Track instructions with a this-cpu variable
    Date
    Like global variables, this per-cpu variables should be tracked
    correctly. Factor our get_global_var_type() to handle both global
    and per-cpu (for this cpu) variables in the same manner.

    Signed-off-by: Namhyung Kim <namhyung@kernel.org>
    ---
    tools/perf/util/annotate-data.c | 84 +++++++++++++++++++++++----------
    1 file changed, 60 insertions(+), 24 deletions(-)

    diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
    index 56dfbddb53d2..416c0b5649fc 100644
    --- a/tools/perf/util/annotate-data.c
    +++ b/tools/perf/util/annotate-data.c
    @@ -409,6 +409,37 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc,
    }
    }

    +static bool get_global_var_type(Dwarf_Die *cu_die, struct map_symbol *ms, u64 ip,
    + u64 var_addr, const char *var_name, int var_offset,
    + Dwarf_Die *type_die)
    +{
    + u64 pc;
    + int offset = var_offset;
    + bool is_pointer = false;
    + Dwarf_Die var_die;
    +
    + pc = map__rip_2objdump(ms->map, ip);
    +
    + /* Try to get the variable by address first */
    + if (die_find_variable_by_addr(cu_die, pc, var_addr, &var_die, &offset) &&
    + check_variable(&var_die, type_die, offset, is_pointer) == 0 &&
    + die_get_member_type(type_die, offset, type_die))
    + return true;
    +
    + if (var_name == NULL)
    + return false;
    +
    + offset = var_offset;
    +
    + /* 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, offset, is_pointer) == 0 &&
    + die_get_member_type(type_die, offset, type_die))
    + return true;
    +
    + return false;
    +}
    +
    /**
    * update_insn_state - Update type state for an instruction
    * @state: type state table
    @@ -472,14 +503,36 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc,
    fbreg = -1;
    }

    - /* Case 1. register to register transfers */
    + /* Case 1. register to register or segment:offset to register transfers */
    if (!src->mem_ref && !dst->mem_ref) {
    if (!has_reg_type(state, dst->reg1))
    return;

    if (has_reg_type(state, src->reg1))
    state->regs[dst->reg1] = state->regs[src->reg1];
    - else
    + else if (dloc->ms->map->dso->kernel &&
    + src->segment == INSN_SEG_X86_GS) {
    + struct map_symbol *ms = dloc->ms;
    + int offset = src->offset;
    + u64 ip = ms->sym->start + dl->al.offset;
    + const char *var_name = NULL;
    + u64 var_addr;
    +
    + /*
    + * In kernel, %gs points to a per-cpu region for the
    + * current CPU. Access with a constant offset should
    + * be treated as a global variable access.
    + */
    + var_addr = src->offset;
    + get_percpu_var_info(dloc->thread, ms, dloc->cpumode,
    + var_addr, &var_name, &offset);
    +
    + if (get_global_var_type(cu_die, ms, ip, var_addr,
    + var_name, offset, &type_die)) {
    + state->regs[dst->reg1].type = type_die;
    + state->regs[dst->reg1].ok = true;
    + }
    + } else
    state->regs[dst->reg1].ok = false;
    }
    /* Case 2. memory to register transers */
    @@ -492,37 +545,20 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc,
    retry:
    /* Check if it's a global variable */
    if (sreg == DWARF_REG_PC) {
    - Dwarf_Die var_die;
    struct map_symbol *ms = dloc->ms;
    int offset = src->offset;
    u64 ip = ms->sym->start + dl->al.offset;
    - u64 pc, addr;
    const char *var_name = NULL;
    + u64 var_addr;

    - addr = annotate_calc_pcrel(ms, ip, offset, dl);
    - pc = map__rip_2objdump(ms->map, ip);
    -
    - if (die_find_variable_by_addr(cu_die, pc, addr,
    - &var_die, &offset) &&
    - check_variable(&var_die, &type_die, offset,
    - /*is_pointer=*/false) == 0 &&
    - die_get_member_type(&type_die, offset, &type_die)) {
    - state->regs[dst->reg1].type = type_die;
    - state->regs[dst->reg1].ok = true;
    - return;
    - }
    + var_addr = annotate_calc_pcrel(ms, ip, offset, dl);

    - /* Try to get the name of global variable */
    - offset = src->offset;
    get_global_var_info(dloc->thread, ms, ip, dl,
    - dloc->cpumode, &addr,
    + dloc->cpumode, &var_addr,
    &var_name, &offset);

    - if (var_name && die_find_variable_at(cu_die, var_name,
    - pc, &var_die) &&
    - check_variable(&var_die, &type_die, offset,
    - /*is_pointer=*/false) == 0 &&
    - die_get_member_type(&type_die, offset, &type_die)) {
    + if (get_global_var_type(cu_die, ms, ip, var_addr,
    + var_name, offset, &type_die)) {
    state->regs[dst->reg1].type = type_die;
    state->regs[dst->reg1].ok = true;
    } else
    --
    2.42.0.869.gea05f2083d-goog
    \
     
     \ /
      Last update: 2023-11-20 13:54    [W:6.509 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site