mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
perf dwarf-aux: Add die_find_variable_by_addr()
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@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-33-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
72108c0b9c
commit
d60469d7c0
@ -1250,8 +1250,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 */
|
||||
@ -1312,6 +1316,81 @@ 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
|
||||
|
||||
/*
|
||||
|
@ -141,6 +141,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,
|
||||
@ -158,6 +163,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 */
|
||||
|
Loading…
Reference in New Issue
Block a user