All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] perf probe: Ignore tail calls to probed functions
@ 2015-04-30 11:42 Naveen N. Rao
  2015-04-30 13:06 ` Masami Hiramatsu
  2015-05-15  6:46 ` [tip:perf/core] " tip-bot for Naveen N. Rao
  0 siblings, 2 replies; 6+ messages in thread
From: Naveen N. Rao @ 2015-04-30 11:42 UTC (permalink / raw)
  To: acme, masami.hiramatsu.pt; +Cc: linux-kernel

perf probe currently errors out if there are any tail calls to probed
functions:

[root@rhel71be]# perf probe do_fork
Failed to find probe point in any functions.
  Error: Failed to add events.

Fix this by teaching perf to ignore tail calls.

Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
---
I'm seeing this with RHEL7 kernels on ppc64. The specific example in this case is do_fork:

   <1><82e7e1>: Abbrev Number: 118 (DW_TAG_subprogram)
      <82e7e2>   DW_AT_external    : 1
      <82e7e2>   DW_AT_name        : (indirect string, offset: 0x3dfe0): do_fork
      <82e7e6>   DW_AT_decl_file   : 7
      <82e7e7>   DW_AT_decl_line   : 1583
      <82e7e9>   DW_AT_prototyped  : 1
      <82e7e9>   DW_AT_type        : <0x8110eb>
      <82e7ed>   DW_AT_inline      : 1    (inlined)
      <82e7ee>   DW_AT_sibling     : <0x82e878>

<snip>

   <1><830081>: Abbrev Number: 133 (DW_TAG_subprogram)
      <830083>   DW_AT_external    : 1
      <830083>   DW_AT_name        : (indirect string, offset: 0x3cea3): SyS_clone
      <830087>   DW_AT_decl_file   : 7
      <830088>   DW_AT_decl_line   : 1689
      <83008a>   DW_AT_prototyped  : 1
      <83008a>   DW_AT_type        : <0x8110eb>
      <83008e>   DW_AT_low_pc      : 0xc0000000000bc270
      <830096>   DW_AT_high_pc     : 0xc
      <83009e>   DW_AT_frame_base  : 1 byte block: 9c (DW_OP_call_frame_cfa)
      <8300a0>   DW_AT_GNU_all_call_sites: 1
      <8300a0>   DW_AT_sibling     : <0x830178>

<snip>

   <3><830147>: Abbrev Number: 125 (DW_TAG_GNU_call_site)
      <830148>   DW_AT_low_pc      : 0xc0000000000bc27c
      <830150>   DW_AT_GNU_tail_call: 1
      <830150>   DW_AT_abstract_origin: <0x82e7e1>


- Naveen

 tools/perf/util/dwarf-aux.c    | 37 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/dwarf-aux.h    |  4 ++++
 tools/perf/util/probe-finder.c | 12 +++++++++---
 3 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index c34e024..851a76f 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -417,6 +417,43 @@ struct __addr_die_search_param {
 	Dwarf_Die	*die_mem;
 };
 
+static int __die_search_func_tail_cb(Dwarf_Die *fn_die, void *data)
+{
+	struct __addr_die_search_param *ad = data;
+	Dwarf_Addr addr = 0;
+
+	if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
+	    !dwarf_highpc(fn_die, &addr) &&
+	    addr == ad->addr) {
+		memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
+		return DWARF_CB_ABORT;
+	}
+	return DWARF_CB_OK;
+}
+
+/**
+ * die_find_tailfunc - Search for a non-inlined function with tail call at
+ * given address
+ * @cu_die: a CU DIE which including @addr
+ * @addr: target address
+ * @die_mem: a buffer for result DIE
+ *
+ * Search for a non-inlined function DIE with tail call at @addr. Stores the
+ * DIE to @die_mem and returns it if found. Returns NULL if failed.
+ */
+Dwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
+				    Dwarf_Die *die_mem)
+{
+	struct __addr_die_search_param ad;
+	ad.addr = addr;
+	ad.die_mem = die_mem;
+	/* dwarf_getscopes can't find subprogram. */
+	if (!dwarf_getfuncs(cu_die, __die_search_func_tail_cb, &ad, 0))
+		return NULL;
+	else
+		return die_mem;
+}
+
 /* die_find callback for non-inlined function search */
 static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
 {
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index af7dbcd..c9278ed 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -82,6 +82,10 @@ extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
 extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
 				    Dwarf_Die *die_mem);
 
+/* Search a non-inlined function with tail call at given address */
+Dwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
+				    Dwarf_Die *die_mem);
+
 /* Search the top inlined function including given address */
 extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 					  Dwarf_Die *die_mem);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index b5bf9d5..4cb461e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -660,9 +660,15 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 	/* If not a real subprogram, find a real one */
 	if (!die_is_func_def(sc_die)) {
 		if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
-			pr_warning("Failed to find probe point in any "
-				   "functions.\n");
-			return -ENOENT;
+			if (die_find_tailfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
+				pr_warning("Ignoring tail call from %s\n",
+						dwarf_diename(&pf->sp_die));
+				return 0;
+			} else {
+				pr_warning("Failed to find probe point in any "
+					   "functions.\n");
+				return -ENOENT;
+			}
 		}
 	} else
 		memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-05-15  6:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-30 11:42 [PATCH] perf probe: Ignore tail calls to probed functions Naveen N. Rao
2015-04-30 13:06 ` Masami Hiramatsu
2015-04-30 14:58   ` Naveen N. Rao
2015-04-30 23:41     ` Masami Hiramatsu
2015-05-12 13:40       ` Arnaldo Carvalho de Melo
2015-05-15  6:46 ` [tip:perf/core] " tip-bot for Naveen N. Rao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.