perf dwarf-aux: Add die_find_variable_by_reg() helper
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 simplest and most common case, memory access usually happens with a base register and an offset to the field so the register holds a pointer in a variable or function parameter. Then we can find one if it has a location expression at the (instruction) address. This function only handles such a simple case for now. In this case, the expression has 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 rejects expressions with more operations. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: linux-toolchains@vger.kernel.org Cc: linux-trace-devel@vger.kernel.org Link: https://lore.kernel.org/r/20231110000012.3538610-8-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
981620fd27
commit
3f5928e461
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user