diff --git a/tools/perf/arch/x86/annotate/instructions.c b/tools/perf/arch/x86/annotate/instructions.c index 15dfc2988e24..5caf5a17f03d 100644 --- a/tools/perf/arch/x86/annotate/instructions.c +++ b/tools/perf/arch/x86/annotate/instructions.c @@ -267,6 +267,7 @@ static void update_insn_state_x86(struct type_state *state, return; tsr = &state->regs[dst->reg1]; + tsr->copied_from = -1; if (src->imm) imm_value = src->offset; @@ -326,6 +327,8 @@ static void update_insn_state_x86(struct type_state *state, return; tsr = &state->regs[dst->reg1]; + tsr->copied_from = -1; + if (dso__kernel(map__dso(dloc->ms->map)) && src->segment == INSN_SEG_X86_GS && src->imm) { u64 ip = dloc->ms->sym->start + dl->al.offset; @@ -386,6 +389,10 @@ static void update_insn_state_x86(struct type_state *state, tsr->imm_value = state->regs[src->reg1].imm_value; tsr->ok = true; + /* To copy back the variable type later (hopefully) */ + if (tsr->kind == TSR_KIND_TYPE) + tsr->copied_from = src->reg1; + pr_debug_dtp("mov [%x] reg%d -> reg%d", insn_offset, src->reg1, dst->reg1); pr_debug_type_name(&tsr->type, tsr->kind); @@ -398,6 +405,7 @@ static void update_insn_state_x86(struct type_state *state, return; tsr = &state->regs[dst->reg1]; + tsr->copied_from = -1; retry: /* Check stack variables with offset */ diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 5d23c30b3a7b..a0ea4e07e570 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -774,6 +774,11 @@ ok: return true; } +static bool die_is_same(Dwarf_Die *die_a, Dwarf_Die *die_b) +{ + return (die_a->cu == die_b->cu) && (die_a->addr == die_b->addr); +} + /** * update_var_state - Update type state using given variables * @state: type state table @@ -825,6 +830,7 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } else if (has_reg_type(state, var->reg) && var->offset == 0) { struct type_state_reg *reg; + Dwarf_Die orig_type; reg = &state->regs[var->reg]; @@ -832,6 +838,8 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo !is_better_type(®->type, &mem_die)) continue; + orig_type = reg->type; + reg->type = mem_die; reg->kind = TSR_KIND_TYPE; reg->ok = true; @@ -839,6 +847,29 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo pr_debug_dtp("var [%"PRIx64"] reg%d", insn_offset, var->reg); pr_debug_type_name(&mem_die, TSR_KIND_TYPE); + + /* + * If this register is directly copied from another and it gets a + * better type, also update the type of the source register. This + * is usually the case of container_of() macro with offset of 0. + */ + if (has_reg_type(state, reg->copied_from)) { + struct type_state_reg *copy_reg; + + copy_reg = &state->regs[reg->copied_from]; + + /* TODO: check if type is compatible or embedded */ + if (!copy_reg->ok || (copy_reg->kind != TSR_KIND_TYPE) || + !die_is_same(©_reg->type, &orig_type) || + !is_better_type(©_reg->type, &mem_die)) + continue; + + copy_reg->type = mem_die; + + pr_debug_dtp("var [%"PRIx64"] copyback reg%d", + insn_offset, reg->copied_from); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); + } } } } diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 37a1a3b68e0b..8ac0fd94a0ba 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -176,6 +176,7 @@ struct type_state_reg { bool ok; bool caller_saved; u8 kind; + u8 copied_from; }; /* Type information in a stack location, dynamically allocated */