On Wed, 11 Oct 2023 20:50:30 -0700 Namhyung Kim <namhyung@xxxxxxxxxx> wrote: > The die_find_variable_by_reg() will search for a variable or a parameter > sub-DIE in the given scope DIE where the location matches to the given > register. > > For the simpliest and most common case, memory access usually happens > with a base register and an offset to the field so the register would > hold a pointer in a variable or function parameter. Then we can find > one if it has a location expression at the (instruction) address. So > this function only handles such a simple case for now. > > In this case, the expression would have a DW_OP_regN operation where > N < 32. If the register index (N) is greater than or equal to 32, > DW_OP_regx operation with an operand which saves the value for the N > would be used. It would reject expressions with more operations. > Nice! This looks good to me. Acked-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx> Thank you, > Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx> > Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx> > --- > tools/perf/util/dwarf-aux.c | 67 +++++++++++++++++++++++++++++++++++++ > tools/perf/util/dwarf-aux.h | 12 +++++++ > 2 files changed, 79 insertions(+) > > diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c > index 10aa32334d6f..652e6e7368a2 100644 > --- a/tools/perf/util/dwarf-aux.c > +++ b/tools/perf/util/dwarf-aux.c > @@ -1245,6 +1245,73 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) > out: > return ret; > } > + > +/* Interval parameters for __die_find_var_reg_cb() */ > +struct find_var_data { > + /* Target instruction address */ > + Dwarf_Addr pc; > + /* Target register */ > + unsigned reg; > +}; > + > +/* Max number of registers DW_OP_regN supports */ > +#define DWARF_OP_DIRECT_REGS 32 > + > +/* Only checks direct child DIEs in the given scope. */ > +static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) > +{ > + struct find_var_data *data = arg; > + int tag = dwarf_tag(die_mem); > + ptrdiff_t off = 0; > + Dwarf_Attribute attr; > + Dwarf_Addr base, start, end; > + Dwarf_Op *ops; > + size_t nops; > + > + if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter) > + return DIE_FIND_CB_SIBLING; > + > + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) > + return DIE_FIND_CB_SIBLING; > + > + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { > + /* Assuming the location list is sorted by address */ > + if (end < data->pc) > + continue; > + if (start > data->pc) > + break; > + > + /* Only match with a simple case */ > + if (data->reg < DWARF_OP_DIRECT_REGS) { > + if (ops->atom == (DW_OP_reg0 + data->reg) && nops == 1) > + return DIE_FIND_CB_END; > + } else { > + if (ops->atom == DW_OP_regx && ops->number == data->reg && > + nops == 1) > + return DIE_FIND_CB_END; > + } > + } > + return DIE_FIND_CB_SIBLING; > +} > + > +/** > + * die_find_variable_by_reg - Find a variable saved in a register > + * @sc_die: a scope DIE > + * @pc: the program address to find > + * @reg: the register number to find > + * @die_mem: a buffer to save the resulting DIE > + * > + * Find the variable DIE accessed by the given register. > + */ > +Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, > + Dwarf_Die *die_mem) > +{ > + struct find_var_data data = { > + .pc = pc, > + .reg = reg, > + }; > + return die_find_child(sc_die, __die_find_var_reg_cb, &data, die_mem); > +} > #endif > > /* > diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h > index f9d765f80fb0..b6f430730bd1 100644 > --- a/tools/perf/util/dwarf-aux.h > +++ b/tools/perf/util/dwarf-aux.h > @@ -137,6 +137,10 @@ int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes); > /* Get byte offset range of given variable DIE */ > int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); > > +/* Find a variable saved in the 'reg' at given address */ > +Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, > + Dwarf_Die *die_mem); > + > #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ > > static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, > @@ -146,6 +150,14 @@ static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, > return -ENOTSUP; > } > > +static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unused, > + Dwarf_Addr pc __maybe_unused, > + int reg __maybe_unused, > + Dwarf_Die *die_mem __maybe_unused) > +{ > + return NULL; > +} > + > #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ > > #endif /* _DWARF_AUX_H */ > -- > 2.42.0.655.g421f12c284-goog > -- Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>