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-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 22 Feb 2010 21:09:00 -0500
From:	Masami Hiramatsu <mhiramat@...hat.com>
To:	Ingo Molnar <mingo@...e.hu>, lkml <linux-kernel@...r.kernel.org>
Cc:	systemtap <systemtap@...rces.redhat.com>,
	DLE <dle-develop@...ts.sourceforge.net>,
	Masami Hiramatsu <mhiramat@...hat.com>,
	Ingo Molnar <mingo@...e.hu>,
	Frederic Weisbecker <fweisbec@...il.com>,
	Arnaldo Carvalho de Melo <acme@...hat.com>,
	Peter Zijlstra <peterz@...radead.org>,
	Paul Mackerras <paulus@...ba.org>,
	Mike Galbraith <efault@....de>,
	"K.Prasad" <prasad@...ux.vnet.ibm.com>,
	Ulrich Drepper <drepper@...hat.com>,
	Roland McGrath <roland@...hat.com>
Subject: [PATCH -tip v3 6/9] perf probe: Use libdw callback routines

Use libdw callback functions aggressively, and remove
local tree-search API. This change simplifies the code.

Changes in v3:
 - Cast Dwarf_Addr to uintmax_t for printf-formats.

Changes in v2:
 - Cast Dwarf_Addr to unsigned long long for printf-formats.


Signed-off-by: Masami Hiramatsu <mhiramat@...hat.com>
Cc: Ingo Molnar <mingo@...e.hu>
Cc: Frederic Weisbecker <fweisbec@...il.com>
Cc: Arnaldo Carvalho de Melo <acme@...hat.com>
Cc: Peter Zijlstra <peterz@...radead.org>
Cc: Paul Mackerras <paulus@...ba.org>
Cc: Mike Galbraith <efault@....de>
Cc: K.Prasad <prasad@...ux.vnet.ibm.com>
Cc: Ulrich Drepper <drepper@...hat.com>
Cc: Roland McGrath <roland@...hat.com>
---

 tools/perf/util/probe-finder.c |  262 +++++++++++++---------------------------
 tools/perf/util/probe-finder.h |    1 
 2 files changed, 86 insertions(+), 177 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c422472..6305f34 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -38,13 +38,6 @@
 #include "probe-finder.h"
 
 
-/* Dwarf_Die Linkage to parent Die */
-struct die_link {
-	struct die_link *parent;	/* Parent die */
-	Dwarf_Die die;			/* Current die */
-};
-
-
 /*
  * Generic dwarf analysis helpers
  */
@@ -177,26 +170,6 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
 	return strcmp(tname, name);
 }
 
-/* Check the address is in the subprogram(function). */
-static bool die_within_subprogram(Dwarf_Die *sp_die, Dwarf_Addr addr,
-				 size_t *offs)
-{
-	Dwarf_Addr epc;
-	int ret;
-
-	ret = dwarf_haspc(sp_die, addr);
-	if (ret <= 0)
-		return false;
-
-	if (offs) {
-		ret = dwarf_entrypc(sp_die, &epc);
-		DIE_IF(ret == -1);
-		*offs = addr - epc;
-	}
-
-	return true;
-}
-
 /* Get entry pc(or low pc, 1st entry of ranges)  of the die */
 static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
 {
@@ -208,70 +181,34 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
 	return epc;
 }
 
