public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
To: Ingo Molnar <mingo@kernel.org>,
	Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>,
	David Ahern <dsahern@gmail.com>,
	lkml <linux-kernel@vger.kernel.org>,
	"Steven Rostedt (Red Hat)" <rostedt@goodmis.org>,
	Oleg Nesterov <oleg@redhat.com>,
	"David A. Long" <dave.long@linaro.org>,
	systemtap@sourceware.org,	yrl.pp-manager.tt@hitachi.com,
	Namhyung Kim <namhyung@kernel.org>
Subject: [PATCH -tip  2/3] perf-probe: Support dwarf on uprobe events
Date: Fri, 20 Dec 2013 10:08:00 -0000	[thread overview]
Message-ID: <20131220100259.7169.57512.stgit@kbuild-fedora.novalocal> (raw)
In-Reply-To: <20131220100255.7169.19384.stgit@kbuild-fedora.novalocal>

Support dwarf(debuginfo) based operations for uprobe events.
With this change, perf probe can analyze debuginfo of user
application binary to set up new uprobe event.
This allows perf-probe --add/--line works with -x option.
(Actually, --vars has already accepted -x option)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/builtin-probe.c    |    2 
 tools/perf/util/probe-event.c |  230 +++++++++++++++++++++++++++--------------
 2 files changed, 155 insertions(+), 77 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index b40d064..7fc566a 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -420,7 +420,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 	}
 
 #ifdef HAVE_DWARF_SUPPORT
-	if (params.show_lines && !params.uprobes) {
+	if (params.show_lines) {
 		if (params.mod_events) {
 			pr_err("  Error: Don't use --line with"
 			       " --add/--del.\n");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 05be5de..e27cecb 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -186,6 +186,90 @@ static int init_user_exec(void)
 	return ret;
 }
 
+static const char *__target_symbol;
+static struct symbol *__result_sym;
+
+static int filter_target_symbol(struct map *map __maybe_unused,
+				struct symbol *sym)
+{
+	if (strcmp(__target_symbol, sym->name) == 0) {
+		__result_sym = sym;
+		return 0;
+	}
+	return 1;
+}
+
+/* Find the offset of the symbol in the executable binary */
+static int find_symbol_offset(const char *exec, const char *function,
+			      unsigned long *offs)
+{
+	struct symbol *sym;
+	struct map *map = NULL;
+	int ret = -EINVAL;
+
+	if (!offs)
+		return -EINVAL;
+
+	map = dso__new_map(exec);
+	if (!map) {
+		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
+		goto out;
+	}
+	pr_debug("Search %s in %s\n", function, exec);
+	__target_symbol = function;
+	__result_sym = NULL;
+	if (map__load(map, filter_target_symbol)) {
+		pr_err("Failed to find %s in %s.\n", function, exec);
+		goto out;
+	}
+	sym = __result_sym;
+	if (!sym) {
+		pr_warning("Cannot find %s in DSO %s\n", function, exec);
+		goto out;
+	}
+
+	*offs = (map->start > sym->start) ?  map->start : 0;
+	*offs += sym->start + map->pgoff;
+	ret = 0;
+out:
+	if (map) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	return ret;
+}
+
+static int convert_exec_to_group(const char *exec, char **result)
+{
+	char *ptr1, *ptr2, *exec_copy;
+	char buf[64];
+	int ret;
+
+	exec_copy = strdup(exec);
+	if (!exec_copy)
+		return -ENOMEM;
+
+	ptr1 = basename(exec_copy);
+	if (!ptr1) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ptr2 = strpbrk(ptr1, "-._");
+	if (ptr2)
+		*ptr2 = '\0';
+	ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1);
+	if (ret < 0)
+		goto out;
+
+	*result = strdup(buf);
+	ret = *result ? 0 : -ENOMEM;
+
+out:
+	free(exec_copy);
+	return ret;
+}
+
 static int convert_to_perf_probe_point(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
@@ -261,6 +345,45 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 	return 0;
 }
 
+static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
+					  int ntevs, const char *exec,
+					  const char *group)
+{
+	int i, ret = 0;
+	unsigned long offset;
+	char buf[32];
+
+	if (!exec)
+		return 0;
+
+	for (i = 0; i < ntevs && ret >= 0; i++) {
+		/* Get proper offset */
+		ret = find_symbol_offset(exec, tevs[i].point.symbol, &offset);
+		if (ret < 0)
+			break;
+		offset += tevs[i].point.offset;
+		tevs[i].point.offset = 0;
+		free(tevs[i].point.symbol);
+		ret = e_snprintf(buf, 32, "0x%lx", offset);
+		if (ret < 0)
+			break;
+		tevs[i].point.module = strdup(exec);
+		tevs[i].point.symbol = strdup(buf);
+		if (!tevs[i].point.symbol || !tevs[i].point.module) {
+			ret = -ENOMEM;
+			break;
+		}
+		/* Replace group name if not given */
+		if (!group) {
+			free(tevs[i].group);
+			ret = convert_exec_to_group(exec, &tevs[i].group);
+		}
+		tevs[i].uprobes = true;
+	}
+
+	return ret;
+}
+
 static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
 					    int ntevs, const char *module)
 {
@@ -305,15 +428,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 	struct debuginfo *dinfo;
 	int ntevs, ret = 0;
 
-	if (pev->uprobes) {
-		if (need_dwarf) {
-			pr_warning("Debuginfo-analysis is not yet supported"
-					" with -x/--exec option.\n");
-			return -ENOSYS;
-		}
-		return convert_name_to_addr(pev, target);
-	}
-
 	dinfo = open_debuginfo(target);
 
 	if (!dinfo) {
@@ -332,9 +446,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 
 	if (ntevs > 0) {	/* Succeeded to find trace events */
 		pr_debug("find %d probe_trace_events.\n", ntevs);
-		if (target)
-			ret = add_module_to_probe_trace_events(*tevs, ntevs,
-							       target);
+		if (target) {
+			if (pev->uprobes)
+				ret = add_exec_to_probe_trace_events(*tevs,
+						 ntevs, target, pev->group);
+			else
+				ret = add_module_to_probe_trace_events(*tevs,
+						 ntevs, target);
+		}
 		return ret < 0 ? ret : ntevs;
 	}
 
@@ -654,9 +773,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 		return -ENOSYS;
 	}
 
-	if (pev->uprobes)
-		return convert_name_to_addr(pev, target);
-
 	return 0;
 }
 
