All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] perf/sdt: Hardening argument support
@ 2017-03-28  9:47 Ravi Bangoria
  2017-03-28  9:47 ` [PATCH v3 1/3] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers Ravi Bangoria
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Ravi Bangoria @ 2017-03-28  9:47 UTC (permalink / raw)
  To: acme, mhiramat
  Cc: alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant, Ravi Bangoria

SDT event argument support on x86 is recently added to Perf. But
there are couple of issues with it.

It lacks renaming mapping for few 8 bit registers: al, bl, cl, dl,
ah, bh, ch and dh. SDT events using these registers in arguments
are failing at 'perf probe'. Add renaming logic to them. (patch 1)

It still has x86 specific code in general code. It also fails to
convert arguments having no offset but still surrounds register with
parenthesis for ex. 8@(%rdi) is converted to +(%di):u64, which is
rejected by uprobe_events. Also, 'perf probe' is failing for *all SDT
events on all archs except x86*. Solve these issues. (patch 2)

Add argument parser for powerpc. (patch 3)

Changes in v3:
  - (patch 1) Add renaming entries for ah, bh, ch and dh registers.[1]

  - (patch 1) v2 contains silly copy-paste error. It maps all al, bl...
    registers to ax. Fix that.

  - (patch 2) Fix typo 'constant'.

  - Patch 2 is not applying cleanly on top of patch 1 after adding
    ah, bh... registers. Fix that.

v2: https://lkml.org/lkml/2017/3/27/118

This patch is prepared on top of acme/perf/core.

[1] https://lkml.org/lkml/2017/3/27/462

Ravi Bangoria (3):
  perf/sdt/x86: Add renaming logic for (missing) 8 bit registers
  perf/sdt/x86: Move OP parser to tools/perf/arch/x86/
  perf/sdt/powerpc: Add argument support

 tools/perf/arch/powerpc/util/perf_regs.c | 111 ++++++++++++++++++
 tools/perf/arch/x86/util/perf_regs.c     | 187 +++++++++++++++++++++++++------
 tools/perf/util/perf_regs.c              |   6 +-
 tools/perf/util/perf_regs.h              |  11 +-
 tools/perf/util/probe-file.c             | 132 +++++++---------------
 5 files changed, 313 insertions(+), 134 deletions(-)

-- 
2.9.3

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/3] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers
  2017-03-28  9:47 [PATCH v3 0/3] perf/sdt: Hardening argument support Ravi Bangoria
@ 2017-03-28  9:47 ` Ravi Bangoria
  2017-04-02 19:12   ` [tip:perf/core] " tip-bot for Ravi Bangoria
  2017-03-28  9:47 ` [PATCH v3 2/3] perf/sdt/x86: Move OP parser to tools/perf/arch/x86/ Ravi Bangoria
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Ravi Bangoria @ 2017-03-28  9:47 UTC (permalink / raw)
  To: acme, mhiramat
  Cc: alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant, Ravi Bangoria

I found couple of events using al, bl, cl and dl registers for
argument. These are not directly accepted by uprobe_events and
thus needs to be mapped to ax, bx, cx and dx respectively.

Few ex,

  /usr/bin/qemu-system-s390x
    css_adapter_interrupt: 1@%bl
    css_chpid_add: 1@%cl 1@%sil 1@%dl
    dma_bdrv_io: 8@%rbx 8@%rbp -8@%r14 1@%al

  /usr/bin/postgres
    buffer__read__done: ... -1@-bash -1@%al
    buffer__read__start: ... -1@%al

