On Wed, 11 Oct 2023 20:50:51 -0700 Namhyung Kim <namhyung@xxxxxxxxxx> wrote: > The die_find_variable_by_addr() is to find a variables in the given DIE > using given (PC-relative) address. Global variables will have a > location expression with DW_OP_addr which has an address so can simply > compare it with the address. > > <1><143a7>: Abbrev Number: 2 (DW_TAG_variable) > <143a8> DW_AT_name : loops_per_jiffy > <143ac> DW_AT_type : <0x1cca> > <143b0> DW_AT_external : 1 > <143b0> DW_AT_decl_file : 193 > <143b1> DW_AT_decl_line : 213 > <143b2> DW_AT_location : 9 byte block: 3 b0 46 41 82 ff ff ff ff > (DW_OP_addr: ffffffff824146b0) > > Note that the type-offset should be calculated from the base address of > the global variable. > > Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx> Looks good to me. Acked-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx> BTW, for the global variable, you can also find it via maps. Can't you? Thanks, > --- > tools/perf/util/dwarf-aux.c | 80 +++++++++++++++++++++++++++++++++++++ > tools/perf/util/dwarf-aux.h | 14 +++++++ > 2 files changed, 94 insertions(+) > > diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c > index 5bb05c84d249..97d9ae56350e 100644 > --- a/tools/perf/util/dwarf-aux.c > +++ b/tools/perf/util/dwarf-aux.c > @@ -1266,8 +1266,12 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) > struct find_var_data { > /* Target instruction address */ > Dwarf_Addr pc; > + /* Target memory address (for global data) */ > + Dwarf_Addr addr; > /* Target register */ > unsigned reg; > + /* Access offset, set for global data */ > + int offset; > }; > > /* Max number of registers DW_OP_regN supports */ > @@ -1328,6 +1332,82 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, > }; > return die_find_child(sc_die, __die_find_var_reg_cb, &data, die_mem); > } > + > +/* Only checks direct child DIEs in the given scope */ > +static int __die_find_var_addr_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_Word size; > + Dwarf_Die type_die; > + Dwarf_Op *ops; > + size_t nops; > + > + if (tag != DW_TAG_variable) > + 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) { > + if (ops->atom != DW_OP_addr) > + continue; > + > + if (data->addr < ops->number) > + continue; > + > + if (data->addr == ops->number) { > + /* Update offset relative to the start of the variable */ > + data->offset = 0; > + return DIE_FIND_CB_END; > + } > + > + if (die_get_real_type(die_mem, &type_die) == NULL) > + continue; > + > + if (dwarf_aggregate_size(&type_die, &size) < 0) > + continue; > + > + if (data->addr >= ops->number + size) > + continue; > + > + /* Update offset relative to the start of the variable */ > + data->offset = data->addr - ops->number; > + return DIE_FIND_CB_END; > + } > + return DIE_FIND_CB_SIBLING; > +} > + > +/** > + * die_find_variable_by_addr - Find variable located at given address > + * @sc_die: a scope DIE > + * @pc: the program address to find > + * @addr: the data address to find > + * @die_mem: a buffer to save the resulting DIE > + * @offset: the offset in the resulting type > + * > + * Find the variable DIE located at the given address (in PC-relative mode). > + * This is usually for global variables. > + */ > +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, > + Dwarf_Addr addr, Dwarf_Die *die_mem, > + int *offset) > +{ > + struct find_var_data data = { > + .pc = pc, > + .addr = addr, > + }; > + Dwarf_Die *result; > + > + result = die_find_child(sc_die, __die_find_var_addr_cb, &data, die_mem); > + if (result) > + *offset = data.offset; > + return result; > +} > + > #endif > > /* > diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h > index 574405c57d3b..742098e3ee7e 100644 > --- a/tools/perf/util/dwarf-aux.h > +++ b/tools/perf/util/dwarf-aux.h > @@ -144,6 +144,11 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); > Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, > Dwarf_Die *die_mem); > > +/* Find a (global) variable located in the 'addr' */ > +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, > + Dwarf_Addr addr, Dwarf_Die *die_mem, > + int *offset); > + > #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ > > static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, > @@ -161,6 +166,15 @@ static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unus > return NULL; > } > > +static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused, > + Dwarf_Addr pc __maybe_unused, > + Dwarf_Addr addr __maybe_unused, > + Dwarf_Die *die_mem __maybe_unused, > + int *offset __maybe_unused) > +{ > + return NULL; > +} > + > #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ > > #endif /* _DWARF_AUX_H */ > -- > 2.42.0.655.g421f12c284-goog > > -- Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>