perf probe: Fix to handle optimized not-inlined functions
Fix to handle optimized no-inline functions which have only function definition but no actual instance at that point. To fix this problem, we need to find actual instance of the function. Without this patch: ---- # perf probe -a __up Failed to get entry address of __up. Error: Failed to add events. # perf probe -L __up Specified source line is not found. Error: Failed to show lines. ---- With this patch: ---- # perf probe -a __up Added new event: probe:__up (on __up) You can now use it in all perf tools, such as: perf record -e probe:__up -aR sleep 1 # perf probe -L __up <__up@/home/fedora/ksrc/linux-3/kernel/locking/semaphore.c:0> 0 static noinline void __sched __up(struct semaphore *sem) { struct semaphore_waiter *waiter = list_first_entry(&sem->wait_ struct semaphore_waite 4 list_del(&waiter->list); 5 waiter->up = true; 6 wake_up_process(waiter->task); 7 } ---- Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20150130093744.30575.43290.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
a3c0cc2ac0
commit
e1ecbbc3fa
@ -277,6 +277,21 @@ bool die_is_func_def(Dwarf_Die *dw_die)
|
||||
dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* die_is_func_instance - Ensure that this DIE is an instance of a subprogram
|
||||
* @dw_die: a DIE
|
||||
*
|
||||
* Ensure that this DIE is an instance (which has an entry address).
|
||||
* This returns true if @dw_die is a function instance. If not, you need to
|
||||
* call die_walk_instances() to find actual instances.
|
||||
**/
|
||||
bool die_is_func_instance(Dwarf_Die *dw_die)
|
||||
{
|
||||
Dwarf_Addr tmp;
|
||||
|
||||
/* Actually gcc optimizes non-inline as like as inlined */
|
||||
return !dwarf_func_inline(dw_die) && dwarf_entrypc(dw_die, &tmp) == 0;
|
||||
}
|
||||
/**
|
||||
* die_get_data_member_location - Get the data-member offset
|
||||
* @mb_die: a DIE of a member of a data structure
|
||||
|
@ -41,6 +41,9 @@ extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
|
||||
/* Ensure that this DIE is a subprogram and definition (not declaration) */
|
||||
extern bool die_is_func_def(Dwarf_Die *dw_die);
|
||||
|
||||
/* Ensure that this DIE is an instance of a subprogram */
|
||||
extern bool die_is_func_instance(Dwarf_Die *dw_die);
|
||||
|
||||
/* Compare diename and tname */
|
||||
extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
|
||||
|
||||
|
@ -915,17 +915,13 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
|
||||
dwarf_decl_line(sp_die, &pf->lno);
|
||||
pf->lno += pp->line;
|
||||
param->retval = find_probe_point_by_line(pf);
|
||||
} else if (!dwarf_func_inline(sp_die)) {
|
||||
} else if (die_is_func_instance(sp_die)) {
|
||||
/* Instances always have the entry address */
|
||||
dwarf_entrypc(sp_die, &pf->addr);
|
||||
/* Real function */
|
||||
if (pp->lazy_line)
|
||||
param->retval = find_probe_point_lazy(sp_die, pf);
|
||||
else {
|
||||
if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
|
||||
pr_warning("Failed to get entry address of "
|
||||
"%s.\n", dwarf_diename(sp_die));
|
||||
param->retval = -ENOENT;
|
||||
return DWARF_CB_ABORT;
|
||||
}
|
||||
pf->addr += pp->offset;
|
||||
/* TODO: Check the address in this function */
|
||||
param->retval = call_probe_finder(sp_die, pf);
|
||||
@ -1536,7 +1532,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
|
||||
pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
|
||||
lr->start = lf->lno_s;
|
||||
lr->end = lf->lno_e;
|
||||
if (dwarf_func_inline(sp_die))
|
||||
if (!die_is_func_instance(sp_die))
|
||||
param->retval = die_walk_instances(sp_die,
|
||||
line_range_inline_cb, lf);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user