[PATCH 4/5] perf/sdt/powerpc: Add argument support

From: Ravi Bangoria
Date: Thu Feb 02 2017 - 06:13:07 EST


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@xxxxxxxxxxxxxxxxxx>
---
tools/perf/arch/powerpc/util/perf_regs.c | 115 +++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)

diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
index a3c3e1c..bbd6f91 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,113 @@ const struct sample_reg sample_reg_masks[] = {
SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR),
SMPL_REG_END
};
+
+bool arch_sdt_probe_arg_supp(void)
+{
+ return true;
+}
+
+static regex_t regex1, regex2;
+
+static int init_op_regex(void)
+{
+ static int initialized;
+
+ if (initialized)
+ return 0;
+
+ /* REG or %rREG */
+ if (regcomp(&regex1, "^(%r)?([1-2]?[0-9]|3[0-1])$", REG_EXTENDED))
+ goto error;
+
+ /* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
+ if (regcomp(&regex2, "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$",
+ REG_EXTENDED))
+ goto free_regex1;
+
+ initialized = 1;
+ return 0;
+
+free_regex1:
+ regfree(&regex1);
+error:
+ pr_debug4("Regex compilation error.\n");
+ return -1;
+}
+
+/*
+ * 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.
+ *
+ * return value of the function:
+ * <0 : error
+ * 0 : success
+ * >0 : skip
+ */
+int arch_sdt_probe_parse_op(char **desc, const char **prefix)
+{
+ char *tmp = NULL;
+ size_t new_len;
+ regmatch_t rm[5];
+
+ /* Constant argument. Uprobe does not support it */
+ if (*desc[0] == 'i') {
+ pr_debug4("Skipping unsupported SDT argument: %s\n", *desc);
+ return 1;
+ }
+
+ if (init_op_regex() < 0)
+ return -1;
+
+ if (!regexec(&regex1, *desc, 3, rm, 0)) {
+ /* REG or %rREG --> %gprREG */
+ new_len = 5;
+ new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+
+ tmp = zalloc(new_len);
+ if (!tmp)
+ return -1;
+
+ scnprintf(tmp, new_len, "%%gpr%.*s",
+ (int)(rm[2].rm_eo - rm[2].rm_so), *desc + rm[2].rm_so);
+ } else if (!regexec(&regex2, *desc, 5, rm, 0)) {
+ /*
+ * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
+ * +/-NUM(%gprREG)
+ */
+ *prefix = (rm[1].rm_so == -1) ? "+" : "-";
+
+ new_len = 7;
+ new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+ new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
+
+ tmp = zalloc(new_len);
+ if (!tmp)
+ return -1;
+
+ scnprintf(tmp, new_len, "%.*s(%%gpr%.*s)",
+ (int)(rm[2].rm_eo - rm[2].rm_so), *desc + rm[2].rm_so,
+ (int)(rm[4].rm_eo - rm[4].rm_so), *desc + rm[4].rm_so);
+ } else {
+ pr_debug4("Skipping unsupported SDT argument: %s\n", *desc);
+ return 1;
+ }
+
+ free(*desc);
+ *desc = tmp;
+ return 0;
+}
--
2.9.3