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]
Message-Id: <1468462855-30196-14-git-send-email-acme@kernel.org>
Date:	Wed, 13 Jul 2016 23:20:49 -0300
From:	Arnaldo Carvalho de Melo <acme@...nel.org>
To:	Ingo Molnar <mingo@...nel.org>
Cc:	linux-kernel@...r.kernel.org,
	Masami Hiramatsu <mhiramat@...nel.org>,
	Ananth N Mavinakayanahalli <ananth@...ux.vnet.ibm.com>,
	Brendan Gregg <brendan.d.gregg@...il.com>,
	Hemant Kumar <hemant@...ux.vnet.ibm.com>,
	Namhyung Kim <namhyung@...nel.org>,
	Peter Zijlstra <peterz@...radead.org>,
	Arnaldo Carvalho de Melo <acme@...hat.com>
Subject: [PATCH 13/19] perf probe: Allow wildcard for cached events

From: Masami Hiramatsu <mhiramat@...nel.org>

Allo glob wildcard for reusing cached/SDT events. E.g.

  # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\*

This example adds probes for all SDT in libc.
Note that the SDTs must have been scanned by perf buildid-cache.

Committer note:

Using it to check what of those SDT probes would take place when doing
a cargo run (rust):

  # trace --no-sys --event sdt_libc:* cargo run
     0.000 sdt_libc:setjmp:(7f326b69c4d1))
    28.423 sdt_libc:setjmp:(7f4b0a5364d1))
    29.000 sdt_libc:setjmp:(7f4b0a5364d1))
    88.597 sdt_libc:setjmp:(7fc01fd414d1))
    89.220 sdt_libc:setjmp:(7fc01fd414d1))
    95.501 sdt_libc:setjmp:(7f326b69c4d1))
     Running `target/debug/hello_world`
    97.110 sdt_libc:setjmp:(7f95e09234d1))
  Hello, world!
  #

Signed-off-by: Masami Hiramatsu <mhiramat@...nel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@...hat.com>
Cc: Ananth N Mavinakayanahalli <ananth@...ux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@...il.com>
Cc: Hemant Kumar <hemant@...ux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung@...nel.org>
Cc: Peter Zijlstra <peterz@...radead.org>
Link: http://lkml.kernel.org/r/146831791813.17065.17846564230840594888.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@...hat.com>
---
 tools/perf/util/probe-event.c | 107 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-file.c  |  38 ++++++++++++---
 tools/perf/util/probe-file.h  |   3 ++
 3 files changed, 138 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 85f25d41cf8d..7b96e687568e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1204,7 +1204,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
 	ptr = strchr(*arg, ':');
 	if (ptr) {
 		*ptr = '\0';
-		if (!is_c_func_name(*arg))
+		if (!pev->sdt && !is_c_func_name(*arg))
 			goto ng_name;
 		pev->group = strdup(*arg);
 		if (!pev->group)
@@ -1212,7 +1212,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
 		*arg = ptr + 1;
 	} else
 		pev->group = NULL;
-	if (!is_c_func_name(*arg)) {
+	if (!pev->sdt && !is_c_func_name(*arg)) {
 ng_name:
 		semantic_error("%s is bad for event name -it must "
 			       "follow C symbol-naming rule.\n", *arg);
@@ -1644,6 +1644,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
 			ret = -ENOMEM;
 			goto out;
 		}
+		tev->uprobes = (tp->module[0] == '/');
 		p++;
 	} else
 		p = argv[1];
@@ -2518,7 +2519,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 	int ret;
 
 	/* If probe_event or trace_event already have the name, reuse it */
-	if (pev->event)
+	if (pev->event && !pev->sdt)
 		event = pev->event;
 	else if (tev->event)
 		event = tev->event;
@@ -2531,7 +2532,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev,
 		else
 			event = tev->point.realname;
 	}
-	if (pev->group)
+	if (pev->group && !pev->sdt)
 		group = pev->group;
 	else if (tev->group)
 		group = tev->group;
@@ -2894,6 +2895,100 @@ errout:
 
 bool __weak arch__prefers_symtab(void) { return false; }
 