@@ -1916,11 +2032,26 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	int ret = 0, i;
 	struct probe_trace_event *tev;
 
+	if (pev->uprobes)
+		if (!pev->group) {
+			ret = convert_exec_to_group(target, &pev->group);
+			if (ret != 0) {
+				pr_warning("Failed to make group name.\n");
+				return ret;
+			}
+		}
+
 	/* Convert perf_probe_event with debuginfo */
 	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
 	if (ret != 0)
 		return ret;	/* Found in debuginfo or got an error */
 
+	if (pev->uprobes) {
+		ret = convert_name_to_addr(pev, target);
+		if (ret < 0)
+			return ret;
+	}
+
 	/* Allocate trace event buffer */
 	tev = *tevs = zalloc(sizeof(struct probe_trace_event));
 	if (tev == NULL)
@@ -2279,88 +2410,35 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
 static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
 {
 	struct perf_probe_point *pp = &pev->point;
-	struct symbol *sym;
-	struct map *map = NULL;
-	char *function = NULL;
 	int ret = -EINVAL;
-	unsigned long long vaddr = 0;
+	unsigned long vaddr = 0;
 
 	if (!pp->function) {
 		pr_warning("No function specified for uprobes");
 		goto out;
 	}
 
-	function = strdup(pp->function);
-	if (!function) {
-		pr_warning("Failed to allocate memory by strdup.\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	map = dso__new_map(exec);
-	if (!map) {
-		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
-		goto out;
-	}
-	available_func_filter = strfilter__new(function, NULL);
-	if (map__load(map, filter_available_functions)) {
-		pr_err("Failed to load map.\n");
-		goto out;
-	}
-
-	sym = map__find_symbol_by_name(map, function, NULL);
-	if (!sym) {
-		pr_warning("Cannot find %s in DSO %s\n", function, exec);
+	ret = find_symbol_offset(exec, pp->function, &vaddr);
+	if (ret < 0)
 		goto out;
-	}
 
-	if (map->start > sym->start)
-		vaddr = map->start;
-	vaddr += sym->start + pp->offset + map->pgoff;
+	vaddr += pp->offset;
 	pp->offset = 0;
 
 	if (!pev->event) {
-		pev->event = function;
-		function = NULL;
-	}
-	if (!pev->group) {
-		char *ptr1, *ptr2, *exec_copy;
-
-		pev->group = zalloc(sizeof(char *) * 64);
-		exec_copy = strdup(exec);
-		if (!exec_copy) {
-			ret = -ENOMEM;
-			pr_warning("Failed to copy exec string.\n");
-			goto out;
-		}
+		pev->event = pp->function;
+	} else
+		free(pp->function);
 
-		ptr1 = strdup(basename(exec_copy));
-		if (ptr1) {
-			ptr2 = strpbrk(ptr1, "-._");
-			if (ptr2)
-				*ptr2 = '\0';
-			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
-					ptr1);
-			free(ptr1);
-		}
-		free(exec_copy);
-	}
-	free(pp->function);
 	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
 	if (!pp->function) {
 		ret = -ENOMEM;
 		pr_warning("Failed to allocate memory by zalloc.\n");
 		goto out;
 	}
-	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
+	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%lx", vaddr);
 	ret = 0;
 
 out:
-	if (map) {
-		dso__delete(map->dso);
-		map__delete(map);
-	}
-	if (function)
-		free(function);
 	return ret;
 }


  reply	other threads:[~2013-12-20 10:08 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-20 10:08 [PATCH -tip 0/3] perf-probe: Dwarf support for uprobes Masami Hiramatsu
2013-12-20 10:08 ` Masami Hiramatsu [this message]
2013-12-20 18:02   ` [PATCH -tip 2/3] perf-probe: Support dwarf on uprobe events Arnaldo Carvalho de Melo
2013-12-22 21:39     ` Masami Hiramatsu
2013-12-23 14:34       ` Arnaldo Carvalho de Melo
2013-12-24  1:03         ` Masami Hiramatsu
2013-12-20 10:08 ` [PATCH -tip 3/3] perf-probe: Use the actual address as a hint for uprobes Masami Hiramatsu
2013-12-20 18:04   ` Arnaldo Carvalho de Melo
2013-12-22 21:54     ` Masami Hiramatsu
2013-12-23  7:46       ` Namhyung Kim
2013-12-23 10:50         ` Masami Hiramatsu
2013-12-24  7:54           ` Namhyung Kim
2013-12-24  8:28             ` Masami Hiramatsu
2013-12-24  8:46               ` Namhyung Kim
2013-12-24 15:03                 ` Masami Hiramatsu
2013-12-20 10:08 ` [PATCH -tip 1/3] [CLEANUP] perf-probe: Expand given path to absolute path Masami Hiramatsu
2013-12-20 18:00   ` Arnaldo Carvalho de Melo
2013-12-22 21:35     ` Masami Hiramatsu
2013-12-23 14:28       ` Arnaldo Carvalho de Melo
2013-12-24  6:51         ` Masami Hiramatsu
2013-12-23  6:17   ` Namhyung Kim
2013-12-23 10:46     ` Masami Hiramatsu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20131220100259.7169.57512.stgit@kbuild-fedora.novalocal \
    --to=masami.hiramatsu.pt@hitachi.com \
    --cc=acme@ghostprotocols.net \
    --cc=dave.long@linaro.org \
    --cc=dsahern@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=namhyung@kernel.org \
    --cc=oleg@redhat.com \
    --cc=rostedt@goodmis.org \
    --cc=srikar@linux.vnet.ibm.com \
    --cc=systemtap@sourceware.org \
    --cc=yrl.pp-manager.tt@hitachi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).