Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1ecbbc3 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Tested-by: default avatarArnaldo 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent a3c0cc2a
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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);

+4 −8
Original line number Diff line number Diff line
@@ -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