+/* Concatinate two arrays */
+static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b)
+{
+	void *ret;
+
+	ret = malloc(sz_a + sz_b);
+	if (ret) {
+		memcpy(ret, a, sz_a);
+		memcpy(ret + sz_a, b, sz_b);
+	}
+	return ret;
+}
+
+static int
+concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs,
+			  struct probe_trace_event **tevs2, int ntevs2)
+{
+	struct probe_trace_event *new_tevs;
+	int ret = 0;
+
+	if (ntevs == 0) {
+		*tevs = *tevs2;
+		*ntevs = ntevs2;
+		*tevs2 = NULL;
+		return 0;
+	}
+
+	if (*ntevs + ntevs2 > probe_conf.max_probes)
+		ret = -E2BIG;
+	else {
+		/* Concatinate the array of probe_trace_event */
+		new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs),
+				  *tevs2, ntevs2 * sizeof(**tevs2));
+		if (!new_tevs)
+			ret = -ENOMEM;
+		else {
+			free(*tevs);
+			*tevs = new_tevs;
+			*ntevs += ntevs2;
+		}
+	}
+	if (ret < 0)
+		clear_probe_trace_events(*tevs2, ntevs2);
+	zfree(tevs2);
+
+	return ret;
+}
+
+/*
+ * Try to find probe_trace_event from given probe caches. Return the number
+ * of cached events found, if an error occurs return the error.
+ */
+static int find_cached_events(struct perf_probe_event *pev,
+			      struct probe_trace_event **tevs,
+			      const char *target)
+{
+	struct probe_cache *cache;
+	struct probe_cache_entry *entry;
+	struct probe_trace_event *tmp_tevs = NULL;
+	int ntevs = 0;
+	int ret = 0;
+
+	cache = probe_cache__new(target);
+	/* Return 0 ("not found") if the target has no probe cache. */
+	if (!cache)
+		return 0;
+
+	for_each_probe_cache_entry(entry, cache) {
+		/* Skip the cache entry which has no name */
+		if (!entry->pev.event || !entry->pev.group)
+			continue;
+		if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) &&
+		    strglobmatch(entry->pev.event, pev->event)) {
+			ret = probe_cache_entry__get_event(entry, &tmp_tevs);
+			if (ret > 0)
+				ret = concat_probe_trace_events(tevs, &ntevs,
+								&tmp_tevs, ret);
+			if (ret < 0)
+				break;
+		}
+	}
+	probe_cache__delete(cache);
+	if (ret < 0) {
+		clear_probe_trace_events(*tevs, ntevs);
+		zfree(tevs);
+	} else {
+		ret = ntevs;
+		if (ntevs > 0 && target && target[0] == '/')
+			pev->uprobes = true;
+	}
+
+	return ret;
+}
+
 static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 					      struct probe_trace_event **tevs)
 {
@@ -2903,6 +2998,10 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
 	struct str_node *node;
 	int ret, i;
 
+	if (pev->sdt)
+		/* For SDT/cached events, we use special search functions */
+		return find_cached_events(pev, tevs, pev->target);
+
 	cache = probe_cache__new(pev->target);
 	if (!cache)
 		return 0;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index abfb05cf135b..9aed9c332da6 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -362,13 +362,38 @@ probe_cache_entry__new(struct perf_probe_event *pev)
 	return entry;
 }
 
-/* For the kernel probe caches, pass target = NULL */
+int probe_cache_entry__get_event(struct probe_cache_entry *entry,
+				 struct probe_trace_event **tevs)
+{
+	struct probe_trace_event *tev;
+	struct str_node *node;
+	int ret, i;
+
+	ret = strlist__nr_entries(entry->tevlist);
+	if (ret > probe_conf.max_probes)
+		return -E2BIG;
+
+	*tevs = zalloc(ret * sizeof(*tev));
+	if (!*tevs)
+		return -ENOMEM;
+
+	i = 0;
+	strlist__for_each_entry(node, entry->tevlist) {
+		tev = &(*tevs)[i++];
+		ret = parse_probe_trace_command(node->s, tev);
+		if (ret < 0)
+			break;
+	}
+	return i;
+}
+
+/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
 static int probe_cache__open(struct probe_cache *pcache, const char *target)
 {
 	char cpath[PATH_MAX];
 	char sbuildid[SBUILD_ID_SIZE];
 	char *dir_name = NULL;
-	bool is_kallsyms = !target;
+	bool is_kallsyms = false;
 	int ret, fd;
 
 	if (target && build_id_cache__cached(target)) {
@@ -378,12 +403,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)
 		goto found;
 	}
 
-	if (target)
-		ret = filename__sprintf_build_id(target, sbuildid);
-	else {
+	if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
 		target = DSO__NAME_KALLSYMS;
+		is_kallsyms = true;
 		ret = sysfs__sprintf_build_id("/", sbuildid);
-	}
+	} else
+		ret = filename__sprintf_build_id(target, sbuildid);
+
 	if (ret < 0) {
 		pr_debug("Failed to get build-id from %s.\n", target);
 		return ret;
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index d513b346a70e..cafbe1d3f3bf 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -34,6 +34,9 @@ int probe_file__get_events(int fd, struct strfilter *filter,
 				  struct strlist *plist);
 int probe_file__del_strlist(int fd, struct strlist *namelist);
 
+int probe_cache_entry__get_event(struct probe_cache_entry *entry,
+				 struct probe_trace_event **tevs);
+
 struct probe_cache *probe_cache__new(const char *target);
 int probe_cache__add_entry(struct probe_cache *pcache,
 			   struct perf_probe_event *pev,
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