-/* Check if the abstract origin's address or not */
-static bool die_compare_abstract_origin(Dwarf_Die *in_die, void *origin_addr)
-{
-	Dwarf_Attribute attr;
-	Dwarf_Die origin;
-
-	if (!dwarf_attr(in_die, DW_AT_abstract_origin, &attr))
-		return false;
-	if (!dwarf_formref_die(&attr, &origin))
-		return false;
-
-	return origin.addr == origin_addr;
-}
-
-/*
- * Search a Die from Die tree.
- * Note: cur_link->die should be deallocated in this function.
- */
-static int __search_die_tree(struct die_link *cur_link,
-			     int (*die_cb)(struct die_link *, void *),
-			     void *data)
+/* Get a variable die */
+static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
+				    Dwarf_Die *die_mem)
 {
-	struct die_link new_link;
+	Dwarf_Die child_die;
+	int tag;
 	int ret;
 
-	if (!die_cb)
-		return 0;
-
-	/* Check current die */
-	while (!(ret = die_cb(cur_link, data))) {
-		/* Check child die */
-		ret = dwarf_child(&cur_link->die, &new_link.die);
-		if (ret == 0) {
-			new_link.parent = cur_link;
-			ret = __search_die_tree(&new_link, die_cb, data);
-			if (ret)
-				break;
-		}
+	ret = dwarf_child(sp_die, die_mem);
+	if (ret != 0)
+		return NULL;
 
-		/* Move to next sibling */
-		ret = dwarf_siblingof(&cur_link->die, &cur_link->die);
-		if (ret != 0)
-			return 0;
-	}
-	return ret;
-}
+	do {
+		tag = dwarf_tag(die_mem);
+		if ((tag == DW_TAG_formal_parameter ||
+		     tag == DW_TAG_variable) &&
+		    (die_compare_name(die_mem, name) == 0))
+			return die_mem;
 
-/* Search a die in its children's die tree */
-static int search_die_from_children(Dwarf_Die *parent_die,
-				    int (*die_cb)(struct die_link *, void *),
-				    void *data)
-{
-	struct die_link new_link;
-	int ret;
+		if (die_find_variable(die_mem, name, &child_die)) {
+			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
+			return die_mem;
+		}
+	} while (dwarf_siblingof(die_mem, die_mem) == 0);
 
-	new_link.parent = NULL;
-	ret = dwarf_child(parent_die, &new_link.die);
-	if (ret == 0)
-		return __search_die_tree(&new_link, die_cb, data);
-	else
-		return 0;
+	return NULL;
 }
 
-
 /*
  * Probe finder related functions
  */
@@ -347,28 +284,13 @@ error:
 	    " Perhaps, it has been optimized out.", pf->var);
 }
 
-static int variable_search_cb(struct die_link *dlink, void *data)
-{
-	struct probe_finder *pf = (struct probe_finder *)data;
-	int tag;
-
-	tag = dwarf_tag(&dlink->die);
-	DIE_IF(tag < 0);
-	if ((tag == DW_TAG_formal_parameter ||
-	     tag == DW_TAG_variable) &&
-	    (die_compare_name(&dlink->die, pf->var) == 0)) {
-		show_variable(&dlink->die, pf);
-		return 1;
-	}
-	/* TODO: Support struct members and arrays */
-	return 0;
-}
-
 /* Find a variable in a subprogram die */
 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
 	int ret;
+	Dwarf_Die vr_die;
 
+	/* TODO: Support struct members and arrays */
 	if (!is_c_varname(pf->var)) {
 		/* Output raw parameters */
 		ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -379,31 +301,42 @@ static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 	pr_debug("Searching '%s' variable in context.\n", pf->var);
 	/* Search child die for local variables and parameters. */
-	ret = search_die_from_children(sp_die, variable_search_cb, pf);
-	if (!ret)
+	if (!die_find_variable(sp_die, pf->var, &vr_die))
 		die("Failed to find '%s' in this function.", pf->var);
+
+	show_variable(&vr_die, pf);
 }
 
 /* Show a probe point to output buffer */
-static void show_probe_point(Dwarf_Die *sp_die, size_t offs,
-			     struct probe_finder *pf)
+static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
 	struct probe_point *pp = pf->pp;
+	Dwarf_Addr eaddr;
+	Dwarf_Die die_mem;
 	const char *name;
 	char tmp[MAX_PROBE_BUFFER];
 	int ret, i, len;
 	Dwarf_Attribute fb_attr;
 	size_t nops;
 
