lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1430394151-15928-1-git-send-email-naveen.n.rao@linux.vnet.ibm.com>
Date:	Thu, 30 Apr 2015 17:12:31 +0530
From:	"Naveen N. Rao" <naveen.n.rao@...ux.vnet.ibm.com>
To:	acme@...nel.org, masami.hiramatsu.pt@...achi.com
Cc:	linux-kernel@...r.kernel.org
Subject: [PATCH] perf probe: Ignore tail calls to probed functions

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

[root@...l71be]# 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@...ux.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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