I don't find any sdt events using ah, bh,... registers. But I
also don't see any reason to not use them, so there might be
rare events using these registers, and if so, perf should have
a renaming logic for them too.

Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
---
 tools/perf/arch/x86/util/perf_regs.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index d8a8dcf..fa1fd19 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -40,12 +40,20 @@ struct sdt_name_reg {
 static const struct sdt_name_reg sdt_reg_renamings[] = {
 	SDT_NAME_REG(eax, ax),
 	SDT_NAME_REG(rax, ax),
+	SDT_NAME_REG(al,  ax),
+	SDT_NAME_REG(ah,  ax),
 	SDT_NAME_REG(ebx, bx),
 	SDT_NAME_REG(rbx, bx),
+	SDT_NAME_REG(bl,  bx),
+	SDT_NAME_REG(bh,  bx),
 	SDT_NAME_REG(ecx, cx),
 	SDT_NAME_REG(rcx, cx),
+	SDT_NAME_REG(cl,  cx),
+	SDT_NAME_REG(ch,  cx),
 	SDT_NAME_REG(edx, dx),
 	SDT_NAME_REG(rdx, dx),
+	SDT_NAME_REG(dl,  dx),
+	SDT_NAME_REG(dh,  dx),
 	SDT_NAME_REG(esi, si),
 	SDT_NAME_REG(rsi, si),
 	SDT_NAME_REG(sil, si),
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/3] perf/sdt/x86: Move OP parser to tools/perf/arch/x86/
  2017-03-28  9:47 [PATCH v3 0/3] perf/sdt: Hardening argument support Ravi Bangoria
  2017-03-28  9:47 ` [PATCH v3 1/3] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers Ravi Bangoria
@ 2017-03-28  9:47 ` Ravi Bangoria
  2017-04-02 19:12   ` [tip:perf/core] " tip-bot for Ravi Bangoria
  2017-03-28  9:47 ` [PATCH v3 3/3] perf/sdt/powerpc: Add argument support Ravi Bangoria
  2017-03-28 15:29 ` [PATCH v3 0/3] perf/sdt: Hardening " Masami Hiramatsu
  3 siblings, 1 reply; 10+ messages in thread
From: Ravi Bangoria @ 2017-03-28  9:47 UTC (permalink / raw)
  To: acme, mhiramat
  Cc: alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant, Ravi Bangoria

SDT marker argument is in N@OP format. N is the size of argument and
OP is the actual assembly operand. OP is arch dependent component and
hence it's parsing logic also should be placed under tools/perf/arch/.

Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
---
 tools/perf/arch/x86/util/perf_regs.c | 179 ++++++++++++++++++++++++++++-------
 tools/perf/util/perf_regs.c          |   6 +-
 tools/perf/util/perf_regs.h          |  11 ++-
 tools/perf/util/probe-file.c         | 132 ++++++++------------------
 4 files changed, 194 insertions(+), 134 deletions(-)

diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index fa1fd19..3bf3548 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -1,8 +1,10 @@
 #include <string.h>
+#include <regex.h>
 
 #include "../../perf.h"
 #include "../../util/util.h"
 #include "../../util/perf_regs.h"
+#include "../../util/debug.h"
 
 const struct sample_reg sample_reg_masks[] = {
 	SMPL_REG(AX, PERF_REG_X86_AX),
@@ -37,7 +39,7 @@ struct sdt_name_reg {
 #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
 #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
 
-static const struct sdt_name_reg sdt_reg_renamings[] = {
+static const struct sdt_name_reg sdt_reg_tbl[] = {
 	SDT_NAME_REG(eax, ax),
 	SDT_NAME_REG(rax, ax),
 	SDT_NAME_REG(al,  ax),
@@ -95,45 +97,158 @@ static const struct sdt_name_reg sdt_reg_renamings[] = {
 	SDT_NAME_REG_END,
 };
 
-int sdt_rename_register(char **pdesc, char *old_name)
+/*
+ * Perf only supports OP which is in  +/-NUM(REG)  form.
+ * Here plus-minus sign, NUM and parenthesis are optional,
+ * only REG is mandatory.
+ *
+ * SDT events also supports indirect addressing mode with a
+ * symbol as offset, scaled mode and constants in OP. But
+ * perf does not support them yet. Below are few examples.
+ *
+ * OP with scaled mode:
+ *     (%rax,%rsi,8)
+ *     10(%ras,%rsi,8)
+ *
+ * OP with indirect addressing mode:
+ *     check_action(%rip)
+ *     mp_+52(%rip)
+ *     44+mp_(%rip)
+ *
+ * OP with constant values:
+ *     $0
+ *     $123
+ *     $-1
+ */
+#define SDT_OP_REGEX  "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
+
+static regex_t sdt_op_regex;
+
+static int sdt_init_op_regex(void)
 {
-	const struct sdt_name_reg *rnames = sdt_reg_renamings;
-	char *new_desc, *old_desc = *pdesc;
-	size_t prefix_len, sdt_len, uprobe_len, old_desc_len, offset;
-	int ret = -1;
-
-	while (ret != 0 && rnames->sdt_name != NULL) {
-		sdt_len = strlen(rnames->sdt_name);
-		ret = strncmp(old_name, rnames->sdt_name, sdt_len);
-		rnames += !!ret;
-	}
+	static int initialized;
+	int ret = 0;
 
-	if (rnames->sdt_name == NULL)
+	if (initialized)
 		return 0;
 
-	sdt_len = strlen(rnames->sdt_name);
-	uprobe_len = strlen(rnames->uprobe_name);
-	old_desc_len = strlen(old_desc) + 1;
+	ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
+	if (ret < 0) {
+		pr_debug4("Regex compilation error.\n");
+		return ret;
+	}
 
-	new_desc = zalloc(old_desc_len + uprobe_len - sdt_len);
-	if (new_desc == NULL)
-		return -1;
+	initialized = 1;
+	return 0;
+}
 
-	/* Copy the chars before the register name (at least '%') */
-	prefix_len = old_name - old_desc;
-	memcpy(new_desc, old_desc, prefix_len);
+/*
+ * Max x86 register name length is 5(ex: %r15d). So, 6th char
+ * should always contain NULL. This helps to find register name
+ * length using strlen, insted of maintaing one more variable.
+ */
+#define SDT_REG_NAME_SIZE  6
 
-	/* Copy the new register name */
-	memcpy(new_desc + prefix_len, rnames->uprobe_name, uprobe_len);
+/*
+ * The uprobe parser does not support all gas register names;
+ * so, we have to replace them (ex. for x86_64: %rax -> %ax).
+ * Note: If register does not require renaming, just copy
+ * paste as it is, but don't leave it empty.
+ */
+static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
+{
+	int i = 0;
 
-	/* Copy the chars after the register name (if need be) */
-	offset = prefix_len + sdt_len;
-	if (offset < old_desc_len)
-		memcpy(new_desc + prefix_len + uprobe_len,
-			old_desc + offset, old_desc_len - offset);
+	for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
+		if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
+			strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
+			return;
+		}
+	}
 
-	free(old_desc);
-	*pdesc = new_desc;
+	strncpy(uprobe_reg, sdt_reg, sdt_len);
+}
 
-	return 0;
+int arch_sdt_arg_parse_op(char *old_op, char **new_op)
+{
+	char new_reg[SDT_REG_NAME_SIZE] = {0};
+	int new_len = 0, ret;
+	/*
+	 * rm[0]:  +/-NUM(REG)
+	 * rm[1]:  +/-
+	 * rm[2]:  NUM
+	 * rm[3]:  (
+	 * rm[4]:  REG
+	 * rm[5]:  )
+	 */
+	regmatch_t rm[6];
+	/*
+	 * Max prefix length is 2 as it may contains sign(+/-)
+	 * and displacement 0 (Both sign and displacement 0 are
+	 * optional so it may be empty). Use one more character
+	 * to hold last NULL so that strlen can be used to find
+	 * prefix length, instead of maintaing one more variable.
+	 */
+	char prefix[3] = {0};
+
+	ret = sdt_init_op_regex();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If unsupported OR does not match with regex OR
+	 * register name too long, skip it.
+	 */
+	if (strchr(old_op, ',') || strchr(old_op, '$') ||
+	    regexec(&sdt_op_regex, old_op, 6, rm, 0)   ||
+	    rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
+		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+		return SDT_ARG_SKIP;
+	}
+
+	/*
+	 * Prepare prefix.
+	 * If SDT OP has parenthesis but does not provide
+	 * displacement, add 0 for displacement.
+	 *     SDT         Uprobe     Prefix
+	 *     -----------------------------
+	 *     +24(%rdi)   +24(%di)   +
+	 *     24(%rdi)    +24(%di)   +
+	 *     %rdi        %di
+	 *     (%rdi)      +0(%di)    +0
+	 *     -80(%rbx)   -80(%bx)   -
+	 */
+	if (rm[3].rm_so != rm[3].rm_eo) {
+		if (rm[1].rm_so != rm[1].rm_eo)
+			prefix[0] = *(old_op + rm[1].rm_so);
+		else if (rm[2].rm_so != rm[2].rm_eo)
+			prefix[0] = '+';
+		else
+			strncpy(prefix, "+0", 2);
+	}
+
+	/* Rename register */
+	sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
+			    new_reg);
+
+	/* Prepare final OP which should be valid for uprobe_events */
+	new_len = strlen(prefix)              +
+		  (rm[2].rm_eo - rm[2].rm_so) +
+		  (rm[3].rm_eo - rm[3].rm_so) +
+		  strlen(new_reg)             +
+		  (rm[5].rm_eo - rm[5].rm_so) +
+		  1;					/* NULL */
+
+	*new_op = zalloc(new_len);
+	if (!*new_op)
+		return -ENOMEM;
+
+	scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
+		  strlen(prefix), prefix,
+		  (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+		  (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
+		  strlen(new_reg), new_reg,
+		  (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
+
+	return SDT_ARG_VALID;
 }
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index a37e593..b2ae039 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -6,10 +6,10 @@ const struct sample_reg __weak sample_reg_masks[] = {
 	SMPL_REG_END
 };
 
-int __weak sdt_rename_register(char **pdesc __maybe_unused,
-			char *old_name __maybe_unused)
+int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
+				 char **new_op __maybe_unused)
 {
-	return 0;
+	return SDT_ARG_SKIP;
 }
 
 #ifdef HAVE_PERF_REGS_SUPPORT
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 7544a15..32b37d1 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -15,11 +15,12 @@ struct sample_reg {
 
 extern const struct sample_reg sample_reg_masks[];
 
-/*
- * The table sdt_reg_renamings is used for adjusting gcc/gas-generated
- * registers before filling the uprobe tracer interface.
- */
-int sdt_rename_register(char **pdesc, char *old_name);
+enum {
+	SDT_ARG_VALID = 0,
+	SDT_ARG_SKIP,
+};
+
+int arch_sdt_arg_parse_op(char *old_op, char **new_op);
 
 #ifdef HAVE_PERF_REGS_SUPPORT
 #include <perf_regs.h>
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index d741634..88714de 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -694,10 +694,29 @@ static const char * const type_to_suffix[] = {
 	"", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
 };
 
+/*
+ * Isolate the string number and convert it into a decimal value;
+ * this will be an index to get suffix of the uprobe name (defining
+ * the type)
+ */
+static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
+{
+	long type_idx;
+
+	type_idx = strtol(n_ptr, NULL, 10);
+	if (type_idx < -8 || type_idx > 8) {
+		pr_debug4("Failed to get a valid sdt type\n");
+		return -1;
+	}
+
+	*suffix = type_to_suffix[type_idx + 8];
+	return 0;
+}
+
 static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
 {
-	char *tmp, *desc = strdup(arg);
-	const char *prefix = "", *suffix = "";
+	char *op, *desc = strdup(arg), *new_op = NULL;
+	const char *suffix = "";
 	int ret = -1;
 
 	if (desc == NULL) {
@@ -705,112 +724,37 @@ static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
 		return ret;
 	}
 
-	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);
-		/* Check that the conversion went OK */
-		if (type_idx == LONG_MIN || type_idx == LONG_MAX) {
-			pr_debug4("Failed to parse sdt type\n");
-			goto error;
-		}
-		/* Check that the converted value is OK */
-		if (type_idx < -8 || type_idx > 8) {
-			pr_debug4("Failed to get a valid 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 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.
+	 * Argument is in N@OP format. N is size of the argument and OP is
+	 * the actual assembly operand. N can be omitted; in that case
+	 * argument is just OP(without @).
 	 */
-	if (strchr(desc, ',')) {
-		pr_debug4("Skipping unsupported SDT argument; %s\n", desc);
-		goto out;
-	}
+	op = strchr(desc, '@');
+	if (op) {
+		op[0] = '\0';
+		op++;
 
-	/*
-	 * If the argument addressing mode is indirect, we must check
-	 * a few things...
-	 */
-	tmp = strchr(desc, '(');
-	if (tmp) {
-		int j;
-
-		/*
-		 * ...if the addressing mode is indirect with a
-		 * positive offset (ex.: "1608(%ax)"), we need to add
-		 * a '+' prefix so as to be compliant with uprobe
-		 * format.
-		 */
-		if (desc[0] != '+' && desc[0] != '-')
-			prefix = "+";
-
-		/*
-		 * ...or if the addressing mode is indirect with a symbol
-		 * as offset, the argument will not be supported by
-		 * the uprobe tracer format; so, let's skip this one.
-		 */
-		for (j = 0; j < tmp - desc; j++) {
-			if (desc[j] != '+' && desc[j] != '-' &&
-				!isdigit(desc[j])) {
-				pr_debug4("Skipping unsupported SDT argument; "
-					"%s\n", desc);
-				goto out;
-			}
-		}
+		if (sdt_arg_parse_size(desc, &suffix))
+			goto error;
+	} else {
+		op = desc;
 	}
 
-	/*
-	 * The uprobe tracer format does not support constants; if we
-	 * find one in the current argument, let's skip the argument.
-	 */
-	if (strchr(desc, '$')) {
-		pr_debug4("Skipping unsupported SDT argument; %s\n", desc);
-		goto out;
-	}
+	ret = arch_sdt_arg_parse_op(op, &new_op);
 
-	/*
-	 * 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 looks for the register names (starting with
-	 * a '%' and tries to perform the needed renamings.
-	 */
-	tmp = strchr(desc, '%');
-	while (tmp) {
-		size_t offset = tmp - desc;
+	if (ret < 0)
+		goto error;
 
-		ret = sdt_rename_register(&desc, desc + offset);
+	if (ret == SDT_ARG_VALID) {
+		ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
 		if (ret < 0)
 			goto error;
-
-		/*
-		 * The desc pointer might have changed; so, let's not
-		 * try to reuse tmp for next lookup
-		 */
-		tmp = strchr(desc + offset + 1, '%');
 	}
 
-	if (strbuf_addf(buf, " arg%d=%s%s%s", i + 1, prefix, desc, suffix) < 0)
-		goto error;
-
-out:
 	ret = 0;
 error:
 	free(desc);
+	free(new_op);
 	return ret;
 }
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/3] perf/sdt/powerpc: Add argument support
  2017-03-28  9:47 [PATCH v3 0/3] perf/sdt: Hardening argument support Ravi Bangoria
  2017-03-28  9:47 ` [PATCH v3 1/3] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers Ravi Bangoria
  2017-03-28  9:47 ` [PATCH v3 2/3] perf/sdt/x86: Move OP parser to tools/perf/arch/x86/ Ravi Bangoria
@ 2017-03-28  9:47 ` Ravi Bangoria
  2017-04-05  5:50   ` [tip:perf/core] perf sdt powerpc: " tip-bot for Ravi Bangoria
  2017-03-28 15:29 ` [PATCH v3 0/3] perf/sdt: Hardening " Masami Hiramatsu
  3 siblings, 1 reply; 10+ messages in thread
From: Ravi Bangoria @ 2017-03-28  9:47 UTC (permalink / raw)
  To: acme, mhiramat
  Cc: alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant, Ravi Bangoria

SDT marker argument is in N@OP format. Here OP is arch dependent
component. Add powerpc logic to parse OP and convert it to uprobe
compatible format.

Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
---
 tools/perf/arch/powerpc/util/perf_regs.c | 111 +++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
index a3c3e1c..390ff93 100644
--- a/tools/perf/arch/powerpc/util/perf_regs.c
+++ b/tools/perf/arch/powerpc/util/perf_regs.c
@@ -1,5 +1,10 @@
+#include <string.h>
+#include <regex.h>
+
 #include "../../perf.h"
+#include "../../util/util.h"
 #include "../../util/perf_regs.h"
+#include "../../util/debug.h"
 
 const struct sample_reg sample_reg_masks[] = {
 	SMPL_REG(r0, PERF_REG_POWERPC_R0),
@@ -47,3 +52,109 @@ const struct sample_reg sample_reg_masks[] = {
 	SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR),
 	SMPL_REG_END
 };
+
+/* REG or %rREG */
+#define SDT_OP_REGEX1  "^(%r)?([1-2]?[0-9]|3[0-1])$"
+
+/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
+#define SDT_OP_REGEX2  "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
+
+static regex_t sdt_op_regex1, sdt_op_regex2;
+
+static int sdt_init_op_regex(void)
+{
+	static int initialized;
+	int ret = 0;
+
+	if (initialized)
+		return 0;
+
+	ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
+	if (ret)
+		goto error;
+
+	ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
+	if (ret)
+		goto free_regex1;
+
+	initialized = 1;
+	return 0;
+
+free_regex1:
+	regfree(&sdt_op_regex1);
+error:
+	pr_debug4("Regex compilation error.\n");
+	return ret;
+}
+
+/*
+ * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
+ * Possible variants of OP are:
+ *	Format		Example
+ *	-------------------------
+ *	NUM(REG)	48(18)
+ *	-NUM(REG)	-48(18)
+ *	NUM(%rREG)	48(%r18)
+ *	-NUM(%rREG)	-48(%r18)
+ *	REG		18
+ *	%rREG		%r18
+ *	iNUM		i0
+ *	i-NUM		i-1
+ *
+ * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
+ * and REG form with -mno-regnames. Here REG is general purpose register,
+ * which is in 0 to 31 range.
+ */
+int arch_sdt_arg_parse_op(char *old_op, char **new_op)
+{
+	int ret, new_len;
+	regmatch_t rm[5];
+	char prefix;
+
+	/* Constant argument. Uprobe does not support it */
+	if (old_op[0] == 'i') {
+		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+		return SDT_ARG_SKIP;
+	}
+
+	ret = sdt_init_op_regex();
+	if (ret < 0)
+		return ret;
+
+	if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
+		/* REG or %rREG --> %gprREG */
+
+		new_len = 5;	/* % g p r NULL */
+		new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+
+		*new_op = zalloc(new_len);
+		if (!*new_op)
+			return -ENOMEM;
+
+		scnprintf(*new_op, new_len, "%%gpr%.*s",
+			(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
+	} else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
+		/*
+		 * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
+		 *	+/-NUM(%gprREG)
+		 */
+		prefix = (rm[1].rm_so == -1) ? '+' : '-';
+
+		new_len = 8;	/* +/- ( % g p r ) NULL */
+		new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+		new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
+
+		*new_op = zalloc(new_len);
+		if (!*new_op)
+			return -ENOMEM;
+
+		scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
+			(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+			(int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
+	} else {
+		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+		return SDT_ARG_SKIP;
+	}
+
+	return SDT_ARG_VALID;
+}
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 0/3] perf/sdt: Hardening argument support
  2017-03-28  9:47 [PATCH v3 0/3] perf/sdt: Hardening argument support Ravi Bangoria
                   ` (2 preceding siblings ...)
  2017-03-28  9:47 ` [PATCH v3 3/3] perf/sdt/powerpc: Add argument support Ravi Bangoria
@ 2017-03-28 15:29 ` Masami Hiramatsu
  2017-03-28 15:40   ` Arnaldo Carvalho de Melo
  3 siblings, 1 reply; 10+ messages in thread
From: Masami Hiramatsu @ 2017-03-28 15:29 UTC (permalink / raw)
  To: Ravi Bangoria
  Cc: acme, alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant

Hi Arnaldo,

please pull this, I've already acked to this series.

Thank you, 

On Tue, 28 Mar 2017 15:17:51 +0530
Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> wrote:

> SDT event argument support on x86 is recently added to Perf. But
> there are couple of issues with it.
> 
> It lacks renaming mapping for few 8 bit registers: al, bl, cl, dl,
> ah, bh, ch and dh. SDT events using these registers in arguments
> are failing at 'perf probe'. Add renaming logic to them. (patch 1)
> 
> It still has x86 specific code in general code. It also fails to
> convert arguments having no offset but still surrounds register with
> parenthesis for ex. 8@(%rdi) is converted to +(%di):u64, which is
> rejected by uprobe_events. Also, 'perf probe' is failing for *all SDT
> events on all archs except x86*. Solve these issues. (patch 2)
> 
> Add argument parser for powerpc. (patch 3)
> 
> Changes in v3:
>   - (patch 1) Add renaming entries for ah, bh, ch and dh registers.[1]
> 
>   - (patch 1) v2 contains silly copy-paste error. It maps all al, bl...
>     registers to ax. Fix that.
> 
>   - (patch 2) Fix typo 'constant'.
> 
>   - Patch 2 is not applying cleanly on top of patch 1 after adding
>     ah, bh... registers. Fix that.
> 
> v2: https://lkml.org/lkml/2017/3/27/118
> 
> This patch is prepared on top of acme/perf/core.
> 
> [1] https://lkml.org/lkml/2017/3/27/462
> 
> Ravi Bangoria (3):
>   perf/sdt/x86: Add renaming logic for (missing) 8 bit registers
>   perf/sdt/x86: Move OP parser to tools/perf/arch/x86/
>   perf/sdt/powerpc: Add argument support
> 
>  tools/perf/arch/powerpc/util/perf_regs.c | 111 ++++++++++++++++++
>  tools/perf/arch/x86/util/perf_regs.c     | 187 +++++++++++++++++++++++++------
>  tools/perf/util/perf_regs.c              |   6 +-
>  tools/perf/util/perf_regs.h              |  11 +-
>  tools/perf/util/probe-file.c             | 132 +++++++---------------
>  5 files changed, 313 insertions(+), 134 deletions(-)
> 
> -- 
> 2.9.3
> 


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 0/3] perf/sdt: Hardening argument support
  2017-03-28 15:29 ` [PATCH v3 0/3] perf/sdt: Hardening " Masami Hiramatsu
@ 2017-03-28 15:40   ` Arnaldo Carvalho de Melo
  2017-04-01  5:31     ` Ravi Bangoria
  0 siblings, 1 reply; 10+ messages in thread
From: Arnaldo Carvalho de Melo @ 2017-03-28 15:40 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ravi Bangoria, alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant

Em Wed, Mar 29, 2017 at 12:29:29AM +0900, Masami Hiramatsu escreveu:
> Hi Arnaldo,
> 
> please pull this, I've already acked to this series.

I did it 15 minutes ago, running build tests on it now.

- Arnaldo
 
> Thank you, 
> 
> On Tue, 28 Mar 2017 15:17:51 +0530
> Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> wrote:
> 
> > SDT event argument support on x86 is recently added to Perf. But
> > there are couple of issues with it.
> > 
> > It lacks renaming mapping for few 8 bit registers: al, bl, cl, dl,
> > ah, bh, ch and dh. SDT events using these registers in arguments
> > are failing at 'perf probe'. Add renaming logic to them. (patch 1)
> > 
> > It still has x86 specific code in general code. It also fails to
> > convert arguments having no offset but still surrounds register with
> > parenthesis for ex. 8@(%rdi) is converted to +(%di):u64, which is
> > rejected by uprobe_events. Also, 'perf probe' is failing for *all SDT
> > events on all archs except x86*. Solve these issues. (patch 2)
> > 
> > Add argument parser for powerpc. (patch 3)
> > 
> > Changes in v3:
> >   - (patch 1) Add renaming entries for ah, bh, ch and dh registers.[1]
> > 
> >   - (patch 1) v2 contains silly copy-paste error. It maps all al, bl...
> >     registers to ax. Fix that.
> > 
> >   - (patch 2) Fix typo 'constant'.
> > 
> >   - Patch 2 is not applying cleanly on top of patch 1 after adding
> >     ah, bh... registers. Fix that.
> > 
> > v2: https://lkml.org/lkml/2017/3/27/118
> > 
> > This patch is prepared on top of acme/perf/core.
> > 
> > [1] https://lkml.org/lkml/2017/3/27/462
> > 
> > Ravi Bangoria (3):
> >   perf/sdt/x86: Add renaming logic for (missing) 8 bit registers
> >   perf/sdt/x86: Move OP parser to tools/perf/arch/x86/
> >   perf/sdt/powerpc: Add argument support
> > 
> >  tools/perf/arch/powerpc/util/perf_regs.c | 111 ++++++++++++++++++
> >  tools/perf/arch/x86/util/perf_regs.c     | 187 +++++++++++++++++++++++++------
> >  tools/perf/util/perf_regs.c              |   6 +-
> >  tools/perf/util/perf_regs.h              |  11 +-
> >  tools/perf/util/probe-file.c             | 132 +++++++---------------
> >  5 files changed, 313 insertions(+), 134 deletions(-)
> > 
> > -- 
> > 2.9.3
> > 
> 
> 
> -- 
> Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 0/3] perf/sdt: Hardening argument support
  2017-03-28 15:40   ` Arnaldo Carvalho de Melo
@ 2017-04-01  5:31     ` Ravi Bangoria
  0 siblings, 0 replies; 10+ messages in thread
From: Ravi Bangoria @ 2017-04-01  5:31 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, alexis.berlemont, linux-kernel, peterz, mingo,
	alexander.shishkin, naveen.n.rao, mpe, hemant, Ravi Bangoria



On Tuesday 28 March 2017 09:10 PM, Arnaldo Carvalho de Melo wrote:
> Em Wed, Mar 29, 2017 at 12:29:29AM +0900, Masami Hiramatsu escreveu:
>> Hi Arnaldo,
>>
>> please pull this, I've already acked to this series.
> I did it 15 minutes ago, running build tests on it now.

Hi Arnaldo,

Thanks for pulling patches.

Looking at your pull request, https://lkml.org/lkml/2017/3/31/789, I think
you missed to include 3rd patch. Can you please also take that.

Let me know if you have any issues with 3rd patch.

Ravi

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [tip:perf/core] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers
  2017-03-28  9:47 ` [PATCH v3 1/3] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers Ravi Bangoria
@ 2017-04-02 19:12   ` tip-bot for Ravi Bangoria
  0 siblings, 0 replies; 10+ messages in thread
From: tip-bot for Ravi Bangoria @ 2017-04-02 19:12 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mhiramat, linux-kernel, alexander.shishkin, ravi.bangoria,
	alexis.berlemont, acme, peterz, tglx, hemant, mingo, mpe, hpa,
	naveen.n.rao

Commit-ID:  2d01ecc580405169ecd6e3880617bc61cf482fdd
Gitweb:     http://git.kernel.org/tip/2d01ecc580405169ecd6e3880617bc61cf482fdd
Author:     Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
AuthorDate: Tue, 28 Mar 2017 15:17:52 +0530
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 28 Mar 2017 12:24:56 -0300

perf/sdt/x86: Add renaming logic for (missing) 8 bit registers

I found couple of events using al, bl, cl and dl registers for argument.
These are not directly accepted by uprobe_events and thus needs to be
mapped to ax, bx, cx and dx respectively.

Few ex,

  /usr/bin/qemu-system-s390x
    css_adapter_interrupt: 1@%bl
    css_chpid_add: 1@%cl 1@%sil 1@%dl
    dma_bdrv_io: 8@%rbx 8@%rbp -8@%r14 1@%al

  /usr/bin/postgres
    buffer__read__done: ... -1@-bash -1@%al
    buffer__read__start: ... -1@%al

I don't find any sdt events using ah, bh,... registers. But I also don't
see any reason to not use them, so there might be rare events using
these registers, and if so, perf should have a renaming logic for them
too.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexis Berlemont <alexis.berlemont@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20170328094754.3156-2-ravi.bangoria@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/x86/util/perf_regs.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index d8a8dcf..fa1fd19 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -40,12 +40,20 @@ struct sdt_name_reg {
 static const struct sdt_name_reg sdt_reg_renamings[] = {
 	SDT_NAME_REG(eax, ax),
 	SDT_NAME_REG(rax, ax),
+	SDT_NAME_REG(al,  ax),
+	SDT_NAME_REG(ah,  ax),
 	SDT_NAME_REG(ebx, bx),
 	SDT_NAME_REG(rbx, bx),
+	SDT_NAME_REG(bl,  bx),
+	SDT_NAME_REG(bh,  bx),
 	SDT_NAME_REG(ecx, cx),
 	SDT_NAME_REG(rcx, cx),
+	SDT_NAME_REG(cl,  cx),
+	SDT_NAME_REG(ch,  cx),
 	SDT_NAME_REG(edx, dx),
 	SDT_NAME_REG(rdx, dx),
+	SDT_NAME_REG(dl,  dx),
+	SDT_NAME_REG(dh,  dx),
 	SDT_NAME_REG(esi, si),
 	SDT_NAME_REG(rsi, si),
 	SDT_NAME_REG(sil, si),

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [tip:perf/core] perf/sdt/x86: Move OP parser to tools/perf/arch/x86/
  2017-03-28  9:47 ` [PATCH v3 2/3] perf/sdt/x86: Move OP parser to tools/perf/arch/x86/ Ravi Bangoria
@ 2017-04-02 19:12   ` tip-bot for Ravi Bangoria
  0 siblings, 0 replies; 10+ messages in thread
From: tip-bot for Ravi Bangoria @ 2017-04-02 19:12 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: naveen.n.rao, linux-kernel, hpa, mpe, alexis.berlemont, tglx,
	hemant, mhiramat, peterz, alexander.shishkin, ravi.bangoria,
	mingo, acme

Commit-ID:  d451a205da29c5485ca634367154e83997571aa0
Gitweb:     http://git.kernel.org/tip/d451a205da29c5485ca634367154e83997571aa0
Author:     Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
AuthorDate: Tue, 28 Mar 2017 15:17:53 +0530
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 28 Mar 2017 12:25:30 -0300

perf/sdt/x86: Move OP parser to tools/perf/arch/x86/

SDT marker argument is in N@OP format. N is the size of argument and OP
is the actual assembly operand. OP is arch dependent component and hence
it's parsing logic also should be placed under tools/perf/arch/.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexis Berlemont <alexis.berlemont@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20170328094754.3156-3-ravi.bangoria@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/x86/util/perf_regs.c | 179 ++++++++++++++++++++++++++++-------
 tools/perf/util/perf_regs.c          |   6 +-
 tools/perf/util/perf_regs.h          |  11 ++-
 tools/perf/util/probe-file.c         | 132 ++++++++------------------
 4 files changed, 194 insertions(+), 134 deletions(-)

diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index fa1fd19..3bf3548 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -1,8 +1,10 @@
 #include <string.h>
+#include <regex.h>
 
 #include "../../perf.h"
 #include "../../util/util.h"
 #include "../../util/perf_regs.h"
+#include "../../util/debug.h"
 
 const struct sample_reg sample_reg_masks[] = {
 	SMPL_REG(AX, PERF_REG_X86_AX),
@@ -37,7 +39,7 @@ struct sdt_name_reg {
 #define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
 #define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
 
-static const struct sdt_name_reg sdt_reg_renamings[] = {
+static const struct sdt_name_reg sdt_reg_tbl[] = {
 	SDT_NAME_REG(eax, ax),
 	SDT_NAME_REG(rax, ax),
 	SDT_NAME_REG(al,  ax),
@@ -95,45 +97,158 @@ static const struct sdt_name_reg sdt_reg_renamings[] = {
 	SDT_NAME_REG_END,
 };
 
-int sdt_rename_register(char **pdesc, char *old_name)
+/*
+ * Perf only supports OP which is in  +/-NUM(REG)  form.
+ * Here plus-minus sign, NUM and parenthesis are optional,
+ * only REG is mandatory.
+ *
+ * SDT events also supports indirect addressing mode with a
+ * symbol as offset, scaled mode and constants in OP. But
+ * perf does not support them yet. Below are few examples.
+ *
+ * OP with scaled mode:
+ *     (%rax,%rsi,8)
+ *     10(%ras,%rsi,8)
+ *
+ * OP with indirect addressing mode:
+ *     check_action(%rip)
+ *     mp_+52(%rip)
+ *     44+mp_(%rip)
+ *
+ * OP with constant values:
+ *     $0
+ *     $123
+ *     $-1
+ */
+#define SDT_OP_REGEX  "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
+
+static regex_t sdt_op_regex;
+
+static int sdt_init_op_regex(void)
 {
-	const struct sdt_name_reg *rnames = sdt_reg_renamings;
-	char *new_desc, *old_desc = *pdesc;
-	size_t prefix_len, sdt_len, uprobe_len, old_desc_len, offset;
-	int ret = -1;
-
-	while (ret != 0 && rnames->sdt_name != NULL) {
-		sdt_len = strlen(rnames->sdt_name);
-		ret = strncmp(old_name, rnames->sdt_name, sdt_len);
-		rnames += !!ret;
-	}
+	static int initialized;
+	int ret = 0;
 
-	if (rnames->sdt_name == NULL)
+	if (initialized)
 		return 0;
 
-	sdt_len = strlen(rnames->sdt_name);
-	uprobe_len = strlen(rnames->uprobe_name);
-	old_desc_len = strlen(old_desc) + 1;
+	ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
+	if (ret < 0) {
+		pr_debug4("Regex compilation error.\n");
+		return ret;
+	}
 
-	new_desc = zalloc(old_desc_len + uprobe_len - sdt_len);
-	if (new_desc == NULL)
-		return -1;
+	initialized = 1;
+	return 0;
+}
 
-	/* Copy the chars before the register name (at least '%') */
-	prefix_len = old_name - old_desc;
-	memcpy(new_desc, old_desc, prefix_len);
+/*
+ * Max x86 register name length is 5(ex: %r15d). So, 6th char
+ * should always contain NULL. This helps to find register name
+ * length using strlen, insted of maintaing one more variable.
+ */
+#define SDT_REG_NAME_SIZE  6
 
-	/* Copy the new register name */
-	memcpy(new_desc + prefix_len, rnames->uprobe_name, uprobe_len);
+/*
+ * The uprobe parser does not support all gas register names;
+ * so, we have to replace them (ex. for x86_64: %rax -> %ax).
+ * Note: If register does not require renaming, just copy
+ * paste as it is, but don't leave it empty.
+ */
+static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
+{
+	int i = 0;
 
-	/* Copy the chars after the register name (if need be) */
-	offset = prefix_len + sdt_len;
-	if (offset < old_desc_len)
-		memcpy(new_desc + prefix_len + uprobe_len,
-			old_desc + offset, old_desc_len - offset);
+	for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
+		if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
+			strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
+			return;
+		}
+	}
 
-	free(old_desc);
-	*pdesc = new_desc;
+	strncpy(uprobe_reg, sdt_reg, sdt_len);
+}
 
-	return 0;
+int arch_sdt_arg_parse_op(char *old_op, char **new_op)
+{
+	char new_reg[SDT_REG_NAME_SIZE] = {0};
+	int new_len = 0, ret;
+	/*
+	 * rm[0]:  +/-NUM(REG)
+	 * rm[1]:  +/-
+	 * rm[2]:  NUM
+	 * rm[3]:  (
+	 * rm[4]:  REG
+	 * rm[5]:  )
+	 */
+	regmatch_t rm[6];
+	/*
+	 * Max prefix length is 2 as it may contains sign(+/-)
+	 * and displacement 0 (Both sign and displacement 0 are
+	 * optional so it may be empty). Use one more character
+	 * to hold last NULL so that strlen can be used to find
+	 * prefix length, instead of maintaing one more variable.
+	 */
+	char prefix[3] = {0};
+
+	ret = sdt_init_op_regex();
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If unsupported OR does not match with regex OR
+	 * register name too long, skip it.
+	 */
+	if (strchr(old_op, ',') || strchr(old_op, '$') ||
+	    regexec(&sdt_op_regex, old_op, 6, rm, 0)   ||
+	    rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
+		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+		return SDT_ARG_SKIP;
+	}
+
+	/*
+	 * Prepare prefix.
+	 * If SDT OP has parenthesis but does not provide
+	 * displacement, add 0 for displacement.
+	 *     SDT         Uprobe     Prefix
+	 *     -----------------------------
+	 *     +24(%rdi)   +24(%di)   +
+	 *     24(%rdi)    +24(%di)   +
+	 *     %rdi        %di
+	 *     (%rdi)      +0(%di)    +0
+	 *     -80(%rbx)   -80(%bx)   -
+	 */
+	if (rm[3].rm_so != rm[3].rm_eo) {
+		if (rm[1].rm_so != rm[1].rm_eo)
+			prefix[0] = *(old_op + rm[1].rm_so);
+		else if (rm[2].rm_so != rm[2].rm_eo)
+			prefix[0] = '+';
+		else
+			strncpy(prefix, "+0", 2);
+	}
+
+	/* Rename register */
+	sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
+			    new_reg);
+
+	/* Prepare final OP which should be valid for uprobe_events */
+	new_len = strlen(prefix)              +
+		  (rm[2].rm_eo - rm[2].rm_so) +
+		  (rm[3].rm_eo - rm[3].rm_so) +
+		  strlen(new_reg)             +
+		  (rm[5].rm_eo - rm[5].rm_so) +
+		  1;					/* NULL */
+
+	*new_op = zalloc(new_len);
+	if (!*new_op)
+		return -ENOMEM;
+
+	scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
+		  strlen(prefix), prefix,
+		  (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+		  (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
+		  strlen(new_reg), new_reg,
+		  (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
+
+	return SDT_ARG_VALID;
 }
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index a37e593..b2ae039 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -6,10 +6,10 @@ const struct sample_reg __weak sample_reg_masks[] = {
 	SMPL_REG_END
 };
 
-int __weak sdt_rename_register(char **pdesc __maybe_unused,
-			char *old_name __maybe_unused)
+int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
+				 char **new_op __maybe_unused)
 {
-	return 0;
+	return SDT_ARG_SKIP;
 }
 
 #ifdef HAVE_PERF_REGS_SUPPORT
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 7544a15..32b37d1 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -15,11 +15,12 @@ struct sample_reg {
 
 extern const struct sample_reg sample_reg_masks[];
 
-/*
- * The table sdt_reg_renamings is used for adjusting gcc/gas-generated
- * registers before filling the uprobe tracer interface.
- */
-int sdt_rename_register(char **pdesc, char *old_name);
+enum {
+	SDT_ARG_VALID = 0,
+	SDT_ARG_SKIP,
+};
+
+int arch_sdt_arg_parse_op(char *old_op, char **new_op);
 
 #ifdef HAVE_PERF_REGS_SUPPORT
 #include <perf_regs.h>
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index d741634..88714de 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -694,10 +694,29 @@ static const char * const type_to_suffix[] = {
 	"", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
 };
 
+/*
+ * Isolate the string number and convert it into a decimal value;
+ * this will be an index to get suffix of the uprobe name (defining
+ * the type)
+ */
+static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
+{
+	long type_idx;
+
+	type_idx = strtol(n_ptr, NULL, 10);
+	if (type_idx < -8 || type_idx > 8) {
+		pr_debug4("Failed to get a valid sdt type\n");
+		return -1;
+	}
+
+	*suffix = type_to_suffix[type_idx + 8];
+	return 0;
+}
+
 static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
 {
-	char *tmp, *desc = strdup(arg);
-	const char *prefix = "", *suffix = "";
+	char *op, *desc = strdup(arg), *new_op = NULL;
+	const char *suffix = "";
 	int ret = -1;
 
 	if (desc == NULL) {
@@ -705,112 +724,37 @@ static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
 		return ret;
 	}
 
-	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);
-		/* Check that the conversion went OK */
-		if (type_idx == LONG_MIN || type_idx == LONG_MAX) {
-			pr_debug4("Failed to parse sdt type\n");
-			goto error;
-		}
-		/* Check that the converted value is OK */
-		if (type_idx < -8 || type_idx > 8) {
-			pr_debug4("Failed to get a valid 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 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.
+	 * Argument is in N@OP format. N is size of the argument and OP is
+	 * the actual assembly operand. N can be omitted; in that case
+	 * argument is just OP(without @).
 	 */
-	if (strchr(desc, ',')) {
-		pr_debug4("Skipping unsupported SDT argument; %s\n", desc);
-		goto out;
-	}
+	op = strchr(desc, '@');
+	if (op) {
+		op[0] = '\0';
+		op++;
 
-	/*
-	 * If the argument addressing mode is indirect, we must check
-	 * a few things...
-	 */
-	tmp = strchr(desc, '(');
-	if (tmp) {
-		int j;
-
-		/*
-		 * ...if the addressing mode is indirect with a
-		 * positive offset (ex.: "1608(%ax)"), we need to add
-		 * a '+' prefix so as to be compliant with uprobe
-		 * format.
-		 */
-		if (desc[0] != '+' && desc[0] != '-')
-			prefix = "+";
-
-		/*
-		 * ...or if the addressing mode is indirect with a symbol
-		 * as offset, the argument will not be supported by
-		 * the uprobe tracer format; so, let's skip this one.
-		 */
-		for (j = 0; j < tmp - desc; j++) {
-			if (desc[j] != '+' && desc[j] != '-' &&
-				!isdigit(desc[j])) {
-				pr_debug4("Skipping unsupported SDT argument; "
-					"%s\n", desc);
-				goto out;
-			}
-		}
+		if (sdt_arg_parse_size(desc, &suffix))
+			goto error;
+	} else {
+		op = desc;
 	}
 
-	/*
-	 * The uprobe tracer format does not support constants; if we
-	 * find one in the current argument, let's skip the argument.
-	 */
-	if (strchr(desc, '$')) {
-		pr_debug4("Skipping unsupported SDT argument; %s\n", desc);
-		goto out;
-	}
+	ret = arch_sdt_arg_parse_op(op, &new_op);
 
-	/*
-	 * 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 looks for the register names (starting with
-	 * a '%' and tries to perform the needed renamings.
-	 */
-	tmp = strchr(desc, '%');
-	while (tmp) {
-		size_t offset = tmp - desc;
+	if (ret < 0)
+		goto error;
 
-		ret = sdt_rename_register(&desc, desc + offset);
+	if (ret == SDT_ARG_VALID) {
+		ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
 		if (ret < 0)
 			goto error;
-
-		/*
-		 * The desc pointer might have changed; so, let's not
-		 * try to reuse tmp for next lookup
-		 */
-		tmp = strchr(desc + offset + 1, '%');
 	}
 
-	if (strbuf_addf(buf, " arg%d=%s%s%s", i + 1, prefix, desc, suffix) < 0)
-		goto error;
-
-out:
 	ret = 0;
 error:
 	free(desc);
+	free(new_op);
 	return ret;
 }
 

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [tip:perf/core] perf sdt powerpc: Add argument support
  2017-03-28  9:47 ` [PATCH v3 3/3] perf/sdt/powerpc: Add argument support Ravi Bangoria
@ 2017-04-05  5:50   ` tip-bot for Ravi Bangoria
  0 siblings, 0 replies; 10+ messages in thread
From: tip-bot for Ravi Bangoria @ 2017-04-05  5:50 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mpe, naveen.n.rao, linux-kernel, acme, tglx, peterz, mhiramat,
	mingo, alexis.berlemont, hpa, hemant, alexander.shishkin,
	ravi.bangoria

Commit-ID:  f5a70801b7832bfcb865e95c39bdef8eac21226f
Gitweb:     http://git.kernel.org/tip/f5a70801b7832bfcb865e95c39bdef8eac21226f
Author:     Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
AuthorDate: Tue, 28 Mar 2017 15:17:54 +0530
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 4 Apr 2017 10:36:59 -0300

perf sdt powerpc: Add argument support

SDT marker argument is in N@OP format. Here OP is arch dependent
component. Add powerpc logic to parse OP and convert it to uprobe
compatible format.

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexis Berlemont <alexis.berlemont@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20170328094754.3156-4-ravi.bangoria@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/powerpc/util/perf_regs.c | 111 +++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
index a3c3e1c..4268f77 100644
--- a/tools/perf/arch/powerpc/util/perf_regs.c
+++ b/tools/perf/arch/powerpc/util/perf_regs.c
@@ -1,5 +1,10 @@
+#include <string.h>
+#include <regex.h>
+
 #include "../../perf.h"
+#include "../../util/util.h"
 #include "../../util/perf_regs.h"
+#include "../../util/debug.h"
 
 const struct sample_reg sample_reg_masks[] = {
 	SMPL_REG(r0, PERF_REG_POWERPC_R0),
@@ -47,3 +52,109 @@ const struct sample_reg sample_reg_masks[] = {
 	SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR),
 	SMPL_REG_END
 };
+
+/* REG or %rREG */
+#define SDT_OP_REGEX1  "^(%r)?([1-2]?[0-9]|3[0-1])$"
+
+/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
+#define SDT_OP_REGEX2  "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
+
+static regex_t sdt_op_regex1, sdt_op_regex2;
+
+static int sdt_init_op_regex(void)
+{
+	static int initialized;
+	int ret = 0;
+
+	if (initialized)
+		return 0;
+
+	ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
+	if (ret)
+		goto error;
+
+	ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
+	if (ret)
+		goto free_regex1;
+
+	initialized = 1;
+	return 0;
+
+free_regex1:
+	regfree(&sdt_op_regex1);
+error:
+	pr_debug4("Regex compilation error.\n");
+	return ret;
+}
+
+/*
+ * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
+ * Possible variants of OP are:
+ *	Format		Example
+ *	-------------------------
+ *	NUM(REG)	48(18)
+ *	-NUM(REG)	-48(18)
+ *	NUM(%rREG)	48(%r18)
+ *	-NUM(%rREG)	-48(%r18)
+ *	REG		18
+ *	%rREG		%r18
+ *	iNUM		i0
+ *	i-NUM		i-1
+ *
+ * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
+ * and REG form with -mno-regnames. Here REG is general purpose register,
+ * which is in 0 to 31 range.
+ */
+int arch_sdt_arg_parse_op(char *old_op, char **new_op)
+{
+	int ret, new_len;
+	regmatch_t rm[5];
+	char prefix;
+
+	/* Constant argument. Uprobe does not support it */
+	if (old_op[0] == 'i') {
+		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+		return SDT_ARG_SKIP;
+	}
+
+	ret = sdt_init_op_regex();
+	if (ret < 0)
+		return ret;
+
+	if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
+		/* REG or %rREG --> %gprREG */
+
+		new_len = 5;	/* % g p r NULL */
+		new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+
+		*new_op = zalloc(new_len);
+		if (!*new_op)
+			return -ENOMEM;
+
+		scnprintf(*new_op, new_len, "%%gpr%.*s",
+			(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
+	} else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
+		/*
+		 * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
+		 *	+/-NUM(%gprREG)
+		 */
+		prefix = (rm[1].rm_so == -1) ? '+' : '-';
+
+		new_len = 8;	/* +/- ( % g p r ) NULL */
+		new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+		new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
+
+		*new_op = zalloc(new_len);
+		if (!*new_op)
+			return -ENOMEM;
+
+		scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
+			(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+			(int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
+	} else {
+		pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+		return SDT_ARG_SKIP;
+	}
+
+	return SDT_ARG_VALID;
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-04-05  5:55 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-28  9:47 [PATCH v3 0/3] perf/sdt: Hardening argument support Ravi Bangoria
2017-03-28  9:47 ` [PATCH v3 1/3] perf/sdt/x86: Add renaming logic for (missing) 8 bit registers Ravi Bangoria
2017-04-02 19:12   ` [tip:perf/core] " tip-bot for Ravi Bangoria
2017-03-28  9:47 ` [PATCH v3 2/3] perf/sdt/x86: Move OP parser to tools/perf/arch/x86/ Ravi Bangoria
2017-04-02 19:12   ` [tip:perf/core] " tip-bot for Ravi Bangoria
2017-03-28  9:47 ` [PATCH v3 3/3] perf/sdt/powerpc: Add argument support Ravi Bangoria
2017-04-05  5:50   ` [tip:perf/core] perf sdt powerpc: " tip-bot for Ravi Bangoria
2017-03-28 15:29 ` [PATCH v3 0/3] perf/sdt: Hardening " Masami Hiramatsu
2017-03-28 15:40   ` Arnaldo Carvalho de Melo
2017-04-01  5:31     ` Ravi Bangoria

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.