+	/* If no real subprogram, find a real one */
+	if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
+		sp_die = die_get_real_subprogram(&pf->cu_die,
+						 pf->addr, &die_mem);
+		if (!sp_die)
+			die("Probe point is not found in subprograms.");
+	}
+
 	/* Output name of probe point */
 	name = dwarf_diename(sp_die);
 	if (name) {
-		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
-				(unsigned int)offs);
+		dwarf_entrypc(sp_die, &eaddr);
+		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
+				(unsigned long)(pf->addr - eaddr));
 		/* Copy the function name if possible */
 		if (!pp->function) {
 			pp->function = strdup(name);
-			pp->offset = offs;
+			pp->offset = (size_t)(pf->addr - eaddr);
 		}
 	} else {
 		/* This function has no name. */
@@ -450,10 +383,9 @@ static void find_probe_point_by_line(struct probe_finder *pf)
 	Dwarf_Lines *lines;
 	Dwarf_Line *line;
 	size_t nlines, i;
-	Dwarf_Addr addr, epc;
+	Dwarf_Addr addr;
 	int lineno;
 	int ret;
-	Dwarf_Die *sp_die, die_mem;
 
 	ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
 	DIE_IF(ret != 0);
@@ -474,77 +406,57 @@ static void find_probe_point_by_line(struct probe_finder *pf)
 			 (int)i, lineno, (uintmax_t)addr);
 		pf->addr = addr;
 
-		sp_die = die_get_real_subprogram(&pf->cu_die, addr, &die_mem);
-		if (!sp_die)
-			die("Probe point is not found in subprograms.");
-		dwarf_entrypc(sp_die, &epc);
-		show_probe_point(sp_die, (size_t)(addr - epc), pf);
+		show_probe_point(NULL, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 }
 
+static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
+{
+	struct probe_finder *pf = (struct probe_finder *)data;
+	struct probe_point *pp = pf->pp;
+
+	/* Get probe address */
+	pf->addr = die_get_entrypc(in_die);
+	pf->addr += pp->offset;
+	pr_debug("found inline addr: 0x%jx\n", (uintmax_t)pf->addr);
+
+	show_probe_point(in_die, pf);
+	return DWARF_CB_OK;
+}
 
 /* Search function from function name */
-static int probe_point_search_cb(struct die_link *dlink, void *data)
+static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
 	struct probe_finder *pf = (struct probe_finder *)data;
 	struct probe_point *pp = pf->pp;
-	struct die_link *lk;
-	size_t offs;
-	int tag;
-	int ret;
 
