summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/arch/x86/annotate/instructions.c8
-rw-r--r--tools/perf/util/annotate-data.c31
-rw-r--r--tools/perf/util/annotate-data.h1
3 files changed, 40 insertions, 0 deletions
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(&reg->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(&copy_reg->type, &orig_type) ||
+ !is_better_type(&copy_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 */