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:   Thu, 17 Nov 2016 00:56:01 +0100
From:   Alexis Berlemont <alexis.berlemont@...il.com>
To:     linux-kernel@...r.kernel.org
Cc:     Alexis Berlemont <alexis.berlemont@...il.com>,
        peterz@...radead.org, mingo@...hat.com, acme@...nel.org,
        alexander.shishkin@...ux.intel.com
Subject: [PATCH 2/2] perf probe: add sdt probes arguments into the uprobe cmd string

An sdt probe can be associated with arguments but they were not passed
to the user probe tracing interface (uprobe_events); this patch adapts
the sdt argument descriptors according to the uprobe input format.

As the uprobe parser does not support scaled address mode, perf will
skip arguments which cannot be adapted to the uprobe format.

Here are the results:

$ perf buildid-cache -v --add test_sdt
$ perf probe -x test_sdt sdt_libfoo:table_frob
$ perf probe -x test_sdt sdt_libfoo:table_diddle
$ perf record -e sdt_libfoo:table_frob -e sdt_libfoo:table_diddle test_sdt
$ perf script
test_sdt  ...   666.255678:   sdt_libfoo:table_frob: (4004d7) arg0=0 arg1=0
test_sdt  ...   666.255683: sdt_libfoo:table_diddle: (40051a) arg0=0 arg1=0
test_sdt  ...   666.255686:   sdt_libfoo:table_frob: (4004d7) arg0=1 arg1=2
test_sdt  ...   666.255689: sdt_libfoo:table_diddle: (40051a) arg0=3 arg1=4
test_sdt  ...   666.255692:   sdt_libfoo:table_frob: (4004d7) arg0=2 arg1=4
test_sdt  ...   666.255694: sdt_libfoo:table_diddle: (40051a) arg0=6 arg1=8

Signed-off-by: Alexis Berlemont <alexis.berlemont@...il.com>
---
 tools/perf/util/probe-file.c | 176 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 172 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 436b647..a97a170 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -28,6 +28,46 @@
 #include "probe-file.h"
 #include "session.h"
 
+#ifdef HAVE_GELF_GETNOTE_SUPPORT
+
+/*
+ * Local declarations needed for adjusting gcc/gas-generated registers
+ * before filling the uprobe tracer interface.
+ */
+
+struct sdt_reg_renaming {
+	const char *sdt_name;
+	const char *uprobe_name;
+};
+
+#define REG_RENAMING(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
+#define REG_RENAMING_END {.sdt_name = NULL, .uprobe_name = NULL}
+
+static const struct sdt_reg_renaming sdt_reg_renaming_table[] = {
+	REG_RENAMING(eax, ax),
+	REG_RENAMING(rax, ax),
+	REG_RENAMING(ebx, bx),
+	REG_RENAMING(rbx, bx),
+	REG_RENAMING(ecx, cx),
+	REG_RENAMING(rcx, cx),
+	REG_RENAMING(edx, dx),
+	REG_RENAMING(rdx, dx),
+	REG_RENAMING(esi, si),
+	REG_RENAMING(rsi, si),
+	REG_RENAMING(edi, di),
+	REG_RENAMING(rdi, di),
+	REG_RENAMING(ebp, bp),
+	REG_RENAMING(rbp, bp),
+	REG_RENAMING_END,
+};
+
+static const char * const type_to_suffix[] = {
+	":s64", "", "", "", ":s32", "", ":s16", ":s8",
+	"", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
+};
+
+#endif /* HAVE_GELF_GETNOTE_SUPPORT */
+
 #define MAX_CMDLEN 256
 
 static void print_open_warning(int err, bool uprobe)
@@ -687,6 +727,133 @@ static unsigned long long sdt_note__get_addr(struct sdt_note *note)
 		 : (unsigned long long)note->addr.a64[0];
 }
 