-	tag = dwarf_tag(&dlink->die);
-	if (tag == DW_TAG_subprogram) {
-		if (die_compare_name(&dlink->die, pp->function) == 0) {
-			if (pp->line) {	/* Function relative line */
-				pf->fname = dwarf_decl_file(&dlink->die);
-				dwarf_decl_line(&dlink->die, &pf->lno);
-				pf->lno += pp->line;
-				find_probe_point_by_line(pf);
-				return 1;
-			}
-			if (dwarf_func_inline(&dlink->die)) {
-				/* Inlined function, save it. */
-				pf->origin = dlink->die.addr;
-				return 0;	/* Continue to search */
-			}
-			/* Get probe address */
-			pf->addr = die_get_entrypc(&dlink->die);
-			pf->addr += pp->offset;
-			/* TODO: Check the address in this function */
-			show_probe_point(&dlink->die, pp->offset, pf);
-			return 1; /* Exit; no same symbol in this CU. */
-		}
-	} else if (tag == DW_TAG_inlined_subroutine && pf->origin) {
-		if (die_compare_abstract_origin(&dlink->die, pf->origin)) {
-			/* Get probe address */
-			pf->addr = die_get_entrypc(&dlink->die);
-			pf->addr += pp->offset;
-			pr_debug("found inline addr: 0x%jx\n",
-				 (uintmax_t)pf->addr);
-			/* Inlined function. Get a real subprogram */
-			for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
-				tag = dwarf_tag(&lk->die);
-				if (tag == DW_TAG_subprogram &&
-				    !dwarf_func_inline(&lk->die))
-					goto found;
-			}
-			die("Failed to find real subprogram.");
-found:
-			/* Get offset from subprogram */
-			ret = die_within_subprogram(&lk->die, pf->addr, &offs);
-			DIE_IF(!ret);
-			show_probe_point(&lk->die, offs, pf);
-			/* Continue to search */
-		}
-	}
-	return 0;
+	/* Check tag and diename */
+	if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
+	    die_compare_name(sp_die, pp->function) != 0)
+		return 0;
+
+	if (pp->line) { /* Function relative line */
+		pf->fname = dwarf_decl_file(sp_die);
+		dwarf_decl_line(sp_die, &pf->lno);
+		pf->lno += pp->line;
+		find_probe_point_by_line(pf);
+	} else if (!dwarf_func_inline(sp_die)) {
+		/* Real function */
+		pf->addr = die_get_entrypc(sp_die);
+		pf->addr += pp->offset;
+		/* TODO: Check the address in this function */
+		show_probe_point(sp_die, pf);
+	} else
+		/* Inlined function: search instances */
+		dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
+
+	return 1; /* Exit; no same symbol in this CU. */
 }
 
 static void find_probe_point_by_func(struct probe_finder *pf)
 {
-	search_die_from_children(&pf->cu_die, probe_point_search_cb, pf);
+	dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
 }
 
 /* Find a probe point */
@@ -669,27 +581,25 @@ static void find_line_range_by_line(struct line_finder *lf)
 }
 
 /* Search function from function name */
-static int line_range_search_cb(struct die_link *dlink, void *data)
+static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 {
 	struct line_finder *lf = (struct line_finder *)data;
 	struct line_range *lr = lf->lr;
-	int tag;
 	int ret;
 
-	tag = dwarf_tag(&dlink->die);
-	if (tag == DW_TAG_subprogram &&
-	    die_compare_name(&dlink->die, lr->function) == 0) {
+	if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
+	    die_compare_name(sp_die, lr->function) == 0) {
 		/* Get the address range of this function */
-		ret = dwarf_highpc(&dlink->die, &lf->addr_e);
+		ret = dwarf_highpc(sp_die, &lf->addr_e);
 		if (ret == 0)
-			ret = dwarf_lowpc(&dlink->die, &lf->addr_s);
+			ret = dwarf_lowpc(sp_die, &lf->addr_s);
 		if (ret != 0) {
 			lf->addr_s = 0;
 			lf->addr_e = 0;
 		}
 
-		lf->fname = dwarf_decl_file(&dlink->die);
-		dwarf_decl_line(&dlink->die, &lr->offset);
+		lf->fname = dwarf_decl_file(sp_die);
+		dwarf_decl_line(sp_die, &lr->offset);
 		pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
 		lf->lno_s = lr->offset + lr->start;
 		if (!lr->end)
@@ -706,7 +616,7 @@ static int line_range_search_cb(struct die_link *dlink, void *data)
 
 static void find_line_range_by_func(struct line_finder *lf)
 {
-	search_die_from_children(&lf->cu_die, line_range_search_cb, lf);
+	dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
 }
 
 int find_line_range(int fd, struct line_range *lr)
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 9dd4a88..74525ae 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -66,7 +66,6 @@ struct probe_finder {
 	Dwarf_Addr		addr;		/* Address */
 	const char		*fname;		/* File name */
 	int			lno;		/* Line number */
-	void			*origin;	/* Inline origin addr */
 	Dwarf_Die		cu_die;		/* Current CU */
 
 	/* For variable searching */


-- 
Masami Hiramatsu

Software Engineer
Hitachi Computer Products (America), Inc.
Software Solutions Division

e-mail: mhiramat@...hat.com
--
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