diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/util/annotate-arch/annotate-x86.c | 25 | ||||
| -rw-r--r-- | tools/perf/util/annotate-data.c | 24 | ||||
| -rw-r--r-- | tools/perf/util/annotate-data.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.c | 6 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.h | 2 |
5 files changed, 54 insertions, 6 deletions
diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c index df9fc0a51b39..c77aabd48eba 100644 --- a/tools/perf/util/annotate-arch/annotate-x86.c +++ b/tools/perf/util/annotate-arch/annotate-x86.c @@ -208,6 +208,8 @@ static void invalidate_reg_state(struct type_state_reg *reg) { reg->kind = TSR_KIND_INVALID; reg->ok = false; + reg->lifetime_active = false; + reg->lifetime_end = 0; reg->copied_from = -1; } @@ -230,6 +232,7 @@ static void update_insn_state_x86(struct type_state *state, if (ins__is_call(&dl->ins)) { struct symbol *func = dl->ops.target.sym; const char *call_name; + u64 call_addr; /* Try to resolve the call target name */ if (func) @@ -246,10 +249,18 @@ static void update_insn_state_x86(struct type_state *state, else pr_debug_dtp("call [%x] <unknown>\n", insn_offset); - /* Invalidate caller-saved registers after call (ABI requirement) */ + /* Invalidate caller-saved registers after call */ + call_addr = map__rip_2objdump(dloc->ms->map, + dloc->ms->sym->start + dl->al.offset); for (unsigned i = 0; i < ARRAY_SIZE(state->regs); i++) { - if (state->regs[i].caller_saved) - invalidate_reg_state(&state->regs[i]); + struct type_state_reg *reg = &state->regs[i]; + + if (!reg->caller_saved) + continue; + /* Keep register valid within DWARF location lifetime */ + if (reg->lifetime_active && call_addr < reg->lifetime_end) + continue; + invalidate_reg_state(reg); } /* Update register with the return type (if any) */ @@ -279,6 +290,8 @@ static void update_insn_state_x86(struct type_state *state, tsr = &state->regs[dst->reg1]; tsr->copied_from = -1; + tsr->lifetime_active = false; + tsr->lifetime_end = 0; if (src->imm) imm_value = src->offset; @@ -344,6 +357,8 @@ static void update_insn_state_x86(struct type_state *state, tsr = &state->regs[dst->reg1]; tsr->copied_from = -1; + tsr->lifetime_active = false; + tsr->lifetime_end = 0; if (src->imm) imm_value = src->offset; @@ -458,6 +473,8 @@ static void update_insn_state_x86(struct type_state *state, state->regs[dst->reg1].kind = TSR_KIND_CONST; state->regs[dst->reg1].imm_value = 0; state->regs[dst->reg1].ok = true; + state->regs[dst->reg1].lifetime_active = false; + state->regs[dst->reg1].lifetime_end = 0; state->regs[dst->reg1].copied_from = -1; return; } @@ -544,6 +561,8 @@ static void update_insn_state_x86(struct type_state *state, tsr->kind = state->regs[src->reg1].kind; tsr->imm_value = state->regs[src->reg1].imm_value; tsr->offset = state->regs[src->reg1].offset; + tsr->lifetime_active = state->regs[src->reg1].lifetime_active; + tsr->lifetime_end = state->regs[src->reg1].lifetime_end; tsr->ok = true; /* To copy back the variable type later (hopefully) */ diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 50c82c91f828..1eff0a27237d 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -840,6 +840,18 @@ 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); } +static void tsr_set_lifetime(struct type_state_reg *tsr, + const struct die_var_type *var) +{ + if (var && var->has_range && var->end > var->addr) { + tsr->lifetime_active = true; + tsr->lifetime_end = var->end; + } else { + tsr->lifetime_active = false; + tsr->lifetime_end = 0; + } +} + /** * update_var_state - Update type state using given variables * @state: type state table @@ -865,8 +877,14 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo } for (var = var_types; var != NULL; var = var->next) { - if (var->addr != addr) - continue; + /* Check if addr falls within the variable's valid range */ + if (var->has_range) { + if (addr < var->addr || (var->end && addr >= var->end)) + continue; + } else { + if (addr != var->addr) + continue; + } /* Get the type DIE using the offset */ if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die)) continue; @@ -923,6 +941,7 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo reg->type = mem_die; reg->kind = TSR_KIND_POINTER; reg->ok = true; + tsr_set_lifetime(reg, var); pr_debug_dtp("var [%"PRIx64"] reg%d addr offset %x", insn_offset, var->reg, var->offset); @@ -939,6 +958,7 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo reg->type = mem_die; reg->kind = TSR_KIND_TYPE; reg->ok = true; + tsr_set_lifetime(reg, var); pr_debug_dtp("var [%"PRIx64"] reg%d offset %x", insn_offset, var->reg, var->offset); diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 9b222869e42d..c26130744260 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -182,6 +182,9 @@ struct type_state_reg { s32 offset; bool ok; bool caller_saved; + /* DWARF location range tracking for register lifetime */ + bool lifetime_active; + u64 lifetime_end; u8 kind; u8 copied_from; }; diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 1feefc329154..0710c875416f 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1641,7 +1641,7 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, void *arg) Dwarf_Die type_die; int tag = dwarf_tag(die_mem); Dwarf_Attribute attr; - Dwarf_Addr base, start, end; + Dwarf_Addr base, start, end = 0; Dwarf_Op *ops; size_t nops; struct die_var_type *vt; @@ -1681,6 +1681,8 @@ static int __die_collect_vars_cb(Dwarf_Die *die_mem, void *arg) vt->die_off = dwarf_dieoffset(&type_die); vt->addr = start; + vt->end = end; + vt->has_range = (end != 0 || start != 0); vt->reg = reg_from_dwarf_op(ops); vt->offset = offset_from_dwarf_op(ops); vt->next = *var_types; @@ -1743,6 +1745,8 @@ static int __die_collect_global_vars_cb(Dwarf_Die *die_mem, void *arg) vt->die_off = dwarf_dieoffset(&type_die); vt->addr = ops->number; + vt->end = 0; + vt->has_range = false; vt->reg = -1; vt->offset = 0; vt->next = *var_types; diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 939a59c91796..a79968a2e573 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -148,10 +148,12 @@ struct die_var_type { struct die_var_type *next; u64 die_off; u64 addr; + u64 end; /* end address of location range */ int reg; int offset; /* Whether the register holds a address to the type */ bool is_reg_var_addr; + bool has_range; /* whether end is valid */ }; /* Return type info of a member at offset */ |