+static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
+{
+	const struct sdt_reg_renaming *rnames;
+	char *tmp, *desc = strdup(arg);
+	const char *suffix = "";
+	int ret = -1;
+
+	if (desc == NULL) {
+		pr_debug4("Allocation error\n");
+		return ret;
+	}
+
+	/*
+	 * The uprobe tracer format does not support all the
+	 * addressing modes (notably: in x86 the scaled mode); so, we
+	 * detect ',' characters, if there is just one, there is no
+	 * use converting the sdt arg into a uprobe one.
+	 */
+	if (strchr(desc, ',')) {
+		pr_debug4("SDT argument format not supported\n");
+		goto out;
+	}
+
+	tmp = strchr(desc, '@');
+	if (tmp) {
+		long type_idx;
+		/*
+		 * Isolate the string number and convert it into a
+		 * binary value; this will be an index to get suffix
+		 * of the uprobe name (defining the type)
+		 */
+		tmp[0] = '\0';
+		type_idx = strtol(desc, NULL, 10);
+		if (type_idx == LONG_MIN ||
+			type_idx == LONG_MAX) {
+			pr_debug4("Failed to get sdt type\n");
+			goto error;
+		}
+		suffix = type_to_suffix[type_idx + 8];
+		/* Get rid of the sdt prefix which is now useless */
+		tmp++;
+		memmove(desc, tmp, strlen(tmp) + 1);
+	}
+
+	/*
+	 * The uprobe parser does not support all gas register names;
+	 * so, we have to replace them (ex. for x86_64: %rax -> %ax);
+	 * the loop below performs all the needed renamings if needed.
+	 */
+
+	for (rnames = sdt_reg_renaming_table;
+	     rnames->sdt_name != NULL; rnames++) {
+		char *new_desc, *sdt_name;
+		size_t prefix_len, uprobe_len, mid_ofs, desc_len;
+
+		sdt_name = strstr(desc, rnames->sdt_name);
+		if (sdt_name == NULL)
+			continue;
+
+		new_desc = zalloc(strlen(desc) + 1 +
+				strlen(rnames->uprobe_name) -
+				strlen(rnames->sdt_name));
+		if (new_desc == NULL)
+			goto error;
+
+		prefix_len = sdt_name - desc;
+		if (prefix_len != 0)
+			memcpy(new_desc, desc, prefix_len);
+
+		uprobe_len = strlen(rnames->uprobe_name);
+		memcpy(new_desc + prefix_len, rnames->uprobe_name, uprobe_len);
+
+		mid_ofs = prefix_len + strlen(rnames->sdt_name);
+		desc_len = strlen(desc);
+		if (mid_ofs < desc_len)
+			memcpy(new_desc + prefix_len + uprobe_len,
+				desc + mid_ofs, desc_len - mid_ofs);
+
+		free(desc);
+		desc = new_desc;
+	}
+
+	if (strbuf_addf(buf, " arg%d=%s%s", i, desc, suffix) < 0)
+		goto error;
+
+out:
+	ret = 0;
+error:
+	free(desc);
+	return ret;
+}
+
+static char *synthesize_sdt_probe_command(struct sdt_note *note,
+					const char *pathname,
+					const char *sdtgrp)
+{
+	struct strbuf buf;
+	char *ret = NULL, **args;
+	int i, args_count;
+
+	if (strbuf_init(&buf, 32) < 0)
+		return NULL;
+
+	if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
+				sdtgrp, note->name, pathname,
+				sdt_note__get_addr(note)) < 0)
+		goto error;
+
+	if (!note->args)
+		goto out;
+
+	if (note->args) {
+		args = argv_split(note->args, &args_count);
+
+		for (i = 0; i < args_count; ++i) {
+			if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0)
+				goto error;
+		}
+	}
+
+out:
+	ret = strbuf_detach(&buf, NULL);
+error:
+	strbuf_release(&buf);
+	return ret;
+}
+
 int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
 {
 	struct probe_cache_entry *entry = NULL;
@@ -723,11 +890,12 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
 			entry->pev.group = strdup(sdtgrp);
 			list_add_tail(&entry->node, &pcache->entries);
 		}
-		ret = asprintf(&buf, "p:%s/%s %s:0x%llx",
-				sdtgrp, note->name, pathname,
-				sdt_note__get_addr(note));
-		if (ret < 0)
+		buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);
+		if (!buf) {
+			ret = -ENOMEM;
 			break;
+		}
+
 		strlist__add(entry->tevlist, buf);
 		free(buf);
 		entry = NULL;
-- 
2.10.2

Powered by blists - more mailing lists